comparison +scheme/Elastic2dVariable.m @ 981:a2fcc4cf2298 feature/getBoundaryOp

Update scheme.Elastic2dVariable by copy-pasting from feature/poroelastic. This is compatible with new getBoundaryOperator in multiblock.DiffOp.
author Martin Almquist <malmquist@stanford.edu>
date Mon, 07 Jan 2019 17:10:06 +0100
parents 21394c78c72e
children adbb80e60b10
comparison
equal deleted inserted replaced
980:a3accd2f1283 981:a2fcc4cf2298
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
36
45 d1_l, d1_r % Normal derivatives at the boundary 37 d1_l, d1_r % Normal derivatives at the boundary
46 E % E{i}^T picks out component i 38 E % E{i}^T picks out component i
47 39
48 H_boundary % Boundary inner products 40 H_boundary % Boundary inner products
49 41
50 % Kroneckered norms and coefficients 42 % Kroneckered norms and coefficients
51 RHOi_kron 43 RHOi_kron
52 Hi_kron 44 Hi_kron
45
46 % Borrowing constants of the form gamma*h, where gamma is a dimensionless constant.
47 theta_R % Borrowing (d1- D1)^2 from R
48 theta_H % First entry in norm matrix
49 theta_M % Borrowing d1^2 from M.
50
51 % Structures used for adjoint optimization
52 B
53 end 53 end
54 54
55 methods 55 methods
56 56
57 function obj = Elastic2dVariable(g ,order, lambda_fun, mu_fun, rho_fun, opSet) 57 % The coefficients can either be function handles or grid functions
58 function obj = Elastic2dVariable(g ,order, lambda, mu, rho, opSet)
58 default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable}); 59 default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable});
59 default_arg('lambda_fun', @(x,y) 0*x+1); 60 default_arg('lambda', @(x,y) 0*x+1);
60 default_arg('mu_fun', @(x,y) 0*x+1); 61 default_arg('mu', @(x,y) 0*x+1);
61 default_arg('rho_fun', @(x,y) 0*x+1); 62 default_arg('rho', @(x,y) 0*x+1);
62 dim = 2; 63 dim = 2;
63 64
64 assert(isa(g, 'grid.Cartesian')) 65 assert(isa(g, 'grid.Cartesian'))
65 66
66 lambda = grid.evalOn(g, lambda_fun); 67 if isa(lambda, 'function_handle')
67 mu = grid.evalOn(g, mu_fun); 68 lambda = grid.evalOn(g, lambda);
68 rho = grid.evalOn(g, rho_fun); 69 end
70 if isa(mu, 'function_handle')
71 mu = grid.evalOn(g, mu);
72 end
73 if isa(rho, 'function_handle')
74 rho = grid.evalOn(g, rho);
75 end
76
69 m = g.size(); 77 m = g.size();
70 m_tot = g.N(); 78 m_tot = g.N();
71 79
72 h = g.scaling(); 80 h = g.scaling();
73 lim = g.lim; 81 lim = g.lim;
85 ops{i} = opSet{i}(m(i), lim{i}, order); 93 ops{i} = opSet{i}(m(i), lim{i}, order);
86 end 94 end
87 95
88 % Borrowing constants 96 % Borrowing constants
89 for i = 1:dim 97 for i = 1:dim
90 beta = ops{i}.borrowing.R.delta_D; 98 obj.theta_R{i} = h(i)*ops{i}.borrowing.R.delta_D;
91 obj.H11{i} = ops{i}.borrowing.H11; 99 obj.theta_H{i} = h(i)*ops{i}.borrowing.H11;
92 obj.phi{i} = beta/obj.H11{i}; 100 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 101 end
100 102
101 I = cell(dim,1); 103 I = cell(dim,1);
102 D1 = cell(dim,1); 104 D1 = cell(dim,1);
103 D2 = cell(dim,1); 105 D2 = cell(dim,1);
181 obj.H = kron(H{1},H{2}); 183 obj.H = kron(H{1},H{2});
182 obj.Hi = inv(obj.H); 184 obj.Hi = inv(obj.H);
183 obj.H_boundary = cell(dim,1); 185 obj.H_boundary = cell(dim,1);
184 obj.H_boundary{1} = H{2}; 186 obj.H_boundary{1} = H{2};
185 obj.H_boundary{2} = H{1}; 187 obj.H_boundary{2} = H{1};
188 obj.H_1D = {H{1}, H{2}};
186 189
187 % E{i}^T picks out component i. 190 % E{i}^T picks out component i.
188 E = cell(dim,1); 191 E = cell(dim,1);
189 I = speye(m_tot,m_tot); 192 I = speye(m_tot,m_tot);
190 for i = 1:dim 193 for i = 1:dim
211 D2_mu{j}*E{i}' ... 214 D2_mu{j}*E{i}' ...
212 ); 215 );
213 end 216 end
214 end 217 end
215 obj.D = D; 218 obj.D = D;
216 %=========================================% 219 %=========================================%'
217 220
218 % Numerical traction operators for BC. 221 % Numerical traction operators for BC.
219 % Because d1 =/= e0^T*D1, the numerical tractions are different 222 % Because d1 =/= e0^T*D1, the numerical tractions are different
220 % at every boundary. 223 % at every boundary.
221 T_l = cell(dim,1); 224 T_l = cell(dim,1);
235 T_l{j} = cell(dim,dim); 238 T_l{j} = cell(dim,dim);
236 T_r{j} = cell(dim,dim); 239 T_r{j} = cell(dim,dim);
237 tau_l{j} = cell(dim,1); 240 tau_l{j} = cell(dim,1);
238 tau_r{j} = cell(dim,1); 241 tau_r{j} = cell(dim,1);
239 242
243 LAMBDA_l = e_l{j}'*LAMBDA*e_l{j};
244 LAMBDA_r = e_r{j}'*LAMBDA*e_r{j};
245 MU_l = e_l{j}'*MU*e_l{j};
246 MU_r = e_r{j}'*MU*e_r{j};
247
248 [~, n_l] = size(e_l{j});
249 [~, n_r] = size(e_r{j});
250
240 % Loop over components 251 % Loop over components
241 for i = 1:dim 252 for i = 1:dim
242 tau_l{j}{i} = sparse(m_tot,dim*m_tot); 253 tau_l{j}{i} = sparse(n_l, dim*m_tot);
243 tau_r{j}{i} = sparse(m_tot,dim*m_tot); 254 tau_r{j}{i} = sparse(n_r, dim*m_tot);
244 for k = 1:dim 255 for k = 1:dim
245 T_l{j}{i,k} = ... 256 T_l{j}{i,k} = ...
246 -d(i,j)*LAMBDA*(d(i,k)*e_l{k}*d1_l{k}' + db(i,k)*D1{k})... 257 -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})... 258 -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}'; 259 -d(i,k)*MU_l*d1_l{j}';
249 260
250 T_r{j}{i,k} = ... 261 T_r{j}{i,k} = ...
251 d(i,j)*LAMBDA*(d(i,k)*e_r{k}*d1_r{k}' + db(i,k)*D1{k})... 262 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})... 263 +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}'; 264 +d(i,k)*MU_r*d1_r{j}';
254 265
255 tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}'; 266 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}'; 267 tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}';
257 end 268 end
258 269
259 end 270 end
260 end 271 end
272
273 % Transpose T and tau to match boundary operator convention
274 for i = 1:dim
275 for j = 1:dim
276 tau_l{i}{j} = transpose(tau_l{i}{j});
277 tau_r{i}{j} = transpose(tau_r{i}{j});
278 for k = 1:dim
279 T_l{i}{j,k} = transpose(T_l{i}{j,k});
280 T_r{i}{j,k} = transpose(T_r{i}{j,k});
281 end
282 end
283 end
284
261 obj.T_l = T_l; 285 obj.T_l = T_l;
262 obj.T_r = T_r; 286 obj.T_r = T_r;
263 obj.tau_l = tau_l; 287 obj.tau_l = tau_l;
264 obj.tau_r = tau_r; 288 obj.tau_r = tau_r;
265 289
272 obj.m = m; 296 obj.m = m;
273 obj.h = h; 297 obj.h = h;
274 obj.order = order; 298 obj.order = order;
275 obj.grid = g; 299 obj.grid = g;
276 obj.dim = dim; 300 obj.dim = dim;
301
302 % B, used for adjoint optimization
303 B = cell(dim, 1);
304 for i = 1:dim
305 B{i} = cell(m_tot, 1);
306 end
307
308 for i = 1:dim
309 for j = 1:m_tot
310 B{i}{j} = sparse(m_tot, m_tot);
311 end
312 end
313
314 ind = grid.funcToMatrix(g, 1:m_tot);
315
316 % Direction 1
317 for k = 1:m(1)
318 c = sparse(m(1),1);
319 c(k) = 1;
320 [~, B_1D] = ops{1}.D2(c);
321 for l = 1:m(2)
322 p = ind(:,l);
323 B{1}{(k-1)*m(2) + l}(p, p) = B_1D;
324 end
325 end
326
327 % Direction 2
328 for k = 1:m(2)
329 c = sparse(m(2),1);
330 c(k) = 1;
331 [~, B_1D] = ops{2}.D2(c);
332 for l = 1:m(1)
333 p = ind(l,:);
334 B{2}{(l-1)*m(2) + k}(p, p) = B_1D;
335 end
336 end
337
338 obj.B = B;
277 339
278 end 340 end
279 341
280 342
281 % Closure functions return the operators applied to the own domain to close the boundary 343 % Closure functions return the operators applied to the own domain to close the boundary
293 comp = bc{1}; 355 comp = bc{1};
294 type = bc{2}; 356 type = bc{2};
295 357
296 % j is the coordinate direction of the boundary 358 % j is the coordinate direction of the boundary
297 j = obj.get_boundary_number(boundary); 359 j = obj.get_boundary_number(boundary);
298 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); 360 [e, T, tau, H_gamma] = obj.getBoundaryOperator({'e','T','tau','H'}, boundary);
361
299 362
300 E = obj.E; 363 E = obj.E;
301 Hi = obj.Hi; 364 Hi = obj.Hi;
302 LAMBDA = obj.LAMBDA; 365 LAMBDA = obj.LAMBDA;
303 MU = obj.MU; 366 MU = obj.MU;
314 switch type 377 switch type
315 378
316 % Dirichlet boundary condition 379 % Dirichlet boundary condition
317 case {'D','d','dirichlet','Dirichlet'} 380 case {'D','d','dirichlet','Dirichlet'}
318 381
319 phi = obj.phi{j}; 382 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 383
334 % Loop over components that Dirichlet penalties end up on 384 % Loop over components that Dirichlet penalties end up on
335 for i = 1:dim 385 for i = 1:dim
336 C = T{k,i}; 386 C = transpose(T{k,i});
337 A = -d(i,k)*alpha(i,j); 387 A = -tuning*e*transpose(alpha{i,k});
338 B = A + C; 388 B = A + e*C;
339 closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' ); 389 closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' );
340 penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma; 390 penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma;
341 end 391 end
342 392
343 % Free boundary condition 393 % Free boundary condition
344 case {'F','f','Free','free','traction','Traction','t','T'} 394 case {'F','f','Free','free','traction','Traction','t','T'}
345 closure = closure - E{k}*RHOi*Hi*e*H_gamma* (e'*tau{k} ); 395 closure = closure - E{k}*RHOi*Hi*e*H_gamma*tau{k}';
346 penalty = penalty + E{k}*RHOi*Hi*e*H_gamma; 396 penalty = penalty + E{k}*RHOi*Hi*e*H_gamma;
347 397
348 % Unknown boundary condition 398 % Unknown boundary condition
349 otherwise 399 otherwise
350 error('No such boundary condition: type = %s',type); 400 error('No such boundary condition: type = %s',type);
351 end 401 end
352 end 402 end
353 403
354 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary) 404 % type Struct that specifies the interface coupling.
405 % Fields:
406 % -- tuning: penalty strength, defaults to 1.2
407 % -- interpolation: type of interpolation, default 'none'
408 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type)
409
410 defaultType.tuning = 1.2;
411 defaultType.interpolation = 'none';
412 default_struct('type', defaultType);
413
414 switch type.interpolation
415 case {'none', ''}
416 [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type);
417 case {'op','OP'}
418 [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type);
419 otherwise
420 error('Unknown type of interpolation: %s ', type.interpolation);
421 end
422 end
423
424 function [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type)
425 tuning = type.tuning;
426
355 % u denotes the solution in the own domain 427 % u denotes the solution in the own domain
356 % v denotes the solution in the neighbour domain 428 % v denotes the solution in the neighbour domain
357 % Operators without subscripts are from the own domain. 429 % Operators without subscripts are from the own domain.
358 tuning = 1.2;
359
360 % j is the coordinate direction of the boundary
361 j = obj.get_boundary_number(boundary);
362 j_v = neighbour_scheme.get_boundary_number(neighbour_boundary);
363 430
364 % Get boundary operators 431 % Get boundary operators
365 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); 432 [e, tau] = obj.getBoundaryOperator({'e_tot','tau_tot'}, boundary);
366 [e_v, tau_v] = neighbour_scheme.get_boundary_operator({'e','tau'}, neighbour_boundary); 433 [e_v, tau_v] = neighbour_scheme.getBoundaryOperator({'e_tot','tau_tot'}, neighbour_boundary);
434 H_gamma = obj.getBoundaryQuadrature(boundary);
367 435
368 % Operators and quantities that correspond to the own domain only 436 % Operators and quantities that correspond to the own domain only
369 Hi = obj.Hi; 437 Hi = obj.Hi_kron;
370 RHOi = obj.RHOi; 438 RHOi = obj.RHOi_kron;
371 dim = obj.dim; 439
372 440 % Penalty strength operators
373 %--- Other operators ---- 441 alpha_u = 1/4*tuning*obj.getBoundaryOperator('alpha_tot', boundary);
374 m_tot_u = obj.grid.N(); 442 alpha_v = 1/4*tuning*neighbour_scheme.getBoundaryOperator('alpha_tot', neighbour_boundary);
375 E = obj.E; 443
376 LAMBDA_u = obj.LAMBDA; 444 closure = -RHOi*Hi*e*H_gamma*(alpha_u' + alpha_v'*e_v*e');
377 MU_u = obj.MU; 445 penalty = RHOi*Hi*e*H_gamma*(alpha_u'*e*e_v' + alpha_v');
378 lambda_u = e'*LAMBDA_u*e; 446
379 mu_u = e'*MU_u*e; 447 closure = closure - 1/2*RHOi*Hi*e*H_gamma*tau';
380 448 penalty = penalty - 1/2*RHOi*Hi*e*H_gamma*tau_v';
381 m_tot_v = neighbour_scheme.grid.N(); 449
382 E_v = neighbour_scheme.E; 450 closure = closure + 1/2*RHOi*Hi*tau*H_gamma*e';
383 LAMBDA_v = neighbour_scheme.LAMBDA; 451 penalty = penalty - 1/2*RHOi*Hi*tau*H_gamma*e_v';
384 MU_v = neighbour_scheme.MU; 452
385 lambda_v = e_v'*LAMBDA_v*e_v; 453 end
386 mu_v = e_v'*MU_v*e_v; 454
387 %------------------------- 455 function [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type)
388 456 error('Non-conforming interfaces not implemented yet.');
389 % Borrowing constants
390 h_u = obj.h(j);
391 thR_u = obj.thR{j}*h_u;
392 thM_u = obj.thM{j}*h_u;
393 thH_u = obj.thH{j}*h_u;
394
395 h_v = neighbour_scheme.h(j_v);
396 thR_v = neighbour_scheme.thR{j_v}*h_v;
397 thH_v = neighbour_scheme.thH{j_v}*h_v;
398 thM_v = neighbour_scheme.thM{j_v}*h_v;
399
400 % alpha = penalty strength for normal component, beta for tangential
401 alpha_u = dim*lambda_u/(4*thH_u) + lambda_u/(4*thR_u) + mu_u/(2*thM_u);
402 alpha_v = dim*lambda_v/(4*thH_v) + lambda_v/(4*thR_v) + mu_v/(2*thM_v);
403 beta_u = mu_u/(2*thH_u) + mu_u/(4*thR_u);
404 beta_v = mu_v/(2*thH_v) + mu_v/(4*thR_v);
405 alpha = alpha_u + alpha_v;
406 beta = beta_u + beta_v;
407
408 d = @kroneckerDelta; % Kronecker delta
409 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);
411
412 % Preallocate
413 closure = sparse(dim*m_tot_u, dim*m_tot_u);
414 penalty = sparse(dim*m_tot_u, dim*m_tot_v);
415
416 % Loop over components that penalties end up on
417 for i = 1:dim
418 closure = closure - E{i}*RHOi*Hi*e*strength(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}';
420
421 closure = closure - 1/2*E{i}*RHOi*Hi*e*H_gamma*e'*tau{i};
422 penalty = penalty - 1/2*E{i}*RHOi*Hi*e*H_gamma*e_v'*tau_v{i};
423
424 % Loop over components that we have interface conditions on
425 for k = 1:dim
426 closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}'*e*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}';
428 end
429 end
430 end 457 end
431 458
432 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. 459 % 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) 460 function [j, nj] = get_boundary_number(obj, boundary)
434 461
449 end 476 end
450 end 477 end
451 478
452 % Returns the boundary operator op for the boundary specified by the string boundary. 479 % Returns the boundary operator op for the boundary specified by the string boundary.
453 % op: may be a cell array of strings 480 % op: may be a cell array of strings
454 function [varargout] = get_boundary_operator(obj, op, boundary) 481 % Only operators with name *_tot can be used with multiblock.DiffOp.getBoundaryOperator()
482 function [varargout] = getBoundaryOperator(obj, op, boundary)
455 483
456 switch boundary 484 switch boundary
457 case {'w','W','west','West', 'e', 'E', 'east', 'East'} 485 case {'w','W','west','West', 'e', 'E', 'east', 'East'}
458 j = 1; 486 j = 1;
459 case {'s','S','south','South', 'n', 'N', 'north', 'North'} 487 case {'s','S','south','South', 'n', 'N', 'north', 'North'}
464 492
465 if ~iscell(op) 493 if ~iscell(op)
466 op = {op}; 494 op = {op};
467 end 495 end
468 496
469 for i = 1:length(op) 497 for k = 1:length(op)
470 switch op{i} 498 switch op{k}
471 case 'e' 499 case 'e'
472 switch boundary 500 switch boundary
473 case {'w','W','west','West','s','S','south','South'} 501 case {'w','W','west','West','s','S','south','South'}
474 varargout{i} = obj.e_l{j}; 502 varargout{k} = obj.e_l{j};
475 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 503 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
476 varargout{i} = obj.e_r{j}; 504 varargout{k} = obj.e_r{j};
477 end 505 end
506
507 case 'e_tot'
508 e = obj.getBoundaryOperator('e', boundary);
509 I_dim = speye(obj.dim, obj.dim);
510 varargout{k} = kron(e, I_dim);
511
478 case 'd' 512 case 'd'
479 switch boundary 513 switch boundary
480 case {'w','W','west','West','s','S','south','South'} 514 case {'w','W','west','West','s','S','south','South'}
481 varargout{i} = obj.d1_l{j}; 515 varargout{k} = obj.d1_l{j};
482 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 516 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
483 varargout{i} = obj.d1_r{j}; 517 varargout{k} = obj.d1_r{j};
484 end 518 end
485 case 'H' 519
486 varargout{i} = obj.H_boundary{j};
487 case 'T' 520 case 'T'
488 switch boundary 521 switch boundary
489 case {'w','W','west','West','s','S','south','South'} 522 case {'w','W','west','West','s','S','south','South'}
490 varargout{i} = obj.T_l{j}; 523 varargout{k} = obj.T_l{j};
491 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 524 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
492 varargout{i} = obj.T_r{j}; 525 varargout{k} = obj.T_r{j};
493 end 526 end
527
494 case 'tau' 528 case 'tau'
495 switch boundary 529 switch boundary
496 case {'w','W','west','West','s','S','south','South'} 530 case {'w','W','west','West','s','S','south','South'}
497 varargout{i} = obj.tau_l{j}; 531 varargout{k} = obj.tau_l{j};
498 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 532 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
499 varargout{i} = obj.tau_r{j}; 533 varargout{k} = obj.tau_r{j};
500 end 534 end
535
536 case 'tau_tot'
537 [e, tau] = obj.getBoundaryOperator({'e', 'tau'}, boundary);
538
539 I_dim = speye(obj.dim, obj.dim);
540 e_tot = kron(e, I_dim);
541 E = obj.E;
542 tau_tot = (e_tot'*E{1}*e*tau{1}')';
543 for i = 2:obj.dim
544 tau_tot = tau_tot + (e_tot'*E{i}*e*tau{i}')';
545 end
546 varargout{k} = tau_tot;
547
548 case 'H'
549 varargout{k} = obj.H_boundary{j};
550
551 case 'alpha'
552 % alpha = alpha(i,j) is the penalty strength for displacement BC.
553 e = obj.getBoundaryOperator('e', boundary);
554
555 LAMBDA = obj.LAMBDA;
556 MU = obj.MU;
557
558 dim = obj.dim;
559 theta_R = obj.theta_R{j};
560 theta_H = obj.theta_H{j};
561 theta_M = obj.theta_M{j};
562
563 a_lambda = dim/theta_H + 1/theta_R;
564 a_mu_i = 2/theta_M;
565 a_mu_ij = 2/theta_H + 1/theta_R;
566
567 d = @kroneckerDelta; % Kronecker delta
568 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
569 alpha = cell(obj.dim, obj.dim);
570
571 alpha_func = @(i,j) d(i,j)* a_lambda*LAMBDA ...
572 + d(i,j)* a_mu_i*MU ...
573 + db(i,j)*a_mu_ij*MU;
574 for i = 1:obj.dim
575 for l = 1:obj.dim
576 alpha{i,l} = d(i,l)*alpha_func(i,j)*e;
577 end
578 end
579
580 varargout{k} = alpha;
581
582 case 'alpha_tot'
583 % alpha = alpha(i,j) is the penalty strength for displacement BC.
584 [e, e_tot, alpha] = obj.getBoundaryOperator({'e', 'e_tot', 'alpha'}, boundary);
585 E = obj.E;
586 [m, n] = size(alpha{1,1});
587 alpha_tot = sparse(m*obj.dim, n*obj.dim);
588 for i = 1:obj.dim
589 for l = 1:obj.dim
590 alpha_tot = alpha_tot + (e_tot'*E{i}*e*alpha{i,l}'*E{l}')';
591 end
592 end
593 varargout{k} = alpha_tot;
594
501 otherwise 595 otherwise
502 error(['No such operator: operator = ' op{i}]); 596 error(['No such operator: operator = ' op{k}]);
503 end 597 end
504 end 598 end
505 599
600 end
601
602 function H = getBoundaryQuadrature(obj, boundary)
603 switch boundary
604 case {'w','W','west','West', 'e', 'E', 'east', 'East'}
605 j = 1;
606 case {'s','S','south','South', 'n', 'N', 'north', 'North'}
607 j = 2;
608 otherwise
609 error('No such boundary: boundary = %s',boundary);
610 end
611 H = obj.H_boundary{j};
612 I_dim = speye(obj.dim, obj.dim);
613 H = kron(H, I_dim);
506 end 614 end
507 615
508 function N = size(obj) 616 function N = size(obj)
509 N = obj.dim*prod(obj.m); 617 N = obj.dim*prod(obj.m);
510 end 618 end