Example #1
0
    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,
        )
Example #2
0
def test_order_finder(knl):
    from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder

    ofind = SimpleExpansionOrderFinder(1e-5)

    tree = FakeTree(knl.dim, 200, 0.5)
    orders = [
        ofind(knl, frozenset([("k", 5)]), tree, level) for level in range(30)
    ]
    print(orders)
Example #3
0
def test_order_finder(knl):
    from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder

    ofind = SimpleExpansionOrderFinder(1e-5)

    tree = FakeTree(knl.dim, 200, 0.5)
    orders = [
        ofind(knl, frozenset([("k", 5)]), tree, level) for level in range(30)
    ]
    print(orders)

    # Order should not increase with level
    assert (np.diff(orders) <= 0).all()
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))
Example #5
0
def test_cost_model_metadata_gathering(ctx_getter):
    """Test that the cost model correctly gathers metadata."""
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder

    fmm_level_to_order = SimpleExpansionOrderFinder(tol=1e-5)

    lpot_source = get_lpot_source(
        queue, 2).copy(fmm_level_to_order=fmm_level_to_order)

    sigma = get_density(queue, lpot_source)

    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(lpot_source, sym_op_S)

    cost_S = one(op_S.get_modeled_cost(queue, sigma=sigma, k=k).values())

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

    tree = geo_data.tree()

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

    for level in range(tree.nlevels):
        assert (cost_S.params["p_fmm_lev%d" % level] == fmm_level_to_order(
            k_sym, {"k": 2}, tree, level))
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 test_target_specific_qbx(ctx_getter, op, helmholtz_k, qbx_order):
    logging.basicConfig(level=logging.INFO)

    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    target_order = 4
    fmm_tol = 1e-3

    from meshmode.mesh.generation import generate_icosphere
    mesh = generate_icosphere(1, target_order)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
        InterpolatoryQuadratureSimplexGroupFactory
    from pytential.qbx import QBXLayerPotentialSource
    pre_density_discr = Discretization(
        cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order))

    from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder

    refiner_extra_kwargs = {}

    if helmholtz_k != 0:
        refiner_extra_kwargs["kernel_length_scale"] = 5 / abs(helmholtz_k)

    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,
    ).with_refinement(**refiner_extra_kwargs)

    density_discr = qbx.density_discr

    nodes = density_discr.nodes().with_queue(queue)
    u_dev = clmath.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(qbx, expr)
    pot_ref = bound_op(queue, u=u_dev, k=helmholtz_k).get()

    qbx = qbx.copy(_use_target_specific_qbx=True)
    bound_op = bind(qbx, expr)
    pot_tsqbx = bound_op(queue, u=u_dev, k=helmholtz_k).get()

    assert np.allclose(pot_tsqbx, pot_ref, atol=1e-13, rtol=1e-13)
