|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | + |
| 4 | +__copyright__ = """ |
| 5 | +Copyright (C) 2025 Shawn Lin |
| 6 | +Copyright (C) 2025 University of Illinois Board of Trustees |
| 7 | +""" |
| 8 | + |
| 9 | +__license__ = """ |
| 10 | +Permission is hereby granted, free of charge, to any person obtaining a copy |
| 11 | +of this software and associated documentation files (the "Software"), to deal |
| 12 | +in the Software without restriction, including without limitation the rights |
| 13 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 14 | +copies of the Software, and to permit persons to whom the Software is |
| 15 | +furnished to do so, subject to the following conditions: |
| 16 | +
|
| 17 | +The above copyright notice and this permission notice shall be included in |
| 18 | +all copies or substantial portions of the Software. |
| 19 | +
|
| 20 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 21 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 22 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 23 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 24 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 25 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 26 | +THE SOFTWARE. |
| 27 | +""" |
| 28 | + |
| 29 | +import sys |
| 30 | +from typing import TYPE_CHECKING |
| 31 | + |
| 32 | +import numpy as np |
| 33 | +import pytest |
| 34 | + |
| 35 | +from arraycontext import ( |
| 36 | + PyOpenCLArrayContext, |
| 37 | + pytest_generate_tests_for_array_contexts, |
| 38 | +) |
| 39 | +from pytools.convergence import EOCRecorder |
| 40 | + |
| 41 | +from sumpy.array_context import PytestPyOpenCLArrayContextFactory, _acf # noqa: F401 |
| 42 | +from sumpy.expansion.local import LineTaylorLocalExpansion |
| 43 | +from sumpy.kernel import AxisTargetDerivative, Kernel, LaplaceKernel |
| 44 | +from sumpy.test.geometries import make_starfish |
| 45 | + |
| 46 | + |
| 47 | +if TYPE_CHECKING: |
| 48 | + from arraycontext import ArrayContextFactory |
| 49 | + |
| 50 | +pytest_generate_tests = pytest_generate_tests_for_array_contexts([ |
| 51 | + PytestPyOpenCLArrayContextFactory, |
| 52 | + ]) |
| 53 | + |
| 54 | + |
| 55 | +@pytest.mark.parametrize("knl", [LaplaceKernel(2)]) |
| 56 | +def test_lpot_dx_jump_relation_convergence( |
| 57 | + actx_factory: ArrayContextFactory, |
| 58 | + knl: Kernel): |
| 59 | + """Test convergence of jump relations for single layer potential derivatives.""" |
| 60 | + |
| 61 | + actx = actx_factory() |
| 62 | + if not isinstance(actx, PyOpenCLArrayContext): |
| 63 | + pytest.skip() |
| 64 | + |
| 65 | + qbx_order = 5 |
| 66 | + nelements = [100, 150, 200] |
| 67 | + target_order = 5 |
| 68 | + upsampling_factor = 5 |
| 69 | + |
| 70 | + ntargets = 20 |
| 71 | + target_geo = make_starfish(npoints=ntargets) |
| 72 | + targets_h = target_geo.nodes |
| 73 | + targets = actx.from_numpy(targets_h) |
| 74 | + |
| 75 | + from sumpy.qbx import LayerPotential |
| 76 | + expansion = LineTaylorLocalExpansion(knl, qbx_order) |
| 77 | + lplot_dx = LayerPotential( |
| 78 | + actx.context, |
| 79 | + expansion=expansion, |
| 80 | + target_kernels=(AxisTargetDerivative(0, knl),), |
| 81 | + source_kernels=(knl,) |
| 82 | + ) |
| 83 | + lplot_dy = LayerPotential( |
| 84 | + actx.context, |
| 85 | + expansion=expansion, |
| 86 | + target_kernels=(AxisTargetDerivative(1, knl),), |
| 87 | + source_kernels=(knl,) |
| 88 | + ) |
| 89 | + eocrec = EOCRecorder() |
| 90 | + |
| 91 | + for nsources in [320, 640, 1280, 2560]: |
| 92 | + source_geo = make_starfish(npoints=nsources) |
| 93 | + sources = actx.from_numpy(source_geo.nodes) |
| 94 | + |
| 95 | + weights_nodes_h = source_geo.area_elements * source_geo.weights |
| 96 | + weights_nodes = actx.from_numpy(weights_nodes_h) |
| 97 | + |
| 98 | + expansion_radii_h = 4 * target_geo.area_elements / nsources |
| 99 | + centers_in = actx.from_numpy( |
| 100 | + targets_h - target_geo.normals * expansion_radii_h) |
| 101 | + centers_out = actx.from_numpy( |
| 102 | + targets_h + target_geo.normals * expansion_radii_h) |
| 103 | + |
| 104 | + strengths = (weights_nodes,) |
| 105 | + _, (eval_in_dx,) = lplot_dx( |
| 106 | + actx.queue, |
| 107 | + targets, sources, centers_in, strengths, |
| 108 | + expansion_radii=expansion_radii_h |
| 109 | + ) |
| 110 | + |
| 111 | + _, (eval_in_dy,) = lplot_dy( |
| 112 | + actx.queue, |
| 113 | + targets, sources, centers_in, strengths, |
| 114 | + expansion_radii=expansion_radii_h |
| 115 | + ) |
| 116 | + |
| 117 | + _, (eval_out_dx,) = lplot_dx( |
| 118 | + actx.queue, |
| 119 | + targets, sources, centers_out, strengths, |
| 120 | + expansion_radii=expansion_radii_h |
| 121 | + ) |
| 122 | + |
| 123 | + _, (eval_out_dy,) = lplot_dy( |
| 124 | + actx.queue, |
| 125 | + targets, sources, centers_out, strengths, |
| 126 | + expansion_radii=expansion_radii_h |
| 127 | + ) |
| 128 | + |
| 129 | + eval_in_dx = actx.to_numpy(eval_in_dx) |
| 130 | + eval_in_dy = actx.to_numpy(eval_in_dy) |
| 131 | + eval_out_dx = actx.to_numpy(eval_out_dx) |
| 132 | + eval_out_dy = actx.to_numpy(eval_out_dy) |
| 133 | + |
| 134 | + eval_in = eval_in_dx * target_geo.normals[0] + \ |
| 135 | + eval_in_dy * target_geo.normals[1] |
| 136 | + eval_out = eval_out_dx * target_geo.normals[0] + \ |
| 137 | + eval_out_dy * target_geo.normals[1] |
| 138 | + |
| 139 | + # check jump relation: S'_int - S'_ext = sigma (=1 for constant density) |
| 140 | + jump_error = np.abs(eval_in - eval_out - 1) |
| 141 | + |
| 142 | + h_max = 1/nsources |
| 143 | + eocrec.add_data_point(h_max, np.max(jump_error)) |
| 144 | + |
| 145 | + print(eocrec) |
| 146 | + assert eocrec.order_estimate() > qbx_order - 1.5 |
| 147 | + |
| 148 | + |
| 149 | +if __name__ == "__main__": |
| 150 | + if len(sys.argv) > 1: |
| 151 | + exec(sys.argv[1]) |
| 152 | + else: |
| 153 | + pytest.main([__file__]) |
0 commit comments