Skip to content

Commit d8ecfb7

Browse files
committed
add a test for target derivative (starfish)
1 parent 34e1395 commit d8ecfb7

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import pytest
2+
import numpy as np
3+
4+
import pyopencl as cl
5+
from arraycontext import flatten
6+
from meshmode.array_context import PyOpenCLArrayContext
7+
from meshmode.discretization import Discretization
8+
from meshmode.discretization.poly_element import InterpolatoryQuadratureSimplexGroupFactory
9+
from meshmode.mesh.generation import make_curve_mesh, starfish
10+
11+
from pytential.qbx import QBXLayerPotentialSource
12+
from pytential import GeometryCollection, bind, sym
13+
14+
from sumpy.kernel import AxisTargetDerivative, LaplaceKernel
15+
from sumpy.expansion.local import LineTaylorLocalExpansion
16+
from sumpy.qbx import LayerPotentialMatrixGenerator
17+
from pytools.convergence import EOCRecorder
18+
19+
20+
def starfish_parametrization(t, n_arms=5, amplitude=0.25):
21+
"""Parametrization (x(θ), y(θ)) = r(θ)(cos(θ), sin(θ)), where r(θ) = 1 + amplitude * sin(n_arms * θ)."""
22+
theta = 2 * np.pi * t
23+
24+
r = 1 + amplitude * np.sin(n_arms * theta)
25+
dr_dt = amplitude * n_arms * 2 * np.pi * np.cos(n_arms * theta)
26+
27+
x = r * np.cos(theta)
28+
y = r * np.sin(theta)
29+
30+
dx_dt = dr_dt * np.cos(theta) - r * np.sin(theta) * 2 * np.pi
31+
dy_dt = dr_dt * np.sin(theta) + r * np.cos(theta) * 2 * np.pi
32+
33+
jacobian_norm = np.sqrt(dx_dt**2 + dy_dt**2)
34+
35+
tangent_x = dx_dt / jacobian_norm
36+
tangent_y = dy_dt / jacobian_norm
37+
38+
normal_x = tangent_y
39+
normal_y = -tangent_x
40+
41+
coords = np.vstack([x, y])
42+
tangents = np.vstack([tangent_x, tangent_y])
43+
normals = np.vstack([normal_x, normal_y])
44+
45+
return coords, tangents, normals, jacobian_norm
46+
47+
48+
@pytest.mark.parametrize("kernel_type", ["laplace"])
49+
def test_lpot_dx_jump_relation_convergence(kernel_type):
50+
"""Test convergence of jump relations for single layer potential derivatives."""
51+
52+
cl_ctx = cl.create_some_context()
53+
queue = cl.CommandQueue(cl_ctx)
54+
actx = PyOpenCLArrayContext(queue)
55+
56+
if kernel_type == "laplace":
57+
knl = LaplaceKernel(2)
58+
else:
59+
raise ValueError(f"Unknown kernel type: {kernel_type}")
60+
61+
qbx_order = 5
62+
nelements = [100, 150, 200]
63+
target_order = 5
64+
upsampling_factor = 5
65+
66+
ntargets = 20
67+
np.random.seed(42)
68+
t = np.random.uniform(0, 1, ntargets)
69+
targets_h, _, targets_normals_h, jac = starfish_parametrization(
70+
t, n_arms=5, amplitude=0.25
71+
)
72+
targets = actx.from_numpy(targets_h)
73+
74+
eocrec = EOCRecorder()
75+
76+
for nelement in nelements:
77+
mesh = make_curve_mesh(starfish, np.linspace(0, 1, nelement + 1), target_order)
78+
pre_density_discr = Discretization(
79+
actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)
80+
)
81+
82+
qbx = QBXLayerPotentialSource(
83+
pre_density_discr,
84+
upsampling_factor * target_order,
85+
qbx_order,
86+
fmm_order=False
87+
)
88+
places = GeometryCollection({"qbx": qbx}, auto_where=('qbx'))
89+
90+
source_discr = places.get_discretization('qbx', sym.QBX_SOURCE_QUAD_STAGE2)
91+
sources_h = actx.to_numpy(flatten(source_discr.nodes(), actx)).reshape(2, -1)
92+
sources = actx.from_numpy(sources_h)
93+
94+
dofdesc = sym.DOFDescriptor("qbx", sym.QBX_SOURCE_QUAD_STAGE2)
95+
weights_nodes = bind(
96+
places,
97+
sym.weights_and_area_elements(ambient_dim=2, dim=1, dofdesc=dofdesc)
98+
)(actx)
99+
weights_nodes_h = actx.to_numpy(flatten(weights_nodes, actx))
100+
101+
expansion_radii_h = jac / (2 * nelement)
102+
centers_in = actx.from_numpy(targets_h - targets_normals_h * expansion_radii_h)
103+
centers_out = actx.from_numpy(targets_h + targets_normals_h * expansion_radii_h)
104+
105+
mat_gen_x = LayerPotentialMatrixGenerator(
106+
actx.context,
107+
expansion=LineTaylorLocalExpansion(knl, qbx_order),
108+
source_kernels=(knl,),
109+
target_kernels=(AxisTargetDerivative(0, knl),)
110+
)
111+
112+
mat_gen_y = LayerPotentialMatrixGenerator(
113+
actx.context,
114+
expansion=LineTaylorLocalExpansion(knl, qbx_order),
115+
source_kernels=(knl,),
116+
target_kernels=(AxisTargetDerivative(1, knl),)
117+
)
118+
119+
_, (mat_in_x,) = mat_gen_x(
120+
actx.queue,
121+
targets=targets,
122+
sources=sources,
123+
expansion_radii=expansion_radii_h,
124+
centers=centers_in,
125+
)
126+
mat_in_x = actx.to_numpy(mat_in_x)
127+
weighted_mat_in_x = mat_in_x * weights_nodes_h[None, :]
128+
129+
_, (mat_in_y,) = mat_gen_y(
130+
actx.queue,
131+
targets=targets,
132+
sources=sources,
133+
expansion_radii=expansion_radii_h,
134+
centers=centers_in,
135+
)
136+
mat_in_y = actx.to_numpy(mat_in_y)
137+
weighted_mat_in_y = mat_in_y * weights_nodes_h[None, :]
138+
139+
_, (mat_out_x,) = mat_gen_x(
140+
actx.queue,
141+
targets=targets,
142+
sources=sources,
143+
expansion_radii=expansion_radii_h,
144+
centers=centers_out,
145+
)
146+
mat_out_x = actx.to_numpy(mat_out_x)
147+
weighted_mat_out_x = mat_out_x * weights_nodes_h[None, :]
148+
149+
_, (mat_out_y,) = mat_gen_y(
150+
actx.queue,
151+
targets=targets,
152+
sources=sources,
153+
expansion_radii=expansion_radii_h,
154+
centers=centers_out,
155+
)
156+
mat_out_y = actx.to_numpy(mat_out_y)
157+
weighted_mat_out_y = mat_out_y * weights_nodes_h[None, :]
158+
159+
eval_in = (weighted_mat_in_x.sum(axis=1) * targets_normals_h[0] +
160+
weighted_mat_in_y.sum(axis=1) * targets_normals_h[1])
161+
eval_out = (weighted_mat_out_x.sum(axis=1) * targets_normals_h[0] +
162+
weighted_mat_out_y.sum(axis=1) * targets_normals_h[1])
163+
164+
# check jump relation: S'_int - S'_ext = sigma (=1 for constant density)
165+
jump_error = np.abs(eval_in - eval_out - 1)
166+
167+
h_max = actx.to_numpy(bind(places, sym.h_max(places.ambient_dim))(actx))
168+
eocrec.add_data_point(h_max, np.max(jump_error))
169+
170+
assert eocrec.order_estimate() > qbx_order - 1
171+
172+
173+
if __name__ == "__main__":
174+
pytest.main([__file__])

0 commit comments

Comments
 (0)