Exemplo n.º 1
0
 def operator(self, sigma):
     """
     Returns the two second kind integral equations.
     """
     rep = self.representation(sigma, qbx_forced_limit="avg")
     rep_diff = sym.normal_derivative(2, rep)
     int_eq1 = sigma[0] / 2 + rep
     int_eq2 = -sym.mean_curvature(2) * sigma[0] + sigma[1] / 2 + rep_diff
     return np.array([int_eq1, int_eq2])
Exemplo n.º 2
0
    def operator(self, sigma, **kwargs):
        """
        :param u: symbolic variable for the density.
        :param kwargs: additional keyword arguments passed on to the layer
            potential constructor.

        :returns: the second kind integral operator for the clamped plate
            problem from [Farkas1990]_.
        """
        rep = self.representation(sigma, qbx_forced_limit="avg", **kwargs)
        drep_dn = sym.normal_derivative(self.dim, rep)

        int_eq1 = sigma[0] / 2 + rep
        int_eq2 = -sym.mean_curvature(self.dim) * sigma[0] + sigma[1] / 2 + drep_dn

        return np.array([int_eq1, int_eq2])
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
    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,
                                        dofdesc=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,
Exemplo n.º 5
0
    def bc_term_to_operator_contrib(self, term, side, raw_potential_op,
                                    density, discrete):
        potential_op = raw_potential_op

        side_sign = self.side_to_sign[side]

        domain_outer, domain_inner, interface_id = \
                self.interfaces[term.i_interface]
        if side == self.side_in:
            K_expr = self.domain_K_exprs[domain_inner]  # noqa
            bc_coeff = term.coeff_inner
        elif side == self.side_out:
            K_expr = self.domain_K_exprs[domain_outer]  # noqa
            bc_coeff = term.coeff_outer
        else:
            raise ValueError("invalid value of 'side'")

        potential_op = potential_op(self.kernel,
                                    density,
                                    source=interface_id,
                                    k=K_expr)

        if term.direction == self.dir_none:
            if raw_potential_op is sym.S:
                jump_term = 0
            elif raw_potential_op is sym.D:
                jump_term = (side_sign * 0.5) * discrete
            else:
                assert False, raw_potential_op
        elif term.direction == self.dir_normal:
            potential_op = sym.normal_derivative(potential_op, interface_id)

            if raw_potential_op is sym.S:
                # S'
                jump_term = (-side_sign * 0.5) * discrete
            elif raw_potential_op is sym.D:
                jump_term = 0
            else:
                assert False, raw_potential_op

        elif term.direction == self.dir_tangential:
            potential_op = sym.tangential_derivative(
                raw_potential_op(self.kernel,
                                 density,
                                 source=interface_id,
                                 k=K_expr,
                                 qbx_forced_limit=side_sign),
                interface_id).a.as_scalar()

            # Some of these may have jumps, but QBX does the dirty
            # work here by directly computing the limit.
            jump_term = 0

        else:
            raise ValueError("invalid direction")

        potential_op = (jump_term +
                        self.get_sqrt_weight(interface_id) * potential_op)

        del jump_term

        contrib = bc_coeff * potential_op

        if (raw_potential_op is sym.D and term.direction == self.dir_normal):
            # FIXME The hypersingular part should perhaps be
            # treated specially to avoid cancellation.
            pass

        return contrib
Exemplo n.º 6
0
 def Sn(dom, density):  # noqa
     return sym.normal_derivative(
         2, S(dom, density, qbx_forced_limit="avg"))
