comparison +scheme/Elastic2dCurvilinearAnisotropic.m @ 1295:cb053fabbedc feature/poroelastic

Add displacement BC on normal tangential components, but it is only provably stable if traction bc are used for the other component.
author Martin Almquist <malmquist@stanford.edu>
date Thu, 02 Jul 2020 20:05:50 -0700
parents fe712a1fca3f
children a0d615bde7f8
comparison
equal deleted inserted replaced
1294:fe712a1fca3f 1295:cb053fabbedc
34 % Traction operators 34 % Traction operators
35 tau_w, tau_e, tau_s, tau_n % Return vector field 35 tau_w, tau_e, tau_s, tau_n % Return vector field
36 tau1_w, tau1_e, tau1_s, tau1_n % Return scalar field 36 tau1_w, tau1_e, tau1_s, tau1_n % Return scalar field
37 tau2_w, tau2_e, tau2_s, tau2_n % Return scalar field 37 tau2_w, tau2_e, tau2_s, tau2_n % Return scalar field
38 tau_n_w, tau_n_e, tau_n_s, tau_n_n % Return scalar field 38 tau_n_w, tau_n_e, tau_n_s, tau_n_n % Return scalar field
39 tau_t_w, tau_t_e, tau_t_s, tau_t_n % Return scalar field
39 40
40 % Inner products 41 % Inner products
41 H 42 H
42 43
43 % Boundary inner products (for scalar field) 44 % Boundary inner products (for scalar field)
318 obj.et_w = (obj.tangent_w{1}*obj.e1_w' + obj.tangent_w{2}*obj.e2_w')'; 319 obj.et_w = (obj.tangent_w{1}*obj.e1_w' + obj.tangent_w{2}*obj.e2_w')';
319 obj.et_e = (obj.tangent_e{1}*obj.e1_e' + obj.tangent_e{2}*obj.e2_e')'; 320 obj.et_e = (obj.tangent_e{1}*obj.e1_e' + obj.tangent_e{2}*obj.e2_e')';
320 obj.et_s = (obj.tangent_s{1}*obj.e1_s' + obj.tangent_s{2}*obj.e2_s')'; 321 obj.et_s = (obj.tangent_s{1}*obj.e1_s' + obj.tangent_s{2}*obj.e2_s')';
321 obj.et_n = (obj.tangent_n{1}*obj.e1_n' + obj.tangent_n{2}*obj.e2_n')'; 322 obj.et_n = (obj.tangent_n{1}*obj.e1_n' + obj.tangent_n{2}*obj.e2_n')';
322 323
323 % obj.tau_n_w = (obj.en_w'*obj.e_w*obj.tau_w')';
324 % obj.tau_n_e = (obj.en_e'*obj.e_e*obj.tau_e')';
325 % obj.tau_n_s = (obj.en_s'*obj.e_s*obj.tau_s')';
326 % obj.tau_n_n = (obj.en_n'*obj.e_n*obj.tau_n')';
327
328 obj.tau_n_w = (obj.n_w{1}*obj.tau1_w' + obj.n_w{2}*obj.tau2_w')'; 324 obj.tau_n_w = (obj.n_w{1}*obj.tau1_w' + obj.n_w{2}*obj.tau2_w')';
329 obj.tau_n_e = (obj.n_e{1}*obj.tau1_e' + obj.n_e{2}*obj.tau2_e')'; 325 obj.tau_n_e = (obj.n_e{1}*obj.tau1_e' + obj.n_e{2}*obj.tau2_e')';
330 obj.tau_n_s = (obj.n_s{1}*obj.tau1_s' + obj.n_s{2}*obj.tau2_s')'; 326 obj.tau_n_s = (obj.n_s{1}*obj.tau1_s' + obj.n_s{2}*obj.tau2_s')';
331 obj.tau_n_n = (obj.n_n{1}*obj.tau1_n' + obj.n_n{2}*obj.tau2_n')'; 327 obj.tau_n_n = (obj.n_n{1}*obj.tau1_n' + obj.n_n{2}*obj.tau2_n')';
328
329 obj.tau_t_w = (obj.tangent_w{1}*obj.tau1_w' + obj.tangent_w{2}*obj.tau2_w')';
330 obj.tau_t_e = (obj.tangent_e{1}*obj.tau1_e' + obj.tangent_e{2}*obj.tau2_e')';
331 obj.tau_t_s = (obj.tangent_s{1}*obj.tau1_s' + obj.tangent_s{2}*obj.tau2_s')';
332 obj.tau_t_n = (obj.tangent_n{1}*obj.tau1_n' + obj.tangent_n{2}*obj.tau2_n')';
332 333
333 % Stress operators 334 % Stress operators
334 sigma = cell(dim, dim); 335 sigma = cell(dim, dim);
335 D1 = {obj.Dx, obj.Dy}; 336 D1 = {obj.Dx, obj.Dy};
336 E = obj.E; 337 E = obj.E;
396 case 't' 397 case 't'
397 en = obj.getBoundaryOperator('et', boundary); 398 en = obj.getBoundaryOperator('et', boundary);
398 end 399 end
399 e1 = obj.getBoundaryOperator('e1', boundary); 400 e1 = obj.getBoundaryOperator('e1', boundary);
400 401
401 bc = {1, type}; 402 bc1 = {1, type};
402 [c1, p1] = obj.refObj.boundary_condition(boundary, bc, tuning); 403 [c1, p1] = obj.refObj.boundary_condition(boundary, bc1, tuning);
403 bc = {2, type}; 404 bc2 = {2, type};
404 c2 = obj.refObj.boundary_condition(boundary, bc, tuning); 405 c2 = obj.refObj.boundary_condition(boundary, bc2, tuning);
405 406
406 switch type 407 switch type
407 case {'F','f','Free','free','traction','Traction','t','T'} 408 case {'F','f','Free','free','traction','Traction','t','T'}
408 closure = en*en'*(c1+c2); 409 closure = en*en'*(c1+c2);
409 penalty = en*e1'*p1; 410 penalty = en*e1'*p1;
410 case {'D','d','dirichlet','Dirichlet','displacement','Displacement'} 411 case {'D','d','dirichlet','Dirichlet','displacement','Displacement'}
411 error('Not implemented'); 412 [closure, penalty] = obj.displacementBCNormalTangential(boundary, bc, tuning);
412 end 413 end
413 414
414 end 415 end
415 416
416 switch type 417 switch type
421 penalty = penalty*s; 422 penalty = penalty*s;
422 423
423 end 424 end
424 end 425 end
425 426
426 function [closure, penalty] = displacementBCNormalTangential(boundary, bc, tuning) 427 function [closure, penalty] = displacementBCNormalTangential(obj, boundary, bc, tuning)
427 error('not implemented'); 428 disp('WARNING: displacementBCNormalTangential is only guaranteed to work for displaacement BC on one component and traction on the other');
428 u = obj; 429 u = obj;
429 430
430 component = bc{1}; 431 component = bc{1};
431 type = bc{2}; 432 type = bc{2};
432 433
433 switch component 434 switch component
434 case 'n' 435 case 'n'
435 en_u = u.getBoundaryOperator('en', boundary); 436 en = u.getBoundaryOperator('en', boundary);
436 tau_n_u = u.getBoundaryOperator('tau_n', boundary); 437 tau_n = u.getBoundaryOperator('tau_n', boundary);
438 N = u.getNormal(boundary);
437 case 't' 439 case 't'
438 en_u = u.getBoundaryOperator('et', boundary); 440 en = u.getBoundaryOperator('et', boundary);
439 tau_n_u = u.getBoundaryOperator('tau_t', boundary); 441 tau_n = u.getBoundaryOperator('tau_t', boundary);
442 N = u.getTangent(boundary);
440 end 443 end
441 444
442 % Operators 445 % Operators
446 e = u.getBoundaryOperatorForScalarField('e', boundary);
447 h11 = u.getBorrowing(boundary);
448 n = u.getNormal(boundary);
449
450 C = u.C;
451 Ji = u.Ji;
452 s = spdiag(u.(['s_' boundary]));
453 m_tot = u.grid.N();
454
455 Hi = u.E{1}*inv(u.H)*u.E{1}' + u.E{2}*inv(u.H)*u.E{2}';
456 RHOi = u.E{1}*inv(u.RHO)*u.E{1}' + u.E{2}*inv(u.RHO)*u.E{2}';
457
458 H_gamma = u.getBoundaryQuadratureForScalarField(boundary);
459 dim = u.dim;
460
461 % Preallocate
462 [~, m_int] = size(H_gamma);
463 closure = sparse(dim*m_tot, dim*m_tot);
464 penalty = sparse(dim*m_tot, m_int);
465
466 % Term 1: The symmetric term
467 Z = sparse(m_int, m_int);
468 for i = 1:dim
469 for j = 1:dim
470 for l = 1:dim
471 for k = 1:dim
472 Z = Z + n{i}*N{j}*e'*Ji*C{i,j,k,l}*e*n{k}*N{l};
473 end
474 end
475 end
476 end
477
478 Z = -tuning*dim*1/h11*s*Z;
479 closure = closure + en*H_gamma*Z*en';
480 penalty = penalty - en*H_gamma*Z;
481
482 % Term 2: The symmetrizing term
483 closure = closure + tau_n*H_gamma*en';
484 penalty = penalty - tau_n*H_gamma;
485
486 % Multiply all normal component terms by inverse of density x quadraure
487 closure = RHOi*Hi*closure;
488 penalty = RHOi*Hi*penalty;
489 end
490
491 % type Struct that specifies the interface coupling.
492 % Fields:
493 % -- tuning: penalty strength, defaults to 1.0
494 % -- interpolation: type of interpolation, default 'none'
495 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type)
496
497 defaultType.tuning = 1.0;
498 defaultType.interpolation = 'none';
499 defaultType.type = 'standard';
500 default_struct('type', defaultType);
501
502 switch type.type
503 case 'standard'
504 [closure, penalty] = obj.refObj.interface(boundary,neighbour_scheme.refObj,neighbour_boundary,type);
505 case 'frictionalFault'
506 [closure, penalty] = obj.interfaceFrictionalFault(boundary,neighbour_scheme,neighbour_boundary,type);
507 end
508
509 end
510
511 function [closure, penalty] = interfaceFrictionalFault(obj,boundary,neighbour_scheme,neighbour_boundary,type)
512 tuning = type.tuning;
513
514 % u denotes the solution in the own domain
515 % v denotes the solution in the neighbour domain
516
517 u = obj;
518 v = neighbour_scheme;
519
520 % Operators, u side
443 e_u = u.getBoundaryOperatorForScalarField('e', boundary); 521 e_u = u.getBoundaryOperatorForScalarField('e', boundary);
522 en_u = u.getBoundaryOperator('en', boundary);
523 tau_n_u = u.getBoundaryOperator('tau_n', boundary);
444 h11_u = u.getBorrowing(boundary); 524 h11_u = u.getBorrowing(boundary);
445 n_u = u.getNormal(boundary); 525 n_u = u.getNormal(boundary);
446 526
447 C_u = u.C; 527 C_u = u.C;
448 Ji_u = u.Ji; 528 Ji_u = u.Ji;
449 s_u = spdiag(u.(['s_' boundary])); 529 s_u = spdiag(u.(['s_' boundary]));
450 m_tot_u = u.grid.N(); 530 m_tot_u = u.grid.N();
451 531
532 % Operators, v side
533 e_v = v.getBoundaryOperatorForScalarField('e', neighbour_boundary);
534 en_v = v.getBoundaryOperator('en', neighbour_boundary);
535 tau_n_v = v.getBoundaryOperator('tau_n', neighbour_boundary);
536 h11_v = v.getBorrowing(neighbour_boundary);
537 n_v = v.getNormal(neighbour_boundary);
538
539 C_v = v.C;
540 Ji_v = v.Ji;
541 s_v = spdiag(v.(['s_' neighbour_boundary]));
542 m_tot_v = v.grid.N();
543
544 % Operators that are only required for own domain
452 Hi = u.E{1}*inv(u.H)*u.E{1}' + u.E{2}*inv(u.H)*u.E{2}'; 545 Hi = u.E{1}*inv(u.H)*u.E{1}' + u.E{2}*inv(u.H)*u.E{2}';
453 RHOi = u.E{1}*inv(u.RHO)*u.E{1}' + u.E{2}*inv(u.RHO)*u.E{2}'; 546 RHOi = u.E{1}*inv(u.RHO)*u.E{1}' + u.E{2}*inv(u.RHO)*u.E{2}';
454 547
455 % Shared operators 548 % Shared operators
456 H_gamma = u.getBoundaryQuadratureForScalarField(boundary); 549 H_gamma = u.getBoundaryQuadratureForScalarField(boundary);
466 Z_v = sparse(m_int, m_int); 559 Z_v = sparse(m_int, m_int);
467 for i = 1:dim 560 for i = 1:dim
468 for j = 1:dim 561 for j = 1:dim
469 for l = 1:dim 562 for l = 1:dim
470 for k = 1:dim 563 for k = 1:dim
471 Z_u = Z_u + n_u{i}*n_u{j}*e_u'*Ji_u*C_u{l,i,k,j}*e_u*n_u{k}*n_u{l}; 564 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};
472 Z_v = Z_v + n_v{i}*n_v{j}*e_v'*Ji_v*C_v{l,i,k,j}*e_v*n_v{k}*n_v{l}; 565 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};
473 end
474 end
475 end
476 end
477
478 Z = -tuning*dim*( 1/(4*h11_u)*s_u*Z_u + 1/(4*h11_v)*s_v*Z_v );
479 closure = closure + en_u*H_gamma*Z*en_u';
480 penalty = penalty + en_u*H_gamma*Z*en_v';
481
482 % Continuity of normal displacement, term 2: The symmetrizing term
483 closure = closure + 1/2*tau_n_u*H_gamma*en_u';
484 penalty = penalty + 1/2*tau_n_u*H_gamma*en_v';
485
486 % Continuity of normal traction
487 closure = closure - 1/2*en_u*H_gamma*tau_n_u';
488 penalty = penalty - 1/2*en_u*H_gamma*tau_n_v';
489
490 % Multiply all normal component terms by inverse of density x quadraure
491 closure = RHOi*Hi*closure;
492 penalty = RHOi*Hi*penalty;
493 end
494
495 % type Struct that specifies the interface coupling.
496 % Fields:
497 % -- tuning: penalty strength, defaults to 1.0
498 % -- interpolation: type of interpolation, default 'none'
499 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type)
500
501 defaultType.tuning = 1.0;
502 defaultType.interpolation = 'none';
503 defaultType.type = 'standard';
504 default_struct('type', defaultType);
505
506 switch type.type
507 case 'standard'
508 [closure, penalty] = obj.refObj.interface(boundary,neighbour_scheme.refObj,neighbour_boundary,type);
509 case 'frictionalFault'
510 [closure, penalty] = obj.interfaceFrictionalFault(boundary,neighbour_scheme,neighbour_boundary,type);
511 end
512
513 end
514
515 function [closure, penalty] = interfaceFrictionalFault(obj,boundary,neighbour_scheme,neighbour_boundary,type)
516 tuning = type.tuning;
517
518 % u denotes the solution in the own domain
519 % v denotes the solution in the neighbour domain
520
521 u = obj;
522 v = neighbour_scheme;
523
524 % Operators, u side
525 e_u = u.getBoundaryOperatorForScalarField('e', boundary);
526 en_u = u.getBoundaryOperator('en', boundary);
527 tau_n_u = u.getBoundaryOperator('tau_n', boundary);
528 h11_u = u.getBorrowing(boundary);
529 n_u = u.getNormal(boundary);
530
531 C_u = u.C;
532 Ji_u = u.Ji;
533 s_u = spdiag(u.(['s_' boundary]));
534 m_tot_u = u.grid.N();
535
536 % Operators, v side
537 e_v = v.getBoundaryOperatorForScalarField('e', neighbour_boundary);
538 en_v = v.getBoundaryOperator('en', neighbour_boundary);
539 tau_n_v = v.getBoundaryOperator('tau_n', neighbour_boundary);
540 h11_v = v.getBorrowing(neighbour_boundary);
541 n_v = v.getNormal(neighbour_boundary);
542
543 C_v = v.C;
544 Ji_v = v.Ji;
545 s_v = spdiag(v.(['s_' neighbour_boundary]));
546 m_tot_v = v.grid.N();
547
548 % Operators that are only required for own domain
549 Hi = u.E{1}*inv(u.H)*u.E{1}' + u.E{2}*inv(u.H)*u.E{2}';
550 RHOi = u.E{1}*inv(u.RHO)*u.E{1}' + u.E{2}*inv(u.RHO)*u.E{2}';
551
552 % Shared operators
553 H_gamma = u.getBoundaryQuadratureForScalarField(boundary);
554 dim = u.dim;
555
556 % Preallocate
557 [~, m_int] = size(H_gamma);
558 closure = sparse(dim*m_tot_u, dim*m_tot_u);
559 penalty = sparse(dim*m_tot_u, dim*m_tot_v);
560
561 % Continuity of normal displacement, term 1: The symmetric term
562 Z_u = sparse(m_int, m_int);
563 Z_v = sparse(m_int, m_int);
564 for i = 1:dim
565 for j = 1:dim
566 for l = 1:dim
567 for k = 1:dim
568 Z_u = Z_u + n_u{i}*n_u{j}*e_u'*Ji_u*C_u{l,i,k,j}*e_u*n_u{k}*n_u{l};
569 Z_v = Z_v + n_v{i}*n_v{j}*e_v'*Ji_v*C_v{l,i,k,j}*e_v*n_v{k}*n_v{l};
570 end 566 end
571 end 567 end
572 end 568 end
573 end 569 end
574 570
613 assertIsMember(boundary, {'w', 'e', 's', 'n'}) 609 assertIsMember(boundary, {'w', 'e', 's', 'n'})
614 610
615 n = obj.(['n_' boundary]); 611 n = obj.(['n_' boundary]);
616 end 612 end
617 613
614 % Returns the unit tangent vector for the boundary specified by the string boundary.
615 % t is a cell of diagonal matrices for each normal component, t{1} = t_1, t{2} = t_2.
616 function t = getTangent(obj, boundary)
617 assertIsMember(boundary, {'w', 'e', 's', 'n'})
618
619 t = obj.(['tangent_' boundary]);
620 end
621
618 % Returns the boundary operator op for the boundary specified by the string boundary. 622 % Returns the boundary operator op for the boundary specified by the string boundary.
619 % op -- string 623 % op -- string
620 function o = getBoundaryOperator(obj, op, boundary) 624 function o = getBoundaryOperator(obj, op, boundary)
621 assertIsMember(boundary, {'w', 'e', 's', 'n'}) 625 assertIsMember(boundary, {'w', 'e', 's', 'n'})
622 assertIsMember(op, {'e', 'e1', 'e2', 'tau', 'tau1', 'tau2', 'en', 'et', 'tau_n'}) 626 assertIsMember(op, {'e', 'e1', 'e2', 'tau', 'tau1', 'tau2', 'en', 'et', 'tau_n', 'tau_t'})
623 627
624 o = obj.([op, '_', boundary]); 628 o = obj.([op, '_', boundary]);
625 629
626 end 630 end
627 631