@@ -416,6 +416,7 @@ class Method(Enum):
416416 naive = 1
417417 laplace = 2
418418 biharmonic = 3
419+ laplace_slow = 4
419420
420421
421422def make_elasticity_wrapper (
@@ -449,6 +450,12 @@ def make_elasticity_wrapper(
449450 else :
450451 return ElasticityWrapperYoshida (dim = dim ,
451452 mu = mu , nu = nu )
453+ elif method == Method .laplace_slow :
454+ if nu == 0.5 :
455+ raise ValueError ("invalid value of nu=0.5 for method laplace_slow" )
456+ else :
457+ return ElasticityWrapperFu (dim = dim ,
458+ mu = mu , nu = nu )
452459 else :
453460 raise ValueError (f"invalid method: { method } ."
454461 "Needs to be one of naive, laplace, biharmonic" )
@@ -486,6 +493,12 @@ def make_elasticity_double_layer_wrapper(
486493 else :
487494 return ElasticityDoubleLayerWrapperYoshida (dim = dim ,
488495 mu = mu , nu = nu )
496+ elif method == Method .laplace_slow :
497+ if nu == 0.5 :
498+ raise ValueError ("invalid value of nu=0.5 for method laplace_slow" )
499+ else :
500+ return ElasticityDoubleLayerWrapperFu (dim = dim ,
501+ mu = mu , nu = nu )
489502 else :
490503 raise ValueError (f"invalid method: { method } ."
491504 "Needs to be one of naive, laplace, biharmonic" )
@@ -641,6 +654,162 @@ def apply(self, density_vec_sym, qbx_forced_limit, extra_deriv_dirs=()):
641654 [0 ]* self .dim , [0 ]* self .dim , qbx_forced_limit , 1 , 0 ,
642655 extra_deriv_dirs )
643656
657+
658+ # }}}
659+
660+ # {{{ Fu
661+
662+ @dataclass
663+ class ElasticityDoubleLayerWrapperFu (ElasticityDoubleLayerWrapperBase ):
664+ r"""ElasticityDoubleLayer Wrapper using Fu et al's method [1] which uses
665+ Laplace derivatives.
666+
667+ [1] Fu, Y., Klimkowski, K. J., Rodin, G. J., Berger, E., Browne, J. C.,
668+ Singer, J. K., ... & Vemaganti, K. S. (1998). A fast solution method for
669+ three‐dimensional many‐particle problems of linear elasticity.
670+ International Journal for Numerical Methods in Engineering, 42(7), 1215-1229.
671+ """
672+ dim : int
673+ mu : ExpressionT
674+ nu : ExpressionT
675+
676+ def __post_init__ (self ):
677+ if not self .dim == 3 :
678+ raise ValueError ("unsupported dimension given to "
679+ "ElasticityDoubleLayerWrapperFu: {self.dim}" )
680+
681+ @cached_property
682+ def laplace_kernel (self ):
683+ return LaplaceKernel (dim = 3 )
684+
685+ def apply (self , density_vec_sym , dir_vec_sym , qbx_forced_limit ,
686+ extra_deriv_dirs = ()):
687+ return self .apply_single_and_double_layer ([0 ]* self .dim ,
688+ density_vec_sym , dir_vec_sym , qbx_forced_limit , 0 , 1 ,
689+ extra_deriv_dirs )
690+
691+ def apply_single_and_double_layer (self , stokeslet_density_vec_sym ,
692+ stresslet_density_vec_sym , dir_vec_sym ,
693+ qbx_forced_limit , stokeslet_weight , stresslet_weight ,
694+ extra_deriv_dirs = ()):
695+
696+ mu = self .mu
697+ nu = self .nu
698+ stokeslet_weight *= - 1
699+
700+ def add_extra_deriv_dirs (target_kernel ):
701+ for deriv_dir in extra_deriv_dirs :
702+ target_kernel = AxisTargetDerivative (deriv_dir , target_kernel )
703+ return target_kernel
704+
705+ def P (i , j , int_g ):
706+ res = - int_g .copy (target_kernel = add_extra_deriv_dirs (
707+ TargetPointMultiplier (j ,
708+ AxisTargetDerivative (i , int_g .target_kernel ))))
709+ if i == j :
710+ res += (3 - 4 * nu )* int_g .copy (
711+ target_kernel = add_extra_deriv_dirs (int_g .target_kernel ))
712+ return res / (4 * mu * (1 - nu ))
713+
714+ def Q (i , int_g ):
715+ res = int_g .copy (target_kernel = add_extra_deriv_dirs (
716+ AxisTargetDerivative (i , int_g .target_kernel )))
717+ return res / (4 * mu * (1 - nu ))
718+
719+ def R (i , j , p , int_g ):
720+ res = int_g .copy (target_kernel = add_extra_deriv_dirs (
721+ TargetPointMultiplier (j , AxisTargetDerivative (i ,
722+ AxisTargetDerivative (p , int_g .target_kernel )))))
723+ if j == p :
724+ res += (1 - 2 * nu )* int_g .copy (target_kernel = add_extra_deriv_dirs (
725+ AxisTargetDerivative (i , int_g .target_kernel )))
726+ if i == j :
727+ res -= (1 - 2 * nu )* int_g .copy (target_kernel = add_extra_deriv_dirs (
728+ AxisTargetDerivative (p , int_g .target_kernel )))
729+ if i == p :
730+ res -= 2 * (1 - nu )* int_g .copy (target_kernel = add_extra_deriv_dirs (
731+ AxisTargetDerivative (j , int_g .target_kernel )))
732+ return res / (2 * mu * (1 - nu ))
733+
734+ def S (i , p , int_g ):
735+ res = int_g .copy (target_kernel = add_extra_deriv_dirs (
736+ AxisTargetDerivative (i ,
737+ AxisTargetDerivative (p , int_g .target_kernel ))))
738+ return res / (- 2 * mu * (1 - nu ))
739+
740+ sym_expr = np .zeros ((3 ,), dtype = object )
741+
742+ kernel = self .laplace_kernel
743+ source = sym .nodes (3 ).as_vector ()
744+ normal = dir_vec_sym
745+ sigma = stresslet_density_vec_sym
746+
747+ for i in range (3 ):
748+ for j in range (3 ):
749+ density = stokeslet_weight * stokeslet_density_vec_sym [j ]
750+ int_g = sym .IntG (target_kernel = kernel ,
751+ source_kernels = (kernel ,),
752+ densities = (density ,),
753+ qbx_forced_limit = qbx_forced_limit )
754+ sym_expr [i ] += P (i , j , int_g )
755+
756+ density = sum (stokeslet_weight
757+ * stokeslet_density_vec_sym [j ] * source [j ] for j in range (3 ))
758+ int_g = sym .IntG (target_kernel = kernel ,
759+ source_kernels = (kernel ,),
760+ densities = (density ,),
761+ qbx_forced_limit = qbx_forced_limit )
762+ sym_expr [i ] += Q (i , int_g )
763+
764+ for j in range (3 ):
765+ for p in range (3 ):
766+ density = stresslet_weight * normal [p ] * sigma [j ]
767+ int_g = sym .IntG (target_kernel = kernel ,
768+ source_kernels = (kernel ,),
769+ densities = (density ,),
770+ qbx_forced_limit = qbx_forced_limit )
771+ sym_expr [i ] += R (i , j , p , int_g )
772+
773+ for p in range (3 ):
774+ density = sum (stresslet_weight * normal [p ] * sigma [j ] * source [j ]
775+ for j in range (3 ))
776+ int_g = sym .IntG (target_kernel = kernel ,
777+ source_kernels = (kernel ,),
778+ densities = (density ,),
779+ qbx_forced_limit = qbx_forced_limit )
780+ sym_expr [i ] += S (i , p , int_g )
781+
782+ return sym_expr
783+
784+
785+ @dataclass
786+ class ElasticityWrapperFu (ElasticityWrapperBase ):
787+ r"""Elasticity single layer using Fu et al's method [1] which uses
788+ Laplace derivatives.
789+
790+ [1] Fu, Y., Klimkowski, K. J., Rodin, G. J., Berger, E., Browne, J. C.,
791+ Singer, J. K., ... & Vemaganti, K. S. (1998). A fast solution method for
792+ three‐dimensional many‐particle problems of linear elasticity.
793+ International Journal for Numerical Methods in Engineering, 42(7), 1215-1229.
794+ """
795+ dim : int
796+ mu : ExpressionT
797+ nu : ExpressionT
798+
799+ def __post_init__ (self ):
800+ if not self .dim == 3 :
801+ raise ValueError ("unsupported dimension given to "
802+ f"ElasticityDoubleLayerWrapperFu: { self .dim } " )
803+
804+ @cached_property
805+ def stresslet (self ):
806+ return ElasticityDoubleLayerWrapperFu (3 , self .mu , self .nu )
807+
808+ def apply (self , density_vec_sym , qbx_forced_limit , extra_deriv_dirs = ()):
809+ return self .stresslet .apply_single_and_double_layer (density_vec_sym ,
810+ [0 ]* self .dim , [0 ]* self .dim , qbx_forced_limit , 1 , 0 ,
811+ extra_deriv_dirs )
812+
644813# }}}
645814
646815
0 commit comments