def starfish_lpot_source(queue, n_arms): from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) from meshmode.mesh.generation import make_curve_mesh, NArmedStarfish mesh = make_curve_mesh(NArmedStarfish(n_arms, 0.8), np.linspace(0, 1, 1 + PANELS_PER_ARM * n_arms), TARGET_ORDER) pre_density_discr = Discretization( queue.context, mesh, InterpolatoryQuadratureSimplexGroupFactory(TARGET_ORDER)) lpot_kwargs = DEFAULT_LPOT_KWARGS.copy() lpot_kwargs.update(target_association_tolerance=0.025, _expansion_stick_out_factor=TCF, fmm_order=FMM_ORDER, qbx_order=QBX_ORDER, fmm_backend="fmmlib") from pytential.qbx import QBXLayerPotentialSource lpot_source = QBXLayerPotentialSource(pre_density_discr, OVSMP_FACTOR * TARGET_ORDER, **lpot_kwargs) lpot_source, _ = lpot_source.with_refinement() return lpot_source
def lpot_source_from_mesh(queue, mesh, lpot_kwargs=None): from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) target_order = TARGET_ORDER pre_density_discr = Discretization( queue.context, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) refiner_extra_kwargs = { "_force_stage2_uniform_refinement_rounds": (FORCE_STAGE2_UNIFORM_REFINEMENT_ROUNDS), "_scaled_max_curvature_threshold": (SCALED_MAX_CURVATURE_THRESHOLD), } if lpot_kwargs is None: lpot_kwargs = DEFAULT_LPOT_KWARGS from pytential.qbx import QBXLayerPotentialSource lpot_source = QBXLayerPotentialSource( pre_density_discr, OVSMP_FACTOR * target_order, **lpot_kwargs, ) lpot_source, _ = lpot_source.with_refinement(**refiner_extra_kwargs) return lpot_source
def _build_qbx_discr(queue, ndim=2, nelements=30, target_order=7, qbx_order=4, curve_f=None): if curve_f is None: curve_f = NArmedStarfish(5, 0.25) if ndim == 2: mesh = make_curve_mesh(curve_f, np.linspace(0, 1, nelements + 1), target_order) elif ndim == 3: mesh = generate_torus(10.0, 2.0, order=target_order) else: raise ValueError("unsupported ambient dimension") from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource density_discr = Discretization( queue.context, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx, _ = QBXLayerPotentialSource(density_discr, fine_order=4 * target_order, qbx_order=qbx_order, fmm_order=False).with_refinement() return qbx
def get_lpot_source(actx: PyOpenCLArrayContext, dim): from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) target_order = TARGET_ORDER if dim == 2: from meshmode.mesh.generation import starfish, make_curve_mesh mesh = make_curve_mesh(starfish, np.linspace(0, 1, 50), order=target_order) elif dim == 3: from meshmode.mesh.generation import generate_torus mesh = generate_torus(2, 1, order=target_order) else: raise ValueError("unsupported dimension: %d" % dim) pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) lpot_kwargs = DEFAULT_LPOT_KWARGS.copy() lpot_kwargs.update( _expansion_stick_out_factor=TCF, fmm_order=FMM_ORDER, qbx_order=QBX_ORDER, fmm_backend="fmmlib", ) from pytential.qbx import QBXLayerPotentialSource lpot_source = QBXLayerPotentialSource( pre_density_discr, OVSMP_FACTOR*target_order, **lpot_kwargs) return lpot_source
def get_layer_potential(self, actx, resolution, mesh_order): pre_density_discr = self.get_discretization(actx, resolution, mesh_order) from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder fmm_kwargs = {} if self.fmm_backend is None: fmm_kwargs["fmm_order"] = False else: if self.fmm_tol is not None: fmm_kwargs["fmm_order"] = SimpleExpansionOrderFinder( self.fmm_tol) elif self.fmm_order is not None: fmm_kwargs["fmm_order"] = self.fmm_order else: fmm_kwargs["fmm_order"] = self.qbx_order + 5 from pytential.qbx import QBXLayerPotentialSource return QBXLayerPotentialSource( pre_density_discr, fine_order=self.source_ovsmp * self.target_order, qbx_order=self.qbx_order, fmm_backend=self.fmm_backend, **fmm_kwargs, _disable_refinement=not self.use_refinement, _box_extent_norm=getattr(self, "box_extent_norm", None), _from_sep_smaller_crit=getattr(self, "from_sep_smaller_crit", None), _from_sep_smaller_min_nsources_cumul=30, )
def test_interpolation(actx_factory, name, source_discr_stage, target_granularity): actx = actx_factory() nelements = 32 target_order = 7 qbx_order = 4 where = sym.as_dofdesc("test_interpolation") from_dd = sym.DOFDescriptor( geometry=where.geometry, discr_stage=source_discr_stage, granularity=sym.GRANULARITY_NODE) to_dd = sym.DOFDescriptor( geometry=where.geometry, discr_stage=sym.QBX_SOURCE_QUAD_STAGE2, granularity=target_granularity) mesh = mgen.make_curve_mesh(mgen.starfish, np.linspace(0.0, 1.0, nelements + 1), target_order) discr = Discretization(actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource(discr, fine_order=4 * target_order, qbx_order=qbx_order, fmm_order=False) from pytential import GeometryCollection places = GeometryCollection(qbx, auto_where=where) sigma_sym = sym.var("sigma") op_sym = sym.sin(sym.interp(from_dd, to_dd, sigma_sym)) bound_op = bind(places, op_sym, auto_where=where) def discr_and_nodes(stage): density_discr = places.get_discretization(where.geometry, stage) return density_discr, actx.to_numpy( flatten(density_discr.nodes(), actx) ).reshape(density_discr.ambient_dim, -1) _, target_nodes = discr_and_nodes(sym.QBX_SOURCE_QUAD_STAGE2) source_discr, source_nodes = discr_and_nodes(source_discr_stage) sigma_target = np.sin(la.norm(target_nodes, axis=0)) sigma_dev = unflatten( thaw(source_discr.nodes()[0], actx), actx.from_numpy(la.norm(source_nodes, axis=0)), actx) sigma_target_interp = actx.to_numpy( flatten(bound_op(actx, sigma=sigma_dev), actx) ) if name in ("default", "default_explicit", "stage2", "quad"): error = la.norm(sigma_target_interp - sigma_target) / la.norm(sigma_target) assert error < 1.0e-10 elif name in ("stage2_center",): assert len(sigma_target_interp) == 2 * len(sigma_target) else: raise ValueError(f"unknown test case name: {name}")
def get_lpot_source(queue, mesh_getter, nelements, stickout_factor, well_sep_is_n_away, with_extents, max_leaf_refine_weight, k=0, fmm_backend="sumpy", from_sep_smaller_threshold=None): from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) target_order = TARGET_ORDER mesh = mesh_getter(nelements, target_order) pre_density_discr = Discretization( queue.context, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) refiner_extra_kwargs = {} if k != 0: refiner_extra_kwargs["kernel_length_scale"] = 5 / k from pytential.qbx import QBXLayerPotentialSource lpot_source = QBXLayerPotentialSource( pre_density_discr, OVSMP_FACTOR * target_order, fmm_backend=fmm_backend, _well_sep_is_n_away=well_sep_is_n_away, _expansions_in_tree_have_extent=with_extents, _expansion_stick_out_factor=stickout_factor, _max_leaf_refine_weight=max_leaf_refine_weight, target_association_tolerance=1e-3, fmm_order=10, qbx_order=10, _from_sep_smaller_min_nsources_cumul=from_sep_smaller_threshold, _from_sep_smaller_crit="static_linf", _box_extent_norm="linf", ) lpot_source, _ = lpot_source.with_refinement(**refiner_extra_kwargs) return lpot_source
def test_off_surface_eval(ctx_factory, use_fmm, do_plot=False): logging.basicConfig(level=logging.INFO) cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) # prevent cache 'splosion from sympy.core.cache import clear_cache clear_cache() nelements = 30 target_order = 8 qbx_order = 3 if use_fmm: fmm_order = qbx_order else: fmm_order = False mesh = make_curve_mesh(partial(ellipse, 3), np.linspace(0, 1, nelements + 1), target_order) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx, _ = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=fmm_order, ).with_refinement() density_discr = qbx.density_discr from sumpy.kernel import LaplaceKernel op = sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=-2) sigma = density_discr.zeros(queue) + 1 fplot = FieldPlotter(np.zeros(2), extent=0.54, npoints=30) from pytential.target import PointsTarget fld_in_vol = bind((qbx, PointsTarget(fplot.points)), op)(queue, sigma=sigma) err = cl.clmath.fabs(fld_in_vol - (-1)) linf_err = cl.array.max(err).get() print("l_inf error:", linf_err) if do_plot: fplot.show_scalar_in_matplotlib(fld_in_vol.get()) import matplotlib.pyplot as pt pt.colorbar() pt.show() assert linf_err < 1e-3
def test_off_surface_eval(actx_factory, use_fmm, visualize=False): logging.basicConfig(level=logging.INFO) actx = actx_factory() # prevent cache 'splosion from sympy.core.cache import clear_cache clear_cache() nelements = 30 target_order = 8 qbx_order = 3 if use_fmm: fmm_order = qbx_order else: fmm_order = False mesh = mgen.make_curve_mesh(partial(mgen.ellipse, 3), np.linspace(0, 1, nelements + 1), target_order) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=fmm_order, ) from pytential.target import PointsTarget fplot = FieldPlotter(np.zeros(2), extent=0.54, npoints=30) targets = PointsTarget(actx.freeze(actx.from_numpy(fplot.points))) places = GeometryCollection((qbx, targets)) density_discr = places.get_discretization(places.auto_source.geometry) from sumpy.kernel import LaplaceKernel op = sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=-2) sigma = density_discr.zeros(actx) + 1 fld_in_vol = bind(places, op)(actx, sigma=sigma) fld_in_vol_exact = -1 linf_err = actx.to_numpy( actx.np.linalg.norm(fld_in_vol - fld_in_vol_exact, ord=np.inf)) logger.info("l_inf error: %.12e", linf_err) if visualize: fplot.show_scalar_in_matplotlib(actx.to_numpy(fld_in_vol)) import matplotlib.pyplot as pt pt.colorbar() pt.show() assert linf_err < 1e-3
def main(): cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) target_order = 10 from functools import partial nelements = 30 qbx_order = 4 from sumpy.kernel import LaplaceKernel from meshmode.mesh.generation import ( # noqa ellipse, cloverleaf, starfish, drop, n_gon, qbx_peanut, make_curve_mesh) mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements+1), target_order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization(cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order, fmm_order=False) from pytools.obj_array import join_fields sig_sym = sym.var("sig") knl = LaplaceKernel(2) op = join_fields( sym.tangential_derivative(mesh.ambient_dim, sym.D(knl, sig_sym, qbx_forced_limit=+1)).as_scalar(), sym.tangential_derivative(mesh.ambient_dim, sym.D(knl, sig_sym, qbx_forced_limit=-1)).as_scalar(), ) nodes = density_discr.nodes().with_queue(queue) angle = cl.clmath.atan2(nodes[1], nodes[0]) n = 10 sig = cl.clmath.sin(n*angle) dt_sig = n*cl.clmath.cos(n*angle) res = bind(qbx, op)(queue, sig=sig) extval = res[0].get() intval = res[1].get() pv = 0.5*(extval + intval) dt_sig_h = dt_sig.get() import matplotlib.pyplot as pt pt.plot(extval, label="+num") pt.plot(pv + dt_sig_h*0.5, label="+ex") pt.legend(loc="best") pt.show()
def test_target_association_failure(ctx_factory): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ generate circle order = 5 nelements = 40 # Make the curve mesh. curve_f = partial(ellipse, 1) mesh = make_curve_mesh(curve_f, np.linspace(0, 1, nelements + 1), order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory factory = InterpolatoryQuadratureSimplexGroupFactory(order) discr = Discretization(actx, mesh, factory) lpot_source = QBXLayerPotentialSource( discr, qbx_order=order, # not used in target association fine_order=order) places = GeometryCollection(lpot_source) # }}} # {{{ generate targets and check close_circle = 0.999 * np.exp( 2j * np.pi * np.linspace(0, 1, 500, endpoint=False)) from pytential.target import PointsTarget close_circle_target = (PointsTarget( actx.from_numpy(np.array([close_circle.real, close_circle.imag])))) targets = ((close_circle_target, 0), ) from pytential.qbx.target_assoc import (TargetAssociationCodeContainer, associate_targets_to_qbx_centers, QBXTargetAssociationFailedException ) from pytential.qbx.utils import TreeCodeContainer code_container = TargetAssociationCodeContainer(actx, TreeCodeContainer(actx)) with pytest.raises(QBXTargetAssociationFailedException): associate_targets_to_qbx_centers(places, places.auto_source, code_container.get_wrangler(actx), targets, target_association_tolerance=1e-10)
def test_interpolation(ctx_factory, name, source_discr_stage, target_granularity): ctx = ctx_factory() queue = cl.CommandQueue(ctx) nelements = 32 target_order = 7 qbx_order = 4 mesh = make_curve_mesh(starfish, np.linspace(0.0, 1.0, nelements + 1), target_order) discr = Discretization( ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource qbx, _ = QBXLayerPotentialSource(discr, fine_order=4 * target_order, qbx_order=qbx_order, fmm_order=False).with_refinement() where = 'test-interpolation' from_dd = sym.DOFDescriptor(geometry=where, discr_stage=source_discr_stage, granularity=sym.GRANULARITY_NODE) to_dd = sym.DOFDescriptor(geometry=where, discr_stage=sym.QBX_SOURCE_QUAD_STAGE2, granularity=target_granularity) sigma_sym = sym.var("sigma") op_sym = sym.sin(sym.interp(from_dd, to_dd, sigma_sym)) bound_op = bind(qbx, op_sym, auto_where=where) target_nodes = qbx.quad_stage2_density_discr.nodes().get(queue) if source_discr_stage == sym.QBX_SOURCE_STAGE2: source_nodes = qbx.stage2_density_discr.nodes().get(queue) elif source_discr_stage == sym.QBX_SOURCE_QUAD_STAGE2: source_nodes = target_nodes else: source_nodes = qbx.density_discr.nodes().get(queue) sigma_dev = cl.array.to_device(queue, la.norm(source_nodes, axis=0)) sigma_target = np.sin(la.norm(target_nodes, axis=0)) sigma_target_interp = bound_op(queue, sigma=sigma_dev).get(queue) if name in ('default', 'default-explicit', 'stage2', 'quad'): error = la.norm(sigma_target_interp - sigma_target) / la.norm(sigma_target) assert error < 1.0e-10 elif name in ('stage2-center', ): assert len(sigma_target_interp) == 2 * len(sigma_target) else: raise ValueError('unknown test case name: {}'.format(name))
def get_sphere_lpot_source(queue): from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) target_order = 8 from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) pre_density_discr = Discretization( queue.context, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource lpot_source = QBXLayerPotentialSource(pre_density_discr, qbx_order=5, fmm_order=10, fine_order=4 * target_order, fmm_backend="fmmlib") lpot_source, _ = lpot_source.with_refinement() return lpot_source
def get_qbx(self, **kwargs): """ Return a :class:`QBXLayerPotentialSource` to bind to an operator """ qbx = QBXLayerPotentialSource(self._discr, **kwargs) # {{{ If refining, refine and store connection (possibly composed with bdy # connection if self._refine: self._refine = False from meshmode.discretization.connection import \ ChainedDiscretizationConnection qbx, refinement_connection = qbx.with_refinement() if self._connection: connections = [self._connection, refinement_connection] self._connection = ChainedDiscretizationConnection(connections) else: self._connection = refinement_connection # }}} return qbx
def test_get_qbx_center_neighborhood_sizes(ctx_factory): ctx = ctx_factory() queue = cl.CommandQueue(ctx) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) target_order = 8 n_arms = 5 nelements = 50 * n_arms mesh = make_curve_mesh( NArmedStarfish(n_arms, 0.8), np.linspace(0, 1, nelements+1), target_order) pre_density_discr = Discretization( queue.context, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource lpot_source, _ = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, _max_leaf_refine_weight=64, target_association_tolerance=1e-3, ).with_refinement() t_f = 0.9 result_direct = get_qbx_center_neighborhood_sizes_direct(lpot_source, 8/t_f) result_aq = get_qbx_center_neighborhood_sizes(lpot_source, 8/t_f) assert (result_direct[0] == result_aq[0]).all() assert result_direct[1] == result_aq[1] assert result_direct[2] == result_aq[2]
def test_ellipse_eigenvalues(ctx_factory, ellipse_aspect, mode_nr, qbx_order, force_direct, visualize=False): logging.basicConfig(level=logging.INFO) print("ellipse_aspect: %s, mode_nr: %d, qbx_order: %d" % (ellipse_aspect, mode_nr, qbx_order)) cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) target_order = 8 from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource from pytools.convergence import EOCRecorder s_eoc_rec = EOCRecorder() d_eoc_rec = EOCRecorder() sp_eoc_rec = EOCRecorder() if ellipse_aspect != 1: nelements_values = [60, 100, 150, 200] else: nelements_values = [30, 70] # See # # [1] G. J. Rodin and O. Steinbach, "Boundary Element Preconditioners # for Problems Defined on Slender Domains", SIAM Journal on Scientific # Computing, Vol. 24, No. 4, pg. 1450, 2003. # https://dx.doi.org/10.1137/S1064827500372067 for nelements in nelements_values: mesh = make_curve_mesh(partial(ellipse, ellipse_aspect), np.linspace(0, 1, nelements + 1), target_order) fmm_order = 12 if force_direct: fmm_order = False pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=fmm_order, _expansions_in_tree_have_extent=True, ) places = GeometryCollection(qbx) density_discr = places.get_discretization(places.auto_source.geometry) from meshmode.dof_array import thaw, flatten nodes = thaw(actx, density_discr.nodes()) if visualize: # plot geometry, centers, normals centers = bind(places, sym.expansion_centers(qbx.ambient_dim, +1))(actx) normals = bind(places, sym.normal(qbx.ambient_dim))(actx).as_vector(object) nodes_h = np.array( [actx.to_numpy(axis) for axis in flatten(nodes)]) centers_h = np.array( [actx.to_numpy(axis) for axis in flatten(centers)]) normals_h = np.array( [actx.to_numpy(axis) for axis in flatten(normals)]) pt.plot(nodes_h[0], nodes_h[1], "x-") pt.plot(centers_h[0], centers_h[1], "o") pt.quiver(nodes_h[0], nodes_h[1], normals_h[0], normals_h[1]) pt.gca().set_aspect("equal") pt.show() angle = actx.np.arctan2(nodes[1] * ellipse_aspect, nodes[0]) ellipse_fraction = ((1 - ellipse_aspect) / (1 + ellipse_aspect))**mode_nr # (2.6) in [1] J = actx.np.sqrt( # noqa actx.np.sin(angle)**2 + (1 / ellipse_aspect)**2 * actx.np.cos(angle)**2) from sumpy.kernel import LaplaceKernel lap_knl = LaplaceKernel(2) # {{{ single layer sigma_sym = sym.var("sigma") s_sigma_op = sym.S(lap_knl, sigma_sym, qbx_forced_limit=+1) sigma = actx.np.cos(mode_nr * angle) / J s_sigma = bind(places, s_sigma_op)(actx, sigma=sigma) # SIGN BINGO! :) s_eigval = 1 / (2 * mode_nr) * (1 + (-1)**mode_nr * ellipse_fraction) # (2.12) in [1] s_sigma_ref = s_eigval * J * sigma if 0: #pt.plot(s_sigma.get(), label="result") #pt.plot(s_sigma_ref.get(), label="ref") pt.plot(actx.to_numpy(flatten(s_sigma_ref - s_sigma)), label="err") pt.legend() pt.show() h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx) s_err = (norm(density_discr, s_sigma - s_sigma_ref) / norm(density_discr, s_sigma_ref)) s_eoc_rec.add_data_point(h_max, s_err) # }}} # {{{ double layer d_sigma_op = sym.D(lap_knl, sigma_sym, qbx_forced_limit="avg") sigma = actx.np.cos(mode_nr * angle) d_sigma = bind(places, d_sigma_op)(actx, sigma=sigma) # SIGN BINGO! :) d_eigval = -(-1)**mode_nr * 1 / 2 * ellipse_fraction d_sigma_ref = d_eigval * sigma if 0: pt.plot(actx.to_numpy(flatten(d_sigma)), label="result") pt.plot(actx.to_numpy(flatten(d_sigma_ref)), label="ref") pt.legend() pt.show() if ellipse_aspect == 1: d_ref_norm = norm(density_discr, sigma) else: d_ref_norm = norm(density_discr, d_sigma_ref) d_err = (norm(density_discr, d_sigma - d_sigma_ref) / d_ref_norm) d_eoc_rec.add_data_point(h_max, d_err) # }}} if ellipse_aspect == 1: # {{{ S' sp_sigma_op = sym.Sp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg") sigma = actx.np.cos(mode_nr * angle) sp_sigma = bind(places, sp_sigma_op)(actx, sigma=sigma) sp_eigval = 0 sp_sigma_ref = sp_eigval * sigma sp_err = (norm(density_discr, sp_sigma - sp_sigma_ref) / norm(density_discr, sigma)) sp_eoc_rec.add_data_point(h_max, sp_err) # }}} print("Errors for S:") print(s_eoc_rec) required_order = qbx_order + 1 assert s_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D:") print(d_eoc_rec) required_order = qbx_order assert d_eoc_rec.order_estimate() > required_order - 1.5 if ellipse_aspect == 1: print("Errors for S':") print(sp_eoc_rec) required_order = qbx_order assert sp_eoc_rec.order_estimate() > required_order - 1.5
def main(curve_fn=starfish, visualize=True): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info import pyopencl as cl cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue, force_device_scalars=True) from meshmode.mesh.generation import make_curve_mesh mesh = make_curve_mesh( curve_fn, np.linspace(0, 1, nelements+1), target_order) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource( pre_density_discr, 4*target_order, qbx_order, fmm_order=qbx_order+3, target_association_tolerance=0.005, #fmm_backend="fmmlib", ) from pytential.target import PointsTarget fplot = FieldPlotter(np.zeros(2), extent=5, npoints=1000) targets_dev = actx.from_numpy(fplot.points) from pytential import GeometryCollection places = GeometryCollection({ "qbx": qbx, "targets": PointsTarget(targets_dev), }, auto_where="qbx") density_discr = places.get_discretization("qbx") nodes = thaw(density_discr.nodes(), actx) angle = actx.np.arctan2(nodes[1], nodes[0]) if k: kernel = HelmholtzKernel(2) kernel_kwargs = {"k": sym.var("k")} else: kernel = LaplaceKernel(2) kernel_kwargs = {} def op(**kwargs): kwargs.update(kernel_kwargs) #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), **kwargs)) return sym.D(kernel, sym.var("sigma"), **kwargs) #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None, **kwargs) if 0: from random import randrange sigma = actx.zeros(density_discr.ndofs, angle.entry_dtype) for _ in range(5): sigma[randrange(len(sigma))] = 1 from arraycontext import unflatten sigma = unflatten(angle, sigma, actx) else: sigma = actx.np.cos(mode_nr*angle) if isinstance(kernel, HelmholtzKernel): for i, elem in np.ndenumerate(sigma): sigma[i] = elem.astype(np.complex128) bound_bdry_op = bind(places, op()) if visualize: fld_in_vol = actx.to_numpy( bind(places, op( source="qbx", target="targets", qbx_forced_limit=None))(actx, sigma=sigma, k=k)) if enable_mayavi: fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) else: fplot.write_vtk_file("layerpot-potential.vts", [ ("potential", fld_in_vol) ]) if 0: apply_op = bound_bdry_op.scipy_op(actx, "sigma", np.float64, k=k) from sumpy.tools import build_matrix mat = build_matrix(apply_op) import matplotlib.pyplot as pt pt.imshow(mat) pt.colorbar() pt.show() if enable_mayavi: # {{{ plot boundary field from arraycontext import flatten fld_on_bdry = actx.to_numpy( flatten(bound_bdry_op(actx, sigma=sigma, k=k), actx)) nodes_host = actx.to_numpy( flatten(density_discr.nodes(), actx) ).reshape(density_discr.ambient_dim, -1) mlab.points3d(nodes_host[0], nodes_host[1], fld_on_bdry.real, scale_factor=0.03) mlab.colorbar() mlab.show()
def run_source_refinement_test(ctx_factory, mesh, order, helmholtz_k=None, visualize=False): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ initial geometry from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) discr = Discretization(actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(order)) lpot_source = QBXLayerPotentialSource( discr, qbx_order=order, # not used in refinement fine_order=order) places = GeometryCollection(lpot_source) # }}} # {{{ refined geometry kernel_length_scale = 5 / helmholtz_k if helmholtz_k else None expansion_disturbance_tolerance = 0.025 from pytential.qbx.refinement import refine_geometry_collection places = refine_geometry_collection( places, kernel_length_scale=kernel_length_scale, expansion_disturbance_tolerance=expansion_disturbance_tolerance, visualize=visualize) # }}} dd = places.auto_source stage1_density_discr = places.get_discretization(dd.geometry) from meshmode.dof_array import thaw stage1_density_nodes = dof_array_to_numpy( actx, thaw(actx, stage1_density_discr.nodes())) quad_stage2_density_discr = places.get_discretization( dd.geometry, sym.QBX_SOURCE_QUAD_STAGE2) quad_stage2_density_nodes = dof_array_to_numpy( actx, thaw(actx, quad_stage2_density_discr.nodes())) int_centers = dof_array_to_numpy( actx, bind(places, sym.expansion_centers(lpot_source.ambient_dim, -1))(actx)) ext_centers = dof_array_to_numpy( actx, bind(places, sym.expansion_centers(lpot_source.ambient_dim, +1))(actx)) expansion_radii = dof_array_to_numpy( actx, bind(places, sym.expansion_radii(lpot_source.ambient_dim))(actx)) dd = dd.copy(granularity=sym.GRANULARITY_ELEMENT) source_danger_zone_radii = dof_array_to_numpy( actx, bind( places, sym._source_danger_zone_radii(lpot_source.ambient_dim, dofdesc=dd.to_stage2()))(actx)) quad_res = dof_array_to_numpy( actx, bind(places, sym._quad_resolution(lpot_source.ambient_dim, dofdesc=dd))(actx)) # {{{ check if satisfying criteria def check_disk_undisturbed_by_sources(centers_panel, sources_panel): if centers_panel.element_nr == sources_panel.element_nr: # Same panel return my_int_centers = int_centers[:, centers_panel.discr_slice] my_ext_centers = ext_centers[:, centers_panel.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = stage1_density_nodes[:, sources_panel.discr_slice] # =distance(centers of panel 1, panel 2) dist = (la.norm( (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1).min()) # Criterion: # A center cannot be closer to another panel than to its originating # panel. rad = expansion_radii[centers_panel.discr_slice] assert (dist >= rad * (1-expansion_disturbance_tolerance)).all(), \ (dist, rad, centers_panel.element_nr, sources_panel.element_nr) def check_sufficient_quadrature_resolution(centers_panel, sources_panel): dz_radius = source_danger_zone_radii[sources_panel.element_nr] my_int_centers = int_centers[:, centers_panel.discr_slice] my_ext_centers = ext_centers[:, centers_panel.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = quad_stage2_density_nodes[:, sources_panel.discr_slice] # =distance(centers of panel 1, panel 2) dist = (la.norm( (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1).min()) # Criterion: # The quadrature contribution from each panel is as accurate # as from the center's own source panel. assert dist >= dz_radius, \ (dist, dz_radius, centers_panel.element_nr, sources_panel.element_nr) def check_quad_res_to_helmholtz_k_ratio(panel): # Check wavenumber to panel size ratio. assert quad_res[panel.element_nr] * helmholtz_k <= 5 for i, panel_1 in enumerate(iter_elements(stage1_density_discr)): for panel_2 in iter_elements(stage1_density_discr): check_disk_undisturbed_by_sources(panel_1, panel_2) for panel_2 in iter_elements(quad_stage2_density_discr): check_sufficient_quadrature_resolution(panel_1, panel_2) if helmholtz_k is not None: check_quad_res_to_helmholtz_k_ratio(panel_1)
def test_sphere_eigenvalues(ctx_factory, mode_m, mode_n, qbx_order, fmm_backend): logging.basicConfig(level=logging.INFO) special = pytest.importorskip("scipy.special") cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) target_order = 8 from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource from pytools.convergence import EOCRecorder s_eoc_rec = EOCRecorder() d_eoc_rec = EOCRecorder() sp_eoc_rec = EOCRecorder() dp_eoc_rec = EOCRecorder() def rel_err(comp, ref): return (norm(density_discr, comp - ref) / norm(density_discr, ref)) for nrefinements in [0, 1]: from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) from meshmode.mesh.refinement import Refiner refiner = Refiner(mesh) for i in range(nrefinements): flags = np.ones(mesh.nelements, dtype=bool) refiner.refine(flags) mesh = refiner.get_current_mesh() pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=6, fmm_backend=fmm_backend, ) places = GeometryCollection(qbx) from meshmode.dof_array import flatten, unflatten, thaw density_discr = places.get_discretization(places.auto_source.geometry) nodes = thaw(actx, density_discr.nodes()) r = actx.np.sqrt(nodes[0] * nodes[0] + nodes[1] * nodes[1] + nodes[2] * nodes[2]) phi = actx.np.arccos(nodes[2] / r) theta = actx.np.arctan2(nodes[0], nodes[1]) ymn = unflatten( actx, density_discr, actx.from_numpy( special.sph_harm(mode_m, mode_n, actx.to_numpy(flatten(theta)), actx.to_numpy(flatten(phi))))) from sumpy.kernel import LaplaceKernel lap_knl = LaplaceKernel(3) # {{{ single layer s_sigma_op = bind( places, sym.S(lap_knl, sym.var("sigma"), qbx_forced_limit=+1)) s_sigma = s_sigma_op(actx, sigma=ymn) s_eigval = 1 / (2 * mode_n + 1) h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx) s_eoc_rec.add_data_point(h_max, rel_err(s_sigma, s_eigval * ymn)) # }}} # {{{ double layer d_sigma_op = bind( places, sym.D(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) d_sigma = d_sigma_op(actx, sigma=ymn) d_eigval = -1 / (2 * (2 * mode_n + 1)) d_eoc_rec.add_data_point(h_max, rel_err(d_sigma, d_eigval * ymn)) # }}} # {{{ S' sp_sigma_op = bind( places, sym.Sp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) sp_sigma = sp_sigma_op(actx, sigma=ymn) sp_eigval = -1 / (2 * (2 * mode_n + 1)) sp_eoc_rec.add_data_point(h_max, rel_err(sp_sigma, sp_eigval * ymn)) # }}} # {{{ D' dp_sigma_op = bind( places, sym.Dp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) dp_sigma = dp_sigma_op(actx, sigma=ymn) dp_eigval = -(mode_n * (mode_n + 1)) / (2 * mode_n + 1) dp_eoc_rec.add_data_point(h_max, rel_err(dp_sigma, dp_eigval * ymn)) # }}} print("Errors for S:") print(s_eoc_rec) required_order = qbx_order + 1 assert s_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D:") print(d_eoc_rec) required_order = qbx_order assert d_eoc_rec.order_estimate() > required_order - 0.5 print("Errors for S':") print(sp_eoc_rec) required_order = qbx_order assert sp_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D':") print(dp_eoc_rec) required_order = qbx_order assert dp_eoc_rec.order_estimate() > required_order - 1.5
def test_target_association(ctx_factory, curve_name, curve_f, nelements, visualize=False): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ generate lpot source order = 16 # Make the curve mesh. mesh = make_curve_mesh(curve_f, np.linspace(0, 1, nelements + 1), order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory factory = InterpolatoryQuadratureSimplexGroupFactory(order) discr = Discretization(actx, mesh, factory) lpot_source = QBXLayerPotentialSource( discr, qbx_order=order, # not used in target association fine_order=order) places = GeometryCollection(lpot_source) # }}} # {{{ generate targets from pyopencl.clrandom import PhiloxGenerator rng = PhiloxGenerator(cl_ctx, seed=RNG_SEED) dd = places.auto_source.to_stage1() centers = dof_array_to_numpy( actx, bind( places, sym.interleaved_expansion_centers(lpot_source.ambient_dim, dofdesc=dd))(actx)) density_discr = places.get_discretization(dd.geometry) noise = actx.to_numpy( rng.uniform(queue, density_discr.ndofs, dtype=np.float, a=0.01, b=1.0)) tunnel_radius = dof_array_to_numpy( actx, bind( places, sym._close_target_tunnel_radii(lpot_source.ambient_dim, dofdesc=dd))(actx)) def targets_from_sources(sign, dist, dim=2): nodes = dof_array_to_numpy( actx, bind(places, sym.nodes(dim, dofdesc=dd))(actx).as_vector(np.object)) normals = dof_array_to_numpy( actx, bind(places, sym.normal(dim, dofdesc=dd))(actx).as_vector(np.object)) return actx.from_numpy(nodes + normals * sign * dist) from pytential.target import PointsTarget int_targets = PointsTarget(targets_from_sources(-1, noise * tunnel_radius)) ext_targets = PointsTarget(targets_from_sources(+1, noise * tunnel_radius)) far_targets = PointsTarget( targets_from_sources(+1, FAR_TARGET_DIST_FROM_SOURCE)) # Create target discretizations. target_discrs = ( # On-surface targets, interior (density_discr, -1), # On-surface targets, exterior (density_discr, +1), # Interior close targets (int_targets, -2), # Exterior close targets (ext_targets, +2), # Far targets, should not need centers (far_targets, 0), ) sizes = np.cumsum([discr.ndofs for discr, _ in target_discrs]) ( surf_int_slice, surf_ext_slice, vol_int_slice, vol_ext_slice, far_slice, ) = [slice(start, end) for start, end in zip(np.r_[0, sizes], sizes)] # }}} # {{{ run target associator and check from pytential.qbx.target_assoc import (TargetAssociationCodeContainer, associate_targets_to_qbx_centers) from pytential.qbx.utils import TreeCodeContainer code_container = TargetAssociationCodeContainer(actx, TreeCodeContainer(actx)) target_assoc = (associate_targets_to_qbx_centers( places, places.auto_source, code_container.get_wrangler(actx), target_discrs, target_association_tolerance=1e-10).get(queue=queue)) expansion_radii = dof_array_to_numpy( actx, bind( places, sym.expansion_radii(lpot_source.ambient_dim, granularity=sym.GRANULARITY_CENTER))(actx)) from meshmode.dof_array import thaw surf_targets = dof_array_to_numpy(actx, thaw(actx, density_discr.nodes())) int_targets = actx.to_numpy(int_targets.nodes()) ext_targets = actx.to_numpy(ext_targets.nodes()) def visualize_curve_and_assoc(): import matplotlib.pyplot as plt from meshmode.mesh.visualization import draw_curve draw_curve(density_discr.mesh) targets = int_targets tgt_slice = surf_int_slice plt.plot(centers[0], centers[1], "+", color="orange") ax = plt.gca() for tx, ty, tcenter in zip(targets[0, tgt_slice], targets[1, tgt_slice], target_assoc.target_to_center[tgt_slice]): if tcenter >= 0: ax.add_artist( plt.Line2D( (tx, centers[0, tcenter]), (ty, centers[1, tcenter]), )) ax.set_aspect("equal") plt.show() if visualize: visualize_curve_and_assoc() # Checks that the targets match with centers on the appropriate side and # within the allowable distance. def check_close_targets(centers, targets, true_side, target_to_center, target_to_side_result, tgt_slice): targets_have_centers = (target_to_center >= 0).all() assert targets_have_centers assert (target_to_side_result == true_side).all() TOL = 1e-3 dists = la.norm((targets.T - centers.T[target_to_center]), axis=1) assert (dists <= (1 + TOL) * expansion_radii[target_to_center]).all() # Center side order = -1, 1, -1, 1, ... target_to_center_side = 2 * (target_assoc.target_to_center % 2) - 1 # interior surface check_close_targets(centers, surf_targets, -1, target_assoc.target_to_center[surf_int_slice], target_to_center_side[surf_int_slice], surf_int_slice) # exterior surface check_close_targets(centers, surf_targets, +1, target_assoc.target_to_center[surf_ext_slice], target_to_center_side[surf_ext_slice], surf_ext_slice) # interior volume check_close_targets(centers, int_targets, -1, target_assoc.target_to_center[vol_int_slice], target_to_center_side[vol_int_slice], vol_int_slice) # exterior volume check_close_targets(centers, ext_targets, +1, target_assoc.target_to_center[vol_ext_slice], target_to_center_side[vol_ext_slice], vol_ext_slice) # Checks that far targets are not assigned a center. assert (target_assoc.target_to_center[far_slice] == -1).all()
def timing_run(nx, ny): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) mesh = make_mesh(nx=nx, ny=ny) density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import ( QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order ) # {{{ describe bvp from sumpy.kernel import HelmholtzKernel kernel = HelmholtzKernel(2) cse = sym.cse sigma_sym = sym.var("sigma") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = cse(sigma_sym/sqrt_w) # Brakhage-Werner parameter alpha = 1j # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = (-loc_sign*0.5*sigma_sym + sqrt_w*( alpha*sym.S(kernel, inv_sqrt_w_sigma, k=sym.var("k")) - sym.D(kernel, inv_sqrt_w_sigma, k=sym.var("k")) )) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve mode_nr = 3 nodes = density_discr.nodes().with_queue(queue) angle = cl.clmath.atan2(nodes[1], nodes[0]) sigma = cl.clmath.cos(mode_nr*angle) # }}} # {{{ postprocess/visualize repr_kwargs = dict(k=sym.var("k"), qbx_forced_limit=+1) sym_op = sym.S(kernel, sym.var("sigma"), **repr_kwargs) bound_op = bind(qbx, sym_op) print("FMM WARM-UP RUN 1: %d elements" % mesh.nelements) bound_op(queue, sigma=sigma, k=k) print("FMM WARM-UP RUN 2: %d elements" % mesh.nelements) bound_op(queue, sigma=sigma, k=k) queue.finish() print("FMM TIMING RUN: %d elements" % mesh.nelements) from time import time t_start = time() bound_op(queue, sigma=sigma, k=k) queue.finish() elapsed = time()-t_start print("FMM TIMING RUN DONE: %d elements -> %g s" % (mesh.nelements, elapsed)) return (mesh.nelements, elapsed) if 0: from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=1500) targets = cl.array.to_device(queue, fplot.points) qbx_tgt_tol = qbx.copy(target_association_tolerance=0.05) indicator_qbx = qbx_tgt_tol.copy( fmm_level_to_order=lambda lev: 7, qbx_order=2) ones_density = density_discr.zeros(queue) ones_density.fill(1) indicator = bind( (indicator_qbx, PointsTarget(targets)), sym_op)( queue, sigma=ones_density).get() qbx_stick_out = qbx.copy(target_stick_out_factor=0.1) try: fld_in_vol = bind( (qbx_stick_out, PointsTarget(targets)), sym_op)(queue, sigma=sigma, k=k).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed", e.failed_target_flags.get(queue)) ] ) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential-scaling.vts", [ ("potential", fld_in_vol), ("indicator", indicator) ] )
def main(): # cl.array.to_device(queue, numpy_array) from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource("ellipsoid.step"), 2, order=2, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h]) from meshmode.mesh.processing import perform_flips # Flip elements--gmsh generates inside-out geometry. mesh = perform_flips(mesh, np.ones(mesh.nelements)) print("%d elements" % mesh.nelements) from meshmode.mesh.processing import find_bounding_box bbox_min, bbox_max = find_bounding_box(mesh) bbox_center = 0.5*(bbox_min+bbox_max) bbox_size = max(bbox_max-bbox_min) / 2 logger.info("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order, fmm_order=qbx_order + 10, fmm_backend="fmmlib") from pytential.symbolic.pde.maxwell import MuellerAugmentedMFIEOperator pde_op = MuellerAugmentedMFIEOperator( omega=0.4, epss=[1.4, 1.0], mus=[1.2, 1.0], ) from pytential import bind, sym unk = pde_op.make_unknown("sigma") sym_operator = pde_op.operator(unk) sym_rhs = pde_op.rhs( sym.make_sym_vector("Einc", 3), sym.make_sym_vector("Hinc", 3)) sym_repr = pde_op.representation(0, unk) if 1: expr = sym_repr print(sym.pretty(expr)) print("#"*80) from pytential.target import PointsTarget tgt_points=np.zeros((3,1)) tgt_points[0,0] = 100 tgt_points[1,0] = -200 tgt_points[2,0] = 300 bound_op = bind((qbx, PointsTarget(tgt_points)), expr) print(bound_op.code) if 1: def green3e(x,y,z,source,strength,k): # electric field corresponding to dyadic green's function # due to monochromatic electric dipole located at "source". # "strength" is the the intensity of the dipole. # E = (I + Hess)(exp(ikr)/r) dot (strength) # dx = x - source[0] dy = y - source[1] dz = z - source[2] rr = np.sqrt(dx**2 + dy**2 + dz**2) fout = np.exp(1j*k*rr)/rr evec = fout*strength qmat = np.zeros((3,3),dtype=np.complex128) qmat[0,0]=(2*dx**2-dy**2-dz**2)*(1-1j*k*rr) qmat[1,1]=(2*dy**2-dz**2-dx**2)*(1-1j*k*rr) qmat[2,2]=(2*dz**2-dx**2-dy**2)*(1-1j*k*rr) qmat[0,0]=qmat[0,0]+(-k**2*dx**2*rr**2) qmat[1,1]=qmat[1,1]+(-k**2*dy**2*rr**2) qmat[2,2]=qmat[2,2]+(-k**2*dz**2*rr**2) qmat[0,1]=(3-k**2*rr**2-3*1j*k*rr)*(dx*dy) qmat[1,2]=(3-k**2*rr**2-3*1j*k*rr)*(dy*dz) qmat[2,0]=(3-k**2*rr**2-3*1j*k*rr)*(dz*dx) qmat[1,0]=qmat[0,1] qmat[2,1]=qmat[1,2] qmat[0,2]=qmat[2,0] fout=np.exp(1j*k*rr)/rr**5/k**2 fvec = fout*np.dot(qmat,strength) evec = evec + fvec return evec def green3m(x,y,z,source,strength,k): # magnetic field corresponding to dyadic green's function # due to monochromatic electric dipole located at "source". # "strength" is the the intensity of the dipole. # H = curl((I + Hess)(exp(ikr)/r) dot (strength)) = # strength \cross \grad (exp(ikr)/r) # dx = x - source[0] dy = y - source[1] dz = z - source[2] rr = np.sqrt(dx**2 + dy**2 + dz**2) fout=(1-1j*k*rr)*np.exp(1j*k*rr)/rr**3 fvec = np.zeros(3,dtype=np.complex128) fvec[0] = fout*dx fvec[1] = fout*dy fvec[2] = fout*dz hvec = np.cross(strength,fvec) return hvec def dipole3e(x,y,z,source,strength,k): # # evalaute electric and magnetic field due # to monochromatic electric dipole located at "source" # with intensity "strength" evec = green3e(x,y,z,source,strength,k) evec = evec*1j*k hvec = green3m(x,y,z,source,strength,k) return evec,hvec def dipole3m(x,y,z,source,strength,k): # # evalaute electric and magnetic field due # to monochromatic magnetic dipole located at "source" # with intensity "strength" evec = green3m(x,y,z,source,strength,k) hvec = green3e(x,y,z,source,strength,k) hvec = -hvec*1j*k return evec,hvec def dipole3eall(x,y,z,sources,strengths,k): ns = len(strengths) evec = np.zeros(3,dtype=np.complex128) hvec = np.zeros(3,dtype=np.complex128) for i in range(ns): evect,hvect = dipole3e(x,y,z,sources[i],strengths[i],k) evec = evec + evect hvec = hvec + hvect nodes = density_discr.nodes().with_queue(queue).get() source = [0.01,-0.03,0.02] # source = cl.array.to_device(queue,np.zeros(3)) # source[0] = 0.01 # source[1] =-0.03 # source[2] = 0.02 strength = np.ones(3) # evec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128)) # hvec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128)) evec = np.zeros((3,len(nodes[0])),dtype=np.complex128) hvec = np.zeros((3,len(nodes[0])),dtype=np.complex128) for i in range(len(nodes[0])): evec[:,i],hvec[:,i] = dipole3e(nodes[0][i],nodes[1][i],nodes[2][i],source,strength,k) print(np.shape(hvec)) print(type(evec)) print(type(hvec)) evec = cl.array.to_device(queue,evec) hvec = cl.array.to_device(queue,hvec) bvp_rhs = bind(qbx, sym_rhs)(queue,Einc=evec,Hinc=hvec) print(np.shape(bvp_rhs)) print(type(bvp_rhs)) # print(bvp_rhs) 1/-1 bound_op = bind(qbx, sym_operator) from pytential.solve import gmres if 0: gmres_result = gmres( bound_op.scipy_op(queue, "sigma", dtype=np.complex128, k=k), bvp_rhs, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) sigma = gmres_result.solution fld_at_tgt = bind((qbx, PointsTarget(tgt_points)), sym_repr)(queue, sigma=bvp_rhs,k=k) fld_at_tgt = np.array([ fi.get() for fi in fld_at_tgt ]) print(fld_at_tgt) 1/0 # }}} #mlab.figure(bgcolor=(1, 1, 1)) if 1: from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, target_order) bdry_normals = bind(density_discr, sym.normal(3))(queue)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("source.vtu", [ ("sigma", sigma), ("bdry_normals", bdry_normals), ]) fplot = FieldPlotter(bbox_center, extent=2*bbox_size, npoints=(150, 150, 1)) qbx_tgt_tol = qbx.copy(target_association_tolerance=0.1) from pytential.target import PointsTarget from pytential.qbx import QBXTargetAssociationFailedException rho_sym = sym.var("rho") try: fld_in_vol = bind( (qbx_tgt_tol, PointsTarget(fplot.points)), sym.make_obj_array([ sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None), sym.d_dx(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), sym.d_dy(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), sym.d_dz(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), ]) )(queue, jt=jt, rho=rho, k=k) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed_targets", e.failed_target_flags.get(queue)) ]) raise fld_in_vol = sym.make_obj_array( [fiv.get() for fiv in fld_in_vol]) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential.vts", [ ("potential", fld_in_vol[0]), ("grad", fld_in_vol[1:]), ] )
def main(mesh_name="ellipsoid"): import logging logger = logging.getLogger(__name__) logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) if mesh_name == "ellipsoid": cad_file_name = "geometries/ellipsoid.step" h = 0.6 elif mesh_name == "two-cylinders": cad_file_name = "geometries/two-cylinders-smooth.step" h = 0.4 else: raise ValueError("unknown mesh name: %s" % mesh_name) from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource(cad_file_name), 2, order=2, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h], target_unit="MM") from meshmode.mesh.processing import perform_flips # Flip elements--gmsh generates inside-out geometry. mesh = perform_flips(mesh, np.ones(mesh.nelements)) from meshmode.mesh.processing import find_bounding_box bbox_min, bbox_max = find_bounding_box(mesh) bbox_center = 0.5 * (bbox_min + bbox_max) bbox_size = max(bbox_max - bbox_min) / 2 logger.info("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource(density_discr, 4 * target_order, qbx_order, fmm_order=qbx_order + 3, target_association_tolerance=0.15) from pytential.target import PointsTarget fplot = FieldPlotter(bbox_center, extent=3.5 * bbox_size, npoints=150) from pytential import GeometryCollection places = GeometryCollection( { "qbx": qbx, "targets": PointsTarget(fplot.points) }, auto_where="qbx") density_discr = places.get_discretization("qbx") nodes = thaw(actx, density_discr.nodes()) angle = actx.np.arctan2(nodes[1], nodes[0]) if k: kernel = HelmholtzKernel(3) else: kernel = LaplaceKernel(3) #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None)) op = sym.D(kernel, sym.var("sigma"), qbx_forced_limit=None) #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None) sigma = actx.np.cos(mode_nr * angle) if 0: from meshmode.dof_array import flatten, unflatten sigma = flatten(0 * angle) from random import randrange for i in range(5): sigma[randrange(len(sigma))] = 1 sigma = unflatten(actx, density_discr, sigma) if isinstance(kernel, HelmholtzKernel): for i, elem in np.ndenumerate(sigma): sigma[i] = elem.astype(np.complex128) fld_in_vol = actx.to_numpy( bind(places, op, auto_where=("qbx", "targets"))(actx, sigma=sigma, k=k)) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("layerpot-3d-potential.vts", [("potential", fld_in_vol)]) bdry_normals = bind(places, sym.normal( density_discr.ambient_dim))(actx).as_vector(dtype=object) from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(actx, density_discr, target_order) bdry_vis.write_vtk_file("layerpot-3d-density.vtu", [ ("sigma", sigma), ("bdry_normals", bdry_normals), ])
def test_compare_cl_and_py_cost_model(ctx_factory): nelements = 3600 target_order = 16 fmm_order = 5 qbx_order = fmm_order ctx = ctx_factory() queue = cl.CommandQueue(ctx) actx = PyOpenCLArrayContext(queue) # {{{ Construct geometry from meshmode.mesh.generation import make_curve_mesh, starfish mesh = make_curve_mesh(starfish, np.linspace(0, 1, nelements), target_order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order) ) qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=fmm_order ) places = GeometryCollection(qbx) from pytential.qbx.refinement import refine_geometry_collection places = refine_geometry_collection(places) target_discrs_and_qbx_sides = tuple([(qbx.density_discr, 0)]) geo_data_dev = qbx.qbx_fmm_geometry_data( places, places.auto_source.geometry, target_discrs_and_qbx_sides ) from pytential.qbx.utils import ToHostTransferredGeoDataWrapper geo_data = ToHostTransferredGeoDataWrapper(queue, geo_data_dev) # }}} # {{{ Construct cost models cl_cost_model = QBXCostModel() python_cost_model = _PythonQBXCostModel() tree = geo_data.tree() xlat_cost = make_pde_aware_translation_cost_model( tree.targets.shape[0], tree.nlevels ) constant_one_params = QBXCostModel.get_unit_calibration_params() constant_one_params["p_qbx"] = 5 for ilevel in range(tree.nlevels): constant_one_params["p_fmm_lev%d" % ilevel] = 10 cl_cost_factors = cl_cost_model.qbx_cost_factors_for_kernels_from_model( queue, tree.nlevels, xlat_cost, constant_one_params ) python_cost_factors = python_cost_model.qbx_cost_factors_for_kernels_from_model( None, tree.nlevels, xlat_cost, constant_one_params ) # }}} # {{{ Test process_form_qbxl cl_ndirect_sources_per_target_box = ( cl_cost_model.get_ndirect_sources_per_target_box( queue, geo_data_dev.traversal() ) ) queue.finish() start_time = time.time() cl_p2qbxl = cl_cost_model.process_form_qbxl( queue, geo_data_dev, cl_cost_factors["p2qbxl_cost"], cl_ndirect_sources_per_target_box ) queue.finish() logger.info("OpenCL time for process_form_qbxl: {}".format( str(time.time() - start_time) )) python_ndirect_sources_per_target_box = ( python_cost_model.get_ndirect_sources_per_target_box( queue, geo_data.traversal() ) ) start_time = time.time() python_p2qbxl = python_cost_model.process_form_qbxl( queue, geo_data, python_cost_factors["p2qbxl_cost"], python_ndirect_sources_per_target_box ) logger.info("Python time for process_form_qbxl: {}".format( str(time.time() - start_time) )) assert np.array_equal(cl_p2qbxl.get(), python_p2qbxl) # }}} # {{{ Test process_m2qbxl queue.finish() start_time = time.time() cl_m2qbxl = cl_cost_model.process_m2qbxl( queue, geo_data_dev, cl_cost_factors["m2qbxl_cost"] ) queue.finish() logger.info("OpenCL time for process_m2qbxl: {}".format( str(time.time() - start_time) )) start_time = time.time() python_m2qbxl = python_cost_model.process_m2qbxl( queue, geo_data, python_cost_factors["m2qbxl_cost"] ) logger.info("Python time for process_m2qbxl: {}".format( str(time.time() - start_time) )) assert np.array_equal(cl_m2qbxl.get(), python_m2qbxl) # }}} # {{{ Test process_l2qbxl queue.finish() start_time = time.time() cl_l2qbxl = cl_cost_model.process_l2qbxl( queue, geo_data_dev, cl_cost_factors["l2qbxl_cost"] ) queue.finish() logger.info("OpenCL time for process_l2qbxl: {}".format( str(time.time() - start_time) )) start_time = time.time() python_l2qbxl = python_cost_model.process_l2qbxl( queue, geo_data, python_cost_factors["l2qbxl_cost"] ) logger.info("Python time for process_l2qbxl: {}".format( str(time.time() - start_time) )) assert np.array_equal(cl_l2qbxl.get(), python_l2qbxl) # }}} # {{{ Test process_eval_qbxl queue.finish() start_time = time.time() cl_eval_qbxl = cl_cost_model.process_eval_qbxl( queue, geo_data_dev, cl_cost_factors["qbxl2p_cost"] ) queue.finish() logger.info("OpenCL time for process_eval_qbxl: {}".format( str(time.time() - start_time) )) start_time = time.time() python_eval_qbxl = python_cost_model.process_eval_qbxl( queue, geo_data, python_cost_factors["qbxl2p_cost"] ) logger.info("Python time for process_eval_qbxl: {}".format( str(time.time() - start_time) )) assert np.array_equal(cl_eval_qbxl.get(), python_eval_qbxl) # }}} # {{{ Test eval_target_specific_qbxl queue.finish() start_time = time.time() cl_eval_target_specific_qbxl = cl_cost_model.process_eval_target_specific_qbxl( queue, geo_data_dev, cl_cost_factors["p2p_tsqbx_cost"], cl_ndirect_sources_per_target_box ) queue.finish() logger.info("OpenCL time for eval_target_specific_qbxl: {}".format( str(time.time() - start_time) )) start_time = time.time() python_eval_target_specific_qbxl = \ python_cost_model.process_eval_target_specific_qbxl( queue, geo_data, python_cost_factors["p2p_tsqbx_cost"], python_ndirect_sources_per_target_box ) logger.info("Python time for eval_target_specific_qbxl: {}".format( str(time.time() - start_time) )) assert np.array_equal( cl_eval_target_specific_qbxl.get(), python_eval_target_specific_qbxl )
def main(): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial if 0: mesh = make_curve_mesh( partial(ellipse, 1), np.linspace(0, 1, nelements+1), mesh_order) else: base_mesh = make_curve_mesh( partial(ellipse, 1), np.linspace(0, 1, nelements+1), mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes nx = 2 ny = 2 dx = 2 / nx meshes = [ affine_map( base_mesh, A=np.diag([dx*0.25, dx*0.25]), b=np.array([dx*(ix-nx/2), dx*(iy-ny/2)])) for ix in range(nx) for iy in range(ny)] mesh = merge_disjoint_meshes(meshes, single_group=True) if 0: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import ( QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx, _ = QBXLayerPotentialSource( pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order ).with_refinement() density_discr = qbx.density_discr # {{{ describe bvp from sumpy.kernel import LaplaceKernel, HelmholtzKernel kernel = HelmholtzKernel(2) cse = sym.cse sigma_sym = sym.var("sigma") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = cse(sigma_sym/sqrt_w) # Brakhage-Werner parameter alpha = 1j # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = (-loc_sign*0.5*sigma_sym + sqrt_w*( alpha*sym.S(kernel, inv_sqrt_w_sigma, k=sym.var("k"), qbx_forced_limit=+1) - sym.D(kernel, inv_sqrt_w_sigma, k=sym.var("k"), qbx_forced_limit="avg") )) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve nodes = density_discr.nodes().with_queue(queue) k_vec = np.array([2, 1]) k_vec = k * k_vec / la.norm(k_vec, 2) def u_incoming_func(x): return cl.clmath.exp( 1j * (x[0] * k_vec[0] + x[1] * k_vec[1])) bc = -u_incoming_func(nodes) bvp_rhs = bind(qbx, sqrt_w*sym.var("bc"))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "sigma", dtype=np.complex128, k=k), bvp_rhs, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution repr_kwargs = dict(k=sym.var("k"), qbx_forced_limit=None) representation_sym = ( alpha*sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) - sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) targets = cl.array.to_device(queue, fplot.points) u_incoming = u_incoming_func(targets) qbx_stick_out = qbx.copy(target_association_tolerance=0.05) ones_density = density_discr.zeros(queue) ones_density.fill(1) indicator = bind( (qbx_stick_out, PointsTarget(targets)), sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=None))( queue, sigma=ones_density).get() try: fld_in_vol = bind( (qbx_stick_out, PointsTarget(targets)), representation_sym)(queue, sigma=sigma, k=k).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed", e.failed_target_flags.get(queue)) ] ) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential-helm.vts", [ ("potential", fld_in_vol), ("indicator", indicator), ("u_incoming", u_incoming.get()), ] )
def main(): import logging logging.basicConfig(level=logging.INFO) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial mesh = make_curve_mesh( partial(ellipse, 2), np.linspace(0, 1, nelements+1), mesh_order) pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import ( QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx, _ = QBXLayerPotentialSource( pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order, expansion_disks_in_tree_have_extent=True, ).with_refinement() density_discr = qbx.density_discr from pytential.symbolic.pde.cahn_hilliard import CahnHilliardOperator chop = CahnHilliardOperator( # FIXME: Constants? lambda1=1.5, lambda2=1.25, c=1) unk = chop.make_unknown("sigma") bound_op = bind(qbx, chop.operator(unk)) # {{{ fix rhs and solve nodes = density_discr.nodes().with_queue(queue) def g(xvec): x, y = xvec return cl.clmath.atan2(y, x) bc = sym.make_obj_array([ # FIXME: Realistic BC g(nodes), -g(nodes), ]) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "sigma", dtype=np.complex128), bc, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) targets = cl.array.to_device(queue, fplot.points) qbx_stick_out = qbx.copy(target_association_tolerance=0.05) indicator_qbx = qbx_stick_out.copy(qbx_order=2) from sumpy.kernel import LaplaceKernel ones_density = density_discr.zeros(queue) ones_density.fill(1) indicator = bind( (indicator_qbx, PointsTarget(targets)), sym.D(LaplaceKernel(2), sym.var("sigma")))( queue, sigma=ones_density).get() try: fld_in_vol = bind( (qbx_stick_out, PointsTarget(targets)), chop.representation(unk))(queue, sigma=sigma).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed", e.failed_target_flags.get(queue)) ] ) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential.vts", [ ("potential", fld_in_vol), ("indicator", indicator), ] )
def test_target_specific_qbx(actx_factory, op, helmholtz_k, qbx_order): logging.basicConfig(level=logging.INFO) actx = actx_factory() target_order = 4 fmm_tol = 1e-3 from meshmode.mesh.generation import generate_sphere mesh = generate_sphere(1, target_order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order=qbx_order, fmm_level_to_order=SimpleExpansionOrderFinder(fmm_tol), fmm_backend="fmmlib", _expansions_in_tree_have_extent=True, _expansion_stick_out_factor=0.9, _use_target_specific_qbx=False, ) kernel_length_scale = 5 / abs(helmholtz_k) if helmholtz_k else None places = { "qbx": qbx, "qbx_target_specific": qbx.copy(_use_target_specific_qbx=True) } from pytential.qbx.refinement import refine_geometry_collection places = GeometryCollection(places, auto_where="qbx") places = refine_geometry_collection( places, kernel_length_scale=kernel_length_scale) density_discr = places.get_discretization("qbx") nodes = thaw(density_discr.nodes(), actx) u_dev = actx.np.sin(nodes[0]) if helmholtz_k == 0: kernel = LaplaceKernel(3) kernel_kwargs = {} else: kernel = HelmholtzKernel(3, allow_evanescent=True) kernel_kwargs = {"k": sym.var("k")} u_sym = sym.var("u") if op == "S": op = sym.S elif op == "D": op = sym.D elif op == "Sp": op = sym.Sp else: raise ValueError("unknown operator: '%s'" % op) expr = op(kernel, u_sym, qbx_forced_limit=-1, **kernel_kwargs) bound_op = bind(places, expr) pot_ref = actx.to_numpy( flatten(bound_op(actx, u=u_dev, k=helmholtz_k), actx)) bound_op = bind(places, expr, auto_where="qbx_target_specific") pot_tsqbx = actx.to_numpy( flatten(bound_op(actx, u=u_dev, k=helmholtz_k), actx)) assert np.allclose(pot_tsqbx, pot_ref, atol=1e-13, rtol=1e-13)
def main(mesh_name="ellipse", visualize=False): import logging logging.basicConfig(level=logging.INFO) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial if mesh_name == "ellipse": mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements + 1), mesh_order) elif mesh_name == "ellipse_array": base_mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements + 1), mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes nx = 2 ny = 2 dx = 2 / nx meshes = [ affine_map(base_mesh, A=np.diag([dx * 0.25, dx * 0.25]), b=np.array([dx * (ix - nx / 2), dx * (iy - ny / 2)])) for ix in range(nx) for iy in range(ny) ] mesh = merge_disjoint_meshes(meshes, single_group=True) if visualize: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() else: raise ValueError(f"unknown mesh name: {mesh_name}") pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import (QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx = QBXLayerPotentialSource(pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) targets = actx.from_numpy(fplot.points) from pytential import GeometryCollection places = GeometryCollection( { "qbx": qbx, "qbx_high_target_assoc_tol": qbx.copy(target_association_tolerance=0.05), "targets": PointsTarget(targets) }, auto_where="qbx") density_discr = places.get_discretization("qbx") # {{{ describe bvp from sumpy.kernel import LaplaceKernel, HelmholtzKernel kernel = HelmholtzKernel(2) sigma_sym = sym.var("sigma") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = sym.cse(sigma_sym / sqrt_w) # Brakhage-Werner parameter alpha = 1j # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 k_sym = sym.var("k") bdry_op_sym = ( -loc_sign * 0.5 * sigma_sym + sqrt_w * (alpha * sym.S(kernel, inv_sqrt_w_sigma, k=k_sym, qbx_forced_limit=+1) - sym.D(kernel, inv_sqrt_w_sigma, k=k_sym, qbx_forced_limit="avg"))) # }}} bound_op = bind(places, bdry_op_sym) # {{{ fix rhs and solve from meshmode.dof_array import thaw nodes = thaw(actx, density_discr.nodes()) k_vec = np.array([2, 1]) k_vec = k * k_vec / la.norm(k_vec, 2) def u_incoming_func(x): return actx.np.exp(1j * (x[0] * k_vec[0] + x[1] * k_vec[1])) bc = -u_incoming_func(nodes) bvp_rhs = bind(places, sqrt_w * sym.var("bc"))(actx, bc=bc) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(actx, sigma_sym.name, dtype=np.complex128, k=k), bvp_rhs, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize repr_kwargs = dict(source="qbx_high_target_assoc_tol", target="targets", qbx_forced_limit=None) representation_sym = ( alpha * sym.S(kernel, inv_sqrt_w_sigma, k=k_sym, **repr_kwargs) - sym.D(kernel, inv_sqrt_w_sigma, k=k_sym, **repr_kwargs)) u_incoming = u_incoming_func(targets) ones_density = density_discr.zeros(actx) for elem in ones_density: elem.fill(1) indicator = actx.to_numpy( bind(places, sym.D(LaplaceKernel(2), sigma_sym, **repr_kwargs))(actx, sigma=ones_density)) try: fld_in_vol = actx.to_numpy( bind(places, representation_sym)(actx, sigma=gmres_result.solution, k=k)) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file("helmholtz-dirichlet-failed-targets.vts", [("failed", e.failed_target_flags.get(queue))]) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("helmholtz-dirichlet-potential.vts", [ ("potential", fld_in_vol), ("indicator", indicator), ("u_incoming", actx.to_numpy(u_incoming)), ])
def test_ellipse_eigenvalues(ctx_getter, ellipse_aspect, mode_nr, qbx_order): logging.basicConfig(level=logging.INFO) print("ellipse_aspect: %s, mode_nr: %d, qbx_order: %d" % ( ellipse_aspect, mode_nr, qbx_order)) cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) target_order = 7 from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource from pytools.convergence import EOCRecorder s_eoc_rec = EOCRecorder() d_eoc_rec = EOCRecorder() sp_eoc_rec = EOCRecorder() if ellipse_aspect != 1: nelements_values = [60, 100, 150, 200] else: nelements_values = [30, 70] # See # # [1] G. J. Rodin and O. Steinbach, "Boundary Element Preconditioners # for Problems Defined on Slender Domains", SIAM Journal on Scientific # Computing, Vol. 24, No. 4, pg. 1450, 2003. # http://dx.doi.org/10.1137/S1064827500372067 for nelements in nelements_values: mesh = make_curve_mesh(partial(ellipse, ellipse_aspect), np.linspace(0, 1, nelements+1), target_order) fmm_order = qbx_order if fmm_order > 3: # FIXME: for now fmm_order = False density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order, fmm_order=fmm_order) nodes = density_discr.nodes().with_queue(queue) if 0: # plot geometry, centers, normals centers = qbx.centers(density_discr, 1) nodes_h = nodes.get() centers_h = [centers[0].get(), centers[1].get()] pt.plot(nodes_h[0], nodes_h[1], "x-") pt.plot(centers_h[0], centers_h[1], "o") normal = bind(qbx, sym.normal())(queue).as_vector(np.object) pt.quiver(nodes_h[0], nodes_h[1], normal[0].get(), normal[1].get()) pt.gca().set_aspect("equal") pt.show() angle = cl.clmath.atan2(nodes[1]*ellipse_aspect, nodes[0]) ellipse_fraction = ((1-ellipse_aspect)/(1+ellipse_aspect))**mode_nr # (2.6) in [1] J = cl.clmath.sqrt( # noqa cl.clmath.sin(angle)**2 + (1/ellipse_aspect)**2 * cl.clmath.cos(angle)**2) # {{{ single layer sigma = cl.clmath.cos(mode_nr*angle)/J s_sigma_op = bind(qbx, sym.S(0, sym.var("sigma"))) s_sigma = s_sigma_op(queue=queue, sigma=sigma) # SIGN BINGO! :) s_eigval = 1/(2*mode_nr) * (1 + (-1)**mode_nr * ellipse_fraction) # (2.12) in [1] s_sigma_ref = s_eigval*J*sigma if 0: #pt.plot(s_sigma.get(), label="result") #pt.plot(s_sigma_ref.get(), label="ref") pt.plot((s_sigma_ref-s_sigma).get(), label="err") pt.legend() pt.show() s_err = ( norm(density_discr, queue, s_sigma - s_sigma_ref) / norm(density_discr, queue, s_sigma_ref)) s_eoc_rec.add_data_point(1/nelements, s_err) # }}} # {{{ double layer sigma = cl.clmath.cos(mode_nr*angle) d_sigma_op = bind(qbx, sym.D(0, sym.var("sigma"))) d_sigma = d_sigma_op(queue=queue, sigma=sigma) # SIGN BINGO! :) d_eigval = -(-1)**mode_nr * 1/2*ellipse_fraction d_sigma_ref = d_eigval*sigma if 0: pt.plot(d_sigma.get(), label="result") pt.plot(d_sigma_ref.get(), label="ref") pt.legend() pt.show() if ellipse_aspect == 1: d_ref_norm = norm(density_discr, queue, sigma) else: d_ref_norm = norm(density_discr, queue, d_sigma_ref) d_err = ( norm(density_discr, queue, d_sigma - d_sigma_ref) / d_ref_norm) d_eoc_rec.add_data_point(1/nelements, d_err) # }}} if ellipse_aspect == 1: # {{{ S' sigma = cl.clmath.cos(mode_nr*angle) sp_sigma_op = bind(qbx, sym.Sp(0, sym.var("sigma"))) sp_sigma = sp_sigma_op(queue=queue, sigma=sigma) sp_eigval = 0 sp_sigma_ref = sp_eigval*sigma sp_err = ( norm(density_discr, queue, sp_sigma - sp_sigma_ref) / norm(density_discr, queue, sigma)) sp_eoc_rec.add_data_point(1/nelements, sp_err) # }}} print("Errors for S:") print(s_eoc_rec) required_order = qbx_order + 1 assert s_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D:") print(d_eoc_rec) required_order = qbx_order assert d_eoc_rec.order_estimate() > required_order - 1.5 if ellipse_aspect == 1: print("Errors for S':") print(sp_eoc_rec) required_order = qbx_order assert sp_eoc_rec.order_estimate() > required_order - 1.5
def run_source_refinement_test(ctx_getter, mesh, order, helmholtz_k=None): cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) factory = InterpolatoryQuadratureSimplexGroupFactory(order) discr = Discretization(cl_ctx, mesh, factory) from pytential.qbx.refinement import ( RefinerCodeContainer, refine_for_global_qbx) from pytential.qbx.utils import TreeCodeContainer lpot_source = QBXLayerPotentialSource(discr, qbx_order=order, # not used in refinement fine_order=order) del discr expansion_disturbance_tolerance = 0.025 refiner_extra_kwargs = { "expansion_disturbance_tolerance": expansion_disturbance_tolerance, } if helmholtz_k is not None: refiner_extra_kwargs["kernel_length_scale"] = 5/helmholtz_k lpot_source, conn = refine_for_global_qbx( lpot_source, RefinerCodeContainer( cl_ctx, TreeCodeContainer(cl_ctx)).get_wrangler(queue), factory, **refiner_extra_kwargs) from pytential.qbx.utils import get_centers_on_side discr_nodes = lpot_source.density_discr.nodes().get(queue) fine_discr_nodes = \ lpot_source.quad_stage2_density_discr.nodes().get(queue) int_centers = get_centers_on_side(lpot_source, -1) int_centers = np.array([axis.get(queue) for axis in int_centers]) ext_centers = get_centers_on_side(lpot_source, +1) ext_centers = np.array([axis.get(queue) for axis in ext_centers]) expansion_radii = lpot_source._expansion_radii("nsources").get(queue) quad_res = lpot_source._coarsest_quad_resolution("npanels").get(queue) source_danger_zone_radii = \ lpot_source._source_danger_zone_radii("npanels").get(queue) # {{{ check if satisfying criteria def check_disk_undisturbed_by_sources(centers_panel, sources_panel): if centers_panel.element_nr == sources_panel.element_nr: # Same panel return my_int_centers = int_centers[:, centers_panel.discr_slice] my_ext_centers = ext_centers[:, centers_panel.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = discr_nodes[:, sources_panel.discr_slice] # =distance(centers of panel 1, panel 2) dist = ( la.norm(( all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1) .min()) # Criterion: # A center cannot be closer to another panel than to its originating # panel. rad = expansion_radii[centers_panel.discr_slice] assert (dist >= rad * (1-expansion_disturbance_tolerance)).all(), \ (dist, rad, centers_panel.element_nr, sources_panel.element_nr) def check_sufficient_quadrature_resolution(centers_panel, sources_panel): dz_radius = source_danger_zone_radii[sources_panel.element_nr] my_int_centers = int_centers[:, centers_panel.discr_slice] my_ext_centers = ext_centers[:, centers_panel.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = fine_discr_nodes[:, sources_panel.discr_slice] # =distance(centers of panel 1, panel 2) dist = ( la.norm(( all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1) .min()) # Criterion: # The quadrature contribution from each panel is as accurate # as from the center's own source panel. assert dist >= dz_radius, \ (dist, dz_radius, centers_panel.element_nr, sources_panel.element_nr) def check_quad_res_to_helmholtz_k_ratio(panel): # Check wavenumber to panel size ratio. assert quad_res[panel.element_nr] * helmholtz_k <= 5 for i, panel_1 in enumerate(iter_elements(lpot_source.density_discr)): for panel_2 in iter_elements(lpot_source.density_discr): check_disk_undisturbed_by_sources(panel_1, panel_2) for panel_2 in iter_elements(lpot_source.quad_stage2_density_discr): check_sufficient_quadrature_resolution(panel_1, panel_2) if helmholtz_k is not None: check_quad_res_to_helmholtz_k_ratio(panel_1)
def test_target_association(ctx_getter, curve_name, curve_f, nelements, visualize=False): cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) # {{{ generate lpot source order = 16 # Make the curve mesh. mesh = make_curve_mesh(curve_f, np.linspace(0, 1, nelements+1), order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory factory = InterpolatoryQuadratureSimplexGroupFactory(order) discr = Discretization(cl_ctx, mesh, factory) lpot_source, conn = QBXLayerPotentialSource(discr, qbx_order=order, # not used in target association fine_order=order).with_refinement() del discr from pytential.qbx.utils import get_interleaved_centers centers = np.array([ax.get(queue) for ax in get_interleaved_centers(queue, lpot_source)]) # }}} # {{{ generate targets from pyopencl.clrandom import PhiloxGenerator rng = PhiloxGenerator(cl_ctx, seed=RNG_SEED) nsources = lpot_source.density_discr.nnodes noise = rng.uniform(queue, nsources, dtype=np.float, a=0.01, b=1.0) tunnel_radius = \ lpot_source._close_target_tunnel_radius("nsources").with_queue(queue) def targets_from_sources(sign, dist): from pytential import sym, bind dim = 2 nodes = bind(lpot_source.density_discr, sym.nodes(dim))(queue) normals = bind(lpot_source.density_discr, sym.normal(dim))(queue) return (nodes + normals * sign * dist).as_vector(np.object) from pytential.target import PointsTarget int_targets = PointsTarget(targets_from_sources(-1, noise * tunnel_radius)) ext_targets = PointsTarget(targets_from_sources(+1, noise * tunnel_radius)) far_targets = PointsTarget(targets_from_sources(+1, FAR_TARGET_DIST_FROM_SOURCE)) # Create target discretizations. target_discrs = ( # On-surface targets, interior (lpot_source.density_discr, -1), # On-surface targets, exterior (lpot_source.density_discr, +1), # Interior close targets (int_targets, -2), # Exterior close targets (ext_targets, +2), # Far targets, should not need centers (far_targets, 0), ) sizes = np.cumsum([discr.nnodes for discr, _ in target_discrs]) (surf_int_slice, surf_ext_slice, vol_int_slice, vol_ext_slice, far_slice, ) = [slice(start, end) for start, end in zip(np.r_[0, sizes], sizes)] # }}} # {{{ run target associator and check from pytential.qbx.target_assoc import ( TargetAssociationCodeContainer, associate_targets_to_qbx_centers) from pytential.qbx.utils import TreeCodeContainer code_container = TargetAssociationCodeContainer( cl_ctx, TreeCodeContainer(cl_ctx)) target_assoc = (associate_targets_to_qbx_centers( lpot_source, code_container.get_wrangler(queue), target_discrs, target_association_tolerance=1e-10) .get(queue=queue)) expansion_radii = lpot_source._expansion_radii("ncenters").get(queue) surf_targets = np.array( [axis.get(queue) for axis in lpot_source.density_discr.nodes()]) int_targets = np.array([axis.get(queue) for axis in int_targets.nodes()]) ext_targets = np.array([axis.get(queue) for axis in ext_targets.nodes()]) def visualize_curve_and_assoc(): import matplotlib.pyplot as plt from meshmode.mesh.visualization import draw_curve draw_curve(lpot_source.density_discr.mesh) targets = int_targets tgt_slice = surf_int_slice plt.plot(centers[0], centers[1], "+", color="orange") ax = plt.gca() for tx, ty, tcenter in zip( targets[0, tgt_slice], targets[1, tgt_slice], target_assoc.target_to_center[tgt_slice]): if tcenter >= 0: ax.add_artist( plt.Line2D( (tx, centers[0, tcenter]), (ty, centers[1, tcenter]), )) ax.set_aspect("equal") plt.show() if visualize: visualize_curve_and_assoc() # Checks that the targets match with centers on the appropriate side and # within the allowable distance. def check_close_targets(centers, targets, true_side, target_to_center, target_to_side_result, tgt_slice): targets_have_centers = (target_to_center >= 0).all() assert targets_have_centers assert (target_to_side_result == true_side).all() TOL = 1e-3 dists = la.norm((targets.T - centers.T[target_to_center]), axis=1) assert (dists <= (1 + TOL) * expansion_radii[target_to_center]).all() # Center side order = -1, 1, -1, 1, ... target_to_center_side = 2 * (target_assoc.target_to_center % 2) - 1 # interior surface check_close_targets( centers, surf_targets, -1, target_assoc.target_to_center[surf_int_slice], target_to_center_side[surf_int_slice], surf_int_slice) # exterior surface check_close_targets( centers, surf_targets, +1, target_assoc.target_to_center[surf_ext_slice], target_to_center_side[surf_ext_slice], surf_ext_slice) # interior volume check_close_targets( centers, int_targets, -1, target_assoc.target_to_center[vol_int_slice], target_to_center_side[vol_int_slice], vol_int_slice) # exterior volume check_close_targets( centers, ext_targets, +1, target_assoc.target_to_center[vol_ext_slice], target_to_center_side[vol_ext_slice], vol_ext_slice) # Checks that far targets are not assigned a center. assert (target_assoc.target_to_center[far_slice] == -1).all()
def nonlocal_integral_eq( mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=None, solver_parameters=None, fspace=None, vfspace=None, true_sol_grad_expr=None, actx=None, dgfspace=None, dgvfspace=None, meshmode_src_connection=None, qbx_kwargs=None, ): r""" see run_method for descriptions of unlisted args args: gamma and beta are used to precondition with the following equation: \Delta u - \kappa^2 \gamma u = 0 (\partial_n - i\kappa\beta) u |_\Sigma = 0 """ # make sure we get outer bdy id as tuple in case it consists of multiple ids if isinstance(outer_bdy_id, int): outer_bdy_id = [outer_bdy_id] outer_bdy_id = tuple(outer_bdy_id) # away from the excluded region, but firedrake and meshmode point # into pyt_inner_normal_sign = -1 ambient_dim = mesh.geometric_dimension() # {{{ Build src and tgt # build connection meshmode near src boundary -> src boundary inside meshmode from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from meshmode.discretization.connection import make_face_restriction factory = InterpolatoryQuadratureSimplexGroupFactory( dgfspace.finat_element.degree) src_bdy_connection = make_face_restriction(actx, meshmode_src_connection.discr, factory, scatterer_bdy_id) # source is a qbx layer potential from pytential.qbx import QBXLayerPotentialSource disable_refinement = (fspace.mesh().geometric_dimension() == 3) qbx = QBXLayerPotentialSource(src_bdy_connection.to_discr, **qbx_kwargs, _disable_refinement=disable_refinement) # get target indices and point-set target_indices, target = get_target_points_and_indices( fspace, outer_bdy_id) # }}} # build the operations from pytential import bind, sym r""" ..math: x \in \Sigma grad_op(x) = \nabla( \int_\Gamma( u(y) \partial_n H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ) """ grad_op = pyt_inner_normal_sign * sym.grad( ambient_dim, sym.D(HelmholtzKernel(ambient_dim), sym.var("u"), k=sym.var("k"), qbx_forced_limit=None)) r""" ..math: x \in \Sigma op(x) = i \kappa \cdot \int_\Gamma( u(y) \partial_n H_0^{(1)}(\kappa |x - y|) )d\gamma(y) """ op = pyt_inner_normal_sign * 1j * sym.var("k") * (sym.D( HelmholtzKernel(ambient_dim), sym.var("u"), k=sym.var("k"), qbx_forced_limit=None)) # bind the operations pyt_grad_op = bind((qbx, target), grad_op) pyt_op = bind((qbx, target), op) # }}} class MatrixFreeB(object): def __init__(self, A, pyt_grad_op, pyt_op, actx, kappa): """ :arg kappa: The wave number """ self.actx = actx self.k = kappa self.pyt_op = pyt_op self.pyt_grad_op = pyt_grad_op self.A = A self.meshmode_src_connection = meshmode_src_connection # {{{ Create some functions needed for multing self.x_fntn = Function(fspace) # CG self.potential_int = Function(fspace) self.potential_int.dat.data[:] = 0.0 self.grad_potential_int = Function(vfspace) self.grad_potential_int.dat.data[:] = 0.0 self.pyt_result = Function(fspace) self.n = FacetNormal(mesh) self.v = TestFunction(fspace) # some meshmode ones self.x_mm_fntn = self.meshmode_src_connection.discr.empty( self.actx, dtype='c') # }}} def mult(self, mat, x, y): # Copy function data into the fivredrake function self.x_fntn.dat.data[:] = x[:] # Transfer the function to meshmode self.meshmode_src_connection.from_firedrake(project( self.x_fntn, dgfspace), out=self.x_mm_fntn) # Restrict to boundary x_mm_fntn_on_bdy = src_bdy_connection(self.x_mm_fntn) # Apply the operation potential_int_mm = self.pyt_op(self.actx, u=x_mm_fntn_on_bdy, k=self.k) grad_potential_int_mm = self.pyt_grad_op(self.actx, u=x_mm_fntn_on_bdy, k=self.k) # Store in firedrake self.potential_int.dat.data[target_indices] = potential_int_mm.get( ) for dim in range(grad_potential_int_mm.shape[0]): self.grad_potential_int.dat.data[ target_indices, dim] = grad_potential_int_mm[dim].get() # Integrate the potential r""" Compute the inner products using firedrake. Note this will be subtracted later, hence appears off by a sign. .. math:: \langle n(x) \cdot \nabla( \int_\Gamma( u(y) \partial_n H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ), v \rangle_\Sigma - \langle i \kappa \cdot \int_\Gamma( u(y) \partial_n H_0^{(1)}(\kappa |x - y|) )d\gamma(y), v \rangle_\Sigma """ self.pyt_result = assemble( inner(inner(self.grad_potential_int, self.n), self.v) * ds(outer_bdy_id) - inner(self.potential_int, self.v) * ds(outer_bdy_id)) # y <- Ax - evaluated potential self.A.mult(x, y) with self.pyt_result.dat.vec_ro as ep: y.axpy(-1, ep) # {{{ Compute normal helmholtz operator u = TrialFunction(fspace) v = TestFunction(fspace) r""" .. math:: \langle \nabla u, \nabla v \rangle - \kappa^2 \cdot \langle u, v \rangle - i \kappa \langle u, v \rangle_\Sigma """ a = inner(grad(u), grad(v)) * dx \ - Constant(wave_number**2) * inner(u, v) * dx \ - Constant(1j * wave_number) * inner(u, v) * ds(outer_bdy_id) # get the concrete matrix from a general bilinear form A = assemble(a).M.handle # }}} # {{{ Setup Python matrix B = PETSc.Mat().create() # build matrix context Bctx = MatrixFreeB(A, pyt_grad_op, pyt_op, actx, wave_number) # set up B as same size as A B.setSizes(*A.getSizes()) B.setType(B.Type.PYTHON) B.setPythonContext(Bctx) B.setUp() # }}} # {{{ Create rhs # Remember f is \partial_n(true_sol)|_\Gamma # so we just need to compute \int_\Gamma\partial_n(true_sol) H(x-y) sigma = sym.make_sym_vector("sigma", ambient_dim) r""" ..math: x \in \Sigma grad_op(x) = \nabla( \int_\Gamma( f(y) H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ) """ grad_op = pyt_inner_normal_sign * \ sym.grad(ambient_dim, sym.S(HelmholtzKernel(ambient_dim), sym.n_dot(sigma), k=sym.var("k"), qbx_forced_limit=None)) r""" ..math: x \in \Sigma op(x) = i \kappa \cdot \int_\Gamma( f(y) H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ) """ op = 1j * sym.var("k") * pyt_inner_normal_sign * \ sym.S(HelmholtzKernel(ambient_dim), sym.n_dot(sigma), k=sym.var("k"), qbx_forced_limit=None) rhs_grad_op = bind((qbx, target), grad_op) rhs_op = bind((qbx, target), op) # Transfer to meshmode metadata = {'quadrature_degree': 2 * fspace.ufl_element().degree()} dg_true_sol_grad = project(true_sol_grad_expr, dgvfspace, form_compiler_parameters=metadata) true_sol_grad_mm = meshmode_src_connection.from_firedrake(dg_true_sol_grad, actx=actx) true_sol_grad_mm = src_bdy_connection(true_sol_grad_mm) # Apply the operations f_grad_convoluted_mm = rhs_grad_op(actx, sigma=true_sol_grad_mm, k=wave_number) f_convoluted_mm = rhs_op(actx, sigma=true_sol_grad_mm, k=wave_number) # Transfer function back to firedrake f_grad_convoluted = Function(vfspace) f_convoluted = Function(fspace) f_grad_convoluted.dat.data[:] = 0.0 f_convoluted.dat.data[:] = 0.0 for dim in range(f_grad_convoluted_mm.shape[0]): f_grad_convoluted.dat.data[target_indices, dim] = f_grad_convoluted_mm[dim].get() f_convoluted.dat.data[target_indices] = f_convoluted_mm.get() r""" \langle f, v \rangle_\Gamma + \langle i \kappa \cdot \int_\Gamma( f(y) H_0^{(1)}(\kappa |x - y|) )d\gamma(y), v \rangle_\Sigma - \langle n(x) \cdot \nabla( \int_\Gamma( f(y) H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ), v \rangle_\Sigma """ rhs_form = inner(inner(true_sol_grad_expr, FacetNormal(mesh)), v) * ds(scatterer_bdy_id, metadata=metadata) \ + inner(f_convoluted, v) * ds(outer_bdy_id) \ - inner(inner(f_grad_convoluted, FacetNormal(mesh)), v) * ds(outer_bdy_id) rhs = assemble(rhs_form) # {{{ set up a solver: solution = Function(fspace, name="Computed Solution") # {{{ Used for preconditioning if 'gamma' in solver_parameters or 'beta' in solver_parameters: gamma = complex(solver_parameters.pop('gamma', 1.0)) import cmath beta = complex(solver_parameters.pop('beta', cmath.sqrt(gamma))) p = inner(grad(u), grad(v)) * dx \ - Constant(wave_number**2 * gamma) * inner(u, v) * dx \ - Constant(1j * wave_number * beta) * inner(u, v) * ds(outer_bdy_id) P = assemble(p).M.handle else: P = A # }}} # Set up options to contain solver parameters: ksp = PETSc.KSP().create() if solver_parameters['pc_type'] == 'pyamg': del solver_parameters['pc_type'] # We are using the AMG preconditioner pyamg_tol = solver_parameters.get('pyamg_tol', None) if pyamg_tol is not None: pyamg_tol = float(pyamg_tol) pyamg_maxiter = solver_parameters.get('pyamg_maxiter', None) if pyamg_maxiter is not None: pyamg_maxiter = int(pyamg_maxiter) ksp.setOperators(B) ksp.setUp() pc = ksp.pc pc.setType(pc.Type.PYTHON) pc.setPythonContext( AMGTransmissionPreconditioner(wave_number, fspace, A, tol=pyamg_tol, maxiter=pyamg_maxiter, use_plane_waves=True)) # Otherwise use regular preconditioner else: ksp.setOperators(B, P) options_manager = OptionsManager(solver_parameters, options_prefix) options_manager.set_from_options(ksp) import petsc4py.PETSc petsc4py.PETSc.Sys.popErrorHandler() with rhs.dat.vec_ro as b: with solution.dat.vec as x: ksp.solve(b, x) # }}} return ksp, solution
def main(nelements): import logging logging.basicConfig(level=logging.INFO) def get_obj_array(obj_array): from pytools.obj_array import make_obj_array return make_obj_array([ary.get() for ary in obj_array]) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ( # noqa make_curve_mesh, starfish, ellipse, drop) mesh = make_curve_mesh(lambda t: starfish(t), np.linspace(0, 1, nelements + 1), target_order) coarse_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource target_association_tolerance = 0.05 qbx, _ = QBXLayerPotentialSource( coarse_density_discr, fine_order=ovsmp_target_order, qbx_order=qbx_order, fmm_order=fmm_order, target_association_tolerance=target_association_tolerance, ).with_refinement() density_discr = qbx.density_discr nodes = density_discr.nodes().with_queue(queue) # Get normal vectors for the density discretization -- used in integration with stresslet mv_normal = bind(density_discr, sym.normal(2))(queue) normal = mv_normal.as_vector(np.object) # {{{ describe bvp from sumpy.kernel import LaplaceKernel from pytential.symbolic.stokes import StressletWrapper from pytools.obj_array import make_obj_array dim = 2 cse = sym.cse nvec_sym = sym.make_sym_vector("normal", dim) sigma_sym = sym.make_sym_vector("sigma", dim) mu_sym = sym.var("mu") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = cse(sigma_sym / sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = -1 # Create stresslet object stresslet_obj = StressletWrapper(dim=2) # Describe boundary operator bdry_op_sym = loc_sign * 0.5 * sigma_sym + sqrt_w * stresslet_obj.apply( inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit='avg') # Bind to the qbx discretization bound_op = bind(qbx, bdry_op_sym) # }}} # {{{ fix rhs and solve def fund_soln(x, y, loc): #with direction (1,0) for point source r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2) scaling = 1. / (4 * np.pi * mu) xcomp = (-cl.clmath.log(r) + (x - loc[0])**2 / r**2) * scaling ycomp = ((x - loc[0]) * (y - loc[1]) / r**2) * scaling return [xcomp, ycomp] def couette_soln(x, y, dp, h): scaling = 1. / (2 * mu) xcomp = scaling * dp * ((y + (h / 2.))**2 - h * (y + (h / 2.))) ycomp = scaling * 0 * y return [xcomp, ycomp] if soln_type == 'fundamental': pt_loc = np.array([2.0, 0.0]) bc = fund_soln(nodes[0], nodes[1], pt_loc) else: dp = -10. h = 2.5 bc = couette_soln(nodes[0], nodes[1], dp, h) # Get rhs vector bvp_rhs = bind(qbx, sqrt_w * sym.make_sym_vector("bc", dim))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "sigma", np.float64, mu=mu, normal=normal), bvp_rhs, tol=1e-9, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution # Describe representation of solution for evaluation in domain representation_sym = stresslet_obj.apply(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2) from sumpy.visualization import FieldPlotter nsamp = 10 eval_points_1d = np.linspace(-1., 1., nsamp) eval_points = np.zeros((2, len(eval_points_1d)**2)) eval_points[0, :] = np.tile(eval_points_1d, len(eval_points_1d)) eval_points[1, :] = np.repeat(eval_points_1d, len(eval_points_1d)) gamma_sym = sym.var("gamma") inv_sqrt_w_gamma = cse(gamma_sym / sqrt_w) constant_laplace_rep = sym.D(LaplaceKernel(dim=2), inv_sqrt_w_gamma, qbx_forced_limit=None) sqrt_w_vec = bind(qbx, sqrt_w)(queue) def general_mask(test_points): const_density = bind((qbx, PointsTarget(test_points)), constant_laplace_rep)(queue, gamma=sqrt_w_vec).get() return (abs(const_density) > 0.1) def inside_domain(test_points): mask = general_mask(test_points) return np.array([row[mask] for row in test_points]) def stride_hack(arr): from numpy.lib.stride_tricks import as_strided return np.array(as_strided(arr, strides=(8 * len(arr[0]), 8))) eval_points = inside_domain(eval_points) eval_points_dev = cl.array.to_device(queue, eval_points) # Evaluate the solution at the evaluation points vel = bind((qbx, PointsTarget(eval_points_dev)), representation_sym)(queue, sigma=sigma, mu=mu, normal=normal) print("@@@@@@@@") vel = get_obj_array(vel) if soln_type == 'fundamental': exact_soln = fund_soln(eval_points_dev[0], eval_points_dev[1], pt_loc) else: exact_soln = couette_soln(eval_points_dev[0], eval_points_dev[1], dp, h) err = vel - get_obj_array(exact_soln) print("@@@@@@@@") print( "L2 error estimate: ", np.sqrt((2. / (nsamp - 1))**2 * np.sum(err[0] * err[0]) + (2. / (nsamp - 1))**2 * np.sum(err[1] * err[1]))) max_error_loc = [abs(err[0]).argmax(), abs(err[1]).argmax()] print("max error at sampled points: ", max(abs(err[0])), max(abs(err[1]))) print("exact velocity at max error points: x -> ", err[0][max_error_loc[0]], ", y -> ", err[1][max_error_loc[1]]) from pytential.symbolic.mappers import DerivativeTaker rep_pressure = stresslet_obj.apply_pressure(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2) pressure = bind((qbx, PointsTarget(eval_points_dev)), rep_pressure)(queue, sigma=sigma, mu=mu, normal=normal) pressure = pressure.get() print "pressure = ", pressure x_dir_vecs = np.zeros((2, len(eval_points[0]))) x_dir_vecs[0, :] = 1.0 y_dir_vecs = np.zeros((2, len(eval_points[0]))) y_dir_vecs[1, :] = 1.0 x_dir_vecs = cl.array.to_device(queue, x_dir_vecs) y_dir_vecs = cl.array.to_device(queue, y_dir_vecs) dir_vec_sym = sym.make_sym_vector("force_direction", dim) rep_stress = stresslet_obj.apply_stress(inv_sqrt_w_sigma, nvec_sym, dir_vec_sym, mu_sym, qbx_forced_limit=-2) applied_stress_x = bind((qbx, PointsTarget(eval_points_dev)), rep_stress)(queue, sigma=sigma, normal=normal, force_direction=x_dir_vecs, mu=mu) applied_stress_x = get_obj_array(applied_stress_x) applied_stress_y = bind((qbx, PointsTarget(eval_points_dev)), rep_stress)(queue, sigma=sigma, normal=normal, force_direction=y_dir_vecs, mu=mu) applied_stress_y = get_obj_array(applied_stress_y) print "stress applied to x direction: ", applied_stress_x print "stress applied to y direction: ", applied_stress_y import matplotlib.pyplot as plt plt.quiver(eval_points[0], eval_points[1], vel[0], vel[1], linewidth=0.1) file_name = "field-n%s.pdf" % (nelements) plt.savefig(file_name) return (max(abs(err[0])), max(abs(err[1])))
def main(): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) target_order = 16 qbx_order = 3 nelements = 60 mode_nr = 0 k = 0 if k: kernel = HelmholtzKernel(2) else: kernel = LaplaceKernel(2) #kernel = OneKernel() mesh = make_curve_mesh( #lambda t: ellipse(1, t), starfish, np.linspace(0, 1, nelements+1), target_order) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) slow_qbx, _ = QBXLayerPotentialSource( pre_density_discr, fine_order=2*target_order, qbx_order=qbx_order, fmm_order=False, target_association_tolerance=.05 ).with_refinement() qbx = slow_qbx.copy(fmm_order=10) density_discr = slow_qbx.density_discr nodes = density_discr.nodes().with_queue(queue) angle = cl.clmath.atan2(nodes[1], nodes[0]) from pytential import bind, sym #op = sym.d_dx(sym.S(kernel, sym.var("sigma")), qbx_forced_limit=None) #op = sym.D(kernel, sym.var("sigma"), qbx_forced_limit=None) op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None) sigma = cl.clmath.cos(mode_nr*angle) if isinstance(kernel, HelmholtzKernel): sigma = sigma.astype(np.complex128) fplot = FieldPlotter(np.zeros(2), extent=5, npoints=600) from pytential.target import PointsTarget fld_in_vol = bind( (slow_qbx, PointsTarget(fplot.points)), op)(queue, sigma=sigma, k=k).get() fmm_fld_in_vol = bind( (qbx, PointsTarget(fplot.points)), op)(queue, sigma=sigma, k=k).get() err = fmm_fld_in_vol-fld_in_vol import matplotlib matplotlib.use('Agg') im = fplot.show_scalar_in_matplotlib(np.log10(np.abs(err) + 1e-17)) from matplotlib.colors import Normalize im.set_norm(Normalize(vmin=-12, vmax=0)) import matplotlib.pyplot as pt from matplotlib.ticker import NullFormatter pt.gca().xaxis.set_major_formatter(NullFormatter()) pt.gca().yaxis.set_major_formatter(NullFormatter()) cb = pt.colorbar(shrink=0.9) cb.set_label(r"$\log_{10}(\mathdefault{Error})$") pt.savefig("fmm-error-order-%d.pdf" % qbx_order)
qbx_lpot_kwargs = {} if case.fmm_backend is None: qbx_lpot_kwargs["fmm_order"] = False else: if hasattr(case, "fmm_tol"): from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder qbx_lpot_kwargs["fmm_level_to_order"] = SimpleExpansionOrderFinder( case.fmm_tol) elif hasattr(case, "fmm_order"): qbx_lpot_kwargs["fmm_order"] = case.fmm_order else: qbx_lpot_kwargs["fmm_order"] = case.qbx_order + 5 qbx = QBXLayerPotentialSource( pre_density_discr, fine_order=source_order, qbx_order=case.qbx_order, _box_extent_norm=getattr(case, "box_extent_norm", None), _from_sep_smaller_crit=getattr(case, "from_sep_smaller_crit", None), _from_sep_smaller_min_nsources_cumul=30, fmm_backend=case.fmm_backend, **qbx_lpot_kwargs) if case.use_refinement: if case.k != 0 and getattr(case, "refine_on_helmholtz_k", True): refiner_extra_kwargs["kernel_length_scale"] = 5 / case.k if hasattr(case, "scaled_max_curvature_threshold"): refiner_extra_kwargs["_scaled_max_curvature_threshold"] = \ case.scaled_max_curvature_threshold
def main(): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import generate_torus rout = 10 rin = 1 if 1: base_mesh = generate_torus( rout, rin, 40, 4, mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes # nx = 1 # ny = 1 nz = 1 dz = 0 meshes = [ affine_map( base_mesh, A=np.diag([1, 1, 1]), b=np.array([0, 0, iz*dz])) for iz in range(nz)] mesh = merge_disjoint_meshes(meshes, single_group=True) if 0: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import ( QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx, _ = QBXLayerPotentialSource( pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order ).with_refinement() density_discr = qbx.density_discr # {{{ describe bvp from sumpy.kernel import LaplaceKernel kernel = LaplaceKernel(3) cse = sym.cse sigma_sym = sym.var("sigma") #sqrt_w = sym.sqrt_jac_q_weight(3) sqrt_w = 1 inv_sqrt_w_sigma = cse(sigma_sym/sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = (loc_sign*0.5*sigma_sym + sqrt_w*( sym.S(kernel, inv_sqrt_w_sigma) + sym.D(kernel, inv_sqrt_w_sigma) )) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve nodes = density_discr.nodes().with_queue(queue) source = np.array([rout, 0, 0]) def u_incoming_func(x): # return 1/cl.clmath.sqrt( (x[0] - source[0])**2 # +(x[1] - source[1])**2 # +(x[2] - source[2])**2 ) return 1.0/la.norm(x.get()-source[:, None], axis=0) bc = cl.array.to_device(queue, u_incoming_func(nodes)) bvp_rhs = bind(qbx, sqrt_w*sym.var("bc"))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "sigma", dtype=np.float64), bvp_rhs, tol=1e-14, progress=True, stall_iterations=0, hard_failure=True) sigma = bind(qbx, sym.var("sigma")/sqrt_w)(queue, sigma=gmres_result.solution) # }}} from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, 20) bdry_vis.write_vtk_file("laplace.vtu", [ ("sigma", sigma), ]) # {{{ postprocess/visualize repr_kwargs = dict(qbx_forced_limit=None) representation_sym = ( sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) + sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(3), extent=20, npoints=50) targets = cl.array.to_device(queue, fplot.points) qbx_stick_out = qbx.copy(target_stick_out_factor=0.2) try: fld_in_vol = bind( (qbx_stick_out, PointsTarget(targets)), representation_sym)(queue, sigma=sigma).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed", e.failed_target_flags.get(queue)) ] ) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential-laplace-3d.vts", [ ("potential", fld_in_vol), ] )
def run_int_eq_test(cl_ctx, queue, case, resolution, visualize): mesh = case.get_mesh(resolution, case.target_order) print("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(case.target_order)) source_order = 4*case.target_order refiner_extra_kwargs = {} qbx_lpot_kwargs = {} if case.fmm_backend is None: qbx_lpot_kwargs["fmm_order"] = False else: if hasattr(case, "fmm_tol"): from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder qbx_lpot_kwargs["fmm_level_to_order"] = SimpleExpansionOrderFinder( case.fmm_tol) elif hasattr(case, "fmm_order"): qbx_lpot_kwargs["fmm_order"] = case.fmm_order else: qbx_lpot_kwargs["fmm_order"] = case.qbx_order + 5 qbx = QBXLayerPotentialSource( pre_density_discr, fine_order=source_order, qbx_order=case.qbx_order, _box_extent_norm=getattr(case, "box_extent_norm", None), _from_sep_smaller_crit=getattr(case, "from_sep_smaller_crit", None), _from_sep_smaller_min_nsources_cumul=30, fmm_backend=case.fmm_backend, **qbx_lpot_kwargs) if case.use_refinement: if case.k != 0 and getattr(case, "refine_on_helmholtz_k", True): refiner_extra_kwargs["kernel_length_scale"] = 5/case.k if hasattr(case, "scaled_max_curvature_threshold"): refiner_extra_kwargs["_scaled_max_curvature_threshold"] = \ case.scaled_max_curvature_threshold if hasattr(case, "expansion_disturbance_tolerance"): refiner_extra_kwargs["_expansion_disturbance_tolerance"] = \ case.expansion_disturbance_tolerance if hasattr(case, "refinement_maxiter"): refiner_extra_kwargs["maxiter"] = case.refinement_maxiter #refiner_extra_kwargs["visualize"] = True print("%d elements before refinement" % pre_density_discr.mesh.nelements) qbx, _ = qbx.with_refinement(**refiner_extra_kwargs) print("%d stage-1 elements after refinement" % qbx.density_discr.mesh.nelements) print("%d stage-2 elements after refinement" % qbx.stage2_density_discr.mesh.nelements) print("quad stage-2 elements have %d nodes" % qbx.quad_stage2_density_discr.groups[0].nunit_nodes) density_discr = qbx.density_discr if hasattr(case, "visualize_geometry") and case.visualize_geometry: bdry_normals = bind( density_discr, sym.normal(mesh.ambient_dim) )(queue).as_vector(dtype=object) bdry_vis = make_visualizer(queue, density_discr, case.target_order) bdry_vis.write_vtk_file("geometry.vtu", [ ("normals", bdry_normals) ]) # {{{ plot geometry if 0: if mesh.ambient_dim == 2: # show geometry, centers, normals nodes_h = density_discr.nodes().get(queue=queue) pt.plot(nodes_h[0], nodes_h[1], "x-") normal = bind(density_discr, sym.normal(2))(queue).as_vector(np.object) pt.quiver(nodes_h[0], nodes_h[1], normal[0].get(queue), normal[1].get(queue)) pt.gca().set_aspect("equal") pt.show() elif mesh.ambient_dim == 3: bdry_vis = make_visualizer(queue, density_discr, case.target_order+3) bdry_normals = bind(density_discr, sym.normal(3))(queue)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("pre-solve-source-%s.vtu" % resolution, [ ("bdry_normals", bdry_normals), ]) else: raise ValueError("invalid mesh dim") # }}} # {{{ set up operator from pytential.symbolic.pde.scalar import ( DirichletOperator, NeumannOperator) from sumpy.kernel import LaplaceKernel, HelmholtzKernel if case.k: knl = HelmholtzKernel(mesh.ambient_dim) knl_kwargs = {"k": sym.var("k")} concrete_knl_kwargs = {"k": case.k} else: knl = LaplaceKernel(mesh.ambient_dim) knl_kwargs = {} concrete_knl_kwargs = {} if knl.is_complex_valued: dtype = np.complex128 else: dtype = np.float64 loc_sign = +1 if case.prob_side in [+1, "scat"] else -1 if case.bc_type == "dirichlet": op = DirichletOperator(knl, loc_sign, use_l2_weighting=True, kernel_arguments=knl_kwargs) elif case.bc_type == "neumann": op = NeumannOperator(knl, loc_sign, use_l2_weighting=True, use_improved_operator=False, kernel_arguments=knl_kwargs) else: assert False op_u = op.operator(sym.var("u")) # }}} # {{{ set up test data if case.prob_side == -1: test_src_geo_radius = case.outer_radius test_tgt_geo_radius = case.inner_radius elif case.prob_side == +1: test_src_geo_radius = case.inner_radius test_tgt_geo_radius = case.outer_radius elif case.prob_side == "scat": test_src_geo_radius = case.outer_radius test_tgt_geo_radius = case.outer_radius else: raise ValueError("unknown problem_side") point_sources = make_circular_point_group( mesh.ambient_dim, 10, test_src_geo_radius, func=lambda x: x**1.5) test_targets = make_circular_point_group( mesh.ambient_dim, 20, test_tgt_geo_radius) np.random.seed(22) source_charges = np.random.randn(point_sources.shape[1]) source_charges[-1] = -np.sum(source_charges[:-1]) source_charges = source_charges.astype(dtype) assert np.sum(source_charges) < 1e-15 source_charges_dev = cl.array.to_device(queue, source_charges) # }}} # {{{ establish BCs from pytential.source import PointPotentialSource from pytential.target import PointsTarget point_source = PointPotentialSource(cl_ctx, point_sources) pot_src = sym.IntG( # FIXME: qbx_forced_limit--really? knl, sym.var("charges"), qbx_forced_limit=None, **knl_kwargs) test_direct = bind((point_source, PointsTarget(test_targets)), pot_src)( queue, charges=source_charges_dev, **concrete_knl_kwargs) if case.bc_type == "dirichlet": bc = bind((point_source, density_discr), pot_src)( queue, charges=source_charges_dev, **concrete_knl_kwargs) elif case.bc_type == "neumann": bc = bind( (point_source, density_discr), sym.normal_derivative( qbx.ambient_dim, pot_src, where=sym.DEFAULT_TARGET) )(queue, charges=source_charges_dev, **concrete_knl_kwargs) # }}} # {{{ solve bound_op = bind(qbx, op_u) rhs = bind(density_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bc) try: from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "u", dtype, **concrete_knl_kwargs), rhs, tol=case.gmres_tol, progress=True, hard_failure=True, stall_iterations=50, no_progress_factor=1.05) except QBXTargetAssociationFailedException as e: bdry_vis = make_visualizer(queue, density_discr, case.target_order+3) bdry_vis.write_vtk_file("failed-targets-%s.vtu" % resolution, [ ("failed_targets", e.failed_target_flags), ]) raise print("gmres state:", gmres_result.state) weighted_u = gmres_result.solution # }}} # {{{ build matrix for spectrum check if 0: from sumpy.tools import build_matrix mat = build_matrix( bound_op.scipy_op( queue, arg_name="u", dtype=dtype, k=case.k)) w, v = la.eig(mat) if 0: pt.imshow(np.log10(1e-20+np.abs(mat))) pt.colorbar() pt.show() #assert abs(s[-1]) < 1e-13, "h #assert abs(s[-2]) > 1e-7 #from pudb import set_trace; set_trace() # }}} if case.prob_side != "scat": # {{{ error check points_target = PointsTarget(test_targets) bound_tgt_op = bind((qbx, points_target), op.representation(sym.var("u"))) test_via_bdry = bound_tgt_op(queue, u=weighted_u, k=case.k) err = test_via_bdry - test_direct err = err.get() test_direct = test_direct.get() test_via_bdry = test_via_bdry.get() # {{{ remove effect of net source charge if case.k == 0 and case.bc_type == "neumann" and loc_sign == -1: # remove constant offset in interior Laplace Neumann error tgt_ones = np.ones_like(test_direct) tgt_ones = tgt_ones/la.norm(tgt_ones) err = err - np.vdot(tgt_ones, err)*tgt_ones # }}} rel_err_2 = la.norm(err)/la.norm(test_direct) rel_err_inf = la.norm(err, np.inf)/la.norm(test_direct, np.inf) # }}} print("rel_err_2: %g rel_err_inf: %g" % (rel_err_2, rel_err_inf)) else: rel_err_2 = None rel_err_inf = None # {{{ test gradient if case.check_gradient and case.prob_side != "scat": bound_grad_op = bind((qbx, points_target), op.representation( sym.var("u"), map_potentials=lambda pot: sym.grad(mesh.ambient_dim, pot), qbx_forced_limit=None)) #print(bound_t_deriv_op.code) grad_from_src = bound_grad_op( queue, u=weighted_u, **concrete_knl_kwargs) grad_ref = (bind( (point_source, points_target), sym.grad(mesh.ambient_dim, pot_src) )(queue, charges=source_charges_dev, **concrete_knl_kwargs) ) grad_err = (grad_from_src - grad_ref) rel_grad_err_inf = ( la.norm(grad_err[0].get(), np.inf) / la.norm(grad_ref[0].get(), np.inf)) print("rel_grad_err_inf: %g" % rel_grad_err_inf) # }}} # {{{ test tangential derivative if case.check_tangential_deriv and case.prob_side != "scat": bound_t_deriv_op = bind(qbx, op.representation( sym.var("u"), map_potentials=lambda pot: sym.tangential_derivative(2, pot), qbx_forced_limit=loc_sign)) #print(bound_t_deriv_op.code) tang_deriv_from_src = bound_t_deriv_op( queue, u=weighted_u, **concrete_knl_kwargs).as_scalar().get() tang_deriv_ref = (bind( (point_source, density_discr), sym.tangential_derivative(2, pot_src) )(queue, charges=source_charges_dev, **concrete_knl_kwargs) .as_scalar().get()) if 0: pt.plot(tang_deriv_ref.real) pt.plot(tang_deriv_from_src.real) pt.show() td_err = (tang_deriv_from_src - tang_deriv_ref) rel_td_err_inf = la.norm(td_err, np.inf)/la.norm(tang_deriv_ref, np.inf) print("rel_td_err_inf: %g" % rel_td_err_inf) else: rel_td_err_inf = None # }}} # {{{ any-D file plotting if visualize: bdry_vis = make_visualizer(queue, density_discr, case.target_order+3) bdry_normals = bind(density_discr, sym.normal(qbx.ambient_dim))(queue)\ .as_vector(dtype=object) sym_sqrt_j = sym.sqrt_jac_q_weight(density_discr.ambient_dim) u = bind(density_discr, sym.var("u")/sym_sqrt_j)(queue, u=weighted_u) bdry_vis.write_vtk_file("source-%s.vtu" % resolution, [ ("u", u), ("bc", bc), #("bdry_normals", bdry_normals), ]) from sumpy.visualization import make_field_plotter_from_bbox # noqa from meshmode.mesh.processing import find_bounding_box vis_grid_spacing = (0.1, 0.1, 0.1)[:qbx.ambient_dim] if hasattr(case, "vis_grid_spacing"): vis_grid_spacing = case.vis_grid_spacing vis_extend_factor = 0.2 if hasattr(case, "vis_extend_factor"): vis_grid_spacing = case.vis_grid_spacing fplot = make_field_plotter_from_bbox( find_bounding_box(mesh), h=vis_grid_spacing, extend_factor=vis_extend_factor) qbx_tgt_tol = qbx.copy(target_association_tolerance=0.15) from pytential.target import PointsTarget try: solved_pot = bind( (qbx_tgt_tol, PointsTarget(fplot.points)), op.representation(sym.var("u")) )(queue, u=weighted_u, k=case.k) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed_targets", e.failed_target_flags.get(queue)) ]) raise from sumpy.kernel import LaplaceKernel ones_density = density_discr.zeros(queue) ones_density.fill(1) indicator = bind( (qbx_tgt_tol, PointsTarget(fplot.points)), -sym.D(LaplaceKernel(density_discr.ambient_dim), sym.var("sigma"), qbx_forced_limit=None))( queue, sigma=ones_density).get() solved_pot = solved_pot.get() true_pot = bind((point_source, PointsTarget(fplot.points)), pot_src)( queue, charges=source_charges_dev, **concrete_knl_kwargs).get() #fplot.show_scalar_in_mayavi(solved_pot.real, max_val=5) if case.prob_side == "scat": fplot.write_vtk_file( "potential-%s.vts" % resolution, [ ("pot_scattered", solved_pot), ("pot_incoming", -true_pot), ("indicator", indicator), ] ) else: fplot.write_vtk_file( "potential-%s.vts" % resolution, [ ("solved_pot", solved_pot), ("true_pot", true_pot), ("indicator", indicator), ] ) # }}} class Result(Record): pass return Result( h_max=qbx.h_max, rel_err_2=rel_err_2, rel_err_inf=rel_err_inf, rel_td_err_inf=rel_td_err_inf, gmres_result=gmres_result)
def test_perf_data_gathering(ctx_getter, n_arms=5): cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) # prevent cache 'splosion from sympy.core.cache import clear_cache clear_cache() target_order = 8 starfish_func = NArmedStarfish(n_arms, 0.8) mesh = make_curve_mesh( starfish_func, np.linspace(0, 1, n_arms * 30), target_order) sigma_sym = sym.var("sigma") # The kernel doesn't really matter here from sumpy.kernel import LaplaceKernel k_sym = LaplaceKernel(mesh.ambient_dim) sym_op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) pre_density_discr = Discretization( queue.context, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) results = [] def inspect_geo_data(insn, bound_expr, geo_data): from pytential.qbx.fmm import assemble_performance_data perf_data = assemble_performance_data(geo_data, uses_pde_expansions=True) results.append(perf_data) return False # no need to do the actual FMM from pytential.qbx import QBXLayerPotentialSource lpot_source = QBXLayerPotentialSource( pre_density_discr, 4*target_order, # qbx order and fmm order don't really matter 10, fmm_order=10, _expansions_in_tree_have_extent=True, _expansion_stick_out_factor=0.5, geometry_data_inspector=inspect_geo_data, target_association_tolerance=1e-10, ) lpot_source, _ = lpot_source.with_refinement() density_discr = lpot_source.density_discr if 0: from meshmode.discretization.visualization import draw_curve draw_curve(density_discr) import matplotlib.pyplot as plt plt.show() nodes = density_discr.nodes().with_queue(queue) sigma = cl.clmath.sin(10 * nodes[0]) bind(lpot_source, sym_op)(queue, sigma=sigma)
def main(): import logging logger = logging.getLogger(__name__) logging.basicConfig(level=logging.WARNING) # INFO for more progress info from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource(cad_file_name), 2, order=2, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h]) from meshmode.mesh.processing import perform_flips # Flip elements--gmsh generates inside-out geometry. mesh = perform_flips(mesh, np.ones(mesh.nelements)) from meshmode.mesh.processing import find_bounding_box bbox_min, bbox_max = find_bounding_box(mesh) bbox_center = 0.5*(bbox_min+bbox_max) bbox_size = max(bbox_max-bbox_min) / 2 logger.info("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx, _ = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order, fmm_order=qbx_order + 3, target_association_tolerance=0.15).with_refinement() nodes = density_discr.nodes().with_queue(queue) angle = cl.clmath.atan2(nodes[1], nodes[0]) from pytential import bind, sym #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None)) op = sym.D(kernel, sym.var("sigma"), qbx_forced_limit=None) #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None) sigma = cl.clmath.cos(mode_nr*angle) if 0: sigma = 0*angle from random import randrange for i in range(5): sigma[randrange(len(sigma))] = 1 if isinstance(kernel, HelmholtzKernel): sigma = sigma.astype(np.complex128) fplot = FieldPlotter(bbox_center, extent=3.5*bbox_size, npoints=150) from pytential.target import PointsTarget fld_in_vol = bind( (qbx, PointsTarget(fplot.points)), op)(queue, sigma=sigma, k=k).get() #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential-3d.vts", [ ("potential", fld_in_vol) ] ) bdry_normals = bind( density_discr, sym.normal(density_discr.ambient_dim))(queue).as_vector(dtype=object) from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, target_order) bdry_vis.write_vtk_file("source-3d.vtu", [ ("sigma", sigma), ("bdry_normals", bdry_normals), ])
def run_test(cl_ctx, queue): q_order = 5 qbx_order = q_order fmm_backend = "sumpy" mesh = get_ellipse_mesh(20, 40, mesh_order=5) a = 1 b = 1 / 40 if 0: from meshmode.mesh.visualization import draw_curve import matplotlib.pyplot as plt draw_curve(mesh) plt.axes().set_aspect('equal') plt.show() from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(q_order)) refiner_extra_kwargs = { # "_expansion_disturbance_tolerance": 0.05, "_scaled_max_curvature_threshold": 1, "maxiter": 10, } qbx, _ = QBXLayerPotentialSource( pre_density_discr, fine_order=4 * q_order, qbx_order=qbx_order, fmm_backend=fmm_backend, fmm_order=qbx_order + 5, ).with_refinement(**refiner_extra_kwargs) if 1: print("%d stage-1 elements after refinement" % qbx.density_discr.mesh.nelements) print("%d stage-2 elements after refinement" % qbx.stage2_density_discr.mesh.nelements) print("quad stage-2 elements have %d nodes" % qbx.quad_stage2_density_discr.groups[0].nunit_nodes) def reference_solu(rvec): # a harmonic function x, y = rvec return 2.1 * x * y + (x**2 - y**2) * 0.5 + x bvals = reference_solu(qbx.density_discr.nodes().with_queue(queue)) from pytential.symbolic.pde.scalar import DirichletOperator from sumpy.kernel import LaplaceKernel from pytential import sym, bind op = DirichletOperator(LaplaceKernel(2), -1) bound_op = bind(qbx.copy(target_association_tolerance=0.5), op.operator(sym.var('sigma'))) rhs = bind(qbx.density_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bvals) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "sigma", dtype=np.float64), rhs, tol=1e-12, progress=True, hard_failure=True, stall_iterations=50, no_progress_factor=1.05) from sumpy.visualization import FieldPlotter from pytential.target import PointsTarget pltsize = b * 1.5 fplot = FieldPlotter(np.array([-1 + pltsize * 0.5, 0]), extent=pltsize * 1.05, npoints=500) plt_targets = cl.array.to_device(queue, fplot.points) interior_pts = (fplot.points[0]**2 / a**2 + fplot.points[1]**2 / b**2) < 0.99 exact_vals = reference_solu(fplot.points) out_errs = [] for assotol in [0.05]: qbx_stick_out = qbx.copy(target_association_tolerance=0.05) vol_solution = bind((qbx_stick_out, PointsTarget(plt_targets)), op.representation(sym.var('sigma')))( queue, sigma=gmres_result.solution).get() interior_error_linf = ( np.linalg.norm(np.abs(vol_solution - exact_vals)[interior_pts], ord=np.inf) / np.linalg.norm(exact_vals[interior_pts], ord=np.inf)) interior_error_l2 = (np.linalg.norm( np.abs(vol_solution - exact_vals)[interior_pts], ord=2) / np.linalg.norm(exact_vals[interior_pts], ord=2)) print("\nassotol = %f" % assotol) print("L_inf Error = %e " % interior_error_linf) print("L_2 Error = %e " % interior_error_l2) out_errs.append( ("error-%f" % assotol, np.abs(vol_solution - exact_vals))) if 1: fplot.write_vtk_file("results.vts", out_errs)
from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder for resolution in case.resolutions: scat_mesh = case.get_mesh(resolution, case.target_order) observation_mesh = case.get_observation_mesh(case.target_order) pre_scat_discr = Discretization( cl_ctx, scat_mesh, InterpolatoryQuadratureSimplexGroupFactory(case.target_order)) qbx, _ = QBXLayerPotentialSource( pre_scat_discr, fine_order=4 * case.target_order, qbx_order=case.qbx_order, fmm_level_to_order=SimpleExpansionOrderFinder(case.fmm_tolerance), fmm_backend=case.fmm_backend).with_refinement( _expansion_disturbance_tolerance=0.05) h_max = bind(qbx, sym.h_max(qbx.ambient_dim))(queue) scat_discr = qbx.density_discr obs_discr = Discretization( cl_ctx, observation_mesh, InterpolatoryQuadratureSimplexGroupFactory(case.target_order)) inc_field_scat = EHField(eval_inc_field_at(scat_discr)) inc_field_obs = EHField(eval_inc_field_at(obs_discr))
def test_pec_mfie_extinction(ctx_getter, case, visualize=False): """For (say) is_interior=False (the 'exterior' MFIE), this test verifies extinction of the combined (incoming + scattered) field on the interior of the scatterer. """ logging.basicConfig(level=logging.INFO) cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) np.random.seed(12) knl_kwargs = {"k": case.k} # {{{ come up with a solution to Maxwell's equations j_sym = sym.make_sym_vector("j", 3) jt_sym = sym.make_sym_vector("jt", 2) rho_sym = sym.var("rho") from pytential.symbolic.pde.maxwell import ( PECChargeCurrentMFIEOperator, get_sym_maxwell_point_source, get_sym_maxwell_plane_wave) mfie = PECChargeCurrentMFIEOperator() test_source = case.get_source(queue) calc_patch = CalculusPatch(np.array([-3, 0, 0]), h=0.01) calc_patch_tgt = PointsTarget(cl.array.to_device(queue, calc_patch.points)) rng = cl.clrandom.PhiloxGenerator(cl_ctx, seed=12) src_j = rng.normal(queue, (3, test_source.nnodes), dtype=np.float64) def eval_inc_field_at(tgt): if 0: # plane wave return bind( tgt, get_sym_maxwell_plane_wave( amplitude_vec=np.array([1, 1, 1]), v=np.array([1, 0, 0]), omega=case.k) )(queue) else: # point source return bind( (test_source, tgt), get_sym_maxwell_point_source(mfie.kernel, j_sym, mfie.k) )(queue, j=src_j, k=case.k) pde_test_inc = EHField( vector_from_device(queue, eval_inc_field_at(calc_patch_tgt))) source_maxwell_resids = [ calc_patch.norm(x, np.inf) / calc_patch.norm(pde_test_inc.e, np.inf) for x in frequency_domain_maxwell( calc_patch, pde_test_inc.e, pde_test_inc.h, case.k)] print("Source Maxwell residuals:", source_maxwell_resids) assert max(source_maxwell_resids) < 1e-6 # }}} loc_sign = -1 if case.is_interior else +1 from pytools.convergence import EOCRecorder eoc_rec_repr_maxwell = EOCRecorder() eoc_pec_bc = EOCRecorder() eoc_rec_e = EOCRecorder() eoc_rec_h = EOCRecorder() from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder for resolution in case.resolutions: scat_mesh = case.get_mesh(resolution, case.target_order) observation_mesh = case.get_observation_mesh(case.target_order) pre_scat_discr = Discretization( cl_ctx, scat_mesh, InterpolatoryQuadratureSimplexGroupFactory(case.target_order)) qbx, _ = QBXLayerPotentialSource( pre_scat_discr, fine_order=4*case.target_order, qbx_order=case.qbx_order, fmm_level_to_order=SimpleExpansionOrderFinder( case.fmm_tolerance), fmm_backend=case.fmm_backend ).with_refinement(_expansion_disturbance_tolerance=0.05) h_max = qbx.h_max scat_discr = qbx.density_discr obs_discr = Discretization( cl_ctx, observation_mesh, InterpolatoryQuadratureSimplexGroupFactory(case.target_order)) inc_field_scat = EHField(eval_inc_field_at(scat_discr)) inc_field_obs = EHField(eval_inc_field_at(obs_discr)) # {{{ system solve inc_xyz_sym = EHField(sym.make_sym_vector("inc_fld", 6)) bound_j_op = bind(qbx, mfie.j_operator(loc_sign, jt_sym)) j_rhs = bind(qbx, mfie.j_rhs(inc_xyz_sym.h))( queue, inc_fld=inc_field_scat.field, **knl_kwargs) gmres_settings = dict( tol=case.gmres_tol, progress=True, hard_failure=True, stall_iterations=50, no_progress_factor=1.05) from pytential.solve import gmres gmres_result = gmres( bound_j_op.scipy_op(queue, "jt", np.complex128, **knl_kwargs), j_rhs, **gmres_settings) jt = gmres_result.solution bound_rho_op = bind(qbx, mfie.rho_operator(loc_sign, rho_sym)) rho_rhs = bind(qbx, mfie.rho_rhs(jt_sym, inc_xyz_sym.e))( queue, jt=jt, inc_fld=inc_field_scat.field, **knl_kwargs) gmres_result = gmres( bound_rho_op.scipy_op(queue, "rho", np.complex128, **knl_kwargs), rho_rhs, **gmres_settings) rho = gmres_result.solution # }}} jxyz = bind(qbx, sym.tangential_to_xyz(jt_sym))(queue, jt=jt) # {{{ volume eval sym_repr = mfie.scattered_volume_field(jt_sym, rho_sym) def eval_repr_at(tgt, source=None): if source is None: source = qbx return bind((source, tgt), sym_repr)(queue, jt=jt, rho=rho, **knl_kwargs) pde_test_repr = EHField( vector_from_device(queue, eval_repr_at(calc_patch_tgt))) maxwell_residuals = [ calc_patch.norm(x, np.inf) / calc_patch.norm(pde_test_repr.e, np.inf) for x in frequency_domain_maxwell( calc_patch, pde_test_repr.e, pde_test_repr.h, case.k)] print("Maxwell residuals:", maxwell_residuals) eoc_rec_repr_maxwell.add_data_point(h_max, max(maxwell_residuals)) # }}} # {{{ check PEC BC on total field bc_repr = EHField(mfie.scattered_volume_field( jt_sym, rho_sym, qbx_forced_limit=loc_sign)) pec_bc_e = sym.n_cross(bc_repr.e + inc_xyz_sym.e) pec_bc_h = sym.normal(3).as_vector().dot(bc_repr.h + inc_xyz_sym.h) eh_bc_values = bind(qbx, sym.join_fields(pec_bc_e, pec_bc_h))( queue, jt=jt, rho=rho, inc_fld=inc_field_scat.field, **knl_kwargs) def scat_norm(f): return norm(qbx, queue, f, p=np.inf) e_bc_residual = scat_norm(eh_bc_values[:3]) / scat_norm(inc_field_scat.e) h_bc_residual = scat_norm(eh_bc_values[3]) / scat_norm(inc_field_scat.h) print("E/H PEC BC residuals:", h_max, e_bc_residual, h_bc_residual) eoc_pec_bc.add_data_point(h_max, max(e_bc_residual, h_bc_residual)) # }}} # {{{ visualization if visualize: from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, scat_discr, case.target_order+3) bdry_normals = bind(scat_discr, sym.normal(3))(queue)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("source-%s.vtu" % resolution, [ ("j", jxyz), ("rho", rho), ("Einc", inc_field_scat.e), ("Hinc", inc_field_scat.h), ("bdry_normals", bdry_normals), ("e_bc_residual", eh_bc_values[:3]), ("h_bc_residual", eh_bc_values[3]), ]) fplot = make_field_plotter_from_bbox( find_bounding_box(scat_discr.mesh), h=(0.05, 0.05, 0.3), extend_factor=0.3) from pytential.qbx import QBXTargetAssociationFailedException qbx_tgt_tol = qbx.copy(target_association_tolerance=0.2) fplot_tgt = PointsTarget(cl.array.to_device(queue, fplot.points)) try: fplot_repr = eval_repr_at(fplot_tgt, source=qbx_tgt_tol) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed_targets", e.failed_target_flags.get(queue)) ]) raise fplot_repr = EHField(vector_from_device(queue, fplot_repr)) fplot_inc = EHField( vector_from_device(queue, eval_inc_field_at(fplot_tgt))) fplot.write_vtk_file( "potential-%s.vts" % resolution, [ ("E", fplot_repr.e), ("H", fplot_repr.h), ("Einc", fplot_inc.e), ("Hinc", fplot_inc.h), ] ) # }}} # {{{ error in E, H obs_repr = EHField(eval_repr_at(obs_discr)) def obs_norm(f): return norm(obs_discr, queue, f, p=np.inf) rel_err_e = (obs_norm(inc_field_obs.e + obs_repr.e) / obs_norm(inc_field_obs.e)) rel_err_h = (obs_norm(inc_field_obs.h + obs_repr.h) / obs_norm(inc_field_obs.h)) # }}} print("ERR", h_max, rel_err_h, rel_err_e) eoc_rec_h.add_data_point(h_max, rel_err_h) eoc_rec_e.add_data_point(h_max, rel_err_e) print("--------------------------------------------------------") print("is_interior=%s" % case.is_interior) print("--------------------------------------------------------") good = True for which_eoc, eoc_rec, order_tol in [ ("maxwell", eoc_rec_repr_maxwell, 1.5), ("PEC BC", eoc_pec_bc, 1.5), ("H", eoc_rec_h, 1.5), ("E", eoc_rec_e, 1.5)]: print(which_eoc) print(eoc_rec.pretty_print()) if len(eoc_rec.history) > 1: if eoc_rec.order_estimate() < case.qbx_order - order_tol: good = False assert good