示例#1
0
    def get_operator(self, ambient_dim, qbx_forced_limit="avg"):
        knl = self.knl_class(ambient_dim)
        kwargs = self.knl_sym_kwargs.copy()
        kwargs["qbx_forced_limit"] = qbx_forced_limit

        if self.op_type == "scalar":
            sym_u = sym.var("u")
            sym_op = sym.S(knl, sym_u, **kwargs)
        elif self.op_type == "scalar_mixed":
            sym_u = sym.var("u")
            sym_op = sym.S(knl, 0.3 * sym_u, **kwargs) \
                    + sym.D(knl, 0.5 * sym_u, **kwargs)
        elif self.op_type == "vector":
            sym_u = sym.make_sym_vector("u", ambient_dim)

            sym_op = make_obj_array([
                sym.Sp(knl, sym_u[0], **kwargs) +
                sym.D(knl, sym_u[1], **kwargs),
                sym.S(knl, 0.4 * sym_u[0], **kwargs) +
                0.3 * sym.D(knl, sym_u[0], **kwargs)
            ])
        else:
            raise ValueError(f"unknown operator type: '{self.op_type}'")

        sym_op = 0.5 * sym_u + sym_op
        return sym_u, sym_op
示例#2
0
    def S_G(self, i, density, qbx_forced_limit, op_map=None):  # noqa: N802
        if op_map is None:
            op_map = lambda x: x  # noqa: E731

        from sumpy.kernel import HelmholtzKernel
        hhk = HelmholtzKernel(2, allow_evanescent=True)
        hhk_scaling = 1j / 4

        if i == 0:
            lam1, lam2 = self.lambdas
            return (
                # FIXME: Verify scaling
                -1 / (2 * np.pi * (lam1**2 - lam2**2)) / hhk_scaling * (op_map(
                    sym.S(hhk,
                          density,
                          k=1j * lam1,
                          qbx_forced_limit=qbx_forced_limit)) - op_map(
                              sym.S(hhk,
                                    density,
                                    k=1j * lam2,
                                    qbx_forced_limit=qbx_forced_limit))))
        else:
            return (
                # FIXME: Verify scaling
                -1 / (2 * np.pi) / hhk_scaling * op_map(
                    sym.S(hhk,
                          density,
                          k=1j * self.lambdas[i - 1],
                          qbx_forced_limit=qbx_forced_limit)))
示例#3
0
    def representation(self, u,
            map_potentials=None, qbx_forced_limit=None, **kwargs):
        """
        :param u: symbolic variable for the density.
        :param map_potentials: a callable that can be used to apply
            additional transformations on all the layer potentials in the
            representation, e.g. to take a target derivative.
        """
        sqrt_w = self.get_sqrt_weight()
        inv_sqrt_w_u = sym.cse(u/sqrt_w)
        laplace_s_inv_sqrt_w_u = sym.cse(sym.S(self.laplace_kernel, inv_sqrt_w_u))

        if map_potentials is None:
            def map_potentials(x):  # pylint:disable=function-redefined
                return x

        kwargs["qbx_forced_limit"] = qbx_forced_limit
        kwargs["kernel_arguments"] = self.kernel_arguments

        return (
                map_potentials(
                    sym.S(self.kernel, inv_sqrt_w_u, **kwargs)
                    )
                - self.alpha * map_potentials(
                    sym.D(self.kernel, laplace_s_inv_sqrt_w_u, **kwargs)
                    )
                )
示例#4
0
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
示例#5
0
    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
示例#6
0
    def representation(self,
                       sigma,
                       map_potentials=None,
                       qbx_forced_limit=None):

        if map_potentials is None:

            def map_potentials(x):  # pylint:disable=function-redefined
                return x

        def dv(knl):
            return DirectionalSourceDerivative(knl, "normal_dir")

        def dt(knl):
            return DirectionalSourceDerivative(knl, "tangent_dir")

        normal_dir = sym.normal(2).as_vector()
        tangent_dir = np.array([-normal_dir[1], normal_dir[0]])

        k1 = map_potentials(sym.S(dv(dv(dv(self.knl))), sigma[0],
                    kernel_arguments={"normal_dir": normal_dir},
                    qbx_forced_limit=qbx_forced_limit)) + \
             3*map_potentials(sym.S(dv(dt(dt(self.knl))), sigma[0],
                    kernel_arguments={"normal_dir": normal_dir,
                                      "tangent_dir": tangent_dir},
                    qbx_forced_limit=qbx_forced_limit))

        k2 = -map_potentials(sym.S(dv(dv(self.knl)), sigma[1],
                    kernel_arguments={"normal_dir": normal_dir},
                    qbx_forced_limit=qbx_forced_limit)) + \
             map_potentials(sym.S(dt(dt(self.knl)), sigma[1],
                    kernel_arguments={"tangent_dir": tangent_dir},
                    qbx_forced_limit=qbx_forced_limit))

        return k1 + k2
