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