comparison +scheme/Elastic2dVariable.m @ 971:e54c2f54dbfe feature/getBoundaryOperator

Merge with feature/poroelastic. Use only the changes made to multiblock.DiffOp and scheme.Elastic2dVariable. DiffOp.getBoundaryOperator/Quadrature now use scheme methods instead of propeties.
author Martin Almquist <malmquist@stanford.edu>
date Tue, 25 Dec 2018 07:50:07 +0100
parents 23d9ca6755be
children 104f0af001e0
comparison
equal deleted inserted replaced
957:2412f407749a 971:e54c2f54dbfe
28 28
29 % Traction operators used for BC 29 % Traction operators used for BC
30 T_l, T_r 30 T_l, T_r
31 tau_l, tau_r 31 tau_l, tau_r
32 32
33 H, Hi % Inner products 33 H, Hi, H_1D % Inner products
34
35 phi % Borrowing constant for (d1 - e^T*D1) from R
36 gamma % Borrowing constant for d1 from M
37 H11 % First element of H
38
39 % Borrowing from H, M, and R
40 thH
41 thM
42 thR
43
44 e_l, e_r 34 e_l, e_r
35 e_w, e_e, e_s, e_n
36
37
45 d1_l, d1_r % Normal derivatives at the boundary 38 d1_l, d1_r % Normal derivatives at the boundary
46 E % E{i}^T picks out component i 39 E % E{i}^T picks out component i
47 40
48 H_boundary % Boundary inner products 41 H_boundary % Boundary inner products
42 H_w, H_e, H_s, H_n
49 43
50 % Kroneckered norms and coefficients 44 % Kroneckered norms and coefficients
51 RHOi_kron 45 RHOi_kron
52 Hi_kron 46 Hi_kron
47
48 % Borrowing constants of the form gamma*h, where gamma is a dimensionless constant.
49 theta_R % Borrowing (d1- D1)^2 from R
50 theta_H % First entry in norm matrix
51 theta_M % Borrowing d1^2 from M.
52
53 % Structures used for adjoint optimization
54 B
53 end 55 end
54 56
55 methods 57 methods
56 58
57 function obj = Elastic2dVariable(g ,order, lambda_fun, mu_fun, rho_fun, opSet) 59 % The coefficients can either be function handles or grid functions
60 function obj = Elastic2dVariable(g ,order, lambda, mu, rho, opSet)
58 default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable}); 61 default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable});
59 default_arg('lambda_fun', @(x,y) 0*x+1); 62 default_arg('lambda', @(x,y) 0*x+1);
60 default_arg('mu_fun', @(x,y) 0*x+1); 63 default_arg('mu', @(x,y) 0*x+1);
61 default_arg('rho_fun', @(x,y) 0*x+1); 64 default_arg('rho', @(x,y) 0*x+1);
62 dim = 2; 65 dim = 2;
63 66
64 assert(isa(g, 'grid.Cartesian')) 67 assert(isa(g, 'grid.Cartesian'))
65 68
66 lambda = grid.evalOn(g, lambda_fun); 69 if isa(lambda, 'function_handle')
67 mu = grid.evalOn(g, mu_fun); 70 lambda = grid.evalOn(g, lambda);
68 rho = grid.evalOn(g, rho_fun); 71 end
72 if isa(mu, 'function_handle')
73 mu = grid.evalOn(g, mu);
74 end
75 if isa(rho, 'function_handle')
76 rho = grid.evalOn(g, rho);
77 end
78
69 m = g.size(); 79 m = g.size();
70 m_tot = g.N(); 80 m_tot = g.N();
71 81
72 h = g.scaling(); 82 h = g.scaling();
73 lim = g.lim; 83 lim = g.lim;
85 ops{i} = opSet{i}(m(i), lim{i}, order); 95 ops{i} = opSet{i}(m(i), lim{i}, order);
86 end 96 end
87 97
88 % Borrowing constants 98 % Borrowing constants
89 for i = 1:dim 99 for i = 1:dim
90 beta = ops{i}.borrowing.R.delta_D; 100 obj.theta_R{i} = h(i)*ops{i}.borrowing.R.delta_D;
91 obj.H11{i} = ops{i}.borrowing.H11; 101 obj.theta_H{i} = h(i)*ops{i}.borrowing.H11;
92 obj.phi{i} = beta/obj.H11{i}; 102 obj.theta_M{i} = h(i)*ops{i}.borrowing.M.d1;
93 obj.gamma{i} = ops{i}.borrowing.M.d1;
94
95 % Better names
96 obj.thR{i} = ops{i}.borrowing.R.delta_D;
97 obj.thM{i} = ops{i}.borrowing.M.d1;
98 obj.thH{i} = ops{i}.borrowing.H11;
99 end 103 end
100 104
101 I = cell(dim,1); 105 I = cell(dim,1);
102 D1 = cell(dim,1); 106 D1 = cell(dim,1);
103 D2 = cell(dim,1); 107 D2 = cell(dim,1);
144 % Boundary operators 148 % Boundary operators
145 obj.e_l{1} = kron(e_l{1},I{2}); 149 obj.e_l{1} = kron(e_l{1},I{2});
146 obj.e_l{2} = kron(I{1},e_l{2}); 150 obj.e_l{2} = kron(I{1},e_l{2});
147 obj.e_r{1} = kron(e_r{1},I{2}); 151 obj.e_r{1} = kron(e_r{1},I{2});
148 obj.e_r{2} = kron(I{1},e_r{2}); 152 obj.e_r{2} = kron(I{1},e_r{2});
153 obj.e_w = obj.e_l{1};
154 obj.e_e = obj.e_r{1};
155 obj.e_s = obj.e_l{2};
156 obj.e_n = obj.e_r{2};
149 157
150 obj.d1_l{1} = kron(d1_l{1},I{2}); 158 obj.d1_l{1} = kron(d1_l{1},I{2});
151 obj.d1_l{2} = kron(I{1},d1_l{2}); 159 obj.d1_l{2} = kron(I{1},d1_l{2});
152 obj.d1_r{1} = kron(d1_r{1},I{2}); 160 obj.d1_r{1} = kron(d1_r{1},I{2});
153 obj.d1_r{2} = kron(I{1},d1_r{2}); 161 obj.d1_r{2} = kron(I{1},d1_r{2});
181 obj.H = kron(H{1},H{2}); 189 obj.H = kron(H{1},H{2});
182 obj.Hi = inv(obj.H); 190 obj.Hi = inv(obj.H);
183 obj.H_boundary = cell(dim,1); 191 obj.H_boundary = cell(dim,1);
184 obj.H_boundary{1} = H{2}; 192 obj.H_boundary{1} = H{2};
185 obj.H_boundary{2} = H{1}; 193 obj.H_boundary{2} = H{1};
194 obj.H_1D = {H{1}, H{2}};
195 obj.H_w = H{2};
196 obj.H_e = H{2};
197 obj.H_s = H{1};
198 obj.H_n = H{1};
186 199
187 % E{i}^T picks out component i. 200 % E{i}^T picks out component i.
188 E = cell(dim,1); 201 E = cell(dim,1);
189 I = speye(m_tot,m_tot); 202 I = speye(m_tot,m_tot);
190 for i = 1:dim 203 for i = 1:dim
211 D2_mu{j}*E{i}' ... 224 D2_mu{j}*E{i}' ...
212 ); 225 );
213 end 226 end
214 end 227 end
215 obj.D = D; 228 obj.D = D;
216 %=========================================% 229 %=========================================%'
217 230
218 % Numerical traction operators for BC. 231 % Numerical traction operators for BC.
219 % Because d1 =/= e0^T*D1, the numerical tractions are different 232 % Because d1 =/= e0^T*D1, the numerical tractions are different
220 % at every boundary. 233 % at every boundary.
221 T_l = cell(dim,1); 234 T_l = cell(dim,1);
235 T_l{j} = cell(dim,dim); 248 T_l{j} = cell(dim,dim);
236 T_r{j} = cell(dim,dim); 249 T_r{j} = cell(dim,dim);
237 tau_l{j} = cell(dim,1); 250 tau_l{j} = cell(dim,1);
238 tau_r{j} = cell(dim,1); 251 tau_r{j} = cell(dim,1);
239 252
253 LAMBDA_l = e_l{j}'*LAMBDA*e_l{j};
254 LAMBDA_r = e_r{j}'*LAMBDA*e_r{j};
255 MU_l = e_l{j}'*MU*e_l{j};
256 MU_r = e_r{j}'*MU*e_r{j};
257
258 [~, n_l] = size(e_l{j});
259 [~, n_r] = size(e_r{j});
260
240 % Loop over components 261 % Loop over components
241 for i = 1:dim 262 for i = 1:dim
242 tau_l{j}{i} = sparse(m_tot,dim*m_tot); 263 tau_l{j}{i} = sparse(n_l, dim*m_tot);
243 tau_r{j}{i} = sparse(m_tot,dim*m_tot); 264 tau_r{j}{i} = sparse(n_r, dim*m_tot);
244 for k = 1:dim 265 for k = 1:dim
245 T_l{j}{i,k} = ... 266 T_l{j}{i,k} = ...
246 -d(i,j)*LAMBDA*(d(i,k)*e_l{k}*d1_l{k}' + db(i,k)*D1{k})... 267 -d(i,j)*LAMBDA_l*(d(i,k)*d1_l{j}' + db(i,k)*e_l{j}'*D1{k})...
247 -d(j,k)*MU*(d(i,j)*e_l{i}*d1_l{i}' + db(i,j)*D1{i})... 268 -d(j,k)*MU_l*(d(i,j)*d1_l{j}' + db(i,j)*e_l{j}'*D1{i})...
248 -d(i,k)*MU*e_l{j}*d1_l{j}'; 269 -d(i,k)*MU_l*d1_l{j}';
249 270
250 T_r{j}{i,k} = ... 271 T_r{j}{i,k} = ...
251 d(i,j)*LAMBDA*(d(i,k)*e_r{k}*d1_r{k}' + db(i,k)*D1{k})... 272 d(i,j)*LAMBDA_r*(d(i,k)*d1_r{j}' + db(i,k)*e_r{j}'*D1{k})...
252 +d(j,k)*MU*(d(i,j)*e_r{i}*d1_r{i}' + db(i,j)*D1{i})... 273 +d(j,k)*MU_r*(d(i,j)*d1_r{j}' + db(i,j)*e_r{j}'*D1{i})...
253 +d(i,k)*MU*e_r{j}*d1_r{j}'; 274 +d(i,k)*MU_r*d1_r{j}';
254 275
255 tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}'; 276 tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}';
256 tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}'; 277 tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}';
257 end 278 end
258 279
259 end 280 end
260 end 281 end
282
283 % Transpose T and tau to match boundary operator convention
284 for i = 1:dim
285 for j = 1:dim
286 tau_l{i}{j} = transpose(tau_l{i}{j});
287 tau_r{i}{j} = transpose(tau_r{i}{j});
288 for k = 1:dim
289 T_l{i}{j,k} = transpose(T_l{i}{j,k});
290 T_r{i}{j,k} = transpose(T_r{i}{j,k});
291 end
292 end
293 end
294
261 obj.T_l = T_l; 295 obj.T_l = T_l;
262 obj.T_r = T_r; 296 obj.T_r = T_r;
263 obj.tau_l = tau_l; 297 obj.tau_l = tau_l;
264 obj.tau_r = tau_r; 298 obj.tau_r = tau_r;
265 299
272 obj.m = m; 306 obj.m = m;
273 obj.h = h; 307 obj.h = h;
274 obj.order = order; 308 obj.order = order;
275 obj.grid = g; 309 obj.grid = g;
276 obj.dim = dim; 310 obj.dim = dim;
311
312 % B, used for adjoint optimization
313 B = cell(dim, 1);
314 for i = 1:dim
315 B{i} = cell(m_tot, 1);
316 end
317
318 for i = 1:dim
319 for j = 1:m_tot
320 B{i}{j} = sparse(m_tot, m_tot);
321 end
322 end
323
324 ind = grid.funcToMatrix(g, 1:m_tot);
325
326 % Direction 1
327 for k = 1:m(1)
328 c = sparse(m(1),1);
329 c(k) = 1;
330 [~, B_1D] = ops{1}.D2(c);
331 for l = 1:m(2)
332 p = ind(:,l);
333 B{1}{(k-1)*m(2) + l}(p, p) = B_1D;
334 end
335 end
336
337 % Direction 2
338 for k = 1:m(2)
339 c = sparse(m(2),1);
340 c(k) = 1;
341 [~, B_1D] = ops{2}.D2(c);
342 for l = 1:m(1)
343 p = ind(l,:);
344 B{2}{(l-1)*m(2) + k}(p, p) = B_1D;
345 end
346 end
347
348 obj.B = B;
277 349
278 end 350 end
279 351
280 352
281 % Closure functions return the operators applied to the own domain to close the boundary 353 % Closure functions return the operators applied to the own domain to close the boundary
293 comp = bc{1}; 365 comp = bc{1};
294 type = bc{2}; 366 type = bc{2};
295 367
296 % j is the coordinate direction of the boundary 368 % j is the coordinate direction of the boundary
297 j = obj.get_boundary_number(boundary); 369 j = obj.get_boundary_number(boundary);
298 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); 370 [e, T, tau, H_gamma] = obj.getBoundaryOperator({'e','T','tau','H'}, boundary);
371
299 372
300 E = obj.E; 373 E = obj.E;
301 Hi = obj.Hi; 374 Hi = obj.Hi;
302 LAMBDA = obj.LAMBDA; 375 LAMBDA = obj.LAMBDA;
303 MU = obj.MU; 376 MU = obj.MU;
314 switch type 387 switch type
315 388
316 % Dirichlet boundary condition 389 % Dirichlet boundary condition
317 case {'D','d','dirichlet','Dirichlet'} 390 case {'D','d','dirichlet','Dirichlet'}
318 391
319 phi = obj.phi{j}; 392 alpha = obj.getBoundaryOperator('alpha', boundary);
320 h = obj.h(j);
321 h11 = obj.H11{j}*h;
322 gamma = obj.gamma{j};
323
324 a_lambda = dim/h11 + 1/(h11*phi);
325 a_mu_i = 2/(gamma*h);
326 a_mu_ij = 2/h11 + 1/(h11*phi);
327
328 d = @kroneckerDelta; % Kronecker delta
329 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
330 alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ...
331 + d(i,j)* a_mu_i*MU ...
332 + db(i,j)*a_mu_ij*MU );
333 393
334 % Loop over components that Dirichlet penalties end up on 394 % Loop over components that Dirichlet penalties end up on
335 for i = 1:dim 395 for i = 1:dim
336 C = T{k,i}; 396 C = transpose(T{k,i});
337 A = -d(i,k)*alpha(i,j); 397 A = -e*transpose(alpha{i,k});
338 B = A + C; 398 B = A + e*C;
339 closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' ); 399 closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' );
340 penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma; 400 penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma;
341 end 401 end
342 402
343 % Free boundary condition 403 % Free boundary condition
344 case {'F','f','Free','free','traction','Traction','t','T'} 404 case {'F','f','Free','free','traction','Traction','t','T'}
345 closure = closure - E{k}*RHOi*Hi*e*H_gamma* (e'*tau{k} ); 405 closure = closure - E{k}*RHOi*Hi*e*H_gamma*tau{k}';
346 penalty = penalty + E{k}*RHOi*Hi*e*H_gamma; 406 penalty = penalty + E{k}*RHOi*Hi*e*H_gamma;
347 407
348 % Unknown boundary condition 408 % Unknown boundary condition
349 otherwise 409 otherwise
350 error('No such boundary condition: type = %s',type); 410 error('No such boundary condition: type = %s',type);
351 end 411 end
352 end 412 end
353 413
354 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary) 414 % type Struct that specifies the interface coupling.
415 % Fields:
416 % -- tuning: penalty strength, defaults to 1.2
417 % -- interpolation: type of interpolation, default 'none'
418 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type)
419
420 defaultType.tuning = 1.2;
421 defaultType.interpolation = 'none';
422 default_struct('type', defaultType);
423
424 switch type.interpolation
425 case {'none', ''}
426 [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type);
427 case {'op','OP'}
428 [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type);
429 otherwise
430 error('Unknown type of interpolation: %s ', type.interpolation);
431 end
432 end
433
434 function [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type)
435 tuning = type.tuning;
436
355 % u denotes the solution in the own domain 437 % u denotes the solution in the own domain
356 % v denotes the solution in the neighbour domain 438 % v denotes the solution in the neighbour domain
357 % Operators without subscripts are from the own domain. 439 % Operators without subscripts are from the own domain.
358 tuning = 1.2;
359 440
360 % j is the coordinate direction of the boundary 441 % j is the coordinate direction of the boundary
361 j = obj.get_boundary_number(boundary); 442 j = obj.get_boundary_number(boundary);
362 j_v = neighbour_scheme.get_boundary_number(neighbour_boundary); 443 j_v = neighbour_scheme.get_boundary_number(neighbour_boundary);
363 444
364 % Get boundary operators 445 % Get boundary operators
365 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); 446 [e, T, tau, H_gamma] = obj.getBoundaryOperator({'e','T','tau','H'}, boundary);
366 [e_v, tau_v] = neighbour_scheme.get_boundary_operator({'e','tau'}, neighbour_boundary); 447 [e_v, tau_v] = neighbour_scheme.getBoundaryOperator({'e','tau'}, neighbour_boundary);
367 448
368 % Operators and quantities that correspond to the own domain only 449 % Operators and quantities that correspond to the own domain only
369 Hi = obj.Hi; 450 Hi = obj.Hi;
370 RHOi = obj.RHOi; 451 RHOi = obj.RHOi;
371 dim = obj.dim; 452 dim = obj.dim;
385 lambda_v = e_v'*LAMBDA_v*e_v; 466 lambda_v = e_v'*LAMBDA_v*e_v;
386 mu_v = e_v'*MU_v*e_v; 467 mu_v = e_v'*MU_v*e_v;
387 %------------------------- 468 %-------------------------
388 469
389 % Borrowing constants 470 % Borrowing constants
390 h_u = obj.h(j); 471 theta_R_u = obj.theta_R{j};
391 thR_u = obj.thR{j}*h_u; 472 theta_H_u = obj.theta_H{j};
392 thM_u = obj.thM{j}*h_u; 473 theta_M_u = obj.theta_M{j};
393 thH_u = obj.thH{j}*h_u; 474
394 475 theta_R_v = neighbour_scheme.theta_R{j_v};
395 h_v = neighbour_scheme.h(j_v); 476 theta_H_v = neighbour_scheme.theta_H{j_v};
396 thR_v = neighbour_scheme.thR{j_v}*h_v; 477 theta_M_v = neighbour_scheme.theta_M{j_v};
397 thH_v = neighbour_scheme.thH{j_v}*h_v; 478
398 thM_v = neighbour_scheme.thM{j_v}*h_v; 479 function [alpha_ii, alpha_ij] = computeAlpha(th_R, th_H, th_M, lambda, mu)
399 480 alpha_ii = dim*lambda/(4*th_H) + lambda/(4*th_R) + mu/(2*th_M);
400 % alpha = penalty strength for normal component, beta for tangential 481 alpha_ij = mu/(2*th_H) + mu/(4*th_R);
401 alpha_u = dim*lambda_u/(4*thH_u) + lambda_u/(4*thR_u) + mu_u/(2*thM_u); 482 end
402 alpha_v = dim*lambda_v/(4*thH_v) + lambda_v/(4*thR_v) + mu_v/(2*thM_v); 483
403 beta_u = mu_u/(2*thH_u) + mu_u/(4*thR_u); 484 [alpha_ii_u, alpha_ij_u] = computeAlpha(theta_R_u, theta_H_u, theta_M_u, lambda_u, mu_u);
404 beta_v = mu_v/(2*thH_v) + mu_v/(4*thR_v); 485 [alpha_ii_v, alpha_ij_v] = computeAlpha(theta_R_v, theta_H_v, theta_M_v, lambda_v, mu_v);
405 alpha = alpha_u + alpha_v; 486 sigma_ii = alpha_ii_u + alpha_ii_v;
406 beta = beta_u + beta_v; 487 sigma_ij = alpha_ij_u + alpha_ij_v;
407 488
408 d = @kroneckerDelta; % Kronecker delta 489 d = @kroneckerDelta; % Kronecker delta
409 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta 490 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
410 strength = @(i,j) tuning*(d(i,j)*alpha + db(i,j)*beta); 491 sigma = @(i,j) tuning*(d(i,j)*sigma_ii + db(i,j)*sigma_ij);
411 492
412 % Preallocate 493 % Preallocate
413 closure = sparse(dim*m_tot_u, dim*m_tot_u); 494 closure = sparse(dim*m_tot_u, dim*m_tot_u);
414 penalty = sparse(dim*m_tot_u, dim*m_tot_v); 495 penalty = sparse(dim*m_tot_u, dim*m_tot_v);
415 496
416 % Loop over components that penalties end up on 497 % Loop over components that penalties end up on
417 for i = 1:dim 498 for i = 1:dim
418 closure = closure - E{i}*RHOi*Hi*e*strength(i,j)*H_gamma*e'*E{i}'; 499 closure = closure - E{i}*RHOi*Hi*e*sigma(i,j)*H_gamma*e'*E{i}';
419 penalty = penalty + E{i}*RHOi*Hi*e*strength(i,j)*H_gamma*e_v'*E_v{i}'; 500 penalty = penalty + E{i}*RHOi*Hi*e*sigma(i,j)*H_gamma*e_v'*E_v{i}';
420 501
421 closure = closure - 1/2*E{i}*RHOi*Hi*e*H_gamma*e'*tau{i}; 502 closure = closure - 1/2*E{i}*RHOi*Hi*e*H_gamma*tau{i}';
422 penalty = penalty - 1/2*E{i}*RHOi*Hi*e*H_gamma*e_v'*tau_v{i}; 503 penalty = penalty - 1/2*E{i}*RHOi*Hi*e*H_gamma*tau_v{i}';
423 504
424 % Loop over components that we have interface conditions on 505 % Loop over components that we have interface conditions on
425 for k = 1:dim 506 for k = 1:dim
426 closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e'*E{k}'; 507 closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}*H_gamma*e'*E{k}';
427 penalty = penalty - 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e_v'*E_v{k}'; 508 penalty = penalty - 1/2*E{i}*RHOi*Hi*T{k,i}*H_gamma*e_v'*E_v{k}';
428 end 509 end
429 end 510 end
511 end
512
513 function [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type)
514 error('Non-conforming interfaces not implemented yet.');
430 end 515 end
431 516
432 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. 517 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary.
433 function [j, nj] = get_boundary_number(obj, boundary) 518 function [j, nj] = get_boundary_number(obj, boundary)
434 519
449 end 534 end
450 end 535 end
451 536
452 % Returns the boundary operator op for the boundary specified by the string boundary. 537 % Returns the boundary operator op for the boundary specified by the string boundary.
453 % op: may be a cell array of strings 538 % op: may be a cell array of strings
454 function [varargout] = get_boundary_operator(obj, op, boundary) 539 % Only operators with name *_tot can be used with multiblock.DiffOp.getBoundaryOperator()
540 function [varargout] = getBoundaryOperator(obj, op, boundary)
455 541
456 switch boundary 542 switch boundary
457 case {'w','W','west','West', 'e', 'E', 'east', 'East'} 543 case {'w','W','west','West', 'e', 'E', 'east', 'East'}
458 j = 1; 544 j = 1;
459 case {'s','S','south','South', 'n', 'N', 'north', 'North'} 545 case {'s','S','south','South', 'n', 'N', 'north', 'North'}
464 550
465 if ~iscell(op) 551 if ~iscell(op)
466 op = {op}; 552 op = {op};
467 end 553 end
468 554
469 for i = 1:length(op) 555 for k = 1:length(op)
470 switch op{i} 556 switch op{k}
471 case 'e' 557 case 'e'
472 switch boundary 558 switch boundary
473 case {'w','W','west','West','s','S','south','South'} 559 case {'w','W','west','West','s','S','south','South'}
474 varargout{i} = obj.e_l{j}; 560 varargout{k} = obj.e_l{j};
475 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 561 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
476 varargout{i} = obj.e_r{j}; 562 varargout{k} = obj.e_r{j};
477 end 563 end
564
565 case 'e_tot'
566 e = obj.getBoundaryOperator('e', boundary);
567 I_dim = speye(obj.dim, obj.dim);
568 varargout{k} = kron(e, I_dim);
569
478 case 'd' 570 case 'd'
479 switch boundary 571 switch boundary
480 case {'w','W','west','West','s','S','south','South'} 572 case {'w','W','west','West','s','S','south','South'}
481 varargout{i} = obj.d1_l{j}; 573 varargout{k} = obj.d1_l{j};
482 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 574 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
483 varargout{i} = obj.d1_r{j}; 575 varargout{k} = obj.d1_r{j};
484 end 576 end
485 case 'H' 577
486 varargout{i} = obj.H_boundary{j};
487 case 'T' 578 case 'T'
488 switch boundary 579 switch boundary
489 case {'w','W','west','West','s','S','south','South'} 580 case {'w','W','west','West','s','S','south','South'}
490 varargout{i} = obj.T_l{j}; 581 varargout{k} = obj.T_l{j};
491 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 582 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
492 varargout{i} = obj.T_r{j}; 583 varargout{k} = obj.T_r{j};
493 end 584 end
585
494 case 'tau' 586 case 'tau'
495 switch boundary 587 switch boundary
496 case {'w','W','west','West','s','S','south','South'} 588 case {'w','W','west','West','s','S','south','South'}
497 varargout{i} = obj.tau_l{j}; 589 varargout{k} = obj.tau_l{j};
498 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 590 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
499 varargout{i} = obj.tau_r{j}; 591 varargout{k} = obj.tau_r{j};
500 end 592 end
593
594 case 'tau_tot'
595 [e, tau] = obj.getBoundaryOperator({'e', 'tau'}, boundary);
596
597 I_dim = speye(obj.dim, obj.dim);
598 e_tot = kron(e, I_dim);
599 E = obj.E;
600 tau_tot = (e_tot'*E{1}*e*tau{1}')';
601 for i = 2:obj.dim
602 tau_tot = tau_tot + (e_tot'*E{i}*e*tau{i}')';
603 end
604 varargout{k} = tau_tot;
605
606 case 'H'
607 varargout{k} = obj.H_boundary{j};
608
609 case 'alpha'
610 % alpha = alpha(i,j) is the penalty strength for displacement BC.
611 e = obj.getBoundaryOperator('e', boundary);
612
613 tuning = 1.2;
614 LAMBDA = obj.LAMBDA;
615 MU = obj.MU;
616
617 dim = obj.dim;
618 theta_R = obj.theta_R{j};
619 theta_H = obj.theta_H{j};
620 theta_M = obj.theta_M{j};
621
622 a_lambda = dim/theta_H + 1/theta_R;
623 a_mu_i = 2/theta_M;
624 a_mu_ij = 2/theta_H + 1/theta_R;
625
626 d = @kroneckerDelta; % Kronecker delta
627 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
628 alpha = cell(obj.dim, obj.dim);
629
630 alpha_func = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ...
631 + d(i,j)* a_mu_i*MU ...
632 + db(i,j)*a_mu_ij*MU );
633 for i = 1:obj.dim
634 for l = 1:obj.dim
635 alpha{i,l} = d(i,l)*alpha_func(i,j)*e;
636 end
637 end
638
639 varargout{k} = alpha;
640
641 case 'alpha_tot'
642 % alpha = alpha(i,j) is the penalty strength for displacement BC.
643 [e, e_tot, alpha] = obj.getBoundaryOperator({'e', 'e_tot', 'alpha'}, boundary);
644 E = obj.E;
645 [m, n] = size(alpha{1,1});
646 alpha_tot = sparse(m*obj.dim, n*obj.dim);
647 for i = 1:obj.dim
648 for l = 1:obj.dim
649 alpha_tot = alpha_tot + (e_tot'*E{i}*e*alpha{i,l}'*E{l}')';
650 end
651 end
652 varargout{k} = alpha_tot;
653
501 otherwise 654 otherwise
502 error(['No such operator: operator = ' op{i}]); 655 error(['No such operator: operator = ' op{k}]);
503 end 656 end
504 end 657 end
505 658
659 end
660
661 function H = getBoundaryQuadrature(obj, boundary)
662 switch boundary
663 case {'w','W','west','West', 'e', 'E', 'east', 'East'}
664 j = 1;
665 case {'s','S','south','South', 'n', 'N', 'north', 'North'}
666 j = 2;
667 otherwise
668 error('No such boundary: boundary = %s',boundary);
669 end
670 H = obj.H_boundary{j};
671 I_dim = speye(obj.dim, obj.dim);
672 H = kron(H, I_dim);
506 end 673 end
507 674
508 function N = size(obj) 675 function N = size(obj)
509 N = obj.dim*prod(obj.m); 676 N = obj.dim*prod(obj.m);
510 end 677 end