示例#7
0
    def representation(self, sigma,
            map_potentials=None, qbx_forced_limit=None, **kwargs):
        """
        :param sigma: symbolic variable for the density.
        :param map_potentials: a callable that can be used to apply
            additional transformations on all the layer potentials in the
            representation, e.g. to take a target derivative.
        :param kwargs: additional keyword arguments passed on to the layer
            potential constructor.
        """

        if map_potentials is None:
            def map_potentials(x):  # pylint:disable=function-redefined
                return x

        def dv(knl):
            return DirectionalSourceDerivative(knl, "normal_dir")

        def dt(knl):
            return DirectionalSourceDerivative(knl, "tangent_dir")

        normal_dir = sym.normal(self.dim).as_vector()
        tangent_dir = np.array([-normal_dir[1], normal_dir[0]])
        kwargs["qbx_forced_limit"] = qbx_forced_limit

        k1 = (
                map_potentials(
                    sym.S(dv(dv(dv(self.kernel))), sigma[0],
                        kernel_arguments={"normal_dir": normal_dir},
                        **kwargs)
                    )
                + 3 * map_potentials(
                    sym.S(dv(dt(dt(self.kernel))), sigma[0],
                        kernel_arguments={
                            "normal_dir": normal_dir, "tangent_dir": tangent_dir
                            },
                        **kwargs)
                    )
                )

        k2 = (
                -map_potentials(
                    sym.S(dv(dv(self.kernel)), sigma[1],
                        kernel_arguments={"normal_dir": normal_dir},
                        **kwargs)
                    )
                + map_potentials(
                    sym.S(dt(dt(self.kernel)), sigma[1],
                        kernel_arguments={"tangent_dir": tangent_dir},
                        **kwargs)
                    )
                )

        return k1 + k2
示例#8
0
    def operator(self, u):
        from sumpy.kernel import HelmholtzKernel, LaplaceKernel

        sqrt_w = self.get_sqrt_weight()
        inv_sqrt_w_u = cse(u / sqrt_w)

        knl = self.kernel
        lknl = self.laplace_kernel

        knl_kwargs = {}
        knl_kwargs["kernel_arguments"] = self.kernel_arguments

        DpS0u = sym.Dp(
            knl,  # noqa
            cse(sym.S(lknl, inv_sqrt_w_u)),
            **knl_kwargs)

        if self.use_improved_operator:
            Dp0S0u = -0.25 * u + sym.Sp(  # noqa
                lknl,  # noqa
                sym.Sp(lknl, inv_sqrt_w_u, qbx_forced_limit="avg"),
                qbx_forced_limit="avg")

            if isinstance(self.kernel, HelmholtzKernel):
                DpS0u = (  # noqa
                    sym.Dp(
                        knl - lknl,  # noqa
                        cse(sym.S(lknl, inv_sqrt_w_u, qbx_forced_limit=+1)),
                        qbx_forced_limit=+1,
                        **knl_kwargs) + Dp0S0u)
            elif isinstance(knl, LaplaceKernel):
                DpS0u = Dp0S0u  # noqa
            else:
                raise ValueError(
                    f"no improved operator for '{self.kernel}' known")

        if self.is_unique_only_up_to_constant():
            # The interior Neumann operator in this representation
            # has a nullspace. The mean of the density must be matched
            # to the desired solution separately. As is, this operator
            # returns a mean that is not well-specified.

            amb_dim = self.kernel.dim
            ones_contribution = (sym.Ones() *
                                 sym.mean(amb_dim, amb_dim - 1, inv_sqrt_w_u))
        else:
            ones_contribution = 0

        return (
            -self.loc_sign * 0.5 * u + sqrt_w *
            (sym.Sp(knl, inv_sqrt_w_u, qbx_forced_limit="avg", **knl_kwargs) -
             self.alpha * DpS0u + ones_contribution))
