rbmatlab  1.16.09
 All Classes Namespaces Files Functions Variables Modules Pages
fem_laplace.m
1 function U = fem_laplace(grid,params)
2 %function U = fem_laplace(grid,params)
3 %
4 % function solving the elliptic laplace problem with general dirichlet and
5 % neuman boundary data using a nodal basis. currently cartesian
6 % grid (rectgrid) is assumed and bilinear lagrange-elements. More general
7 % ansatz-functions and quadratures should be implemented in the future.
8 %
9 % Current problem: discrete gradient of the solution is not divergence
10 % free so must be divergence-cleaned if used as velocity field
11 % in other simulations
12 
13 % Bernard Haasdonk 13.4.2006:
14 
15 %if isempty(grid)
16 % grid=grid_geometry(params);
17 %end;
18 
19 if ~isa(grid,'rectgrid')
20  error('currently only rectgrid supported for fem!!');
21 end;
22 
23 % indices of points on dirichlet boundary
24  dir_vertex = zeros(size(grid.X));
25 
26  if params.verbose > 5
27  disp('entering fe_laplace');
28  end;
29 
30  % search all dirichlet edges and mark both corresponding vertices
31  if params.verbose > 5
32  disp('searching dirichlet edges');
33  end;
34  dir_edge = grid.NBI == -1;
35  nfaces = size(grid.NBI,2);
36  for i = 1:nfaces;
37  di = find(dir_edge(:,i));
38  dir_vertex(grid.VI(di,i)) = 1;
39  dir_vertex(grid.VI(di,mod(i,nfaces)+1)) = 1;
40  end;
41  dir_vind = find(dir_vertex);
42 
43  ndof = length(grid.X);
44  dirichlet_fct = zeros(ndof,1);
45 
46  params.decomp_mode = 0;
47  % determine dirichlet boundary values
48  dirichlet_fct(dir_vind) = dirichlet_values(params, grid.X(dir_vind),...
49  grid.Y(dir_vind));
50 
51  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52  % setup stiffness matrix as a sparse matrix
53  % S(i,j) = 1 if i==j and x_i is a dirichlet-vertex
54  % S(i,j) = 0 if i!=j and x_i is a dirichlet-vertex
55  % S(i,j) = int sigma * grad phi_i * grad_phi_j if x_i,j are non-dirichlet
56  %
57  % so first compute complete stiffness-matrix
58  % (then kronecker-kill later on before system solving)
59  if params.verbose > 5
60  disp('setting up stiffness matrix');
61  end;
62  %S = sparse([0]zeros(ndof));
63  S = spalloc(ndof,ndof,13*ndof);
64 
65  % in the general case: compute all local matrices simultaneously
66  % L(i,j,k) contribution of element i, local basis functions j and k
67  %
68  % in our case, L is not element-dependent, so only compute L(j,k)
69  %
70  % for cartesian grid and constant sigma the local matrix is
71  % identical for all elements
72  % domain: [0, dx] x [0, dy],
73  % counting right lower corner 1 then counterclockwise
74  % detAinv = (dx*dy)^-1
75  % grad phi_1 = detAinv * [dy-y, -x ]'
76  % grad phi_2 = detAinv * [ y, x ]'
77  % grad phi_3 = detAinv * [ -y, dx-x]'
78  % grad phi_4 = detAinv * [y-dy, x-dx]'
79  % => L(j,k) = detAinv * sigma
80  % [1/3dx^2+1/3dy^2) -1/3dx^2+1/6dy^2 -1/6dx^2-1/6dy^2 1/6dx^2-1/3dy^2
81  % XXXX 1/3dx^2+1/3dy^2 1/6dx^2-1/3dy^2 -1/6dx^2-1/6dy^2
82  % XXXX XXXX 1/3dx^2+1/3dy^2 -1/3dx^2+1/6dy^2
83  % xxxx XXXX XXXX 1/3(dx^2+dy^2) ]
84  %
85  nbasisfcts = size(grid.VI,2);
86  sigma = 1;
87  dx = (params.xrange(2)-params.xrange(1))/params.xnumintervals;
88  dy = (params.yrange(2)-params.yrange(1))/params.ynumintervals;
89 
90  Lx = [1/3 -1/3 -1/6 1/6;
91  -1/3 1/3 1/6 -1/6;
92  -1/6 1/6 1/3 -1/3;
93  1/6 -1/6 -1/3 1/3];
94 
95  Ly = [1/3 1/6 -1/6 -1/3;
96  1/6 1/3 -1/3 -1/6;
97  -1/6 -1/3 1/3 1/6;
98  -1/3 -1/6 1/6 1/3];
99 
100  L = (dx*dy)^(-1) * sigma * (Lx * dx^2 + Ly * dy^2);
101 
102  % accumulate local matrices to single operator matrix
103  % avoid large element loop, instead perform loop over pairs of
104  % local basis functions
105 
106  for j= 1:nbasisfcts
107  for k= 1:nbasisfcts
108  if params.verbose > 5
109  disp(['(j,k)=(',num2str(j),',',num2str(k),')']);
110  end;
111  global_dofs_j = grid.VI(:,j);
112  global_dofs_k = grid.VI(:,k);
113  global_dofs_ind = sub2ind(size(S),global_dofs_j,global_dofs_k);
114  if max(global_dofs_ind)>1.6e9
115  % the following code results in t = 707.5058 s for 300x150 grid
116  % cut S into column-block-pieces for ommiting large-index accesses
117  % v = lget(S,global_dofs_ind);
118  % v = v + L(j,k);
119  % S = lset(S,global_dofs_ind,v);
120  % the following code results in t = 476.4325 s for 300x150 grid
121  % for z = 1:length(global_dofs_ind)
122  % S(global_dofs_j(z),global_dofs_k(z)) = ...
123  % S(global_dofs_j(z),global_dofs_k(z)) + L(j,k);
124  % end;
125  % the following code results in t = 62s s for 300x150 grid :-)
126  % most time spent in solution of LGS
127  V = sparse(global_dofs_j, global_dofs_k, ...
128  L(j,k),size(S,1),size(S,2));
129  S = S + V;
130  else % direct subvector operation is possible
131  S(global_dofs_ind) = S(global_dofs_ind) + L(j,k);
132  % S(global_dofs_ind) = S(global_dofs_ind) + L(:,j,k);
133  end;
134  end;
135  end;
136 
137 % alternative: Loop over elements, (which is to be omitted)
138 % nelements = length(grid.A);
139 % for i = 1:nelements
140 % global_dofs_i = ...
141 % S(global_dofs_i,global_dofs_i) = ...
142 % S(global_dofs_i,global_dofs_i) + L(i,:,:);
143 % end;
144 
145  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146  % setup right hand side
147  % b(j) = T1 + T2 + T3 if x_j is a non-dirichlet vertex
148  % b(j) = 0 if x_j is a dirichlet vertex
149  %
150  % so first compute all nontrivial quantities, then set dir_vind to 0
151  %
152  %%%%%%%%% source term:
153  % T1 = int source * phi_j (2D integral)
154  % -> zero in our case as we have no source
155  if params.verbose > 5
156  disp('setting up right hand side');
157  end;
158 
159  T1 = zeros(ndof,1);
160 
161  %%%%%%%%% dirichlet term:
162  % T2 = - int sigma * grad b_dir * grad phi_j (negative of a 2D integral)
163  % after projection of b_dir to the discrete function space
164  % this is exactly the stiffness-matrix multiplied with the b_dir
165  % node values
166  T2 = - S * dirichlet_fct;
167 
168  %%%%%%%%% neuman term:
169  % T3 = int_gamma_neu b_neu * phi_j (1D integral)
170  %
171  % goal: Assume b_neu also piecewise linear -> exact integration possible
172  % for all edges, the entries of the two corresponding nodes are modified
173  T3 = zeros(ndof,1);
174 
175  % search all neuman edges and generate list of start and end points
176  neu_edge = find(grid.NBI == -2);
177  [i,j] = ind2sub(size(grid.NBI),neu_edge);
178  % list of global indices of start points
179  neu_vind1 = grid.VI(neu_edge);
180  % list of global indices of end points
181  j2 = mod(j,nfaces)+1;
182  neu_edge_plus1 = sub2ind(size(grid.NBI),i,j2);
183  neu_vind2 = grid.VI(neu_edge_plus1);
184 
185  neu_vals1= neuman_values(params, grid.X(neu_vind1),...
186  grid.Y(neu_vind1),[],[],[]);
187  neu_vals2= neuman_values(params, grid.X(neu_vind2),...
188  grid.Y(neu_vind2),[],[],[]);
189  % generate lists of neuman integral values
190  % neu_int1(neu_edgenr) is the integral contribution to start node
191  neu_lengths = grid.EL(neu_edge);
192 
193  % determine elementary integrals
194  % (phi_1 is basis function of start point, phi_2 of end point)
195  % int_edge Phi_1 Phi_1 = 1/3 |S|
196  % int_edge Phi_1 Phi_2 = 1/6 |S|
197  % int_edge Phi_2 Phi_2 = 1/3 |S|
198 
199  % neu_int1 = int_edge Phi_1 (neu_val1 * Phi1 + neu_val2 * Phi2)
200  neu_int1 = neu_lengths.* (1/3 * neu_vals1 + 1/6 * neu_vals2);
201  neu_int2 = neu_lengths.* (1/6 * neu_vals1 + 1/3 * neu_vals2);
202  T3(neu_vind1) = T3(neu_vind1) + neu_int1;
203  T3(neu_vind2) = T3(neu_vind2) + neu_int2;
204 
205  % assemble
206  b = T1 + T2 + T3;
207  b(dir_vind) = 0;
208 
209  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210  %delete dirichlet-nodes in matrix
211  S(dir_vind,:) = 0;
212  S(:,dir_vind) = 0;
213  S(dir_vind,dir_vind) = speye(length(dir_vind));
214 
215  % solve homogeneous problem
216  % U = S^-1 * b;
217  if params.verbose > 5
218  disp('solving LGS system');
219  end;
220 
221  %[U, flag] = pcg(S,b);
222 % keyboard;
223 % nonsymmetric solvers:
224 % [U, flag] = bicgstab(S,b,[],1000); => 65sec
225 % [U, flag] = cgs(S,b,[],1000); % => 47 sec
226 % symmetric solver, non pd:
227  [U, flag] = symmlq(S,b,[],1000); % => 31 sec
228 % [U, flag] = minres(S,b,[],1000); % => 31 sec
229 % symmetric solver, pd:
230 % [U, flag] = pcg(S,b,[],1000); % => 46 sec
231  if flag>0
232  disp(['error in system solution, solver return flag = ', ...
233  num2str(flag)]);
234  keyboard;
235  end;
236 
237  % add dirichlet boundary values
238  U = U + dirichlet_fct;
239 
240 % TO BE ADJUSTED TO NEW SYNTAX
241 %| \docupdate
242 
243 
244 
245 
function r = verbose(level, message, messageId)
This function displays messages depending on a message-id and/or a level. Aditionally you can set/res...
Definition: verbose.m:17
function Udirichlet = dirichlet_values(model, X, Y)
UDIRICHLET = DIRICHLET_VALUES([X],[Y], MODEL) Examples dirichlet_values([0,1,2],[1,1,1],struct(name_dirichlet_values, homogeneous, ... c_dir, 1)) dirichlet_values([0:0.1:1],[0],struct(name_dirichlet_values, xstripes, ... c_dir, [0 1 2], ... dir_borders, [0.3 0.6])) dirichlet_values([0:0.1:1],[0],struct(name_dirichlet_values, box, ... c_dir, 1, ... dir_box_xrange, [0.3 0.6], ... dir_box_yrange, [-0.1 0.1]))
A cartesian rectangular grid in two dimensions with axis parallel elements.
Definition: rectgrid.m:17