Example #8
0
def run_method(trial,
               method,
               cl_ctx=None,
               queue=None,
               clear_memoized_objects=False,
               true_sol_name="True Solution",
               comp_sol_name="Computed Solution",
               **kwargs):
    """
        Returns (true solution, computed solution, snes_or_ksp)

        :arg clear_memoized_objects: Destroy memoized objects if true.
        :arg trial: A dict mapping each trial option to a valid value
        :arg method: A valid method (see the keys of *method_options*)
        :arg cl_ctx: the computing context
        :arg queue: the computing queue for the context

        kwargs should include the boundary id of the scatterer as 'scatterer_bdy_id'
        and the boundary id of the outer boundary as 'outer_bdy_id'

        kwargs should include the method options for :arg:`trial['method']`.
        for the given method.
    """
    if clear_memoized_objects:
        global memoized_objects
        memoized_objects = {}

    if cl_ctx is None:
        raise ValueError("Missing cl_ctx")
    if queue is None:
        raise ValueError("Missing queue")

    # Get boundary ids
    scatterer_bdy_id = kwargs['scatterer_bdy_id']
    outer_bdy_id = kwargs['outer_bdy_id']

    # Get degree and wave number
    degree = trial['degree']
    wave_number = trial['kappa']

    # Get options prefix and solver parameters, if any
    options_prefix = kwargs.get('options_prefix', None)
    solver_parameters = dict(kwargs.get('solver_parameters', None))

    # Get prepared trial args in kwargs
    prepared_trial = prepare_trial(trial, true_sol_name, cl_ctx, queue)
    mesh, fspace, vfspace, true_sol, true_sol_grad_expr = prepared_trial

    # Create a place to memoize any objects if necessary
    tuple_trial = trial_to_tuple(trial)
    memo_key = tuple_trial[:2]
    if memo_key not in memoized_objects:
        memoized_objects[memo_key] = {}

    comp_sol = None

    # Handle any special kwargs and get computed solution
    if method == 'pml':
        # Get required objects
        pml_max = kwargs['pml_max']
        pml_min = kwargs['pml_min']

        # Get optional argumetns
        pml_type = kwargs.get('pml_type', None)
        quad_const = kwargs.get('quad_const', None)
        speed = kwargs.get('speed', None)

        # Make tensor function space
        if 'tfspace' not in memoized_objects[memo_key]:
            memoized_objects[memo_key]['tfspace'] = \
                TensorFunctionSpace(mesh, 'CG', degree)

        tfspace = memoized_objects[memo_key]['tfspace']

        snes, comp_sol = pml(
            mesh,
            scatterer_bdy_id,
            outer_bdy_id,
            wave_number,
            options_prefix=options_prefix,
            solver_parameters=solver_parameters,
            fspace=fspace,
            tfspace=tfspace,
            true_sol_grad_expr=true_sol_grad_expr,
            pml_type=pml_type,
            quad_const=quad_const,
            speed=speed,
            pml_min=pml_min,
            pml_max=pml_max,
        )
        snes_or_ksp = snes

    elif method == 'nonlocal':
        # Build DG spaces if not already built
        if 'dgfspace' not in memoized_objects[memo_key]:
            memoized_objects[memo_key]['dgfspace'] = \
                FunctionSpace(mesh, 'DG', degree)
        if 'dgvfspace' not in memoized_objects[memo_key]:
            memoized_objects[memo_key]['dgvfspace'] = \
                VectorFunctionSpace(mesh, 'DG', degree)

        dgfspace = memoized_objects[memo_key]['dgfspace']
        dgvfspace = memoized_objects[memo_key]['dgvfspace']

        # Get opencl array context
        from meshmode.array_context import PyOpenCLArrayContext
        actx = PyOpenCLArrayContext(queue)

        # Build connection fd -> meshmode if not already built
        if 'meshmode_src_connection' not in memoized_objects[memo_key]:
            from meshmode.interop.firedrake import build_connection_from_firedrake
            memoized_objects[memo_key]['meshmode_src_connection'] = \
                build_connection_from_firedrake(
                    actx,
                    dgfspace,
                    grp_factory=None,
                    restrict_to_boundary=scatterer_bdy_id)

        meshmode_src_connection = memoized_objects[memo_key][
            'meshmode_src_connection']

        # Set defaults for qbx kwargs
        qbx_order = kwargs.get('qbx_order', degree + 2)
        fine_order = kwargs.get('fine_order', 4 * degree)
        fmm_order = kwargs.get('FMM Order', None)
        fmm_tol = kwargs.get('FMM Tol', None)
        # make sure got either fmm_order xor fmm_tol
        if fmm_order is None and fmm_tol is None:
            raise ValueError("At least one of 'fmm_order', 'fmm_tol' must not "
                             "be *None*")
        if fmm_order is not None and fmm_tol is not None:
            raise ValueError("At most one of 'fmm_order', 'fmm_tol' must not "
                             "be *None*")
        # if got fmm_tol, make a level-to-order
        fmm_level_to_order = None
        if fmm_tol is not None:
            if not isinstance(fmm_tol, float):
                raise TypeError("fmm_tol of type '%s' is not of type float" %
                                type(fmm_tol))
            if fmm_tol <= 0.0:
                raise ValueError(
                    "fmm_tol of '%s' is less than or equal to 0.0" % fmm_tol)
            from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder
            fmm_level_to_order = SimpleExpansionOrderFinder(fmm_tol)
        # Otherwise, make sure we got a valid fmm_order
        else:
            if not isinstance(fmm_order, int):
                if fmm_order != False:
                    raise TypeError(
                        "fmm_order of type '%s' is not of type int" %
                        type(fmm_order))
            if fmm_order != False and fmm_order < 1:
                raise ValueError("fmm_order of '%s' is less than 1" %
                                 fmm_order)

        qbx_kwargs = {
            'qbx_order': qbx_order,
            'fine_order': fine_order,
            'fmm_order': fmm_order,
            'fmm_level_to_order': fmm_level_to_order,
            'fmm_backend': 'fmmlib',
        }
        # }}}

        ksp, comp_sol = nonlocal_integral_eq(
            mesh,
            scatterer_bdy_id,
            outer_bdy_id,
            wave_number,
            options_prefix=options_prefix,
            solver_parameters=solver_parameters,
            fspace=fspace,
            vfspace=vfspace,
            true_sol_grad_expr=true_sol_grad_expr,
            actx=actx,
            dgfspace=dgfspace,
            dgvfspace=dgvfspace,
            meshmode_src_connection=meshmode_src_connection,
            qbx_kwargs=qbx_kwargs,
        )

        snes_or_ksp = ksp

    elif method == 'transmission':

        snes, comp_sol = transmission(
            mesh,
            scatterer_bdy_id,
            outer_bdy_id,
            wave_number,
            options_prefix=options_prefix,
            solver_parameters=solver_parameters,
            fspace=fspace,
            true_sol_grad_expr=true_sol_grad_expr,
        )
        snes_or_ksp = snes
    else:
        raise ValueError("Invalid method")

    comp_sol.rename(name=comp_sol_name)
    return true_sol, comp_sol, snes_or_ksp