Exemplo n.º 7
0
                       auto_where=("point_source",
                                   "point_target"))(actx,
                                                    charges=source_charges_dev,
                                                    **case.knl_concrete_kwargs)

    if case.bc_type == "dirichlet":
        bc = bind(places, pot_src,
                  auto_where=("point_source",
                              case.name))(actx,
                                          charges=source_charges_dev,
                                          **case.knl_concrete_kwargs)

    elif case.bc_type == "neumann":
        bc = bind(places,
                  sym.normal_derivative(ambient_dim,
                                        pot_src,
                                        dofdesc=case.name),
                  auto_where=("point_source",
                              case.name))(actx,
                                          charges=source_charges_dev,
                                          **case.knl_concrete_kwargs)

    elif case.bc_type == "clamped_plate":
        bc_u = bind(places, pot_src,
                    auto_where=("point_source",
                                case.name))(actx,
                                            charges=source_charges_dev,
                                            **case.knl_concrete_kwargs)
        bc_du = bind(places,
                     sym.normal_derivative(ambient_dim,
                                           pot_src,
Exemplo n.º 8
0
def get_bvp_error(lpot_source, fmm_order, qbx_order, k=0):
    # This returns a tuple (err_l2, err_linf, nit).
    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

    assert k == 0  # Helmholtz would require a different representation

    from sumpy.kernel import LaplaceKernel, HelmholtzKernel
    lap_k_sym = LaplaceKernel(d)
    if k == 0:
        k_sym = lap_k_sym
        knl_kwargs = {}
    else:
        k_sym = HelmholtzKernel(d)
        knl_kwargs = {"k": sym.var("k")}

    density_discr = lpot_source.density_discr

    # {{{ find source and target points

    source_angles = (np.pi / 2 +
                     np.linspace(0,
                                 2 * np.pi * BVP_EXPERIMENT_N_ARMS,
                                 BVP_EXPERIMENT_N_ARMS,
                                 endpoint=False)) / BVP_EXPERIMENT_N_ARMS
    source_points = 0.75 * np.array([
        np.cos(source_angles),
        np.sin(source_angles),
    ])
    target_angles = (np.pi + np.pi / 2 +
                     np.linspace(0,
                                 2 * np.pi * BVP_EXPERIMENT_N_ARMS,
                                 BVP_EXPERIMENT_N_ARMS,
                                 endpoint=False)) / BVP_EXPERIMENT_N_ARMS
    target_points = 1.5 * np.array([
        np.cos(target_angles),
        np.sin(target_angles),
    ])

    np.random.seed(17)
    source_charges = np.random.randn(BVP_EXPERIMENT_N_ARMS)

    source_points_dev = cl.array.to_device(queue, source_points)
    target_points_dev = cl.array.to_device(queue, target_points)
    source_charges_dev = cl.array.to_device(queue, source_charges)

    from pytential.source import PointPotentialSource
    from pytential.target import PointsTarget

    point_source = PointPotentialSource(lpot_source.cl_context,
                                        source_points_dev)

    pot_src = sym.IntG(
        # FIXME: qbx_forced_limit--really?
        k_sym,
        sym.var("charges"),
        qbx_forced_limit=None,
        **knl_kwargs)

    ref_direct = bind((point_source, PointsTarget(target_points_dev)),
                      pot_src)(queue, charges=source_charges_dev,
                               **knl_kwargs).get()

    sym_sqrt_j = sym.sqrt_jac_q_weight(density_discr.ambient_dim)

    bc = bind((point_source, density_discr),
              sym.normal_derivative(density_discr.ambient_dim,
                                    pot_src,
                                    where=sym.DEFAULT_TARGET))(
                                        queue,
                                        charges=source_charges_dev,
                                        **knl_kwargs)

    rhs = bind(density_discr, sym.var("bc") * sym_sqrt_j)(queue, bc=bc)

    # }}}

    # {{{ solve

    bound_op = bind(
        lpot_source,
        -0.5 * sym.var("u") + sym_sqrt_j * sym.Sp(k_sym,
                                                  sym.var("u") / sym_sqrt_j,
                                                  qbx_forced_limit="avg",
                                                  **knl_kwargs))

    from pytential.solve import gmres
    gmres_result = gmres(bound_op.scipy_op(queue, "u", np.float64,
                                           **knl_kwargs),
                         rhs,
                         tol=1e-10,
                         stall_iterations=100,
                         progress=True,
                         hard_failure=True)

    u = gmres_result.solution

    # }}}

    points_target = PointsTarget(target_points_dev)
    bound_tgt_op = bind((lpot_source, points_target),
                        sym.S(k_sym,
                              sym.var("u") / sym_sqrt_j,
                              qbx_forced_limit=None))

    test_via_bdry = bound_tgt_op(queue, u=u).get()

    err = ref_direct - test_via_bdry

    err_l2 = la.norm(err, 2) / la.norm(ref_direct, 2)
    err_linf = la.norm(err, np.inf) / la.norm(ref_direct, np.inf)
    return err_l2, err_linf, gmres_result.iteration_count
Exemplo n.º 9
0
    def bc_term_to_operator_contrib(self, term, side, raw_potential_op,
            density, discrete):
        potential_op = raw_potential_op

        side_sign = self.side_to_sign[side]

        domain_outer, domain_inner, interface_id = \
                self.interfaces[term.i_interface]
        if side == self.side_in:
            K_expr = self.domain_K_exprs[domain_inner]  # noqa
            bc_coeff = term.coeff_inner
        elif side == self.side_out:
            K_expr = self.domain_K_exprs[domain_outer]  # noqa
            bc_coeff = term.coeff_outer
        else:
            raise ValueError("invalid value of 'side'")

        potential_op = potential_op(
                self.kernel, density, source=interface_id,
                k=K_expr)

        if term.direction == self.dir_none:
            if raw_potential_op is sym.S:
                jump_term = 0
            elif raw_potential_op is sym.D:
                jump_term = (side_sign*0.5) * discrete
            else:
                assert False, raw_potential_op
        elif term.direction == self.dir_normal:
            potential_op = sym.normal_derivative(
                    potential_op, interface_id)

            if raw_potential_op is sym.S:
                # S'
                jump_term = (-side_sign*0.5) * discrete
            elif raw_potential_op is sym.D:
                jump_term = 0
            else:
                assert False, raw_potential_op

        elif term.direction == self.dir_tangential:
            potential_op = sym.tangential_derivative(
                    raw_potential_op(
                        self.kernel, density, source=interface_id,
                        k=K_expr, qbx_forced_limit=side_sign),
                    interface_id).a.as_scalar()

            # Some of these may have jumps, but QBX does the dirty
            # work here by directly computing the limit.
            jump_term = 0

        else:
            raise ValueError("invalid direction")

        potential_op = (
                jump_term
                + self.get_sqrt_weight(interface_id)*potential_op)

        del jump_term

        contrib = bc_coeff * potential_op

        if (raw_potential_op is sym.D
                and term.direction == self.dir_normal):
            # FIXME The hypersingular part should perhaps be
            # treated specially to avoid cancellation.
            pass

        return contrib
Exemplo n.º 10
0
 def Sn(dom, density):  # noqa
     return sym.normal_derivative(
             2,
             S(dom, density,
                 qbx_forced_limit="avg"))
Exemplo n.º 11
0
    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