示例#9
0
    def operator(self, u):
        sqrt_w = self.get_sqrt_weight()
        inv_sqrt_w_u = cse(u / sqrt_w)

        if self.is_unique_only_up_to_constant():
            # The exterior Dirichlet operator in this representation
            # has a nullspace. The mean of the density must be matched
            # to the desired solution separately. As is, this operator
            # returns a mean that is not well-specified.
            #
            # See Hackbusch, https://books.google.com/books?id=Ssnf7SZB0ZMC
            # Theorem 8.2.18b

            amb_dim = self.kernel.dim
            ones_contribution = (sym.Ones() *
                                 sym.mean(amb_dim, amb_dim - 1, inv_sqrt_w_u))
        else:
            ones_contribution = 0

        return (
            -self.loc_sign * 0.5 * u + sqrt_w *
            (self.alpha * sym.S(self.kernel,
                                inv_sqrt_w_u,
                                qbx_forced_limit=+1,
                                kernel_arguments=self.kernel_arguments) -
             sym.D(self.kernel,
                   inv_sqrt_w_u,
                   qbx_forced_limit="avg",
                   kernel_arguments=self.kernel_arguments) + ones_contribution)
        )
示例#10
0
    def scattered_volume_field(self, Jt, rho, qbx_forced_limit=None):
        """
        This will return an object array of six entries, the first three of which
        represent the electric, and the second three of which represent the
        magnetic field. This satisfies the time-domain Maxwell's equations
        as verified by :func:`sumpy.point_calculus.frequency_domain_maxwell`.
        """
        Jxyz = sym.cse(sym.tangential_to_xyz(Jt), "Jxyz")

        A = sym.S(self.kernel, Jxyz, k=self.k, qbx_forced_limit=qbx_forced_limit)
        phi = sym.S(self.kernel, rho, k=self.k, qbx_forced_limit=qbx_forced_limit)

        E_scat = 1j*self.k*A - sym.grad(3, phi)
        H_scat = sym.curl(A)

        return sym.flat_obj_array(E_scat, H_scat)
示例#11
0
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)
示例#12
0
    def representation(self, unknown, i_domain):
        """
        :return: a symbolic expression for the representation of the PDE solution
            in domain number *i_domain*.
        """
        unk = self._structured_unknown(unknown, with_l2_weights=False)

        result = []

        for field_kind in self.field_kinds:
            if not self.is_field_present(field_kind):
                continue

            field_result = 0
            for i_interface, (i_domain_outer, i_domain_inner,
                              interface_id) in (enumerate(self.interfaces)):
                if i_domain_outer == i_domain:
                    side = self.side_out
                elif i_domain_inner == i_domain:
                    side = self.side_in
                else:
                    continue

                my_unk = unk[side, field_kind, i_interface]
                if my_unk:
                    field_result += sym.S(self.kernel,
                                          my_unk,
                                          source=interface_id,
                                          k=self.domain_K_exprs[i_domain])

            result.append(field_result)

        from pytools.obj_array import make_obj_array
        return make_obj_array(result)
示例#13
0
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)
示例#14
0
        def nxcurlS(qbx_forced_limit):

            return sym.n_cross(
                sym.curl(
                    sym.S(knl,
                          sym.cse(sym.tangential_to_xyz(density_sym), "jxyz"),
                          qbx_forced_limit=qbx_forced_limit)))
示例#15
0
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
示例#16
0
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)
示例#17
0
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_zero_op(self, kernel, **knl_kwargs):

        u_sym = sym.var("u")
        dn_u_sym = sym.var("dn_u")

        return (sym.S(kernel, dn_u_sym, qbx_forced_limit=-1, **knl_kwargs) -
                sym.D(kernel, u_sym, qbx_forced_limit="avg", **knl_kwargs) -
                0.5 * u_sym)
示例#19
0
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
示例#20
0
    def rho_rhs(self, Jt, Einc_xyz):
        Jxyz = cse(tangential_to_xyz(Jt), "Jxyz")

        return (sym.n_dot(Einc_xyz)
                + 1j*self.k*sym.n_dot(sym.S(
                    self.kernel, Jxyz, k=self.k,
                    # continuous--qbx_forced_limit doesn't really matter
                    qbx_forced_limit="avg")))
示例#21
0
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())
示例#22
0
    def apply_pressure(self, density_vec_sym, mu_sym, qbx_forced_limit):
        """ Symbolic expression for pressure field associated with the Stokeslet"""

        from pytential.symbolic.mappers import DerivativeTaker
        kernel = LaplaceKernel(dim=self.dim)

        for i in range(self.dim):

            if i < 1:
                sym_expr = DerivativeTaker(i).map_int_g(
                                sym.S(kernel, density_vec_sym[i],
                                qbx_forced_limit=qbx_forced_limit))
            else:
                sym_expr = sym_expr + (DerivativeTaker(i).map_int_g(
                                sym.S(kernel, density_vec_sym[i],
                                qbx_forced_limit=qbx_forced_limit)))

        return sym_expr
