comparison +scheme/Elastic2dCurvilinearAnisotropic.m @ 1205:3258dca12af8 feature/poroelastic

Add scheme for anisotropic curvilinear
author Martin Almquist <malmquist@stanford.edu>
date Sat, 07 Sep 2019 13:05:26 -0700
parents
children 67eee83fd9c9
comparison
equal deleted inserted replaced
1204:687515778437 1205:3258dca12af8
1 classdef Elastic2dCurvilinearAnisotropic < scheme.Scheme
2
3 % Discretizes the elastic wave equation:
4 % rho u_{i,tt} = dj C_{ijkl} dk u_j
5 % in curvilinear coordinates.
6 % opSet should be cell array of opSets, one per dimension. This
7 % is useful if we have periodic BC in one direction.
8 % Assumes fully compatible operators.
9
10 properties
11 m % Number of points in each direction, possibly a vector
12 h % Grid spacing
13
14 grid
15 dim
16
17 order % Order of accuracy for the approximation
18
19 % Diagonal matrices for variable coefficients
20 J, Ji
21 RHO % Density
22 C % Elastic stiffness tensor
23
24 D % Total operator
25
26 % Boundary operators in cell format, used for BC
27 T_w, T_e, T_s, T_n
28
29 % Traction operators
30 tau_w, tau_e, tau_s, tau_n % Return vector field
31 tau1_w, tau1_e, tau1_s, tau1_n % Return scalar field
32 tau2_w, tau2_e, tau2_s, tau2_n % Return scalar field
33
34 % Inner products
35 H
36
37 % Boundary inner products (for scalar field)
38 H_w, H_e, H_s, H_n
39
40 % Surface Jacobian vectors
41 s_w, s_e, s_s, s_n
42
43 % Boundary restriction operators
44 e_w, e_e, e_s, e_n % Act on vector field, return vector field at boundary
45 e1_w, e1_e, e1_s, e1_n % Act on vector field, return scalar field at boundary
46 e2_w, e2_e, e2_s, e2_n % Act on vector field, return scalar field at boundary
47 e_scalar_w, e_scalar_e, e_scalar_s, e_scalar_n; % Act on scalar field, return scalar field
48
49 % E{i}^T picks out component i
50 E
51
52 % Elastic2dVariableAnisotropic object for reference domain
53 refObj
54 end
55
56 methods
57
58 % The coefficients can either be function handles or grid functions
59 % optFlag -- if true, extra computations are performed, which may be helpful for optimization.
60 function obj = Elastic2dCurvilinearAnisotropic(g, order, rho, C, opSet, optFlag)
61 default_arg('rho', @(x,y) 0*x+1);
62 default_arg('opSet',{@sbp.D2VariableCompatible, @sbp.D2VariableCompatible});
63 default_arg('optFlag', false);
64 dim = 2;
65
66 C_default = cell(dim,dim,dim,dim);
67 for i = 1:dim
68 for j = 1:dim
69 for k = 1:dim
70 for l = 1:dim
71 C_default{i,j,k,l} = @(x,y) 0*x + 1;
72 end
73 end
74 end
75 end
76 default_arg('C', C_default);
77
78 assert(isa(g, 'grid.Curvilinear'));
79
80 if isa(rho, 'function_handle')
81 rho = grid.evalOn(g, rho);
82 end
83
84 C_mat = cell(dim,dim,dim,dim);
85 for i = 1:dim
86 for j = 1:dim
87 for k = 1:dim
88 for l = 1:dim
89 if isa(C{i,j,k,l}, 'function_handle')
90 C{i,j,k,l} = grid.evalOn(g, C{i,j,k,l});
91 end
92 C_mat{i,j,k,l} = spdiag(C{i,j,k,l});
93 end
94 end
95 end
96 end
97 obj.C = C_mat;
98
99 m = g.size();
100 m_tot = g.N();
101
102 % 1D operators
103 m_u = m(1);
104 m_v = m(2);
105 ops_u = opSet{1}(m_u, {0, 1}, order);
106 ops_v = opSet{2}(m_v, {0, 1}, order);
107
108 h_u = ops_u.h;
109 h_v = ops_v.h;
110
111 I_u = speye(m_u);
112 I_v = speye(m_v);
113
114 D1_u = ops_u.D1;
115 H_u = ops_u.H;
116 Hi_u = ops_u.HI;
117 e_l_u = ops_u.e_l;
118 e_r_u = ops_u.e_r;
119 d1_l_u = ops_u.d1_l;
120 d1_r_u = ops_u.d1_r;
121
122 D1_v = ops_v.D1;
123 H_v = ops_v.H;
124 Hi_v = ops_v.HI;
125 e_l_v = ops_v.e_l;
126 e_r_v = ops_v.e_r;
127 d1_l_v = ops_v.d1_l;
128 d1_r_v = ops_v.d1_r;
129
130
131 % Logical operators
132 Du = kr(D1_u,I_v);
133 Dv = kr(I_u,D1_v);
134
135 e_w = kr(e_l_u,I_v);
136 e_e = kr(e_r_u,I_v);
137 e_s = kr(I_u,e_l_v);
138 e_n = kr(I_u,e_r_v);
139
140 % Metric coefficients
141 coords = g.points();
142 x = coords(:,1);
143 y = coords(:,2);
144
145 x_u = Du*x;
146 x_v = Dv*x;
147 y_u = Du*y;
148 y_v = Dv*y;
149
150 J = x_u.*y_v - x_v.*y_u;
151
152 K = cell(dim, dim);
153 K{1,1} = y_v./J;
154 K{1,2} = -y_u./J;
155 K{2,1} = -x_v./J;
156 K{2,2} = x_u./J;
157
158 % Wrap around Aniosotropic Cartesian
159 rho_tilde = J.*rho;
160
161 PHI = cell(dim,dim,dim,dim);
162 for i = 1:dim
163 for j = 1:dim
164 for k = 1:dim
165 for l = 1:dim
166 PHI{i,j,k,l} = 0*C{i,j,k,l};
167 for m = 1:dim
168 for n = 1:dim
169 PHI{i,j,k,l} = PHI{i,j,k,l} + J.*K{m,j}.*C{i,m,n,l}.*K{n,k};
170 end
171 end
172 end
173 end
174 end
175 end
176
177 gRef = grid.equidistant([m_u, m_v], {0,1}, {0,1});
178 refObj = scheme.Elastic2dVariableAnisotropic(gRef, order, rho_tilde, PHI, opSet);
179
180 %---- Set object properties ------
181 obj.RHO = spdiag(rho);
182
183 % Volume quadrature
184 obj.J = spdiag(J);
185 obj.Ji = spdiag(1./J);
186 obj.H = obj.J*kr(H_u,H_v);
187
188 % Boundary quadratures
189 s_w = sqrt((e_w'*x_v).^2 + (e_w'*y_v).^2);
190 s_e = sqrt((e_e'*x_v).^2 + (e_e'*y_v).^2);
191 s_s = sqrt((e_s'*x_u).^2 + (e_s'*y_u).^2);
192 s_n = sqrt((e_n'*x_u).^2 + (e_n'*y_u).^2);
193 obj.s_w = s_w;
194 obj.s_e = s_e;
195 obj.s_s = s_s;
196 obj.s_n = s_n;
197
198 obj.H_w = H_v*spdiag(s_w);
199 obj.H_e = H_v*spdiag(s_e);
200 obj.H_s = H_u*spdiag(s_s);
201 obj.H_n = H_u*spdiag(s_n);
202
203 % Restriction operators
204 obj.e_w = refObj.e_w;
205 obj.e_e = refObj.e_e;
206 obj.e_s = refObj.e_s;
207 obj.e_n = refObj.e_n;
208
209 % Adapt things from reference object
210 obj.D = refObj.D;
211 obj.E = refObj.E;
212
213 obj.e1_w = refObj.e1_w;
214 obj.e1_e = refObj.e1_e;
215 obj.e1_s = refObj.e1_s;
216 obj.e1_n = refObj.e1_n;
217
218 obj.e2_w = refObj.e2_w;
219 obj.e2_e = refObj.e2_e;
220 obj.e2_s = refObj.e2_s;
221 obj.e2_n = refObj.e2_n;
222
223 obj.e_scalar_w = refObj.e_scalar_w;
224 obj.e_scalar_e = refObj.e_scalar_e;
225 obj.e_scalar_s = refObj.e_scalar_s;
226 obj.e_scalar_n = refObj.e_scalar_n;
227
228 e1_w = (obj.e_scalar_w'*obj.E{1}')';
229 e1_e = (obj.e_scalar_e'*obj.E{1}')';
230 e1_s = (obj.e_scalar_s'*obj.E{1}')';
231 e1_n = (obj.e_scalar_n'*obj.E{1}')';
232
233 e2_w = (obj.e_scalar_w'*obj.E{2}')';
234 e2_e = (obj.e_scalar_e'*obj.E{2}')';
235 e2_s = (obj.e_scalar_s'*obj.E{2}')';
236 e2_n = (obj.e_scalar_n'*obj.E{2}')';
237
238 obj.tau1_w = (spdiag(1./s_w)*refObj.tau1_w')';
239 obj.tau1_e = (spdiag(1./s_e)*refObj.tau1_e')';
240 obj.tau1_s = (spdiag(1./s_s)*refObj.tau1_s')';
241 obj.tau1_n = (spdiag(1./s_n)*refObj.tau1_n')';
242
243 obj.tau2_w = (spdiag(1./s_w)*refObj.tau2_w')';
244 obj.tau2_e = (spdiag(1./s_e)*refObj.tau2_e')';
245 obj.tau2_s = (spdiag(1./s_s)*refObj.tau2_s')';
246 obj.tau2_n = (spdiag(1./s_n)*refObj.tau2_n')';
247
248 obj.tau_w = (refObj.e_w'*obj.e1_w*obj.tau1_w')' + (refObj.e_w'*obj.e2_w*obj.tau2_w')';
249 obj.tau_e = (refObj.e_e'*obj.e1_e*obj.tau1_e')' + (refObj.e_e'*obj.e2_e*obj.tau2_e')';
250 obj.tau_s = (refObj.e_s'*obj.e1_s*obj.tau1_s')' + (refObj.e_s'*obj.e2_s*obj.tau2_s')';
251 obj.tau_n = (refObj.e_n'*obj.e1_n*obj.tau1_n')' + (refObj.e_n'*obj.e2_n*obj.tau2_n')';
252
253 % Misc.
254 obj.refObj = refObj;
255 obj.m = refObj.m;
256 obj.h = refObj.h;
257 obj.order = order;
258 obj.grid = g;
259 obj.dim = dim;
260
261 end
262
263
264 % Closure functions return the operators applied to the own domain to close the boundary
265 % Penalty functions return the operators to force the solution. In the case of an interface it returns the operator applied to the other doamin.
266 % boundary is a string specifying the boundary e.g. 'l','r' or 'e','w','n','s'.
267 % bc is a cell array of component and bc type, e.g. {1, 'd'} for Dirichlet condition
268 % on the first component. Can also be e.g.
269 % {'normal', 'd'} or {'tangential', 't'} for conditions on
270 % tangential/normal component.
271 % data is a function returning the data that should be applied at the boundary.
272 % neighbour_scheme is an instance of Scheme that should be interfaced to.
273 % neighbour_boundary is a string specifying which boundary to interface to.
274
275 % For displacement bc:
276 % bc = {comp, 'd', dComps},
277 % where
278 % dComps = vector of components with displacement BC. Default: 1:dim.
279 % In this way, we can specify one BC at a time even though the SATs depend on all BC.
280 function [closure, penalty] = boundary_condition(obj, boundary, bc, tuning)
281 default_arg('tuning', 1.0);
282 assert( iscell(bc), 'The BC type must be a 2x1 or 3x1 cell array' );
283
284 [closure, penalty] = obj.refObj.boundary_condition(boundary, bc, tuning);
285
286 type = bc{2};
287
288 switch type
289 case {'F','f','Free','free','traction','Traction','t','T'}
290 s = obj.(['s_' boundary]);
291 s = spdiag(s);
292 penalty = penalty*s;
293 end
294 end
295
296 % type Struct that specifies the interface coupling.
297 % Fields:
298 % -- tuning: penalty strength, defaults to 1.0
299 % -- interpolation: type of interpolation, default 'none'
300 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type)
301
302 defaultType.tuning = 1.0;
303 defaultType.interpolation = 'none';
304 default_struct('type', defaultType);
305
306 [closure, penalty] = obj.refObj.interface(boundary,neighbour_scheme.refObj,neighbour_boundary,type);
307 end
308
309 % Returns the component number that is the tangential/normal component
310 % at the specified boundary
311 function comp = getComponent(obj, comp_str, boundary)
312 assertIsMember(comp_str, {'normal', 'tangential'});
313 assertIsMember(boundary, {'w', 'e', 's', 'n'});
314
315 switch boundary
316 case {'w', 'e'}
317 switch comp_str
318 case 'normal'
319 comp = 1;
320 case 'tangential'
321 comp = 2;
322 end
323 case {'s', 'n'}
324 switch comp_str
325 case 'normal'
326 comp = 2;
327 case 'tangential'
328 comp = 1;
329 end
330 end
331 end
332
333 % Returns h11 for the boundary specified by the string boundary.
334 % op -- string
335 function h11 = getBorrowing(obj, boundary)
336 assertIsMember(boundary, {'w', 'e', 's', 'n'})
337
338 switch boundary
339 case {'w','e'}
340 h11 = obj.refObj.h11{1};
341 case {'s', 'n'}
342 h11 = obj.refObj.h11{2};
343 end
344 end
345
346 % Returns the outward unit normal vector for the boundary specified by the string boundary.
347 function nu = getNormal(obj, boundary)
348 assertIsMember(boundary, {'w', 'e', 's', 'n'})
349
350 switch boundary
351 case 'w'
352 nu = [-1,0];
353 case 'e'
354 nu = [1,0];
355 case 's'
356 nu = [0,-1];
357 case 'n'
358 nu = [0,1];
359 end
360 end
361
362 % Returns the boundary operator op for the boundary specified by the string boundary.
363 % op -- string
364 function o = getBoundaryOperator(obj, op, boundary)
365 assertIsMember(boundary, {'w', 'e', 's', 'n'})
366 assertIsMember(op, {'e', 'e1', 'e2', 'tau', 'tau1', 'tau2'})
367
368 switch op
369 case {'e', 'e1', 'e2', 'tau', 'tau1', 'tau2'}
370 o = obj.([op, '_', boundary]);
371 end
372
373 end
374
375 % Returns the boundary operator op for the boundary specified by the string boundary.
376 % op -- string
377 function o = getBoundaryOperatorForScalarField(obj, op, boundary)
378 assertIsMember(boundary, {'w', 'e', 's', 'n'})
379 assertIsMember(op, {'e'})
380
381 switch op
382
383 case 'e'
384 o = obj.(['e_scalar', '_', boundary]);
385 end
386
387 end
388
389 % Returns the boundary operator T_ij (cell format) for the boundary specified by the string boundary.
390 % Formula: tau_i = T_ij u_j
391 % op -- string
392 function T = getBoundaryTractionOperator(obj, boundary)
393 assertIsMember(boundary, {'w', 'e', 's', 'n'})
394
395 T = obj.(['T', '_', boundary]);
396 end
397
398 % Returns square boundary quadrature matrix, of dimension
399 % corresponding to the number of boundary unknowns
400 %
401 % boundary -- string
402 function H = getBoundaryQuadrature(obj, boundary)
403 assertIsMember(boundary, {'w', 'e', 's', 'n'})
404
405 H = obj.getBoundaryQuadratureForScalarField(boundary);
406 I_dim = speye(obj.dim, obj.dim);
407 H = kron(H, I_dim);
408 end
409
410 % Returns square boundary quadrature matrix, of dimension
411 % corresponding to the number of boundary grid points
412 %
413 % boundary -- string
414 function H_b = getBoundaryQuadratureForScalarField(obj, boundary)
415 assertIsMember(boundary, {'w', 'e', 's', 'n'})
416
417 H_b = obj.(['H_', boundary]);
418 end
419
420 function N = size(obj)
421 N = obj.dim*prod(obj.m);
422 end
423 end
424 end