Mercurial > repos > public > sbplib
comparison +scheme/Elastic2dCurvilinearAnisotropic.m @ 1331:60c875c18de3 feature/D2_boundary_opt
Merge with feature/poroelastic for Elastic schemes
author | Vidar Stiernström <vidar.stiernstrom@it.uu.se> |
---|---|
date | Thu, 10 Mar 2022 16:54:26 +0100 |
parents | 412b8ceafbc6 |
children | df8c71b80c33 |
comparison
equal
deleted
inserted
replaced
1330:855871e0b852 | 1331:60c875c18de3 |
---|---|
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 K % Transformation gradient | |
27 Dx, Dy % Physical derivatives | |
28 sigma % Cell matrix of physical stress operators | |
29 n_w, n_e, n_s, n_n % Physical normals | |
30 tangent_w, tangent_e, tangent_s, tangent_n % Physical tangents | |
31 | |
32 % Boundary operators in cell format, used for BC | |
33 T_w, T_e, T_s, T_n | |
34 | |
35 % Traction operators | |
36 tau_w, tau_e, tau_s, tau_n % Return vector field | |
37 tau1_w, tau1_e, tau1_s, tau1_n % Return scalar field | |
38 tau2_w, tau2_e, tau2_s, tau2_n % Return scalar field | |
39 tau_n_w, tau_n_e, tau_n_s, tau_n_n % Return scalar field | |
40 tau_t_w, tau_t_e, tau_t_s, tau_t_n % Return scalar field | |
41 | |
42 % Inner products | |
43 H | |
44 | |
45 % Boundary inner products (for scalar field) | |
46 H_w, H_e, H_s, H_n | |
47 | |
48 % Surface Jacobian vectors | |
49 s_w, s_e, s_s, s_n | |
50 | |
51 % Boundary restriction operators | |
52 e_w, e_e, e_s, e_n % Act on vector field, return vector field at boundary | |
53 e1_w, e1_e, e1_s, e1_n % Act on vector field, return scalar field at boundary | |
54 e2_w, e2_e, e2_s, e2_n % Act on vector field, return scalar field at boundary | |
55 e_scalar_w, e_scalar_e, e_scalar_s, e_scalar_n; % Act on scalar field, return scalar field | |
56 en_w, en_e, en_s, en_n % Act on vector field, return normal component | |
57 et_w, et_e, et_s, et_n % Act on vector field, return tangential component | |
58 | |
59 % E{i}^T picks out component i | |
60 E | |
61 | |
62 % Elastic2dVariableAnisotropic object for reference domain | |
63 refObj | |
64 end | |
65 | |
66 methods | |
67 | |
68 % The coefficients can either be function handles or grid functions | |
69 % optFlag -- if true, extra computations are performed, which may be helpful for optimization. | |
70 function obj = Elastic2dCurvilinearAnisotropic(g, order, rho, C, opSet, optFlag, hollow) | |
71 default_arg('hollow', false); | |
72 default_arg('rho', @(x,y) 0*x+1); | |
73 default_arg('opSet',{@sbp.D2VariableCompatible, @sbp.D2VariableCompatible}); | |
74 default_arg('optFlag', false); | |
75 dim = 2; | |
76 | |
77 C_default = cell(dim,dim,dim,dim); | |
78 for i = 1:dim | |
79 for j = 1:dim | |
80 for k = 1:dim | |
81 for l = 1:dim | |
82 C_default{i,j,k,l} = @(x,y) 0*x ; | |
83 end | |
84 end | |
85 end | |
86 end | |
87 default_arg('C', C_default); | |
88 | |
89 assert(isa(g, 'grid.Curvilinear')); | |
90 | |
91 if isa(rho, 'function_handle') | |
92 rho = grid.evalOn(g, rho); | |
93 end | |
94 | |
95 C_mat = cell(dim,dim,dim,dim); | |
96 for i = 1:dim | |
97 for j = 1:dim | |
98 for k = 1:dim | |
99 for l = 1:dim | |
100 if isa(C{i,j,k,l}, 'function_handle') | |
101 C{i,j,k,l} = grid.evalOn(g, C{i,j,k,l}); | |
102 end | |
103 C_mat{i,j,k,l} = spdiag(C{i,j,k,l}); | |
104 end | |
105 end | |
106 end | |
107 end | |
108 obj.C = C_mat; | |
109 | |
110 m = g.size(); | |
111 m_tot = g.N(); | |
112 | |
113 % 1D operators | |
114 m_u = m(1); | |
115 m_v = m(2); | |
116 ops_u = opSet{1}(m_u, {0, 1}, order); | |
117 ops_v = opSet{2}(m_v, {0, 1}, order); | |
118 | |
119 h_u = ops_u.h; | |
120 h_v = ops_v.h; | |
121 | |
122 I_u = speye(m_u); | |
123 I_v = speye(m_v); | |
124 | |
125 D1_u = ops_u.D1; | |
126 H_u = ops_u.H; | |
127 Hi_u = ops_u.HI; | |
128 e_l_u = ops_u.e_l; | |
129 e_r_u = ops_u.e_r; | |
130 d1_l_u = ops_u.d1_l; | |
131 d1_r_u = ops_u.d1_r; | |
132 | |
133 D1_v = ops_v.D1; | |
134 H_v = ops_v.H; | |
135 Hi_v = ops_v.HI; | |
136 e_l_v = ops_v.e_l; | |
137 e_r_v = ops_v.e_r; | |
138 d1_l_v = ops_v.d1_l; | |
139 d1_r_v = ops_v.d1_r; | |
140 | |
141 | |
142 % Logical operators | |
143 Du = kr(D1_u,I_v); | |
144 Dv = kr(I_u,D1_v); | |
145 | |
146 e_w = kr(e_l_u,I_v); | |
147 e_e = kr(e_r_u,I_v); | |
148 e_s = kr(I_u,e_l_v); | |
149 e_n = kr(I_u,e_r_v); | |
150 | |
151 % Metric coefficients | |
152 coords = g.points(); | |
153 x = coords(:,1); | |
154 y = coords(:,2); | |
155 | |
156 x_u = Du*x; | |
157 x_v = Dv*x; | |
158 y_u = Du*y; | |
159 y_v = Dv*y; | |
160 | |
161 J = x_u.*y_v - x_v.*y_u; | |
162 | |
163 K = cell(dim, dim); | |
164 K{1,1} = y_v./J; | |
165 K{1,2} = -y_u./J; | |
166 K{2,1} = -x_v./J; | |
167 K{2,2} = x_u./J; | |
168 obj.K = K; | |
169 | |
170 % Physical derivatives | |
171 obj.Dx = spdiag( y_v./J)*Du + spdiag(-y_u./J)*Dv; | |
172 obj.Dy = spdiag(-x_v./J)*Du + spdiag( x_u./J)*Dv; | |
173 | |
174 % Wrap around Aniosotropic Cartesian | |
175 rho_tilde = J.*rho; | |
176 | |
177 PHI = cell(dim,dim,dim,dim); | |
178 for i = 1:dim | |
179 for j = 1:dim | |
180 for k = 1:dim | |
181 for l = 1:dim | |
182 PHI{i,j,k,l} = 0*C{i,j,k,l}; | |
183 for m = 1:dim | |
184 for n = 1:dim | |
185 PHI{i,j,k,l} = PHI{i,j,k,l} + J.*K{m,i}.*C{m,j,n,l}.*K{n,k}; | |
186 end | |
187 end | |
188 end | |
189 end | |
190 end | |
191 end | |
192 | |
193 gRef = grid.equidistant([m_u, m_v], {0,1}, {0,1}); | |
194 refObj = scheme.Elastic2dVariableAnisotropic(gRef, order, rho_tilde, PHI, opSet, [], hollow); | |
195 | |
196 %---- Set object properties ------ | |
197 obj.RHO = spdiag(rho); | |
198 | |
199 % Volume quadrature | |
200 obj.J = spdiag(J); | |
201 obj.Ji = spdiag(1./J); | |
202 obj.H = obj.J*kr(H_u,H_v); | |
203 | |
204 % Boundary quadratures | |
205 s_w = sqrt((e_w'*x_v).^2 + (e_w'*y_v).^2); | |
206 s_e = sqrt((e_e'*x_v).^2 + (e_e'*y_v).^2); | |
207 s_s = sqrt((e_s'*x_u).^2 + (e_s'*y_u).^2); | |
208 s_n = sqrt((e_n'*x_u).^2 + (e_n'*y_u).^2); | |
209 obj.s_w = s_w; | |
210 obj.s_e = s_e; | |
211 obj.s_s = s_s; | |
212 obj.s_n = s_n; | |
213 | |
214 obj.H_w = H_v*spdiag(s_w); | |
215 obj.H_e = H_v*spdiag(s_e); | |
216 obj.H_s = H_u*spdiag(s_s); | |
217 obj.H_n = H_u*spdiag(s_n); | |
218 | |
219 % Restriction operators | |
220 obj.e_w = refObj.e_w; | |
221 obj.e_e = refObj.e_e; | |
222 obj.e_s = refObj.e_s; | |
223 obj.e_n = refObj.e_n; | |
224 | |
225 % Adapt things from reference object | |
226 obj.D = refObj.D; | |
227 obj.E = refObj.E; | |
228 | |
229 obj.e1_w = refObj.e1_w; | |
230 obj.e1_e = refObj.e1_e; | |
231 obj.e1_s = refObj.e1_s; | |
232 obj.e1_n = refObj.e1_n; | |
233 | |
234 obj.e2_w = refObj.e2_w; | |
235 obj.e2_e = refObj.e2_e; | |
236 obj.e2_s = refObj.e2_s; | |
237 obj.e2_n = refObj.e2_n; | |
238 | |
239 obj.e_scalar_w = refObj.e_scalar_w; | |
240 obj.e_scalar_e = refObj.e_scalar_e; | |
241 obj.e_scalar_s = refObj.e_scalar_s; | |
242 obj.e_scalar_n = refObj.e_scalar_n; | |
243 | |
244 e1_w = obj.e1_w; | |
245 e1_e = obj.e1_e; | |
246 e1_s = obj.e1_s; | |
247 e1_n = obj.e1_n; | |
248 | |
249 e2_w = obj.e2_w; | |
250 e2_e = obj.e2_e; | |
251 e2_s = obj.e2_s; | |
252 e2_n = obj.e2_n; | |
253 | |
254 obj.tau1_w = (spdiag(1./s_w)*refObj.tau1_w')'; | |
255 obj.tau1_e = (spdiag(1./s_e)*refObj.tau1_e')'; | |
256 obj.tau1_s = (spdiag(1./s_s)*refObj.tau1_s')'; | |
257 obj.tau1_n = (spdiag(1./s_n)*refObj.tau1_n')'; | |
258 | |
259 obj.tau2_w = (spdiag(1./s_w)*refObj.tau2_w')'; | |
260 obj.tau2_e = (spdiag(1./s_e)*refObj.tau2_e')'; | |
261 obj.tau2_s = (spdiag(1./s_s)*refObj.tau2_s')'; | |
262 obj.tau2_n = (spdiag(1./s_n)*refObj.tau2_n')'; | |
263 | |
264 obj.tau_w = (refObj.e_w'*obj.e1_w*obj.tau1_w')' + (refObj.e_w'*obj.e2_w*obj.tau2_w')'; | |
265 obj.tau_e = (refObj.e_e'*obj.e1_e*obj.tau1_e')' + (refObj.e_e'*obj.e2_e*obj.tau2_e')'; | |
266 obj.tau_s = (refObj.e_s'*obj.e1_s*obj.tau1_s')' + (refObj.e_s'*obj.e2_s*obj.tau2_s')'; | |
267 obj.tau_n = (refObj.e_n'*obj.e1_n*obj.tau1_n')' + (refObj.e_n'*obj.e2_n*obj.tau2_n')'; | |
268 | |
269 % Physical normals | |
270 e_w = obj.e_scalar_w; | |
271 e_e = obj.e_scalar_e; | |
272 e_s = obj.e_scalar_s; | |
273 e_n = obj.e_scalar_n; | |
274 | |
275 e_w_vec = obj.e_w; | |
276 e_e_vec = obj.e_e; | |
277 e_s_vec = obj.e_s; | |
278 e_n_vec = obj.e_n; | |
279 | |
280 nu_w = [-1,0]; | |
281 nu_e = [1,0]; | |
282 nu_s = [0,-1]; | |
283 nu_n = [0,1]; | |
284 | |
285 obj.n_w = cell(2,1); | |
286 obj.n_e = cell(2,1); | |
287 obj.n_s = cell(2,1); | |
288 obj.n_n = cell(2,1); | |
289 | |
290 % Compute normal and rotate (exactly!) 90 degrees counter-clockwise to get tangent | |
291 n_w_1 = (1./s_w).*e_w'*(J.*(K{1,1}*nu_w(1) + K{1,2}*nu_w(2))); | |
292 n_w_2 = (1./s_w).*e_w'*(J.*(K{2,1}*nu_w(1) + K{2,2}*nu_w(2))); | |
293 obj.n_w{1} = spdiag(n_w_1); | |
294 obj.n_w{2} = spdiag(n_w_2); | |
295 obj.tangent_w = {-obj.n_w{2}, obj.n_w{1}}; | |
296 | |
297 n_e_1 = (1./s_e).*e_e'*(J.*(K{1,1}*nu_e(1) + K{1,2}*nu_e(2))); | |
298 n_e_2 = (1./s_e).*e_e'*(J.*(K{2,1}*nu_e(1) + K{2,2}*nu_e(2))); | |
299 obj.n_e{1} = spdiag(n_e_1); | |
300 obj.n_e{2} = spdiag(n_e_2); | |
301 obj.tangent_e = {-obj.n_e{2}, obj.n_e{1}}; | |
302 | |
303 n_s_1 = (1./s_s).*e_s'*(J.*(K{1,1}*nu_s(1) + K{1,2}*nu_s(2))); | |
304 n_s_2 = (1./s_s).*e_s'*(J.*(K{2,1}*nu_s(1) + K{2,2}*nu_s(2))); | |
305 obj.n_s{1} = spdiag(n_s_1); | |
306 obj.n_s{2} = spdiag(n_s_2); | |
307 obj.tangent_s = {-obj.n_s{2}, obj.n_s{1}}; | |
308 | |
309 n_n_1 = (1./s_n).*e_n'*(J.*(K{1,1}*nu_n(1) + K{1,2}*nu_n(2))); | |
310 n_n_2 = (1./s_n).*e_n'*(J.*(K{2,1}*nu_n(1) + K{2,2}*nu_n(2))); | |
311 obj.n_n{1} = spdiag(n_n_1); | |
312 obj.n_n{2} = spdiag(n_n_2); | |
313 obj.tangent_n = {-obj.n_n{2}, obj.n_n{1}}; | |
314 | |
315 % Operators that extract the normal component | |
316 obj.en_w = (obj.n_w{1}*obj.e1_w' + obj.n_w{2}*obj.e2_w')'; | |
317 obj.en_e = (obj.n_e{1}*obj.e1_e' + obj.n_e{2}*obj.e2_e')'; | |
318 obj.en_s = (obj.n_s{1}*obj.e1_s' + obj.n_s{2}*obj.e2_s')'; | |
319 obj.en_n = (obj.n_n{1}*obj.e1_n' + obj.n_n{2}*obj.e2_n')'; | |
320 | |
321 % Operators that extract the tangential component | |
322 obj.et_w = (obj.tangent_w{1}*obj.e1_w' + obj.tangent_w{2}*obj.e2_w')'; | |
323 obj.et_e = (obj.tangent_e{1}*obj.e1_e' + obj.tangent_e{2}*obj.e2_e')'; | |
324 obj.et_s = (obj.tangent_s{1}*obj.e1_s' + obj.tangent_s{2}*obj.e2_s')'; | |
325 obj.et_n = (obj.tangent_n{1}*obj.e1_n' + obj.tangent_n{2}*obj.e2_n')'; | |
326 | |
327 obj.tau_n_w = (obj.n_w{1}*obj.tau1_w' + obj.n_w{2}*obj.tau2_w')'; | |
328 obj.tau_n_e = (obj.n_e{1}*obj.tau1_e' + obj.n_e{2}*obj.tau2_e')'; | |
329 obj.tau_n_s = (obj.n_s{1}*obj.tau1_s' + obj.n_s{2}*obj.tau2_s')'; | |
330 obj.tau_n_n = (obj.n_n{1}*obj.tau1_n' + obj.n_n{2}*obj.tau2_n')'; | |
331 | |
332 obj.tau_t_w = (obj.tangent_w{1}*obj.tau1_w' + obj.tangent_w{2}*obj.tau2_w')'; | |
333 obj.tau_t_e = (obj.tangent_e{1}*obj.tau1_e' + obj.tangent_e{2}*obj.tau2_e')'; | |
334 obj.tau_t_s = (obj.tangent_s{1}*obj.tau1_s' + obj.tangent_s{2}*obj.tau2_s')'; | |
335 obj.tau_t_n = (obj.tangent_n{1}*obj.tau1_n' + obj.tangent_n{2}*obj.tau2_n')'; | |
336 | |
337 % Stress operators | |
338 sigma = cell(dim, dim); | |
339 D1 = {obj.Dx, obj.Dy}; | |
340 E = obj.E; | |
341 N = length(obj.RHO); | |
342 for i = 1:dim | |
343 for j = 1:dim | |
344 sigma{i,j} = sparse(N,2*N); | |
345 for k = 1:dim | |
346 for l = 1:dim | |
347 sigma{i,j} = sigma{i,j} + obj.C{i,j,k,l}*D1{k}*E{l}'; | |
348 end | |
349 end | |
350 end | |
351 end | |
352 obj.sigma = sigma; | |
353 | |
354 % Misc. | |
355 obj.refObj = refObj; | |
356 obj.m = refObj.m; | |
357 obj.h = refObj.h; | |
358 obj.order = order; | |
359 obj.grid = g; | |
360 obj.dim = dim; | |
361 | |
362 end | |
363 | |
364 | |
365 % Closure functions return the operators applied to the own domain to close the boundary | |
366 % Penalty functions return the operators to force the solution. In the case of an interface it returns the operator applied to the other doamin. | |
367 % boundary is a string specifying the boundary e.g. 'l','r' or 'e','w','n','s'. | |
368 % bc is a cell array of component and bc type, e.g. {1, 'd'} for Dirichlet condition | |
369 % on the first component. Can also be e.g. | |
370 % {'normal', 'd'} or {'tangential', 't'} for conditions on | |
371 % tangential/normal component. | |
372 % data is a function returning the data that should be applied at the boundary. | |
373 % neighbour_scheme is an instance of Scheme that should be interfaced to. | |
374 % neighbour_boundary is a string specifying which boundary to interface to. | |
375 | |
376 % For displacement bc: | |
377 % bc = {comp, 'd', dComps}, | |
378 % where | |
379 % dComps = vector of components with displacement BC. Default: 1:dim. | |
380 % In this way, we can specify one BC at a time even though the SATs depend on all BC. | |
381 function [closure, penalty] = boundary_condition(obj, boundary, bc, tuning) | |
382 default_arg('tuning', 1.0); | |
383 assert( iscell(bc), 'The BC type must be a 2x1 or 3x1 cell array' ); | |
384 | |
385 component = bc{1}; | |
386 type = bc{2}; | |
387 | |
388 switch component | |
389 | |
390 % If conditions on Cartesian components | |
391 case {1,2} | |
392 [closure, penalty] = obj.refObj.boundary_condition(boundary, bc, tuning); | |
393 | |
394 % If conditions on normal or tangential components | |
395 case {'n', 't'} | |
396 | |
397 switch component | |
398 case 'n' | |
399 en = obj.getBoundaryOperator('en', boundary); | |
400 case 't' | |
401 en = obj.getBoundaryOperator('et', boundary); | |
402 end | |
403 e1 = obj.getBoundaryOperator('e1', boundary); | |
404 | |
405 bc1 = {1, type}; | |
406 [c1, p1] = obj.refObj.boundary_condition(boundary, bc1, tuning); | |
407 bc2 = {2, type}; | |
408 c2 = obj.refObj.boundary_condition(boundary, bc2, tuning); | |
409 | |
410 switch type | |
411 case {'F','f','Free','free','traction','Traction','t','T'} | |
412 closure = en*en'*(c1+c2); | |
413 penalty = en*e1'*p1; | |
414 case {'D','d','dirichlet','Dirichlet','displacement','Displacement'} | |
415 [closure, penalty] = obj.displacementBCNormalTangential(boundary, bc, tuning); | |
416 end | |
417 | |
418 end | |
419 | |
420 switch type | |
421 case {'F','f','Free','free','traction','Traction','t','T'} | |
422 | |
423 s = obj.(['s_' boundary]); | |
424 s = spdiag(s); | |
425 penalty = penalty*s; | |
426 | |
427 end | |
428 end | |
429 | |
430 function [closure, penalty] = displacementBCNormalTangential(obj, boundary, bc, tuning) | |
431 u = obj; | |
432 | |
433 component = bc{1}; | |
434 type = bc{2}; | |
435 | |
436 switch component | |
437 case 'n' | |
438 en = u.getBoundaryOperator('en', boundary); | |
439 tau_n = u.getBoundaryOperator('tau_n', boundary); | |
440 N = u.getNormal(boundary); | |
441 case 't' | |
442 en = u.getBoundaryOperator('et', boundary); | |
443 tau_n = u.getBoundaryOperator('tau_t', boundary); | |
444 N = u.getTangent(boundary); | |
445 end | |
446 | |
447 % Operators | |
448 e = u.getBoundaryOperatorForScalarField('e', boundary); | |
449 h11 = u.getBorrowing(boundary); | |
450 n = u.getNormal(boundary); | |
451 | |
452 C = u.C; | |
453 Ji = u.Ji; | |
454 s = spdiag(u.(['s_' boundary])); | |
455 m_tot = u.grid.N(); | |
456 | |
457 Hi = u.E{1}*inv(u.H)*u.E{1}' + u.E{2}*inv(u.H)*u.E{2}'; | |
458 RHOi = u.E{1}*inv(u.RHO)*u.E{1}' + u.E{2}*inv(u.RHO)*u.E{2}'; | |
459 | |
460 H_gamma = u.getBoundaryQuadratureForScalarField(boundary); | |
461 dim = u.dim; | |
462 | |
463 % Preallocate | |
464 [~, m_int] = size(H_gamma); | |
465 closure = sparse(dim*m_tot, dim*m_tot); | |
466 penalty = sparse(dim*m_tot, m_int); | |
467 | |
468 % Term 1: The symmetric term | |
469 Z = sparse(m_int, m_int); | |
470 for i = 1:dim | |
471 for j = 1:dim | |
472 for l = 1:dim | |
473 for k = 1:dim | |
474 Z = Z + n{i}*N{j}*e'*Ji*C{i,j,k,l}*e*n{k}*N{l}; | |
475 end | |
476 end | |
477 end | |
478 end | |
479 | |
480 Z = -tuning*dim*1/h11*s*Z; | |
481 closure = closure + en*H_gamma*Z*en'; | |
482 penalty = penalty - en*H_gamma*Z; | |
483 | |
484 % Term 2: The symmetrizing term | |
485 closure = closure + tau_n*H_gamma*en'; | |
486 penalty = penalty - tau_n*H_gamma; | |
487 | |
488 % Multiply all terms by inverse of density x quadraure | |
489 closure = RHOi*Hi*closure; | |
490 penalty = RHOi*Hi*penalty; | |
491 end | |
492 | |
493 % type Struct that specifies the interface coupling. | |
494 % Fields: | |
495 % -- tuning: penalty strength, defaults to 1.0 | |
496 % -- interpolation: type of interpolation, default 'none' | |
497 function [closure, penalty, forcingPenalties] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type) | |
498 | |
499 defaultType.tuning = 1.0; | |
500 defaultType.interpolation = 'none'; | |
501 defaultType.type = 'standard'; | |
502 default_struct('type', defaultType); | |
503 | |
504 forcingPenalties = []; | |
505 | |
506 switch type.type | |
507 case 'standard' | |
508 [closure, penalty] = obj.refObj.interface(boundary,neighbour_scheme.refObj,neighbour_boundary,type); | |
509 case 'normalTangential' | |
510 [closure, penalty, forcingPenalties] = obj.interfaceNormalTangential(boundary,neighbour_scheme,neighbour_boundary,type); | |
511 case 'frictionalFault' | |
512 [closure, penalty, forcingPenalties] = obj.interfaceFrictionalFault(boundary,neighbour_scheme,neighbour_boundary,type); | |
513 end | |
514 | |
515 end | |
516 | |
517 function [closure, penalty, forcingPenalties] = interfaceFrictionalFault(obj,boundary,neighbour_scheme,neighbour_boundary,type) | |
518 tuning = type.tuning; | |
519 | |
520 % u denotes the solution in the own domain | |
521 % v denotes the solution in the neighbour domain | |
522 | |
523 forcingPenalties = cell(1, 1); | |
524 u = obj; | |
525 v = neighbour_scheme; | |
526 | |
527 % Operators, u side | |
528 e_u = u.getBoundaryOperatorForScalarField('e', boundary); | |
529 en_u = u.getBoundaryOperator('en', boundary); | |
530 tau_n_u = u.getBoundaryOperator('tau_n', boundary); | |
531 h11_u = u.getBorrowing(boundary); | |
532 n_u = u.getNormal(boundary); | |
533 | |
534 C_u = u.C; | |
535 Ji_u = u.Ji; | |
536 s_u = spdiag(u.(['s_' boundary])); | |
537 m_tot_u = u.grid.N(); | |
538 | |
539 % Operators, v side | |
540 e_v = v.getBoundaryOperatorForScalarField('e', neighbour_boundary); | |
541 en_v = v.getBoundaryOperator('en', neighbour_boundary); | |
542 tau_n_v = v.getBoundaryOperator('tau_n', neighbour_boundary); | |
543 h11_v = v.getBorrowing(neighbour_boundary); | |
544 n_v = v.getNormal(neighbour_boundary); | |
545 | |
546 C_v = v.C; | |
547 Ji_v = v.Ji; | |
548 s_v = spdiag(v.(['s_' neighbour_boundary])); | |
549 m_tot_v = v.grid.N(); | |
550 | |
551 % Operators that are only required for own domain | |
552 Hi = u.E{1}*inv(u.H)*u.E{1}' + u.E{2}*inv(u.H)*u.E{2}'; | |
553 RHOi = u.E{1}*inv(u.RHO)*u.E{1}' + u.E{2}*inv(u.RHO)*u.E{2}'; | |
554 | |
555 % Shared operators | |
556 H_gamma = u.getBoundaryQuadratureForScalarField(boundary); | |
557 dim = u.dim; | |
558 | |
559 % Preallocate | |
560 [~, m_int] = size(H_gamma); | |
561 closure = sparse(dim*m_tot_u, dim*m_tot_u); | |
562 penalty = sparse(dim*m_tot_u, dim*m_tot_v); | |
563 | |
564 % Continuity of normal displacement, term 1: The symmetric term | |
565 Z_u = sparse(m_int, m_int); | |
566 Z_v = sparse(m_int, m_int); | |
567 for i = 1:dim | |
568 for j = 1:dim | |
569 for l = 1:dim | |
570 for k = 1:dim | |
571 Z_u = Z_u + n_u{i}*n_u{j}*e_u'*Ji_u*C_u{i,j,k,l}*e_u*n_u{k}*n_u{l}; | |
572 Z_v = Z_v + n_v{i}*n_v{j}*e_v'*Ji_v*C_v{i,j,k,l}*e_v*n_v{k}*n_v{l}; | |
573 end | |
574 end | |
575 end | |
576 end | |
577 | |
578 Z = -tuning*dim*( 1/(4*h11_u)*s_u*Z_u + 1/(4*h11_v)*s_v*Z_v ); | |
579 closure = closure + en_u*H_gamma*Z*en_u'; | |
580 penalty = penalty + en_u*H_gamma*Z*en_v'; | |
581 | |
582 % Continuity of normal displacement, term 2: The symmetrizing term | |
583 closure = closure + 1/2*tau_n_u*H_gamma*en_u'; | |
584 penalty = penalty + 1/2*tau_n_u*H_gamma*en_v'; | |
585 | |
586 % Continuity of normal traction | |
587 closure = closure - 1/2*en_u*H_gamma*tau_n_u'; | |
588 penalty = penalty + 1/2*en_u*H_gamma*tau_n_v'; | |
589 forcing_tau_n = 1/2*en_u*H_gamma; | |
590 | |
591 % Multiply all normal component terms by inverse of density x quadraure | |
592 closure = RHOi*Hi*closure; | |
593 penalty = RHOi*Hi*penalty; | |
594 forcing_tau_n = RHOi*Hi*forcing_tau_n; | |
595 | |
596 % ---- Tangential tractions are imposed just like traction BC ------ | |
597 closure = closure + obj.boundary_condition(boundary, {'t', 't'}); | |
598 | |
599 forcingPenalties{1} = forcing_tau_n; | |
600 | |
601 end | |
602 | |
603 % Same interface conditions as in interfaceStandard, but imposed in the normal-tangential | |
604 % coordinate system. For the isotropic case, the components decouple nicely. | |
605 % The resulting scheme is not identical to that of interfaceStandard. This appears to be better. | |
606 function [closure, penalty, forcingPenalties, Zt] = interfaceNormalTangential(obj,boundary,neighbour_scheme,neighbour_boundary,type) | |
607 tuning = type.tuning; | |
608 | |
609 % u denotes the solution in the own domain | |
610 % v denotes the solution in the neighbour domain | |
611 | |
612 forcingPenalties = cell(2, 1); | |
613 u = obj; | |
614 v = neighbour_scheme; | |
615 | |
616 % Operators, u side | |
617 e_u = u.getBoundaryOperatorForScalarField('e', boundary); | |
618 en_u = u.getBoundaryOperator('en', boundary); | |
619 et_u = u.getBoundaryOperator('et', boundary); | |
620 tau_n_u = u.getBoundaryOperator('tau_n', boundary); | |
621 tau_t_u = u.getBoundaryOperator('tau_t', boundary); | |
622 h11_u = u.getBorrowing(boundary); | |
623 n_u = u.getNormal(boundary); | |
624 t_u = u.getTangent(boundary); | |
625 | |
626 C_u = u.C; | |
627 Ji_u = u.Ji; | |
628 s_u = spdiag(u.(['s_' boundary])); | |
629 m_tot_u = u.grid.N(); | |
630 | |
631 % Operators, v side | |
632 e_v = v.getBoundaryOperatorForScalarField('e', neighbour_boundary); | |
633 en_v = v.getBoundaryOperator('en', neighbour_boundary); | |
634 et_v = v.getBoundaryOperator('et', neighbour_boundary); | |
635 tau_n_v = v.getBoundaryOperator('tau_n', neighbour_boundary); | |
636 tau_t_v = v.getBoundaryOperator('tau_t', neighbour_boundary); | |
637 h11_v = v.getBorrowing(neighbour_boundary); | |
638 n_v = v.getNormal(neighbour_boundary); | |
639 t_v = v.getTangent(neighbour_boundary); | |
640 | |
641 C_v = v.C; | |
642 Ji_v = v.Ji; | |
643 s_v = spdiag(v.(['s_' neighbour_boundary])); | |
644 m_tot_v = v.grid.N(); | |
645 | |
646 % Operators that are only required for own domain | |
647 Hi = u.E{1}*inv(u.H)*u.E{1}' + u.E{2}*inv(u.H)*u.E{2}'; | |
648 RHOi = u.E{1}*inv(u.RHO)*u.E{1}' + u.E{2}*inv(u.RHO)*u.E{2}'; | |
649 | |
650 % Shared operators | |
651 H_gamma = u.getBoundaryQuadratureForScalarField(boundary); | |
652 dim = u.dim; | |
653 | |
654 % Preallocate | |
655 [~, m_int] = size(H_gamma); | |
656 closure = sparse(dim*m_tot_u, dim*m_tot_u); | |
657 penalty = sparse(dim*m_tot_u, dim*m_tot_v); | |
658 | |
659 % -- Continuity of displacement, term 1: The symmetric term --- | |
660 Zn_u = sparse(m_int, m_int); | |
661 Zn_v = sparse(m_int, m_int); | |
662 Zt_u = sparse(m_int, m_int); | |
663 Zt_v = sparse(m_int, m_int); | |
664 for i = 1:dim | |
665 for j = 1:dim | |
666 for l = 1:dim | |
667 for k = 1:dim | |
668 % Penalty strength for normal component | |
669 Zn_u = Zn_u + n_u{i}*n_u{j}*e_u'*Ji_u*C_u{i,j,k,l}*e_u*n_u{k}*n_u{l}; | |
670 Zn_v = Zn_v + n_v{i}*n_v{j}*e_v'*Ji_v*C_v{i,j,k,l}*e_v*n_v{k}*n_v{l}; | |
671 | |
672 % Penalty strength for tangential component | |
673 Zt_u = Zt_u + n_u{i}*t_u{j}*e_u'*Ji_u*C_u{i,j,k,l}*e_u*n_u{k}*t_u{l}; | |
674 Zt_v = Zt_v + n_v{i}*t_v{j}*e_v'*Ji_v*C_v{i,j,k,l}*e_v*n_v{k}*t_v{l}; | |
675 end | |
676 end | |
677 end | |
678 end | |
679 | |
680 Zn = -tuning*dim*( 1/(4*h11_u)*s_u*Zn_u + 1/(4*h11_v)*s_v*Zn_v ); | |
681 Zt = -tuning*dim*( 1/(4*h11_u)*s_u*Zt_u + 1/(4*h11_v)*s_v*Zt_v ); | |
682 | |
683 % Continuity of normal component | |
684 closure = closure + en_u*H_gamma*Zn*en_u'; | |
685 penalty = penalty + en_u*H_gamma*Zn*en_v'; | |
686 forcing_u_n = -en_u*H_gamma*Zn; | |
687 | |
688 % Continuity of tangential component | |
689 closure = closure + et_u*H_gamma*Zt*et_u'; | |
690 penalty = penalty + et_u*H_gamma*Zt*et_v'; | |
691 forcing_u_t = -et_u*H_gamma*Zt; | |
692 %------------------------------------------------------------------ | |
693 | |
694 % --- Continuity of displacement, term 2: The symmetrizing term | |
695 | |
696 % Continuity of normal displacement | |
697 closure = closure + 1/2*tau_n_u*H_gamma*en_u'; | |
698 penalty = penalty + 1/2*tau_n_u*H_gamma*en_v'; | |
699 forcing_u_n = forcing_u_n - 1/2*tau_n_u*H_gamma; | |
700 | |
701 % Continuity of tangential displacement | |
702 closure = closure + 1/2*tau_t_u*H_gamma*et_u'; | |
703 penalty = penalty + 1/2*tau_t_u*H_gamma*et_v'; | |
704 forcing_u_t = forcing_u_t - 1/2*tau_t_u*H_gamma; | |
705 % ------------------------------------------------------------------ | |
706 | |
707 % --- Continuity of tractions ----------------------------- | |
708 | |
709 % Continuity of normal traction | |
710 closure = closure - 1/2*en_u*H_gamma*tau_n_u'; | |
711 penalty = penalty + 1/2*en_u*H_gamma*tau_n_v'; | |
712 | |
713 % Continuity of tangential traction | |
714 closure = closure - 1/2*et_u*H_gamma*tau_t_u'; | |
715 penalty = penalty + 1/2*et_u*H_gamma*tau_t_v'; | |
716 %-------------------------------------------------------------------- | |
717 | |
718 % Multiply all terms by inverse of density x quadraure | |
719 closure = RHOi*Hi*closure; | |
720 penalty = RHOi*Hi*penalty; | |
721 forcing_u_n = RHOi*Hi*forcing_u_n; | |
722 forcing_u_t = RHOi*Hi*forcing_u_t; | |
723 | |
724 forcingPenalties{1} = forcing_u_n; | |
725 forcingPenalties{2} = forcing_u_t; | |
726 | |
727 end | |
728 | |
729 | |
730 % Returns h11 for the boundary specified by the string boundary. | |
731 % op -- string | |
732 function h11 = getBorrowing(obj, boundary) | |
733 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
734 | |
735 switch boundary | |
736 case {'w','e'} | |
737 h11 = obj.refObj.h11{1}; | |
738 case {'s', 'n'} | |
739 h11 = obj.refObj.h11{2}; | |
740 end | |
741 end | |
742 | |
743 % Returns the outward unit normal vector for the boundary specified by the string boundary. | |
744 % n is a cell of diagonal matrices for each normal component, n{1} = n_1, n{2} = n_2. | |
745 function n = getNormal(obj, boundary) | |
746 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
747 | |
748 n = obj.(['n_' boundary]); | |
749 end | |
750 | |
751 % Returns the unit tangent vector for the boundary specified by the string boundary. | |
752 % t is a cell of diagonal matrices for each normal component, t{1} = t_1, t{2} = t_2. | |
753 function t = getTangent(obj, boundary) | |
754 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
755 | |
756 t = obj.(['tangent_' boundary]); | |
757 end | |
758 | |
759 % Returns the boundary operator op for the boundary specified by the string boundary. | |
760 % op -- string | |
761 function o = getBoundaryOperator(obj, op, boundary) | |
762 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
763 assertIsMember(op, {'e', 'e1', 'e2', 'tau', 'tau1', 'tau2', 'en', 'et', 'tau_n', 'tau_t'}) | |
764 | |
765 o = obj.([op, '_', boundary]); | |
766 | |
767 end | |
768 | |
769 % Returns the boundary operator op for the boundary specified by the string boundary. | |
770 % op -- string | |
771 function o = getBoundaryOperatorForScalarField(obj, op, boundary) | |
772 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
773 assertIsMember(op, {'e'}) | |
774 | |
775 switch op | |
776 | |
777 case 'e' | |
778 o = obj.(['e_scalar', '_', boundary]); | |
779 end | |
780 | |
781 end | |
782 | |
783 % Returns the boundary operator T_ij (cell format) for the boundary specified by the string boundary. | |
784 % Formula: tau_i = T_ij u_j | |
785 % op -- string | |
786 function T = getBoundaryTractionOperator(obj, boundary) | |
787 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
788 | |
789 T = obj.(['T', '_', boundary]); | |
790 end | |
791 | |
792 % Returns square boundary quadrature matrix, of dimension | |
793 % corresponding to the number of boundary unknowns | |
794 % | |
795 % boundary -- string | |
796 function H = getBoundaryQuadrature(obj, boundary) | |
797 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
798 | |
799 H = obj.getBoundaryQuadratureForScalarField(boundary); | |
800 I_dim = speye(obj.dim, obj.dim); | |
801 H = kron(H, I_dim); | |
802 end | |
803 | |
804 % Returns square boundary quadrature matrix, of dimension | |
805 % corresponding to the number of boundary grid points | |
806 % | |
807 % boundary -- string | |
808 function H_b = getBoundaryQuadratureForScalarField(obj, boundary) | |
809 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
810 | |
811 H_b = obj.(['H_', boundary]); | |
812 end | |
813 | |
814 function N = size(obj) | |
815 N = obj.dim*prod(obj.m); | |
816 end | |
817 end | |
818 end |