Mercurial > repos > public > sbplib
comparison +scheme/Elastic2dStaggeredAnisotropic.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 | 546ee16760d5 |
children |
comparison
equal
deleted
inserted
replaced
1330:855871e0b852 | 1331:60c875c18de3 |
---|---|
1 classdef Elastic2dStaggeredAnisotropic < scheme.Scheme | |
2 | |
3 % Discretizes the elastic wave equation: | |
4 % rho u_{i,tt} = dj C_{ijkl} dk u_j | |
5 % Uses a staggered Lebedev grid | |
6 % The solution (displacement) is stored on g_u | |
7 % Stresses (and hance tractions) appear on g_s | |
8 % Density is evaluated on g_u | |
9 % The stiffness tensor is evaluated on g_s | |
10 | |
11 properties | |
12 m % Number of points in each direction, possibly a vector | |
13 h % Grid spacing | |
14 | |
15 grid | |
16 dim | |
17 nGrids | |
18 N % Total number of unknowns stored (2 displacement components on 2 grids) | |
19 | |
20 order % Order of accuracy for the approximation | |
21 | |
22 % Diagonal matrices for variable coefficients | |
23 RHO % Density | |
24 C % Elastic stiffness tensor | |
25 | |
26 D % Total operator | |
27 | |
28 % Boundary operators in cell format, used for BC | |
29 % T_w, T_e, T_s, T_n | |
30 | |
31 % Traction operators | |
32 tau_w, tau_e, tau_s, tau_n % Return scalar field | |
33 T_w, T_e, T_s, T_n % Act on scalar, return scalar | |
34 | |
35 % Inner products | |
36 H, H_u, H_s | |
37 % , Hi, Hi_kron, H_1D | |
38 | |
39 % Boundary inner products (for scalar field) | |
40 H_w_u, H_e_u, H_s_u, H_n_u | |
41 H_w_s, H_e_s, H_s_s, H_n_s | |
42 | |
43 % Boundary restriction operators | |
44 e_w_u, e_e_u, e_s_u, e_n_u % Act on scalar field, return scalar field at boundary | |
45 e_w_s, e_e_s, e_s_s, e_n_s % Act on scalar field, return scalar field at boundary | |
46 | |
47 % U{i}^T picks out component i | |
48 U | |
49 | |
50 % G{i}^T picks out displacement grid i | |
51 G | |
52 | |
53 % Borrowing constants of the form gamma*h, where gamma is a dimensionless constant. | |
54 h11 % First entry in norm matrix | |
55 | |
56 end | |
57 | |
58 methods | |
59 | |
60 % The coefficients can either be function handles or grid functions | |
61 function obj = Elastic2dStaggeredAnisotropic(g, order, rho, C) | |
62 default_arg('rho', @(x,y) 0*x+1); | |
63 dim = 2; | |
64 nGrids = 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 assert(isa(g, 'grid.Staggered')) | |
78 | |
79 g_u = g.gridGroups{1}; | |
80 g_s = g.gridGroups{2}; | |
81 | |
82 m_u = {g_u{1}.size(), g_u{2}.size()}; | |
83 m_s = {g_s{1}.size(), g_s{2}.size()}; | |
84 | |
85 if isa(rho, 'function_handle') | |
86 rho_vec = cell(nGrids, 1); | |
87 for i = 1:nGrids | |
88 rho_vec{i} = grid.evalOn(g_u{i}, rho); | |
89 end | |
90 rho = rho_vec; | |
91 end | |
92 for i = 1:nGrids | |
93 RHO{i} = spdiag(rho{i}); | |
94 end | |
95 obj.RHO = RHO; | |
96 | |
97 C_mat = cell(nGrids, 1); | |
98 for a = 1:nGrids | |
99 C_mat{a} = cell(dim,dim,dim,dim); | |
100 end | |
101 for a = 1:nGrids | |
102 for i = 1:dim | |
103 for j = 1:dim | |
104 for k = 1:dim | |
105 for l = 1:dim | |
106 if numel(C) == nGrids | |
107 C_mat{a}{i,j,k,l} = spdiag(C{a}{i,j,k,l}); | |
108 else | |
109 C_mat{a}{i,j,k,l} = spdiag(grid.evalOn(g_s{a}, C{i,j,k,l})); | |
110 end | |
111 end | |
112 end | |
113 end | |
114 end | |
115 end | |
116 C = C_mat; | |
117 obj.C = C; | |
118 | |
119 % Reference m for primal grid | |
120 m = g_u{1}.size(); | |
121 X = g_u{1}.points; | |
122 lim = cell(dim, 1); | |
123 for i = 1:dim | |
124 lim{i} = {min(X(:,i)), max(X(:,i))}; | |
125 end | |
126 | |
127 % 1D operators | |
128 ops = cell(dim,1); | |
129 D1p = cell(dim, 1); | |
130 D1d = cell(dim, 1); | |
131 mp = cell(dim, 1); | |
132 md = cell(dim, 1); | |
133 Ip = cell(dim, 1); | |
134 Id = cell(dim, 1); | |
135 Hp = cell(dim, 1); | |
136 Hd = cell(dim, 1); | |
137 | |
138 opSet = @sbp.D1StaggeredUpwind; | |
139 for i = 1:dim | |
140 ops{i} = opSet(m(i), lim{i}, order); | |
141 D1p{i} = ops{i}.D1_dual; | |
142 D1d{i} = ops{i}.D1_primal; | |
143 mp{i} = length(ops{i}.x_primal); | |
144 md{i} = length(ops{i}.x_dual); | |
145 Ip{i} = speye(mp{i}, mp{i}); | |
146 Id{i} = speye(md{i}, md{i}); | |
147 Hp{i} = ops{i}.H_primal; | |
148 Hd{i} = ops{i}.H_dual; | |
149 ep_l{i} = ops{i}.e_primal_l; | |
150 ep_r{i} = ops{i}.e_primal_r; | |
151 ed_l{i} = ops{i}.e_dual_l; | |
152 ed_r{i} = ops{i}.e_dual_r; | |
153 end | |
154 | |
155 % Borrowing constants | |
156 % for i = 1:dim | |
157 % obj.h11{i} = ops{i}.H_dual(1,1); | |
158 % end | |
159 obj.h11{1}{1} = ops{1}.H_dual(1,1); | |
160 obj.h11{1}{2} = ops{2}.H_primal(1,1); | |
161 obj.h11{2}{1} = ops{1}.H_primal(1,1); | |
162 obj.h11{2}{2} = ops{2}.H_dual(1,1); | |
163 | |
164 %---- Grid layout ------- | |
165 % gu1 = xp o yp; | |
166 % gu2 = xd o yd; | |
167 % gs1 = xd o yp; | |
168 % gs2 = xp o yd; | |
169 %------------------------ | |
170 | |
171 % Quadratures | |
172 obj.H_u = cell(nGrids, 1); | |
173 obj.H_s = cell(nGrids, 1); | |
174 obj.H_u{1} = kron(Hp{1}, Hp{2}); | |
175 obj.H_u{2} = kron(Hd{1}, Hd{2}); | |
176 obj.H_s{1} = kron(Hd{1}, Hp{2}); | |
177 obj.H_s{2} = kron(Hp{1}, Hd{2}); | |
178 | |
179 obj.H_w_s = cell(nGrids, 1); | |
180 obj.H_e_s = cell(nGrids, 1); | |
181 obj.H_s_s = cell(nGrids, 1); | |
182 obj.H_n_s = cell(nGrids, 1); | |
183 | |
184 obj.H_w_s{1} = Hp{2}; | |
185 obj.H_w_s{2} = Hd{2}; | |
186 obj.H_e_s{1} = Hp{2}; | |
187 obj.H_e_s{2} = Hd{2}; | |
188 | |
189 obj.H_s_s{1} = Hd{1}; | |
190 obj.H_s_s{2} = Hp{1}; | |
191 obj.H_n_s{1} = Hd{1}; | |
192 obj.H_n_s{2} = Hp{1}; | |
193 | |
194 % Boundary restriction ops | |
195 e_w_u = cell(nGrids, 1); | |
196 e_s_u = cell(nGrids, 1); | |
197 e_e_u = cell(nGrids, 1); | |
198 e_n_u = cell(nGrids, 1); | |
199 | |
200 e_w_s = cell(nGrids, 1); | |
201 e_s_s = cell(nGrids, 1); | |
202 e_e_s = cell(nGrids, 1); | |
203 e_n_s = cell(nGrids, 1); | |
204 | |
205 e_w_u{1} = kron(ep_l{1}, Ip{2}); | |
206 e_e_u{1} = kron(ep_r{1}, Ip{2}); | |
207 e_s_u{1} = kron(Ip{1}, ep_l{2}); | |
208 e_n_u{1} = kron(Ip{1}, ep_r{2}); | |
209 | |
210 e_w_u{2} = kron(ed_l{1}, Id{2}); | |
211 e_e_u{2} = kron(ed_r{1}, Id{2}); | |
212 e_s_u{2} = kron(Id{1}, ed_l{2}); | |
213 e_n_u{2} = kron(Id{1}, ed_r{2}); | |
214 | |
215 e_w_s{1} = kron(ed_l{1}, Ip{2}); | |
216 e_e_s{1} = kron(ed_r{1}, Ip{2}); | |
217 e_s_s{1} = kron(Id{1}, ep_l{2}); | |
218 e_n_s{1} = kron(Id{1}, ep_r{2}); | |
219 | |
220 e_w_s{2} = kron(ep_l{1}, Id{2}); | |
221 e_e_s{2} = kron(ep_r{1}, Id{2}); | |
222 e_s_s{2} = kron(Ip{1}, ed_l{2}); | |
223 e_n_s{2} = kron(Ip{1}, ed_r{2}); | |
224 | |
225 obj.e_w_u = e_w_u; | |
226 obj.e_e_u = e_e_u; | |
227 obj.e_s_u = e_s_u; | |
228 obj.e_n_u = e_n_u; | |
229 | |
230 obj.e_w_s = e_w_s; | |
231 obj.e_e_s = e_e_s; | |
232 obj.e_s_s = e_s_s; | |
233 obj.e_n_s = e_n_s; | |
234 | |
235 | |
236 % D1_u2s{a, b}{i} approximates ddi and | |
237 % takes from u grid number b to s grid number a | |
238 % Some of D1_x2y{a, b} are 0. | |
239 D1_u2s = cell(nGrids, nGrids); | |
240 D1_s2u = cell(nGrids, nGrids); | |
241 | |
242 N_u = cell(nGrids, 1); | |
243 N_s = cell(nGrids, 1); | |
244 for a = 1:nGrids | |
245 N_u{a} = g_u{a}.N(); | |
246 N_s{a} = g_s{a}.N(); | |
247 end | |
248 | |
249 %---- Grid layout ------- | |
250 % gu1 = xp o yp; | |
251 % gu2 = xd o yd; | |
252 % gs1 = xd o yp; | |
253 % gs2 = xp o yd; | |
254 %------------------------ | |
255 | |
256 D1_u2s{1,1}{1} = kron(D1p{1}, Ip{2}); | |
257 D1_s2u{1,1}{1} = kron(D1d{1}, Ip{2}); | |
258 | |
259 D1_u2s{1,2}{2} = kron(Id{1}, D1d{2}); | |
260 D1_u2s{2,1}{2} = kron(Ip{1}, D1p{2}); | |
261 | |
262 D1_s2u{1,2}{2} = kron(Ip{1}, D1d{2}); | |
263 D1_s2u{2,1}{2} = kron(Id{1}, D1p{2}); | |
264 | |
265 D1_u2s{2,2}{1} = kron(D1d{1}, Id{2}); | |
266 D1_s2u{2,2}{1} = kron(D1p{1}, Id{2}); | |
267 | |
268 D1_u2s{1,1}{2} = sparse(N_s{1}, N_u{1}); | |
269 D1_s2u{1,1}{2} = sparse(N_u{1}, N_s{1}); | |
270 | |
271 D1_u2s{2,2}{2} = sparse(N_s{2}, N_u{2}); | |
272 D1_s2u{2,2}{2} = sparse(N_u{2}, N_s{2}); | |
273 | |
274 D1_u2s{1,2}{1} = sparse(N_s{1}, N_u{2}); | |
275 D1_s2u{1,2}{1} = sparse(N_u{1}, N_s{2}); | |
276 | |
277 D1_u2s{2,1}{1} = sparse(N_s{2}, N_u{1}); | |
278 D1_s2u{2,1}{1} = sparse(N_u{2}, N_s{1}); | |
279 | |
280 | |
281 %---- Combine grids and components ----- | |
282 | |
283 % U{a}{i}^T picks out u component i on grid a | |
284 U = cell(nGrids, 1); | |
285 for a = 1:2 | |
286 U{a} = cell(dim, 1); | |
287 I = speye(N_u{a}, N_u{a}); | |
288 for i = 1:dim | |
289 E = sparse(dim,1); | |
290 E(i) = 1; | |
291 U{a}{i} = kron(I, E); | |
292 end | |
293 end | |
294 obj.U = U; | |
295 | |
296 % Order grids | |
297 % u1, u2 | |
298 Iu1 = speye(dim*N_u{1}, dim*N_u{1}); | |
299 Iu2 = speye(dim*N_u{2}, dim*N_u{2}); | |
300 | |
301 Gu1 = cell2mat( {Iu1; sparse(dim*N_u{2}, dim*N_u{1})} ); | |
302 Gu2 = cell2mat( {sparse(dim*N_u{1}, dim*N_u{2}); Iu2} ); | |
303 | |
304 G = {Gu1; Gu2}; | |
305 obj.G = G; | |
306 | |
307 obj.H = G{1}*(U{1}{1}*obj.H_u{1}*U{1}{1}' + U{1}{2}*obj.H_u{1}*U{1}{2}')*G{1}'... | |
308 + G{2}*(U{2}{1}*obj.H_u{2}*U{2}{1}' + U{2}{2}*obj.H_u{2}*U{2}{2}')*G{2}'; | |
309 | |
310 % e1_w = (e_scalar_w'*E{1}')'; | |
311 % e1_e = (e_scalar_e'*E{1}')'; | |
312 % e1_s = (e_scalar_s'*E{1}')'; | |
313 % e1_n = (e_scalar_n'*E{1}')'; | |
314 | |
315 % e2_w = (e_scalar_w'*E{2}')'; | |
316 % e2_e = (e_scalar_e'*E{2}')'; | |
317 % e2_s = (e_scalar_s'*E{2}')'; | |
318 % e2_n = (e_scalar_n'*E{2}')'; | |
319 | |
320 stencilWidth = order; | |
321 % Differentiation matrix D (without SAT) | |
322 N = dim*(N_u{1} + N_u{2}); | |
323 D = spalloc(N, N, stencilWidth^2*N); | |
324 for a = 1:nGrids | |
325 for b = 1:nGrids | |
326 for c = 1:nGrids | |
327 for i = 1:dim | |
328 for j = 1:dim | |
329 for k = 1:dim | |
330 for l = 1:dim | |
331 D = D + (G{a}*U{a}{j})*(RHO{a}\(D1_s2u{a,b}{i}*C{b}{i,j,k,l}*D1_u2s{b,c}{k}*U{c}{l}'*G{c}')); | |
332 end | |
333 end | |
334 end | |
335 end | |
336 end | |
337 end | |
338 end | |
339 obj.D = D; | |
340 clear D; | |
341 obj.N = N; | |
342 %=========================================%' | |
343 | |
344 % Numerical traction operators for BC. | |
345 % | |
346 % Formula at boundary j: % tau^{j}_i = sum_l T^{j}_{il} u_l | |
347 % | |
348 | |
349 n_w = obj.getNormal('w'); | |
350 n_e = obj.getNormal('e'); | |
351 n_s = obj.getNormal('s'); | |
352 n_n = obj.getNormal('n'); | |
353 | |
354 tau_w = cell(nGrids, 1); | |
355 tau_e = cell(nGrids, 1); | |
356 tau_s = cell(nGrids, 1); | |
357 tau_n = cell(nGrids, 1); | |
358 | |
359 T_w = cell(nGrids, nGrids); | |
360 T_e = cell(nGrids, nGrids); | |
361 T_s = cell(nGrids, nGrids); | |
362 T_n = cell(nGrids, nGrids); | |
363 for b = 1:nGrids | |
364 [~, m_we] = size(e_w_s{b}); | |
365 [~, m_sn] = size(e_s_s{b}); | |
366 for c = 1:nGrids | |
367 T_w{b,c} = cell(dim, dim); | |
368 T_e{b,c} = cell(dim, dim); | |
369 T_s{b,c} = cell(dim, dim); | |
370 T_n{b,c} = cell(dim, dim); | |
371 | |
372 for i = 1:dim | |
373 for j = 1:dim | |
374 T_w{b,c}{i,j} = sparse(N_u{c}, m_we); | |
375 T_e{b,c}{i,j} = sparse(N_u{c}, m_we); | |
376 T_s{b,c}{i,j} = sparse(N_u{c}, m_sn); | |
377 T_n{b,c}{i,j} = sparse(N_u{c}, m_sn); | |
378 end | |
379 end | |
380 end | |
381 end | |
382 | |
383 for b = 1:nGrids | |
384 tau_w{b} = cell(dim, 1); | |
385 tau_e{b} = cell(dim, 1); | |
386 tau_s{b} = cell(dim, 1); | |
387 tau_n{b} = cell(dim, 1); | |
388 | |
389 for j = 1:dim | |
390 tau_w{b}{j} = sparse(N, m_s{b}(2)); | |
391 tau_e{b}{j} = sparse(N, m_s{b}(2)); | |
392 tau_s{b}{j} = sparse(N, m_s{b}(1)); | |
393 tau_n{b}{j} = sparse(N, m_s{b}(1)); | |
394 end | |
395 | |
396 for c = 1:nGrids | |
397 for i = 1:dim | |
398 for j = 1:dim | |
399 for k = 1:dim | |
400 for l = 1:dim | |
401 sigma_b_ij = C{b}{i,j,k,l}*D1_u2s{b,c}{k}*U{c}{l}'*G{c}'; | |
402 | |
403 tau_w{b}{j} = tau_w{b}{j} + (e_w_s{b}'*n_w(i)*sigma_b_ij)'; | |
404 tau_e{b}{j} = tau_e{b}{j} + (e_e_s{b}'*n_e(i)*sigma_b_ij)'; | |
405 tau_s{b}{j} = tau_s{b}{j} + (e_s_s{b}'*n_s(i)*sigma_b_ij)'; | |
406 tau_n{b}{j} = tau_n{b}{j} + (e_n_s{b}'*n_n(i)*sigma_b_ij)'; | |
407 | |
408 S_bc_ijl = C{b}{i,j,k,l}*D1_u2s{b,c}{k}; | |
409 | |
410 T_w{b,c}{j,l} = T_w{b,c}{j,l} + (e_w_s{b}'*n_w(i)*S_bc_ijl)'; | |
411 T_e{b,c}{j,l} = T_e{b,c}{j,l} + (e_e_s{b}'*n_e(i)*S_bc_ijl)'; | |
412 T_s{b,c}{j,l} = T_s{b,c}{j,l} + (e_s_s{b}'*n_s(i)*S_bc_ijl)'; | |
413 T_n{b,c}{j,l} = T_n{b,c}{j,l} + (e_n_s{b}'*n_n(i)*S_bc_ijl)'; | |
414 end | |
415 end | |
416 end | |
417 end | |
418 end | |
419 end | |
420 | |
421 obj.tau_w = tau_w; | |
422 obj.tau_e = tau_e; | |
423 obj.tau_s = tau_s; | |
424 obj.tau_n = tau_n; | |
425 | |
426 obj.T_w = T_w; | |
427 obj.T_e = T_e; | |
428 obj.T_s = T_s; | |
429 obj.T_n = T_n; | |
430 | |
431 % D1 = obj.D1; | |
432 | |
433 % Traction tensors, T_ij | |
434 % obj.T_w = T_l{1}; | |
435 % obj.T_e = T_r{1}; | |
436 % obj.T_s = T_l{2}; | |
437 % obj.T_n = T_r{2}; | |
438 | |
439 % Restriction operators | |
440 % obj.e_w = e_w; | |
441 % obj.e_e = e_e; | |
442 % obj.e_s = e_s; | |
443 % obj.e_n = e_n; | |
444 | |
445 % obj.e1_w = e1_w; | |
446 % obj.e1_e = e1_e; | |
447 % obj.e1_s = e1_s; | |
448 % obj.e1_n = e1_n; | |
449 | |
450 % obj.e2_w = e2_w; | |
451 % obj.e2_e = e2_e; | |
452 % obj.e2_s = e2_s; | |
453 % obj.e2_n = e2_n; | |
454 | |
455 % obj.e_scalar_w = e_scalar_w; | |
456 % obj.e_scalar_e = e_scalar_e; | |
457 % obj.e_scalar_s = e_scalar_s; | |
458 % obj.e_scalar_n = e_scalar_n; | |
459 | |
460 % % First component of traction | |
461 % obj.tau1_w = tau_l{1}{1}; | |
462 % obj.tau1_e = tau_r{1}{1}; | |
463 % obj.tau1_s = tau_l{2}{1}; | |
464 % obj.tau1_n = tau_r{2}{1}; | |
465 | |
466 % % Second component of traction | |
467 % obj.tau2_w = tau_l{1}{2}; | |
468 % obj.tau2_e = tau_r{1}{2}; | |
469 % obj.tau2_s = tau_l{2}{2}; | |
470 % obj.tau2_n = tau_r{2}{2}; | |
471 | |
472 % % Traction vectors | |
473 % obj.tau_w = (e_w'*e1_w*obj.tau1_w')' + (e_w'*e2_w*obj.tau2_w')'; | |
474 % obj.tau_e = (e_e'*e1_e*obj.tau1_e')' + (e_e'*e2_e*obj.tau2_e')'; | |
475 % obj.tau_s = (e_s'*e1_s*obj.tau1_s')' + (e_s'*e2_s*obj.tau2_s')'; | |
476 % obj.tau_n = (e_n'*e1_n*obj.tau1_n')' + (e_n'*e2_n*obj.tau2_n')'; | |
477 | |
478 % Misc. | |
479 obj.m = m; | |
480 obj.h = []; | |
481 obj.order = order; | |
482 obj.grid = g; | |
483 obj.dim = dim; | |
484 obj.nGrids = nGrids; | |
485 | |
486 end | |
487 | |
488 | |
489 % Closure functions return the operators applied to the own domain to close the boundary | |
490 % Penalty functions return the operators to force the solution. In the case of an interface it returns the operator applied to the other doamin. | |
491 % boundary is a string specifying the boundary e.g. 'l','r' or 'e','w','n','s'. | |
492 % bc is a cell array of component and bc type, e.g. {1, 'd'} for Dirichlet condition | |
493 % on the first component. Can also be e.g. | |
494 % {'normal', 'd'} or {'tangential', 't'} for conditions on | |
495 % tangential/normal component. | |
496 % data is a function returning the data that should be applied at the boundary. | |
497 % neighbour_scheme is an instance of Scheme that should be interfaced to. | |
498 % neighbour_boundary is a string specifying which boundary to interface to. | |
499 | |
500 % For displacement bc: | |
501 % bc = {comp, 'd', dComps}, | |
502 % where | |
503 % dComps = vector of components with displacement BC. Default: 1:dim. | |
504 % In this way, we can specify one BC at a time even though the SATs depend on all BC. | |
505 function [closure, penalty] = boundary_condition(obj, boundary, bc, tuning) | |
506 default_arg('tuning', 1.0); | |
507 | |
508 assert( iscell(bc), 'The BC type must be a 2x1 or 3x1 cell array' ); | |
509 comp = bc{1}; | |
510 type = bc{2}; | |
511 if ischar(comp) | |
512 comp = obj.getComponent(comp, boundary); | |
513 end | |
514 | |
515 e_u = obj.getBoundaryOperatorForScalarField('e_u', boundary); | |
516 e_s = obj.getBoundaryOperatorForScalarField('e_s', boundary); | |
517 tau = obj.getBoundaryOperator('tau', boundary); | |
518 T = obj.getBoundaryTractionOperator(boundary); | |
519 H_gamma = obj.getBoundaryQuadratureForScalarField(boundary); | |
520 nu = obj.getNormal(boundary); | |
521 | |
522 U = obj.U; | |
523 G = obj.G; | |
524 H = obj.H_u; | |
525 RHO = obj.RHO; | |
526 C = obj.C; | |
527 | |
528 %---- Grid layout ------- | |
529 % gu1 = xp o yp; | |
530 % gu2 = xd o yd; | |
531 % gs1 = xd o yp; | |
532 % gs2 = xp o yd; | |
533 %------------------------ | |
534 | |
535 switch boundary | |
536 case {'w', 'e'} | |
537 gridCombos = {{1,1}, {2,2}}; | |
538 case {'s', 'n'} | |
539 gridCombos = {{2,1}, {1,2}}; | |
540 end | |
541 | |
542 dim = obj.dim; | |
543 nGrids = obj.nGrids; | |
544 | |
545 m_tot = obj.N; | |
546 | |
547 % Preallocate | |
548 [~, col] = size(tau{1}{1}); | |
549 closure = sparse(m_tot, m_tot); | |
550 penalty = cell(1, nGrids); | |
551 for a = 1:nGrids | |
552 [~, col] = size(e_u{a}); | |
553 penalty{a} = sparse(m_tot, col); | |
554 end | |
555 | |
556 j = comp; | |
557 switch type | |
558 | |
559 % Dirichlet boundary condition | |
560 case {'D','d','dirichlet','Dirichlet','displacement','Displacement'} | |
561 | |
562 if numel(bc) >= 3 | |
563 dComps = bc{3}; | |
564 else | |
565 dComps = 1:dim; | |
566 end | |
567 | |
568 % Loops over components that Dirichlet penalties end up on | |
569 % Y: symmetrizing part of penalty | |
570 % Z: symmetric part of penalty | |
571 % X = Y + Z. | |
572 | |
573 % Nonsymmetric part goes on all components to | |
574 % yield traction in discrete energy rate | |
575 for c = 1:nGrids | |
576 for m = 1:numel(gridCombos) | |
577 gc = gridCombos{m}; | |
578 a = gc{1}; | |
579 b = gc{2}; | |
580 | |
581 for i = 1:dim | |
582 Y = T{a,c}{j,i}'; | |
583 closure = closure + G{c}*U{c}{i}*((RHO{c}*H{c})\(Y'*H_gamma{a}*(e_u{b}'*U{b}{j}'*G{b}') )); | |
584 penalty{b} = penalty{b} - G{c}*U{c}{i}*((RHO{c}*H{c})\(Y'*H_gamma{a}) ); | |
585 end | |
586 end | |
587 end | |
588 | |
589 % Symmetric part only required on components with displacement BC. | |
590 % (Otherwise it's not symmetric.) | |
591 for m = 1:numel(gridCombos) | |
592 gc = gridCombos{m}; | |
593 a = gc{1}; | |
594 b = gc{2}; | |
595 | |
596 h11 = obj.getBorrowing(b, boundary); | |
597 | |
598 for i = dComps | |
599 Z = 0*C{b}{1,1,1,1}; | |
600 for l = 1:dim | |
601 for k = 1:dim | |
602 Z = Z + nu(l)*C{b}{l,i,k,j}*nu(k); | |
603 end | |
604 end | |
605 Z = -tuning*dim/h11*Z; | |
606 X = e_s{b}'*Z*e_s{b}; | |
607 closure = closure + G{a}*U{a}{i}*((RHO{a}*H{a})\(e_u{a}*X'*H_gamma{b}*(e_u{a}'*U{a}{j}'*G{a}' ) )); | |
608 penalty{a} = penalty{a} - G{a}*U{a}{i}*((RHO{a}*H{a})\(e_u{a}*X'*H_gamma{b} )); | |
609 end | |
610 end | |
611 | |
612 % Free boundary condition | |
613 case {'F','f','Free','free','traction','Traction','t','T'} | |
614 for m = 1:numel(gridCombos) | |
615 gc = gridCombos{m}; | |
616 a = gc{1}; | |
617 b = gc{2}; | |
618 closure = closure - G{a}*U{a}{j}*(RHO{a}\(H{a}\(e_u{a}*H_gamma{b}*tau{b}{j}'))); | |
619 penalty{b} = G{a}*U{a}{j}*(RHO{a}\(H{a}\(e_u{a}*H_gamma{b}))); | |
620 end | |
621 | |
622 % Unknown boundary condition | |
623 otherwise | |
624 error('No such boundary condition: type = %s',type); | |
625 end | |
626 | |
627 penalty = cell2mat(penalty); | |
628 end | |
629 | |
630 % type Struct that specifies the interface coupling. | |
631 % Fields: | |
632 % -- tuning: penalty strength, defaults to 1.0 | |
633 % -- interpolation: type of interpolation, default 'none' | |
634 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type) | |
635 | |
636 defaultType.tuning = 1.0; | |
637 defaultType.interpolation = 'none'; | |
638 default_struct('type', defaultType); | |
639 | |
640 switch type.interpolation | |
641 case {'none', ''} | |
642 [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type); | |
643 case {'op','OP'} | |
644 [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type); | |
645 otherwise | |
646 error('Unknown type of interpolation: %s ', type.interpolation); | |
647 end | |
648 end | |
649 | |
650 function [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type) | |
651 tuning = type.tuning; | |
652 | |
653 % u denotes the solution in the own domain | |
654 % v denotes the solution in the neighbour domain | |
655 | |
656 u = obj; | |
657 v = neighbour_scheme; | |
658 | |
659 % Operators, u side | |
660 eu_u = u.getBoundaryOperatorForScalarField('e_u', boundary); | |
661 es_u = u.getBoundaryOperatorForScalarField('e_s', boundary); | |
662 tau_u = u.getBoundaryOperator('tau', boundary); | |
663 nu_u = u.getNormal(boundary); | |
664 | |
665 G_u = u.G; | |
666 U_u = u.U; | |
667 C_u = u.C; | |
668 m_tot_u = u.N; | |
669 | |
670 % Operators, v side | |
671 eu_v = v.getBoundaryOperatorForScalarField('e_u', neighbour_boundary); | |
672 es_v = v.getBoundaryOperatorForScalarField('e_s', neighbour_boundary); | |
673 tau_v = v.getBoundaryOperator('tau', neighbour_boundary); | |
674 nu_v = v.getNormal(neighbour_boundary); | |
675 | |
676 G_v = v.G; | |
677 U_v = v.U; | |
678 C_v = v.C; | |
679 m_tot_v = v.N; | |
680 | |
681 % Operators that are only required for own domain | |
682 % Hi = u.Hi_kron; | |
683 % RHOi = u.RHOi_kron; | |
684 % e_kron = u.getBoundaryOperator('e', boundary); | |
685 H = u.H_u; | |
686 RHO = u.RHO; | |
687 T_u = u.getBoundaryTractionOperator(boundary); | |
688 | |
689 % Shared operators | |
690 H_gamma = u.getBoundaryQuadratureForScalarField(boundary); | |
691 % H_gamma_kron = u.getBoundaryQuadrature(boundary); | |
692 dim = u.dim; | |
693 nGrids = obj.nGrids; | |
694 | |
695 % Preallocate | |
696 % [~, m_int] = size(H_gamma); | |
697 closure = sparse(m_tot_u, m_tot_u); | |
698 penalty = sparse(m_tot_u, m_tot_v); | |
699 | |
700 %---- Grid layout ------- | |
701 % gu1 = xp o yp; | |
702 % gu2 = xd o yd; | |
703 % gs1 = xd o yp; | |
704 % gs2 = xp o yd; | |
705 %------------------------ | |
706 | |
707 switch boundary | |
708 case {'w', 'e'} | |
709 switch neighbour_boundary | |
710 case {'w', 'e'} | |
711 gridCombos = {{1,1,1}, {2,2,2}}; | |
712 case {'s', 'n'} | |
713 gridCombos = {{1,1,2}, {2,2,1}}; | |
714 end | |
715 case {'s', 'n'} | |
716 switch neighbour_boundary | |
717 case {'s', 'n'} | |
718 gridCombos = {{2,1,1}, {1,2,2}}; | |
719 case {'w', 'e'} | |
720 gridCombos = {{2,1,2}, {1,2,1}}; | |
721 end | |
722 end | |
723 | |
724 % Symmetrizing part | |
725 for c = 1:nGrids | |
726 for m = 1:numel(gridCombos) | |
727 gc = gridCombos{m}; | |
728 a = gc{1}; | |
729 b = gc{2}; | |
730 | |
731 for i = 1:dim | |
732 for j = 1:dim | |
733 Y = 1/2*T_u{a,c}{j,i}'; | |
734 closure = closure + G_u{c}*U_u{c}{i}*((RHO{c}*H{c})\(Y'*H_gamma{a}*(eu_u{b}'*U_u{b}{j}'*G_u{b}') )); | |
735 penalty = penalty - G_u{c}*U_u{c}{i}*((RHO{c}*H{c})\(Y'*H_gamma{a}*(eu_v{b}'*U_v{b}{j}'*G_v{b}') )); | |
736 end | |
737 end | |
738 end | |
739 end | |
740 | |
741 % Symmetric part | |
742 for m = 1:numel(gridCombos) | |
743 gc = gridCombos{m}; | |
744 a = gc{1}; | |
745 b = gc{2}; | |
746 bv = gc{3}; | |
747 | |
748 h11_u = u.getBorrowing(b, boundary); | |
749 h11_v = v.getBorrowing(bv, neighbour_boundary); | |
750 | |
751 for i = 1:dim | |
752 for j = 1:dim | |
753 Z_u = 0*es_u{b}'*es_u{b}; | |
754 Z_v = 0*es_v{bv}'*es_v{bv}; | |
755 for l = 1:dim | |
756 for k = 1:dim | |
757 Z_u = Z_u + es_u{b}'*nu_u(l)*C_u{b}{l,i,k,j}*nu_u(k)*es_u{b}; | |
758 Z_v = Z_v + es_v{bv}'*nu_v(l)*C_v{bv}{l,i,k,j}*nu_v(k)*es_v{bv}; | |
759 end | |
760 end | |
761 Z = -tuning*dim*( 1/(4*h11_u)*Z_u + 1/(4*h11_v)*Z_v ); | |
762 % X = es_u{b}'*Z*es_u{b}; | |
763 % X = Z; | |
764 closure = closure + G_u{a}*U_u{a}{i}*((RHO{a}*H{a})\(eu_u{a}*Z'*H_gamma{b}*(eu_u{a}'*U_u{a}{j}'*G_u{a}' ) )); | |
765 penalty = penalty - G_u{a}*U_u{a}{i}*((RHO{a}*H{a})\(eu_u{a}*Z'*H_gamma{b}*(eu_v{a}'*U_v{a}{j}'*G_v{a}' ) )); | |
766 end | |
767 end | |
768 end | |
769 | |
770 % Continuity of traction | |
771 for j = 1:dim | |
772 for m = 1:numel(gridCombos) | |
773 gc = gridCombos{m}; | |
774 a = gc{1}; | |
775 b = gc{2}; | |
776 bv = gc{3}; | |
777 closure = closure - 1/2*G_u{a}*U_u{a}{j}*(RHO{a}\(H{a}\(eu_u{a}*H_gamma{b}*tau_u{b}{j}'))); | |
778 penalty = penalty - 1/2*G_u{a}*U_u{a}{j}*(RHO{a}\(H{a}\(eu_u{a}*H_gamma{b}*tau_v{bv}{j}'))); | |
779 end | |
780 end | |
781 | |
782 end | |
783 | |
784 function [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type) | |
785 error('Non-conforming interfaces not implemented yet.'); | |
786 end | |
787 | |
788 % Returns the component number that is the tangential/normal component | |
789 % at the specified boundary | |
790 function comp = getComponent(obj, comp_str, boundary) | |
791 assertIsMember(comp_str, {'normal', 'tangential'}); | |
792 assertIsMember(boundary, {'w', 'e', 's', 'n'}); | |
793 | |
794 switch boundary | |
795 case {'w', 'e'} | |
796 switch comp_str | |
797 case 'normal' | |
798 comp = 1; | |
799 case 'tangential' | |
800 comp = 2; | |
801 end | |
802 case {'s', 'n'} | |
803 switch comp_str | |
804 case 'normal' | |
805 comp = 2; | |
806 case 'tangential' | |
807 comp = 1; | |
808 end | |
809 end | |
810 end | |
811 | |
812 % Returns h11 for the boundary specified by the string boundary. | |
813 % op -- string | |
814 function h11 = getBorrowing(obj, stressGrid, boundary) | |
815 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
816 | |
817 switch boundary | |
818 case {'w','e'} | |
819 h11 = obj.h11{stressGrid}{1}; | |
820 case {'s', 'n'} | |
821 h11 = obj.h11{stressGrid}{2}; | |
822 end | |
823 end | |
824 | |
825 % Returns the outward unit normal vector for the boundary specified by the string boundary. | |
826 function nu = getNormal(obj, boundary) | |
827 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
828 | |
829 switch boundary | |
830 case 'w' | |
831 nu = [-1,0]; | |
832 case 'e' | |
833 nu = [1,0]; | |
834 case 's' | |
835 nu = [0,-1]; | |
836 case 'n' | |
837 nu = [0,1]; | |
838 end | |
839 end | |
840 | |
841 % Returns the boundary operator op for the boundary specified by the string boundary. | |
842 % op -- string | |
843 function o = getBoundaryOperator(obj, op, boundary) | |
844 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
845 assertIsMember(op, {'e', 'e1', 'e2', 'tau', 'tau1', 'tau2'}) | |
846 | |
847 switch op | |
848 case {'e', 'e1', 'e2', 'tau', 'tau1', 'tau2'} | |
849 o = obj.([op, '_', boundary]); | |
850 end | |
851 | |
852 end | |
853 | |
854 % Returns the boundary operator op for the boundary specified by the string boundary. | |
855 % op -- string | |
856 function o = getBoundaryOperatorForScalarField(obj, op, boundary) | |
857 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
858 assertIsMember(op, {'e_u', 'e_s'}) | |
859 | |
860 switch op | |
861 case 'e_u' | |
862 o = obj.(['e_', boundary, '_u']); | |
863 case 'e_s' | |
864 o = obj.(['e_', boundary, '_s']); | |
865 end | |
866 | |
867 end | |
868 | |
869 % Returns the boundary operator T_ij (cell format) for the boundary specified by the string boundary. | |
870 % Formula: tau_i = T_ij u_j | |
871 % op -- string | |
872 function T = getBoundaryTractionOperator(obj, boundary) | |
873 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
874 | |
875 T = obj.(['T', '_', boundary]); | |
876 end | |
877 | |
878 % Returns square boundary quadrature matrix, of dimension | |
879 % corresponding to the number of boundary unknowns | |
880 % | |
881 % boundary -- string | |
882 function H = getBoundaryQuadrature(obj, boundary) | |
883 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
884 | |
885 H = obj.getBoundaryQuadratureForScalarField(boundary); | |
886 I_dim = speye(obj.dim, obj.dim); | |
887 H = kron(H, I_dim); | |
888 end | |
889 | |
890 % Returns square boundary quadrature matrix, of dimension | |
891 % corresponding to the number of boundary grid points | |
892 % | |
893 % boundary -- string | |
894 function H_b = getBoundaryQuadratureForScalarField(obj, boundary) | |
895 assertIsMember(boundary, {'w', 'e', 's', 'n'}) | |
896 | |
897 H_b = obj.(['H_', boundary, '_s']); | |
898 end | |
899 | |
900 function N = size(obj) | |
901 N = length(obj.D); | |
902 end | |
903 end | |
904 end |