示例#23
0
    def representation(self,
                       u,
                       map_potentials=None,
                       qbx_forced_limit=None,
                       **kwargs):
        sqrt_w = self.get_sqrt_weight()
        inv_sqrt_w_u = cse(u / sqrt_w)

        if map_potentials is None:

            def map_potentials(x):  # pylint:disable=function-redefined
                return x

        kwargs["qbx_forced_limit"] = qbx_forced_limit
        kwargs["kernel_arguments"] = self.kernel_arguments

        return (map_potentials(sym.S(self.kernel, inv_sqrt_w_u, **kwargs)) -
                self.alpha * map_potentials(
                    sym.D(self.kernel, sym.S(self.laplace_kernel,
                                             inv_sqrt_w_u), **kwargs)))
    def get_zero_op(self, kernel, **knl_kwargs):
        d = kernel.dim
        u_sym = sym.var("u")
        grad_u_sym = sym.make_sym_mv("grad_u", d)
        dn_u_sym = sym.var("dn_u")

        return (d1.resolve(
            d1.dnabla(d) *
            d1(sym.S(kernel, dn_u_sym, qbx_forced_limit="avg", **knl_kwargs))
        ) - d2.resolve(
            d2.dnabla(d) *
            d2(sym.D(kernel, u_sym, qbx_forced_limit="avg", **knl_kwargs))) -
                0.5 * grad_u_sym)
示例#25
0
def test_cost_model(actx_factory, dim, use_target_specific_qbx, per_box):
    """Test that cost model gathering can execute successfully."""
    actx = actx_factory()

    lpot_source = get_lpot_source(actx, dim).copy(
        _use_target_specific_qbx=use_target_specific_qbx,
        cost_model=QBXCostModel())
    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)

    if per_box:
        cost_S, _ = op_S.cost_per_box("constant_one", sigma=sigma)
    else:
        cost_S, _ = op_S.cost_per_stage("constant_one", 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)

    if per_box:
        cost_S_plus_D, _ = op_S_plus_D.cost_per_box("constant_one",
                                                    sigma=sigma)
    else:
        cost_S_plus_D, _ = op_S_plus_D.cost_per_stage("constant_one",
                                                      sigma=sigma)

    assert len(cost_S_plus_D) == 2
示例#26
0
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()))
示例#27
0
def test_cost_model(ctx_getter, dim, use_target_specific_qbx):
    """Test that cost model gathering can execute successfully."""
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    lpot_source = (get_lpot_source(queue, dim).copy(
        _use_target_specific_qbx=use_target_specific_qbx,
        cost_model=CostModel()))

    sigma = get_density(queue, lpot_source)

    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(lpot_source, sym_op_S)
    cost_S = op_S.get_modeled_cost(queue, 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))
    op_S_plus_D = bind(lpot_source, sym_op_S_plus_D)
    cost_S_plus_D = op_S_plus_D.get_modeled_cost(queue, sigma=sigma)
    assert len(cost_S_plus_D) == 2
示例#28
0
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)
示例#29
0
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
示例#30
0
def test_cost_model_metadata_gathering(ctx_factory):
    """Test that the cost model correctly gathers metadata."""
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder

    fmm_level_to_order = SimpleExpansionOrderFinder(tol=1e-5)

    lpot_source = get_lpot_source(actx, 2).copy(
            fmm_level_to_order=fmm_level_to_order)
    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 = HelmholtzKernel(2, "k")
    k = 2

    sym_op_S = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1, k=sym.var("k"))
    op_S = bind(places, sym_op_S)

    _, metadata = op_S.cost_per_stage(
        "constant_one", sigma=sigma, k=k, return_metadata=True
    )
    metadata = one(metadata.values())

    geo_data = lpot_source.qbx_fmm_geometry_data(
            places,
            places.auto_source,
            target_discrs_and_qbx_sides=((density_discr, 1),))

    tree = geo_data.tree()

    assert metadata["p_qbx"] == QBX_ORDER
    assert metadata["nlevels"] == tree.nlevels
    assert metadata["nsources"] == tree.nsources
    assert metadata["ntargets"] == tree.ntargets
    assert metadata["ncenters"] == geo_data.ncenters

    for level in range(tree.nlevels):
        assert (
                metadata["p_fmm_lev%d" % level]
                == fmm_level_to_order(k_sym, {"k": 2}, tree, level))