("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]), ]) from pytential.qbx import QBXTargetAssociationFailedException try: fplot_repr = eval_repr_at(places, target="plot_targets", source="qbx_target_tol") except QBXTargetAssociationFailedException as e: fplot.write_vtk_file("failed-targets.vts", [ ("failed_targets", actx.to_numpy(actx.thaw(e.failed_target_flags))), ]) raise fplot_repr = EHField(vector_from_device(actx.queue, fplot_repr)) fplot_inc = EHField( vector_from_device( actx.queue, eval_inc_field_at(places, target="plot_targets"))) fplot.write_vtk_file("potential-%s.vts" % resolution, [ ("E", fplot_repr.e), ("H", fplot_repr.h), ("Einc", fplot_inc.e), ("Hinc", fplot_inc.h), ])
def exec_compute_potential_insn_fmm(self, actx: PyOpenCLArrayContext, insn, bound_expr, evaluate, fmm_driver): """ :arg fmm_driver: A function that accepts four arguments: *wrangler*, *strength*, *geo_data*, *kernel*, *kernel_arguments* :returns: a tuple ``(assignments, extra_outputs)``, where *assignments* is a list of tuples containing pairs ``(name, value)`` representing assignments to be performed in the evaluation context. *extra_outputs* is data that *fmm_driver* may return (such as timing data), passed through unmodified. """ target_name_and_side_to_number, target_discrs_and_qbx_sides = ( self.get_target_discrs_and_qbx_sides(insn, bound_expr)) geo_data = self.qbx_fmm_geometry_data(bound_expr.places, insn.source.geometry, target_discrs_and_qbx_sides) # FIXME Exert more positive control over geo_data attribute lifetimes using # geo_data.<method>.clear_cache(geo_data). # FIXME Synthesize "bad centers" around corners and edges that have # inadequate QBX coverage. # FIXME don't compute *all* output kernels on all targets--respect that # some target discretizations may only be asking for derivatives (e.g.) from pytential import bind, sym waa = bind( bound_expr.places, sym.weights_and_area_elements(self.ambient_dim, dofdesc=insn.source))(actx) densities = [evaluate(density) for density in insn.densities] strengths = [waa * density for density in densities] flat_strengths = tuple(flatten(strength) for strength in strengths) base_kernel = single_valued(knl.get_base_kernel() for knl in insn.source_kernels) output_and_expansion_dtype = (self.get_fmm_output_and_expansion_dtype( insn.source_kernels, flat_strengths[0])) kernel_extra_kwargs, source_extra_kwargs = ( self.get_fmm_expansion_wrangler_extra_kwargs( actx, insn.target_kernels + insn.source_kernels, geo_data.tree().user_source_ids, insn.kernel_arguments, evaluate)) wrangler = self.expansion_wrangler_code_container( target_kernels=insn.target_kernels, source_kernels=insn.source_kernels).get_wrangler( actx.queue, geo_data, output_and_expansion_dtype, self.qbx_order, self.fmm_level_to_order, source_extra_kwargs=source_extra_kwargs, kernel_extra_kwargs=kernel_extra_kwargs, _use_target_specific_qbx=self._use_target_specific_qbx) from pytential.qbx.geometry import target_state if (actx.thaw(geo_data.user_target_to_center()) == target_state.FAILED ).any().get(): raise RuntimeError("geometry has failed targets") # {{{ geometry data inspection hook if self.geometry_data_inspector is not None: perform_fmm = self.geometry_data_inspector(insn, bound_expr, geo_data) if not perform_fmm: return [(o.name, 0) for o in insn.outputs] # }}} # Execute global QBX. all_potentials_on_every_target, extra_outputs = (fmm_driver( wrangler, flat_strengths, geo_data, base_kernel, kernel_extra_kwargs)) results = [] for o in insn.outputs: target_side_number = target_name_and_side_to_number[ o.target_name, o.qbx_forced_limit] target_discr, _ = target_discrs_and_qbx_sides[target_side_number] target_slice = slice(*geo_data.target_info( ).target_discr_starts[target_side_number:target_side_number + 2]) result = \ all_potentials_on_every_target[o.target_kernel_index][target_slice] from meshmode.discretization import Discretization if isinstance(target_discr, Discretization): from meshmode.dof_array import unflatten result = unflatten(actx, target_discr, result) results.append((o.name, result)) return results, extra_outputs
def test_off_surface_eval_vs_direct(ctx_factory, do_plot=False): logging.basicConfig(level=logging.INFO) cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # prevent cache 'splosion from sympy.core.cache import clear_cache clear_cache() nelements = 300 target_order = 8 qbx_order = 3 mesh = make_curve_mesh(WobblyCircle.random(8, seed=30), 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)) direct_qbx = QBXLayerPotentialSource( pre_density_discr, 4*target_order, qbx_order, fmm_order=False, target_association_tolerance=0.05, ) fmm_qbx = QBXLayerPotentialSource( pre_density_discr, 4*target_order, qbx_order, fmm_order=qbx_order + 3, _expansions_in_tree_have_extent=True, target_association_tolerance=0.05, ) fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) from pytential.target import PointsTarget ptarget = PointsTarget(fplot.points) from sumpy.kernel import LaplaceKernel places = GeometryCollection({ "direct_qbx": direct_qbx, "fmm_qbx": fmm_qbx, "target": ptarget}) direct_density_discr = places.get_discretization("direct_qbx") fmm_density_discr = places.get_discretization("fmm_qbx") from pytential.qbx import QBXTargetAssociationFailedException op = sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=None) try: direct_sigma = direct_density_discr.zeros(actx) + 1 direct_fld_in_vol = bind(places, op, auto_where=("direct_qbx", "target"))( actx, sigma=direct_sigma) except QBXTargetAssociationFailedException as e: fplot.show_scalar_in_matplotlib( actx.to_numpy(actx.thaw(e.failed_target_flags))) import matplotlib.pyplot as pt pt.show() raise fmm_sigma = fmm_density_discr.zeros(actx) + 1 fmm_fld_in_vol = bind(places, op, auto_where=("fmm_qbx", "target"))( actx, sigma=fmm_sigma) err = actx.np.fabs(fmm_fld_in_vol - direct_fld_in_vol) linf_err = actx.to_numpy(err).max() print("l_inf error:", linf_err) if do_plot: #fplot.show_scalar_in_mayavi(0.1*.get(queue)) fplot.write_vtk_file("potential.vts", [ ("fmm_fld_in_vol", actx.to_numpy(fmm_fld_in_vol)), ("direct_fld_in_vol", actx.to_numpy(direct_fld_in_vol)) ]) assert linf_err < 1e-3