def get_bound_op(lpot_source): from sumpy.kernel import LaplaceKernel sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(lpot_source.ambient_dim) op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) return bind(lpot_source, op)
def _sumpy_kernel_init(param): name, dim, order = param.name, param.dim, param.order # TODO: add other kernels assert name == "m2l" from sumpy.expansion.multipole import ( LinearPDEConformingVolumeTaylorMultipoleExpansion, ) from sumpy.expansion.local import LinearPDEConformingVolumeTaylorLocalExpansion from sumpy.kernel import LaplaceKernel from sumpy import E2EFromCSR ctx = cl.create_some_context() np.random.seed(17) knl = LaplaceKernel(dim) local_expn_class = LinearPDEConformingVolumeTaylorLocalExpansion mpole_expn_class = LinearPDEConformingVolumeTaylorMultipoleExpansion m_expn = mpole_expn_class(knl, order=order) l_expn = local_expn_class(knl, order=order) m2l = E2EFromCSR(ctx, m_expn, l_expn, name="loopy_kernel") m2l.get_translation_loopy_insns() m2l.ctx = None m2l.device = None return m2l
def test_timing_data_gathering(ctx_factory): """Test that timing data gathering can execute succesfully.""" pytest.importorskip("pyfmmlib") cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) actx = PyOpenCLArrayContext(queue) lpot_source = get_lpot_source(actx, 2) places = GeometryCollection(lpot_source) dofdesc = places.auto_source.to_stage1() density_discr = places.get_discretization(dofdesc.geometry) sigma = get_density(actx, density_discr) sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(lpot_source.ambient_dim) sym_op_S = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) op_S = bind(places, sym_op_S) timing_data = {} op_S.eval(dict(sigma=sigma), timing_data=timing_data, array_context=actx) assert timing_data print(timing_data)
def get_slp_wall_times(lpot_source, fmm_order, qbx_order): queue = cl.CommandQueue(lpot_source.cl_context) lpot_source = lpot_source.copy( qbx_order=qbx_order, fmm_level_to_order=(False if fmm_order is False else lambda *args: fmm_order)) d = lpot_source.ambient_dim u_sym = sym.var("u") from sumpy.kernel import LaplaceKernel S = sym.S(LaplaceKernel(d), u_sym, qbx_forced_limit=-1) density_discr = lpot_source.density_discr u = cl.array.empty(queue, density_discr.nnodes, np.float64) u.fill(1) op = bind(lpot_source, S) # Warmup op(queue, u=u) times = [] from time import perf_counter as curr_time for _ in range(WALL_TIME_EXPERIMENT_TIMING_ROUNDS): t_start = curr_time() op(queue, u=u) t_end = curr_time() times.append(t_end - t_start) return times
def get_bound_op(places): from sumpy.kernel import LaplaceKernel op = sym.S(LaplaceKernel(places.ambient_dim), sym.var("sigma"), qbx_forced_limit=+1) return bind(places, op)
def test_line_taylor_coeff_growth(): # Regression test for LineTaylorLocalExpansion. # See https://gitlab.tiker.net/inducer/pytential/merge_requests/12 from sumpy.kernel import LaplaceKernel from sumpy.expansion.local import LineTaylorLocalExpansion from sumpy.symbolic import make_sym_vector, SympyToPymbolicMapper import numpy as np order = 10 expn = LineTaylorLocalExpansion(LaplaceKernel(2), order) avec = make_sym_vector("a", 2) bvec = make_sym_vector("b", 2) coeffs = expn.coefficients_from_source(avec, bvec, rscale=1) sym2pymbolic = SympyToPymbolicMapper() coeffs_pymbolic = [sym2pymbolic(c) for c in coeffs] from pymbolic.mapper.flop_counter import FlopCounter flop_counter = FlopCounter() counts = [flop_counter(c) for c in coeffs_pymbolic] indices = np.arange(1, order + 2) max_order = 2 assert np.polyfit(np.log(indices), np.log(counts), deg=1)[0] < max_order
def get_lpot_cost(queue, geometry_getter, kind): lpot_source = geometry_getter(queue) from pytential import sym, bind sigma_sym = sym.var("sigma") from sumpy.kernel import LaplaceKernel k_sym = LaplaceKernel(lpot_source.ambient_dim) op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) bound_op = bind(lpot_source, op) density_discr = lpot_source.density_discr nodes = density_discr.nodes().with_queue(queue) sigma = cl.clmath.sin(10 * nodes[0]) from pytools import one if kind == "actual": timing_data = {} result = bound_op.eval(queue, {"sigma": sigma}, timing_data=timing_data) assert not np.isnan(result.get(queue)).any() result = one(timing_data.values()) elif kind == "model": perf_results = bound_op.get_modeled_performance(queue, sigma=sigma) result = one(perf_results.values()) return result
def __init__(self, ambient_dim, *, dim: Optional[int] = None, precond: str = "left") -> None: from sumpy.kernel import LaplaceKernel super().__init__(LaplaceKernel(ambient_dim), dim=dim, precond=precond)
def __init__(self, kernel, loc_sign, alpha=None, use_improved_operator=True, laplace_kernel=0, use_l2_weighting=False, kernel_arguments=None): """ :arg loc_sign: +1 for exterior, -1 for interior :arg alpha: the coefficient for the combined-field representation Set to 0 for Laplace. :arg use_improved_operator: Whether to use the least singular operator available """ assert loc_sign in [-1, 1] from sumpy.kernel import Kernel, LaplaceKernel assert isinstance(kernel, Kernel) if kernel_arguments is None: kernel_arguments = {} self.kernel_arguments = kernel_arguments self.loc_sign = loc_sign self.laplace_kernel = LaplaceKernel(kernel.dim) L2WeightedPDEOperator.__init__(self, kernel, use_l2_weighting) if alpha is None: if isinstance(self.kernel, LaplaceKernel): alpha = 0 else: alpha = 1j self.alpha = alpha self.use_improved_operator = use_improved_operator
def test_cost_model(ctx_factory, dim, use_target_specific_qbx): """Test that cost model gathering can execute successfully.""" cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) lpot_source = get_lpot_source(actx, dim).copy( _use_target_specific_qbx=use_target_specific_qbx, cost_model=CostModel()) places = GeometryCollection(lpot_source) density_discr = places.get_discretization(places.auto_source.geometry) sigma = get_density(actx, density_discr) sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(lpot_source.ambient_dim) sym_op_S = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) op_S = bind(places, sym_op_S) cost_S = op_S.get_modeled_cost(actx, sigma=sigma) assert len(cost_S) == 1 sym_op_S_plus_D = ( sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) + sym.D(k_sym, sigma_sym, qbx_forced_limit="avg")) op_S_plus_D = bind(places, sym_op_S_plus_D) cost_S_plus_D = op_S_plus_D.get_modeled_cost(actx, sigma=sigma) assert len(cost_S_plus_D) == 2
def test_toy_p2e2p(src, ctr, tgt, expn_func, expected): src = src.reshape(3, -1) tgt = tgt.reshape(3, -1) rtol = 1e-2 if not 0 <= expected < 1 / (1 + rtol): raise ValueError() from sumpy.kernel import LaplaceKernel ctx = l3d.InterpretedToyContext(LaplaceKernel(3), l3d.L3DMultipoleExpansion, l3d.L3DLocalExpansion) src_pot = t.PointSources(ctx, src, weights=[1]) pot_actual = src_pot.eval(tgt) errors = [] for order in ORDERS: expn = expn_func(src_pot, ctr, order=order) pot_p2e2p = expn.eval(tgt) errors.append(np.abs(pot_actual - pot_p2e2p)) conv_factor = compute_approx_convergence_factor(ORDERS, errors) assert conv_factor < expected * (1 + rtol)
def apply_pressure(self, density_vec_sym, dir_vec_sym, mu_sym, qbx_forced_limit): """ Symbolic expression for pressure field associated with the stresslet""" import itertools from pytential.symbolic.mappers import DerivativeTaker kernel = LaplaceKernel(dim=self.dim) factor = (2. * mu_sym) for i, j in itertools.product(range(self.dim), range(self.dim)): if i + j < 1: sym_expr = factor * DerivativeTaker(i).map_int_g( DerivativeTaker(j).map_int_g( sym.S(kernel, density_vec_sym[i] * dir_vec_sym[j], qbx_forced_limit=qbx_forced_limit))) else: sym_expr = sym_expr + ( factor * DerivativeTaker(i).map_int_g( DerivativeTaker(j).map_int_g( sym.S(kernel, density_vec_sym[i] * dir_vec_sym[j], qbx_forced_limit=qbx_forced_limit)))) return sym_expr
def test_unregularized_off_surface_fmm_vs_direct(ctx_factory): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) nelements = 300 target_order = 8 fmm_order = 4 # {{{ geometry mesh = make_curve_mesh(WobblyCircle.random(8, seed=30), np.linspace(0, 1, nelements+1), target_order) from pytential.unregularized import UnregularizedLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) direct = UnregularizedLayerPotentialSource( density_discr, fmm_order=False, ) fmm = direct.copy( fmm_level_to_order=lambda kernel, kernel_args, tree, level: fmm_order) sigma = density_discr.zeros(actx) + 1 fplot = FieldPlotter(np.zeros(2), extent=5, npoints=100) from pytential.target import PointsTarget ptarget = PointsTarget(fplot.points) from pytential import GeometryCollection places = GeometryCollection({ "unregularized_direct": direct, "unregularized_fmm": fmm, "targets": ptarget}) # }}} # {{{ check from sumpy.kernel import LaplaceKernel op = sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=None) direct_fld_in_vol = bind(places, op, auto_where=("unregularized_direct", "targets"))( actx, sigma=sigma) fmm_fld_in_vol = bind(places, op, auto_where=("unregularized_fmm", "targets"))(actx, sigma=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) assert linf_err < 5e-3
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 test_expr_pickling(): import pickle from sumpy.kernel import LaplaceKernel, AxisTargetDerivative ops_for_testing = [ sym.d_dx( 2, sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=-2)), sym.D(AxisTargetDerivative(0, LaplaceKernel(2)), sym.var("sigma"), qbx_forced_limit=-2) ] for op in ops_for_testing: pickled_op = pickle.dumps(op) after_pickle_op = pickle.loads(pickled_op) assert op == after_pickle_op
def test_layer_potential_construction(lpot_class, ambient_dim=2): from sumpy.kernel import LaplaceKernel kernel_sym = LaplaceKernel(ambient_dim) density_sym = sym.var("sigma") lpot_sym = lpot_class(kernel_sym, density_sym, qbx_forced_limit=None) assert lpot_sym is not None
def inner_fmm_level_to_nterms(tree, level): if helmholtz_k == 0: return fmm_level_to_order(LaplaceKernel(tree.dimensions), frozenset(), tree, level) else: return fmm_level_to_order(HelmholtzKernel(tree.dimensions), frozenset([("k", helmholtz_k)]), tree, level)
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_direct(ctx_factory): # This evaluates a single layer potential on a circle. logging.basicConfig(level=logging.INFO) ctx = ctx_factory() queue = cl.CommandQueue(ctx) from sumpy.kernel import LaplaceKernel lknl = LaplaceKernel(2) order = 12 from sumpy.qbx import LayerPotential from sumpy.expansion.local import LineTaylorLocalExpansion lpot = LayerPotential(ctx, [LineTaylorLocalExpansion(lknl, order)]) mode_nr = 25 from pytools.convergence import EOCRecorder eocrec = EOCRecorder() for n in [200, 300, 400]: t = np.linspace(0, 2 * np.pi, n, endpoint=False) unit_circle = np.exp(1j * t) unit_circle = np.array([unit_circle.real, unit_circle.imag]) sigma = np.cos(mode_nr * t) eigval = 1 / (2 * mode_nr) result_ref = eigval * sigma h = 2 * np.pi / n targets = unit_circle sources = unit_circle radius = 7 * h centers = unit_circle * (1 - radius) expansion_radii = np.ones(n) * radius strengths = (sigma * h, ) evt, (result_qbx, ) = lpot(queue, targets, sources, centers, strengths, expansion_radii=expansion_radii) eocrec.add_data_point(h, np.max(np.abs(result_ref - result_qbx))) print(eocrec) slack = 1.5 assert eocrec.order_estimate() > order - slack
def operator(self, sigma: sym.var, mean_curvature: Optional[sym.var] = None, **kwargs) -> sym.var: """ :arg mean_curvature: an expression for the mean curvature that can be used in the construction of the operator. :returns: a Fredholm integral equation of the second kind for the Beltrami PDE with the unknown density *sigma*. """ from sumpy.kernel import LaplaceKernel if isinstance(self.kernel, LaplaceKernel): raise TypeError( f"{type(self).__name__} does not support the Laplace " "kernel, use LaplaceBeltramiOperator instead") if mean_curvature is None: mean_curvature = sym.mean_curvature(self.ambient_dim, dim=self.dim) kappa = self.dim * mean_curvature context = self.kernel_arguments.copy() context.update(kwargs) knl = self.kernel lknl = LaplaceKernel(knl.dim) # {{{ layer potentials # laplace S0 = partial(sym.S, lknl, qbx_forced_limit=+1, **kwargs) # noqa: N806 D0 = partial(sym.D, lknl, qbx_forced_limit="avg", **kwargs) # noqa: N806 Sp0 = partial(sym.Sp, lknl, qbx_forced_limit="avg", **kwargs) # noqa: N806 Dp0 = partial(sym.Dp, lknl, qbx_forced_limit="avg", **kwargs) # noqa: N806 # base S = partial(sym.S, knl, qbx_forced_limit=+1, **context) # noqa: N806 Sp = partial(sym.Sp, knl, qbx_forced_limit="avg", **context) # noqa: N806 Spp = partial(sym.Spp, knl, qbx_forced_limit="avg", **context) # noqa: N806 # }}} if self.precond == "left": # similar to 6.2 in [ONeil2017] op = (sigma / 4 - D0(D0(sigma)) + S(kappa * Sp(sigma)) + S(Spp(sigma) + Dp0(sigma)) - S(Dp0(sigma)) + S0(Dp0(sigma))) else: # similar to 6.2 in [ONeil2017] op = (sigma / 4 - Sp0(Sp0(sigma)) + (Spp(S(sigma)) + Dp0(S(sigma))) - Dp0(S(sigma) - S0(sigma)) + kappa * Sp(S(sigma))) return op
def test_cost_model_order_varying_by_level(ctx_factory): """For FMM order varying by level, this checks to ensure that the costs are different. The varying-level case should have larger cost. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ constant level to order def level_to_order_constant(kernel, kernel_args, tree, level): return 1 lpot_source = get_lpot_source(actx, 2).copy( cost_model=QBXCostModel(), fmm_level_to_order=level_to_order_constant) places = GeometryCollection(lpot_source) density_discr = places.get_discretization(places.auto_source.geometry) sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(2) sym_op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) sigma = get_density(actx, density_discr) cost_constant, metadata = bind(places, sym_op).cost_per_stage( "constant_one", sigma=sigma) cost_constant = one(cost_constant.values()) metadata = one(metadata.values()) # }}} # {{{ varying level to order def level_to_order_varying(kernel, kernel_args, tree, level): return metadata["nlevels"] - level lpot_source = get_lpot_source(actx, 2).copy( cost_model=QBXCostModel(), fmm_level_to_order=level_to_order_varying) places = GeometryCollection(lpot_source) density_discr = places.get_discretization(places.auto_source.geometry) sigma = get_density(actx, density_discr) cost_varying, _ = bind(lpot_source, sym_op).cost_per_stage( "constant_one", sigma=sigma) cost_varying = one(cost_varying.values()) # }}} assert sum(cost_varying.values()) > sum(cost_constant.values())
def test_sumpy_fmm_timing_data_collection(ctx_factory): logging.basicConfig(level=logging.INFO) ctx = ctx_factory() queue = cl.CommandQueue( ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) nsources = 500 dtype = np.float64 from boxtree.tools import ( make_normal_particle_array as p_normal) knl = LaplaceKernel(2) local_expn_class = VolumeTaylorLocalExpansion mpole_expn_class = VolumeTaylorMultipoleExpansion order = 1 sources = p_normal(queue, nsources, knl.dim, dtype, seed=15) from boxtree import TreeBuilder tb = TreeBuilder(ctx) tree, _ = tb(queue, sources, max_particles_in_box=30, debug=True) from boxtree.traversal import FMMTraversalBuilder tbuild = FMMTraversalBuilder(ctx) trav, _ = tbuild(queue, tree, debug=True) from pyopencl.clrandom import PhiloxGenerator rng = PhiloxGenerator(ctx) weights = rng.uniform(queue, nsources, dtype=np.float64) out_kernels = [knl] from functools import partial from sumpy.fmm import SumpyExpansionWranglerCodeContainer wcc = SumpyExpansionWranglerCodeContainer( ctx, partial(mpole_expn_class, knl), partial(local_expn_class, knl), out_kernels) wrangler = wcc.get_wrangler(queue, tree, dtype, fmm_level_to_order=lambda kernel, kernel_args, tree, lev: order) from boxtree.fmm import drive_fmm timing_data = {} pot, = drive_fmm(trav, wrangler, (weights,), timing_data=timing_data) print(timing_data) assert timing_data
def test_p2e2e2p(src, ctr, ctr2, tgt, from_expn_class, to_expn_class, expected): errors = [] rtol = 1e-2 if not 0 <= expected < 1 / (1 + rtol): raise ValueError() pot_actual = SCALING / la.norm(tgt - src) for order in ORDERS: expn = from_expn_class(LaplaceKernel(3), order) coeffs = expn.coefficients_from_source(ctr - src) expn2 = to_expn_class(LaplaceKernel(3), order) coeffs2 = expn2.translate_from(expn, coeffs, ctr2 - ctr) pot_p2e2e2p = expn2.evaluate(coeffs2, tgt - ctr2) errors.append(np.abs(pot_actual - pot_p2e2e2p)) conv_factor = compute_approx_convergence_factor(ORDERS, errors) assert conv_factor < expected * (1 + rtol)
def m2l_experiment(param): from sumpy.kernel import LaplaceKernel ctx = l3d.InterpretedToyContext(LaplaceKernel(3), l3d.L3DMultipoleExpansion, l3d.L3DLocalExpansion) assert param.r / param.rho < 1 mpole_center_dist = param.R + param.rho sources = param.r * SPHERE_SAMPLE sources[:, 2] += mpole_center_dist origin = np.zeros(3) mpole_center = np.array([0., 0., mpole_center_dist]) local_centers = BALL_SAMPLE * param.R error = 0 fmm_order = param.p qbx_order = param.q for src in sources: src = src.reshape(3, -1) src_pot = t.PointSources(ctx, src, weights=[1]) mpole_pot = t.multipole_expand(src_pot, mpole_center, order=fmm_order) local_pot = t.local_expand(mpole_pot, origin, order=fmm_order) for local_center in local_centers: targets = ((param.R - la.norm(local_center)) * SPHERE_SAMPLE + local_center) assert (la.norm(targets, axis=1) <= param.R * (1 + 1e-5)).all() if qbx_order == np.inf: actual = src_pot.eval(targets.T) - local_pot.eval(targets.T) else: qbx_src_pot = t.local_expand(src_pot, local_center, order=qbx_order) qbx_local_pot = t.local_expand(local_pot, local_center, order=qbx_order) diff = qbx_src_pot.with_coeffs(qbx_src_pot.coeffs - qbx_local_pot.coeffs) actual = diff.eval(targets.T) error = max(error, np.max(np.abs(actual))) return Result(param.R, param.r, param.rho, param.ratio, param.p, param.q, error)
def test_cost_model_order_varying_by_level(ctx_factory): """For FMM order varying by level, this checks to ensure that the costs are different. The varying-level case should have larger cost. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ constant level to order def level_to_order_constant(kernel, kernel_args, tree, level): return 1 lpot_source = get_lpot_source(actx, 2).copy( cost_model=CostModel( calibration_params=CONSTANT_ONE_PARAMS), fmm_level_to_order=level_to_order_constant) places = GeometryCollection(lpot_source) density_discr = places.get_discretization(places.auto_source.geometry) sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(2) sym_op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) sigma = get_density(actx, density_discr) cost_constant = one( bind(places, sym_op) .get_modeled_cost(actx, sigma=sigma).values()) # }}} # {{{ varying level to order varying_order_params = cost_constant.params.copy() nlevels = cost_constant.params["nlevels"] for level in range(nlevels): varying_order_params["p_fmm_lev%d" % level] = nlevels - level cost_varying = cost_constant.with_params(varying_order_params) # }}} assert ( sum(cost_varying.get_predicted_times().values()) > sum(cost_constant.get_predicted_times().values()))
def test_p2p(ctx_factory, exclude_self): ctx = ctx_factory() queue = cl.CommandQueue(ctx) dimensions = 3 n = 5000 from sumpy.p2p import P2P lknl = LaplaceKernel(dimensions) knl = P2P(ctx, [lknl, AxisTargetDerivative(0, lknl)], exclude_self=exclude_self) targets = np.random.rand(dimensions, n) sources = targets if exclude_self else np.random.rand(dimensions, n) strengths = np.ones(n, dtype=np.float64) extra_kwargs = {} if exclude_self: extra_kwargs["target_to_source"] = np.arange(n, dtype=np.int32) evt, (potential, x_derivative) = knl(queue, targets, sources, [strengths], out_host=True, **extra_kwargs) potential_ref = np.empty_like(potential) targets = targets.T sources = sources.T for itarg in range(n): with np.errstate(divide="ignore"): invdists = np.sum((targets[itarg] - sources)**2, axis=-1)**-0.5 if exclude_self: assert np.isinf(invdists[itarg]) invdists[itarg] = 0 potential_ref[itarg] = np.sum(strengths * invdists) potential_ref *= 1 / (4 * np.pi) rel_err = la.norm(potential - potential_ref) / la.norm(potential_ref) print(rel_err) assert rel_err < 1e-3
def get_qbx_center_neighborhood_sizes_direct(lpot_source, radius): queue = cl.CommandQueue(lpot_source.cl_context) def inspect_geo_data(insn, bound_expr, geo_data): nonlocal sizes, nsources, ncenters tree = geo_data.tree().with_queue(queue) centers = np.array([axis.get(queue) for axis in geo_data.centers()]) search_radii = radius * geo_data.expansion_radii().get(queue) sources = np.array([axis.get(queue) for axis in tree.sources]) ncenters = len(search_radii) nsources = tree.nsources assert nsources == lpot_source.quad_stage2_density_discr.nnodes center_to_source_dists = ( la.norm( (centers[:, np.newaxis, :] - sources[:, :, np.newaxis]).T, ord=np.inf, axis=-1)) sizes = np.count_nonzero( center_to_source_dists <= search_radii[:, np.newaxis], axis=1) return False # no need to do the actual FMM sizes = None nsources = None ncenters = None lpot_source = lpot_source.copy(geometry_data_inspector=inspect_geo_data) density_discr = lpot_source.density_discr nodes = density_discr.nodes().with_queue(queue) sigma = cl.clmath.sin(10 * nodes[0]) # The kernel doesn't really matter here from sumpy.kernel import LaplaceKernel sigma_sym = sym.var('sigma') k_sym = LaplaceKernel(lpot_source.ambient_dim) sym_op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) bound_op = bind(lpot_source, sym_op) bound_op(queue, sigma=sigma) return (sizes, nsources, ncenters)
def _build_op(lpot_id, k=0, ndim=2, source=sym.DEFAULT_SOURCE, target=sym.DEFAULT_TARGET, qbx_forced_limit="avg"): from sumpy.kernel import LaplaceKernel, HelmholtzKernel if k: knl = HelmholtzKernel(ndim) knl_kwargs = {"k": k} else: knl = LaplaceKernel(ndim) knl_kwargs = {} lpot_kwargs = { "qbx_forced_limit": qbx_forced_limit, "source": source, "target": target} lpot_kwargs.update(knl_kwargs) if lpot_id == 1: # scalar single-layer potential u_sym = sym.var("u") op = sym.S(knl, u_sym, **lpot_kwargs) elif lpot_id == 2: # scalar combination of layer potentials u_sym = sym.var("u") op = sym.S(knl, 0.3 * u_sym, **lpot_kwargs) \ + sym.D(knl, 0.5 * u_sym, **lpot_kwargs) elif lpot_id == 3: # vector potential u_sym = sym.make_sym_vector("u", 2) u0_sym, u1_sym = u_sym op = make_obj_array([ sym.Sp(knl, u0_sym, **lpot_kwargs) + sym.D(knl, u1_sym, **lpot_kwargs), sym.S(knl, 0.4 * u0_sym, **lpot_kwargs) + 0.3 * sym.D(knl, u0_sym, **lpot_kwargs) ]) else: raise ValueError("Unknown lpot_id: {}".format(lpot_id)) op = 0.5 * u_sym + op return op, u_sym, knl_kwargs
def get_lpot_cost(which, helmholtz_k, geometry_getter, lpot_kwargs, kind): """ Parameters: which: "D" or "S" kind: "actual" or "model" """ context = cl.create_some_context(interactive=False) queue = cl.CommandQueue(context) lpot_source = geometry_getter(queue, lpot_kwargs) from sumpy.kernel import LaplaceKernel, HelmholtzKernel sigma_sym = sym.var("sigma") if helmholtz_k == 0: k_sym = LaplaceKernel(lpot_source.ambient_dim) kernel_kwargs = {} else: k_sym = HelmholtzKernel(lpot_source.ambient_dim, "k") kernel_kwargs = {"k": helmholtz_k} if which == "S": op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1, **kernel_kwargs) elif which == "D": op = sym.D(k_sym, sigma_sym, qbx_forced_limit="avg", **kernel_kwargs) else: raise ValueError("unknown lpot symbol: '%s'" % which) bound_op = bind(lpot_source, op) density_discr = lpot_source.density_discr nodes = density_discr.nodes().with_queue(queue) sigma = cl.clmath.sin(10 * nodes[0]) if kind == "actual": timing_data = {} result = bound_op.eval(queue, {"sigma": sigma}, timing_data=timing_data) assert not np.isnan(result.get(queue)).any() result = one(timing_data.values()) elif kind == "model": perf_results = bound_op.get_modeled_performance(queue, sigma=sigma) result = one(perf_results.values()) return result