Skip to content

Commit 714da54

Browse files
committed
add Fu et al method
1 parent 7c0e850 commit 714da54

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

pytential/symbolic/elasticity.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ class Method(Enum):
416416
naive = 1
417417
laplace = 2
418418
biharmonic = 3
419+
laplace_slow = 4
419420

420421

421422
def 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

Comments
 (0)