comparison +scheme/Elastic2dVariable.m @ 943:21394c78c72e feature/utux2D

Merge with default
author Martin Almquist <malmquist@stanford.edu>
date Tue, 04 Dec 2018 15:24:36 -0800
parents b9c98661ff5d b374a8aa9246
children a4ad90b37998 a2fcc4cf2298
comparison
equal deleted inserted replaced
942:35701c85e356 943:21394c78c72e
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 % Inner products
34
34 phi % Borrowing constant for (d1 - e^T*D1) from R 35 phi % Borrowing constant for (d1 - e^T*D1) from R
35 gamma % Borrowing constant for d1 from M 36 gamma % Borrowing constant for d1 from M
36 H11 % First element of H 37 H11 % First element of H
38
39 % Borrowing from H, M, and R
40 thH
41 thM
42 thR
43
37 e_l, e_r 44 e_l, e_r
38 d1_l, d1_r % Normal derivatives at the boundary 45 d1_l, d1_r % Normal derivatives at the boundary
39 E % E{i}^T picks out component i 46 E % E{i}^T picks out component i
40 47
41 H_boundary % Boundary inner products 48 H_boundary % Boundary inner products
62 m = g.size(); 69 m = g.size();
63 m_tot = g.N(); 70 m_tot = g.N();
64 71
65 h = g.scaling(); 72 h = g.scaling();
66 lim = g.lim; 73 lim = g.lim;
74 if isempty(lim)
75 x = g.x;
76 lim = cell(length(x),1);
77 for i = 1:length(x)
78 lim{i} = {min(x{i}), max(x{i})};
79 end
80 end
67 81
68 % 1D operators 82 % 1D operators
69 ops = cell(dim,1); 83 ops = cell(dim,1);
70 for i = 1:dim 84 for i = 1:dim
71 ops{i} = opSet{i}(m(i), lim{i}, order); 85 ops{i} = opSet{i}(m(i), lim{i}, order);
75 for i = 1:dim 89 for i = 1:dim
76 beta = ops{i}.borrowing.R.delta_D; 90 beta = ops{i}.borrowing.R.delta_D;
77 obj.H11{i} = ops{i}.borrowing.H11; 91 obj.H11{i} = ops{i}.borrowing.H11;
78 obj.phi{i} = beta/obj.H11{i}; 92 obj.phi{i} = beta/obj.H11{i};
79 obj.gamma{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;
80 end 99 end
81 100
82 I = cell(dim,1); 101 I = cell(dim,1);
83 D1 = cell(dim,1); 102 D1 = cell(dim,1);
84 D2 = cell(dim,1); 103 D2 = cell(dim,1);
260 279
261 280
262 % Closure functions return the operators applied to the own domain to close the boundary 281 % Closure functions return the operators applied to the own domain to close the boundary
263 % Penalty functions return the operators to force the solution. In the case of an interface it returns the operator applied to the other doamin. 282 % Penalty functions return the operators to force the solution. In the case of an interface it returns the operator applied to the other doamin.
264 % boundary is a string specifying the boundary e.g. 'l','r' or 'e','w','n','s'. 283 % boundary is a string specifying the boundary e.g. 'l','r' or 'e','w','n','s'.
265 % type is a cell array of strings specifying the type of boundary condition for each component. 284 % bc is a cell array of component and bc type, e.g. {1, 'd'} for Dirichlet condition
285 % on the first component.
266 % data is a function returning the data that should be applied at the boundary. 286 % data is a function returning the data that should be applied at the boundary.
267 % neighbour_scheme is an instance of Scheme that should be interfaced to. 287 % neighbour_scheme is an instance of Scheme that should be interfaced to.
268 % neighbour_boundary is a string specifying which boundary to interface to. 288 % neighbour_boundary is a string specifying which boundary to interface to.
269 function [closure, penalty] = boundary_condition(obj, boundary, type, parameter) 289 function [closure, penalty] = boundary_condition(obj, boundary, bc, tuning)
270 default_arg('type',{'free','free'}); 290 default_arg('tuning', 1.2);
271 default_arg('parameter', []); 291
292 assert( iscell(bc), 'The BC type must be a 2x1 cell array' );
293 comp = bc{1};
294 type = bc{2};
272 295
273 % j is the coordinate direction of the boundary 296 % j is the coordinate direction of the boundary
274 % nj: outward unit normal component. 297 j = obj.get_boundary_number(boundary);
275 % nj = -1 for west, south, bottom boundaries 298 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary);
276 % nj = 1 for east, north, top boundaries
277 [j, nj] = obj.get_boundary_number(boundary);
278 switch nj
279 case 1
280 e = obj.e_r;
281 d = obj.d1_r;
282 tau = obj.tau_r{j};
283 T = obj.T_r{j};
284 case -1
285 e = obj.e_l;
286 d = obj.d1_l;
287 tau = obj.tau_l{j};
288 T = obj.T_l{j};
289 end
290 299
291 E = obj.E; 300 E = obj.E;
292 Hi = obj.Hi; 301 Hi = obj.Hi;
293 H_gamma = obj.H_boundary{j};
294 LAMBDA = obj.LAMBDA; 302 LAMBDA = obj.LAMBDA;
295 MU = obj.MU; 303 MU = obj.MU;
296 RHOi = obj.RHOi; 304 RHOi = obj.RHOi;
297 305
298 dim = obj.dim; 306 dim = obj.dim;
299 m_tot = obj.grid.N(); 307 m_tot = obj.grid.N();
300 308
301 RHOi_kron = obj.RHOi_kron;
302 Hi_kron = obj.Hi_kron;
303
304 % Preallocate 309 % Preallocate
305 closure = sparse(dim*m_tot, dim*m_tot); 310 closure = sparse(dim*m_tot, dim*m_tot);
306 penalty = cell(dim,1); 311 penalty = sparse(dim*m_tot, m_tot/obj.m(j));
307 for k = 1:dim 312
308 penalty{k} = sparse(dim*m_tot, m_tot/obj.m(j)); 313 k = comp;
309 end 314 switch type
310 315
311 % Loop over components that we (potentially) have different BC on 316 % Dirichlet boundary condition
312 for k = 1:dim 317 case {'D','d','dirichlet','Dirichlet'}
313 switch type{k} 318
314 319 phi = obj.phi{j};
315 % Dirichlet boundary condition 320 h = obj.h(j);
316 case {'D','d','dirichlet','Dirichlet'} 321 h11 = obj.H11{j}*h;
317 322 gamma = obj.gamma{j};
318 tuning = 1.2; 323
319 phi = obj.phi{j}; 324 a_lambda = dim/h11 + 1/(h11*phi);
320 h = obj.h(j); 325 a_mu_i = 2/(gamma*h);
321 h11 = obj.H11{j}*h; 326 a_mu_ij = 2/h11 + 1/(h11*phi);
322 gamma = obj.gamma{j}; 327
323 328 d = @kroneckerDelta; % Kronecker delta
324 a_lambda = dim/h11 + 1/(h11*phi); 329 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
325 a_mu_i = 2/(gamma*h); 330 alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ...
326 a_mu_ij = 2/h11 + 1/(h11*phi); 331 + d(i,j)* a_mu_i*MU ...
327 332 + db(i,j)*a_mu_ij*MU );
328 d = @kroneckerDelta; % Kronecker delta 333
329 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta 334 % Loop over components that Dirichlet penalties end up on
330 alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ... 335 for i = 1:dim
331 + d(i,j)* a_mu_i*MU ... 336 C = T{k,i};
332 + db(i,j)*a_mu_ij*MU ); 337 A = -d(i,k)*alpha(i,j);
333 338 B = A + C;
334 % Loop over components that Dirichlet penalties end up on 339 closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' );
335 for i = 1:dim 340 penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma;
336 C = T{k,i};
337 A = -d(i,k)*alpha(i,j);
338 B = A + C;
339 closure = closure + E{i}*RHOi*Hi*B'*e{j}*H_gamma*(e{j}'*E{k}' );
340 penalty{k} = penalty{k} - E{i}*RHOi*Hi*B'*e{j}*H_gamma;
341 end
342
343 % Free boundary condition
344 case {'F','f','Free','free','traction','Traction','t','T'}
345 closure = closure - E{k}*RHOi*Hi*e{j}*H_gamma* (e{j}'*tau{k} );
346 penalty{k} = penalty{k} + E{k}*RHOi*Hi*e{j}*H_gamma;
347
348 % Unknown boundary condition
349 otherwise
350 error('No such boundary condition: type = %s',type);
351 end 341 end
342
343 % Free boundary condition
344 case {'F','f','Free','free','traction','Traction','t','T'}
345 closure = closure - E{k}*RHOi*Hi*e*H_gamma* (e'*tau{k} );
346 penalty = penalty + E{k}*RHOi*Hi*e*H_gamma;
347
348 % Unknown boundary condition
349 otherwise
350 error('No such boundary condition: type = %s',type);
352 end 351 end
353 end 352 end
354 353
355 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,opts) 354 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
356 % u denotes the solution in the own domain 355 % u denotes the solution in the own domain
357 % v denotes the solution in the neighbour domain 356 % v denotes the solution in the neighbour domain
357 % Operators without subscripts are from the own domain.
358 tuning = 1.2; 358 tuning = 1.2;
359 % tuning = 20.2; 359
360 error('Interface not implemented'); 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
364 % Get boundary operators
365 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary);
366 [e_v, tau_v] = neighbour_scheme.get_boundary_operator({'e','tau'}, neighbour_boundary);
367
368 % Operators and quantities that correspond to the own domain only
369 Hi = obj.Hi;
370 RHOi = obj.RHOi;
371 dim = obj.dim;
372
373 %--- Other operators ----
374 m_tot_u = obj.grid.N();
375 E = obj.E;
376 LAMBDA_u = obj.LAMBDA;
377 MU_u = obj.MU;
378 lambda_u = e'*LAMBDA_u*e;
379 mu_u = e'*MU_u*e;
380
381 m_tot_v = neighbour_scheme.grid.N();
382 E_v = neighbour_scheme.E;
383 LAMBDA_v = neighbour_scheme.LAMBDA;
384 MU_v = neighbour_scheme.MU;
385 lambda_v = e_v'*LAMBDA_v*e_v;
386 mu_v = e_v'*MU_v*e_v;
387 %-------------------------
388
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
361 end 430 end
362 431
363 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. 432 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary.
364 function [j, nj] = get_boundary_number(obj, boundary) 433 function [j, nj] = get_boundary_number(obj, boundary)
365 434
378 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 447 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
379 nj = 1; 448 nj = 1;
380 end 449 end
381 end 450 end
382 451
383 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. 452 % Returns the boundary operator op for the boundary specified by the string boundary.
384 function [return_op] = get_boundary_operator(obj, op, boundary) 453 % op: may be a cell array of strings
454 function [varargout] = get_boundary_operator(obj, op, boundary)
385 455
386 switch boundary 456 switch boundary
387 case {'w','W','west','West', 'e', 'E', 'east', 'East'} 457 case {'w','W','west','West', 'e', 'E', 'east', 'East'}
388 j = 1; 458 j = 1;
389 case {'s','S','south','South', 'n', 'N', 'north', 'North'} 459 case {'s','S','south','South', 'n', 'N', 'north', 'North'}
390 j = 2; 460 j = 2;
391 otherwise 461 otherwise
392 error('No such boundary: boundary = %s',boundary); 462 error('No such boundary: boundary = %s',boundary);
393 end 463 end
394 464
395 switch op 465 if ~iscell(op)
396 case 'e' 466 op = {op};
397 switch boundary 467 end
398 case {'w','W','west','West','s','S','south','South'} 468
399 return_op = obj.e_l{j}; 469 for i = 1:length(op)
400 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 470 switch op{i}
401 return_op = obj.e_r{j}; 471 case 'e'
402 end 472 switch boundary
403 case 'd' 473 case {'w','W','west','West','s','S','south','South'}
404 switch boundary 474 varargout{i} = obj.e_l{j};
405 case {'w','W','west','West','s','S','south','South'} 475 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
406 return_op = obj.d1_l{j}; 476 varargout{i} = obj.e_r{j};
407 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 477 end
408 return_op = obj.d1_r{j}; 478 case 'd'
409 end 479 switch boundary
410 otherwise 480 case {'w','W','west','West','s','S','south','South'}
411 error(['No such operator: operatr = ' op]); 481 varargout{i} = obj.d1_l{j};
482 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
483 varargout{i} = obj.d1_r{j};
484 end
485 case 'H'
486 varargout{i} = obj.H_boundary{j};
487 case 'T'
488 switch boundary
489 case {'w','W','west','West','s','S','south','South'}
490 varargout{i} = obj.T_l{j};
491 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
492 varargout{i} = obj.T_r{j};
493 end
494 case 'tau'
495 switch boundary
496 case {'w','W','west','West','s','S','south','South'}
497 varargout{i} = obj.tau_l{j};
498 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
499 varargout{i} = obj.tau_r{j};
500 end
501 otherwise
502 error(['No such operator: operator = ' op{i}]);
503 end
412 end 504 end
413 505
414 end 506 end
415 507
416 function N = size(obj) 508 function N = size(obj)
417 N = prod(obj.m); 509 N = obj.dim*prod(obj.m);
418 end 510 end
419 end 511 end
420 end 512 end