예제 #1
0
    def apply_stress(self, density_vec_sym, dir_vec_sym,
                        mu_sym, qbx_forced_limit):
        r"""Symbolic expression for viscous stress applied to a direction.

        Returns a vector of symbolic expressions for the force resulting
        from the viscous stress

        .. math::

            -p \delta_{ij} + \mu (\nabla_i u_j + \nabla_j u_i)

        applied in the direction of *dir_vec_sym*.

        Note that this computation is very similar to computing
        a double-layer potential with the Stresslet kernel in
        :class:`StressletWrapper`. The difference is that here the direction
        vector is applied at the target points, while in the Stresslet the
        direction is applied at the source points.

        :arg density_vec_sym: a symbolic vector variable for the density vector.
        :arg dir_vec_sym: a symbolic vector for the application direction.
        :arg mu_sym: a symbolic variable for the viscosity.
        :arg qbx_forced_limit: the *qbx_forced_limit* argument to be passed on
            to :class:`~pytential.symbolic.primitives.IntG`.
        """

        import itertools

        sym_expr = np.empty((self.dim,), dtype=object)
        stresslet_obj = StressletWrapper(dim=self.dim)

        for comp in range(self.dim):

            # Start variable count for kernel with 1 for the requested result
            #   component
            base_count = np.zeros(self.dim, dtype=np.int)
            base_count[comp] += 1

            for i, j in itertools.product(range(self.dim), range(self.dim)):
                var_ctr = base_count.copy()
                var_ctr[i] += 1
                var_ctr[j] += 1
                ctr_key = tuple(var_ctr)

                if i + j < 1:
                    sym_expr[comp] = dir_vec_sym[i] * sym.IntG(
                                     stresslet_obj.kernel_dict[ctr_key],
                                     density_vec_sym[j],
                                     qbx_forced_limit=qbx_forced_limit, mu=mu_sym)

                else:
                    sym_expr[comp] = sym_expr[comp] + dir_vec_sym[i] * sym.IntG(
                                                stresslet_obj.kernel_dict[ctr_key],
                                                density_vec_sym[j],
                                                qbx_forced_limit=qbx_forced_limit,
                                                mu=mu_sym)

        return sym_expr
예제 #2
0
    def apply_derivative(self, deriv_dir, density_vec_sym, dir_vec_sym, mu_sym,
                         qbx_forced_limit):
        """ Symbolic derivative of velocity from stresslet.

        Returns an object array of symbolic expressions for the vector
        resulting from integrating the *deriv_dir* derivative of the
        dyadic stresslet kernel (wrt target, not source) with
        variable *density_vec_sym* and source direction vectors *dir_vec_sym*.

        :arg deriv_dir: which derivative we want: 0, 1, or 2 for x, y, z
        :arg density_vec_sym: a symbolic vector variable for the density vector
        :arg dir_vec_sym: a symbolic vector variable for the normal direction
        :arg mu_sym: a symbolic variable for the viscosity
        :arg qbx_forced_limit: the qbx_forced_limit argument to be passed
            on to IntG.  +/-1 for exterior/interior one-sided boundary limit,
            +/-2 for exterior/interior off-boundary evaluation, and 'avg'
            for the average of the two one-sided boundary limits.
        """

        import itertools
        from pytential.symbolic.mappers import DerivativeTaker

        sym_expr = np.empty((self.dim, ), dtype=object)

        for comp in range(self.dim):

            # Start variable count for kernel with 1 for the requested result
            #   component
            base_count = np.zeros(self.dim, dtype=np.int)
            base_count[comp] += 1

            for i, j in itertools.product(range(self.dim), range(self.dim)):
                var_ctr = base_count.copy()
                var_ctr[i] += 1
                var_ctr[j] += 1
                ctr_key = tuple(var_ctr)

                if i + j < 1:
                    sym_expr[comp] = DerivativeTaker(deriv_dir).map_int_g(
                        sym.IntG(self.kernel_dict[ctr_key],
                                 dir_vec_sym[i] * density_vec_sym[j],
                                 qbx_forced_limit=qbx_forced_limit,
                                 mu=mu_sym))

                else:
                    sym_expr[comp] = sym_expr[comp] + DerivativeTaker(
                        deriv_dir).map_int_g(
                            sym.IntG(self.kernel_dict[ctr_key],
                                     dir_vec_sym[i] * density_vec_sym[j],
                                     qbx_forced_limit=qbx_forced_limit,
                                     mu=mu_sym))

        return sym_expr
예제 #3
0
    def apply_derivative(self, deriv_dir, density_vec_sym, dir_vec_sym,
                             mu_sym, qbx_forced_limit):
        """Symbolic derivative of velocity from stresslet.

        Returns an object array of symbolic expressions for the vector
        resulting from integrating the *deriv_dir* target derivative of the
        dyadic Stresslet kernel with variable *density_vec_sym* and source
        direction vectors *dir_vec_sym*.

        :arg deriv_dir: integer denoting the axis direction for the derivative.
        :arg density_vec_sym: a symbolic vector variable for the density vector.
        :arg dir_vec_sym: a symbolic vector variable for the normal direction.
        :arg mu_sym: a symbolic variable for the viscosity.
        :arg qbx_forced_limit: the *qbx_forced_limit* argument to be passed on
            to :class:`~pytential.symbolic.primitives.IntG`.
        """

        import itertools
        from pytential.symbolic.mappers import DerivativeTaker

        sym_expr = np.empty((self.dim,), dtype=object)

        for comp in range(self.dim):

            # Start variable count for kernel with 1 for the requested result
            #   component
            base_count = np.zeros(self.dim, dtype=np.int)
            base_count[comp] += 1

            for i, j in itertools.product(range(self.dim), range(self.dim)):
                var_ctr = base_count.copy()
                var_ctr[i] += 1
                var_ctr[j] += 1
                ctr_key = tuple(var_ctr)

                if i + j < 1:
                    sym_expr[comp] = DerivativeTaker(deriv_dir).map_int_g(
                                     sym.IntG(self.kernel_dict[ctr_key],
                                     dir_vec_sym[i] * density_vec_sym[j],
                                     qbx_forced_limit=qbx_forced_limit, mu=mu_sym))

                else:
                    sym_expr[comp] = sym_expr[comp] + DerivativeTaker(
                                        deriv_dir).map_int_g(
                                        sym.IntG(self.kernel_dict[ctr_key],
                                        dir_vec_sym[i] * density_vec_sym[j],
                                        qbx_forced_limit=qbx_forced_limit,
                                        mu=mu_sym))

        return sym_expr
예제 #4
0
    def apply(self, density_vec_sym, dir_vec_sym, mu_sym, qbx_forced_limit):
        """ Symbolic expressions for integrating stresslet kernel

        Returns an object array of symbolic expressions for the vector
        resulting from integrating the dyadic stresslet kernel with
        variable *density_vec_sym* and source direction vectors *dir_vec_sym*.

        :arg density_vec_sym: a symbolic vector variable for the density vector
        :arg dir_vec_sym: a symbolic vector variable for the direction vector
        :arg mu_sym: a symbolic variable for the viscosity
        :arg qbx_forced_limit: the qbx_forced_limit argument to be passed
            on to IntG.  +/-1 for exterior/interior one-sided boundary limit,
            +/-2 for exterior/interior off-boundary evaluation, and 'avg'
            for the average of the two one-sided boundary limits.
        """

        import itertools

        sym_expr = np.empty((self.dim, ), dtype=object)

        for comp in range(self.dim):

            # Start variable count for kernel with 1 for the requested result
            #   component
            base_count = np.zeros(self.dim, dtype=np.int)
            base_count[comp] += 1

            for i, j in itertools.product(range(self.dim), range(self.dim)):
                var_ctr = base_count.copy()
                var_ctr[i] += 1
                var_ctr[j] += 1
                ctr_key = tuple(var_ctr)

                if i + j < 1:
                    sym_expr[comp] = sym.IntG(
                        self.kernel_dict[ctr_key],
                        dir_vec_sym[i] * density_vec_sym[j],
                        qbx_forced_limit=qbx_forced_limit,
                        mu=mu_sym)

                else:
                    sym_expr[comp] = sym_expr[comp] + sym.IntG(
                        self.kernel_dict[ctr_key],
                        dir_vec_sym[i] * density_vec_sym[j],
                        qbx_forced_limit=qbx_forced_limit,
                        mu=mu_sym)

        return sym_expr
예제 #5
0
    def apply(self, density_vec_sym, mu_sym, qbx_forced_limit):
        """Symbolic expressions for integrating Stokeslet kernel.

        Returns an object array of symbolic expressions for the vector
        resulting from integrating the dyadic Stokeslet kernel with
        variable *density_vec_sym*.

        :arg density_vec_sym: a symbolic vector variable for the density vector.
        :arg mu_sym: a symbolic variable for the viscosity.
        :arg qbx_forced_limit: the *qbx_forced_limit* argument to be passed on
            to :class:`~pytential.symbolic.primitives.IntG`.
        """

        sym_expr = np.empty((self.dim,), dtype=object)

        for comp in range(self.dim):

            # Start variable count for kernel with 1 for the requested result
            #  component
            base_count = np.zeros(self.dim, dtype=np.int)
            base_count[comp] += 1

            for i in range(self.dim):
                var_ctr = base_count.copy()
                var_ctr[i] += 1
                ctr_key = tuple(var_ctr)

                if i < 1:
                    sym_expr[comp] = sym.IntG(
                                     self.kernel_dict[ctr_key], density_vec_sym[i],
                                     qbx_forced_limit=qbx_forced_limit, mu=mu_sym)

                else:
                    sym_expr[comp] = sym_expr[comp] + sym.IntG(
                                     self.kernel_dict[ctr_key], density_vec_sym[i],
                                     qbx_forced_limit=qbx_forced_limit, mu=mu_sym)

        return sym_expr
예제 #6
0
def test_unregularized_with_ones_kernel(ctx_factory):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    nelements = 10
    order = 8

    mesh = make_curve_mesh(partial(ellipse, 1),
            np.linspace(0, 1, nelements+1),
            order)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory

    discr = Discretization(actx, mesh,
            InterpolatoryQuadratureSimplexGroupFactory(order))

    from pytential.unregularized import UnregularizedLayerPotentialSource
    lpot_source = UnregularizedLayerPotentialSource(discr)
    from pytential.target import PointsTarget
    targets = PointsTarget(np.zeros((2, 1), dtype=float))

    places = GeometryCollection({
        sym.DEFAULT_SOURCE: lpot_source,
        sym.DEFAULT_TARGET: lpot_source,
        "target_non_self": targets})

    from sumpy.kernel import one_kernel_2d
    sigma_sym = sym.var("sigma")
    op = sym.IntG(one_kernel_2d, sigma_sym, qbx_forced_limit=None)

    sigma = discr.zeros(actx) + 1

    result_self = bind(places, op,
            auto_where=places.auto_where)(
                    actx, sigma=sigma)
    result_nonself = bind(places, op,
            auto_where=(places.auto_source, "target_non_self"))(
                    actx, sigma=sigma)

    from meshmode.dof_array import flatten
    assert np.allclose(actx.to_numpy(flatten(result_self)), 2 * np.pi)
    assert np.allclose(actx.to_numpy(result_nonself), 2 * np.pi)
예제 #7
0
def test_unregularized_with_ones_kernel(ctx_factory):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)

    nelements = 10
    order = 8

    mesh = make_curve_mesh(partial(ellipse, 1),
                           np.linspace(0, 1, nelements + 1), order)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory

    discr = Discretization(cl_ctx, mesh,
                           InterpolatoryQuadratureSimplexGroupFactory(order))

    from pytential.unregularized import UnregularizedLayerPotentialSource
    lpot_src = UnregularizedLayerPotentialSource(discr)

    from sumpy.kernel import one_kernel_2d

    expr = sym.IntG(one_kernel_2d, sym.var("sigma"), qbx_forced_limit=None)

    from pytential.target import PointsTarget
    op_self = bind(lpot_src, expr)
    op_nonself = bind((lpot_src, PointsTarget(np.zeros((2, 1), dtype=float))),
                      expr)

    with cl.CommandQueue(cl_ctx) as queue:
        sigma = cl.array.zeros(queue, discr.nnodes, dtype=float)
        sigma.fill(1)
        sigma.finish()

        result_self = op_self(queue, sigma=sigma)
        result_nonself = op_nonself(queue, sigma=sigma)

    assert np.allclose(result_self.get(), 2 * np.pi)
    assert np.allclose(result_nonself.get(), 2 * np.pi)
예제 #8
0
    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":
예제 #9
0
    def apply_stress(self, density_vec_sym, dir_vec_sym,
                        mu_sym, qbx_forced_limit):
        """ Symbolic expression for viscous stress applied to direction

        Returns a vector of symbolic expressions for the force resulting
        from the viscous stress:
        -pressure * I + mu * ( grad U + (grad U).T)),
        applied in the direction of *dir_vec_sym*.

        Note that this computation is very similar to computing
        a double-layer potential with the stresslet kernel.
        The difference is that here the direction vector is the
        direction applied to the stress tensor and is applied
        outside of the integration, whereas the stresslet calculation
        uses the normal vectors at every source point.  As such, the
        length of the argument passed in for the stresslet velocity
        calculation (after binding) is the same length as the number
        of source points/nodes; when calling this routine, the number
        of direction vectors should be the same as the number of targets.

        :arg density_vec_sym: a symbolic vector variable for the density vector
        :arg dir_vec_sym: a symbolic vector for the application direction
        :arg mu_sym: a symbolic variable for the viscosity
        :arg qbx_forced_limit: the qbx_forced_limit argument to be passed
            on to IntG.  +/-1 for exterior/interior one-sided boundary limit,
            +/-2 for exterior/interior off-boundary evaluation, and 'avg'
            for the average of the two one-sided boundary limits.
        """

        import itertools

        sym_expr = np.empty((self.dim,), dtype=object)
        stresslet_obj = StressletWrapper(dim=self.dim)

        for comp in range(self.dim):

            # Start variable count for kernel with 1 for the requested result
            #   component
            base_count = np.zeros(self.dim, dtype=np.int)
            base_count[comp] += 1

            for i, j in itertools.product(range(self.dim), range(self.dim)):
                var_ctr = base_count.copy()
                var_ctr[i] += 1
                var_ctr[j] += 1
                ctr_key = tuple(var_ctr)

                if i + j < 1:
                    sym_expr[comp] = dir_vec_sym[i] * sym.IntG(
                                     stresslet_obj.kernel_dict[ctr_key],
                                     density_vec_sym[j],
                                     qbx_forced_limit=qbx_forced_limit, mu=mu_sym)

                else:
                    sym_expr[comp] = sym_expr[comp] + dir_vec_sym[i] * sym.IntG(
                                                stresslet_obj.kernel_dict[ctr_key],
                                                density_vec_sym[j],
                                                qbx_forced_limit=qbx_forced_limit,
                                                mu=mu_sym)

        return sym_expr
예제 #10
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
예제 #11
0
def compute_biharmonic_extension(queue,
                                 target_discr,
                                 qbx,
                                 density_discr,
                                 f,
                                 fx,
                                 fy,
                                 target_association_tolerance=0.05):
    """Biharmoc extension. Currently only support
    interior domains in 2D (i.e., extension is on the exterior).
    """
    # pylint: disable=invalid-unary-operand-type
    dim = 2
    queue = setup_command_queue(queue=queue)
    qbx_forced_limit = 1

    normal = get_normal_vectors(queue, density_discr, loc_sign=1)

    bdry_op_sym = get_extension_bie_symbolic_operator(loc_sign=1)
    bound_op = bind(qbx, bdry_op_sym)

    bc = [fy, -fx]
    bvp_rhs = bind(qbx, sym.make_sym_vector("bc", dim))(queue, bc=bc)
    gmres_result = gmres(bound_op.scipy_op(queue,
                                           "sigma",
                                           np.float64,
                                           mu=1.,
                                           normal=normal),
                         bvp_rhs,
                         tol=1e-9,
                         progress=True,
                         stall_iterations=0,
                         hard_failure=True)
    mu = gmres_result.solution

    arclength_parametrization_derivatives_sym = sym.make_sym_vector(
        "arclength_parametrization_derivatives", dim)
    density_mu_sym = sym.make_sym_vector("mu", dim)
    dxids_sym = arclength_parametrization_derivatives_sym[0] + \
            1j * arclength_parametrization_derivatives_sym[1]
    dxids_conj_sym = arclength_parametrization_derivatives_sym[0] - \
            1j * arclength_parametrization_derivatives_sym[1]
    density_rho_sym = density_mu_sym[1] - 1j * density_mu_sym[0]
    density_conj_rho_sym = density_mu_sym[1] + 1j * density_mu_sym[0]

    # convolutions
    GS1 = sym.IntG(  # noqa: N806
        ComplexLinearLogKernel(dim),
        density_rho_sym,
        qbx_forced_limit=None)
    GS2 = sym.IntG(  # noqa: N806
        ComplexLinearKernel(dim),
        density_conj_rho_sym,
        qbx_forced_limit=None)
    GD1 = sym.IntG(  # noqa: N806
        ComplexFractionalKernel(dim),
        density_rho_sym * dxids_sym,
        qbx_forced_limit=None)
    GD2 = [
        sym.IntG(  # noqa: N806
            AxisTargetDerivative(iaxis, ComplexLogKernel(dim)),
            density_conj_rho_sym * dxids_sym +
            density_rho_sym * dxids_conj_sym,
            qbx_forced_limit=qbx_forced_limit) for iaxis in range(dim)
    ]

    GS1_bdry = sym.IntG(  # noqa: N806
        ComplexLinearLogKernel(dim),
        density_rho_sym,
        qbx_forced_limit=qbx_forced_limit)
    GS2_bdry = sym.IntG(  # noqa: N806
        ComplexLinearKernel(dim),
        density_conj_rho_sym,
        qbx_forced_limit=qbx_forced_limit)
    GD1_bdry = sym.IntG(  # noqa: N806
        ComplexFractionalKernel(dim),
        density_rho_sym * dxids_sym,
        qbx_forced_limit=qbx_forced_limit)

    xp, yp = get_arclength_parametrization_derivative(queue, density_discr)
    xp = -xp
    yp = -yp
    tangent = get_tangent_vectors(queue,
                                  density_discr,
                                  loc_sign=qbx_forced_limit)

    # check and fix the direction of parametrization
    # logger.info("Fix all negative signs in:" +
    #        str(xp * tangent[0] + yp * tangent[1]))

    grad_v2 = [
        bind(qbx,
             GD2[iaxis])(queue,
                         mu=mu,
                         arclength_parametrization_derivatives=make_obj_array(
                             [xp, yp])).real for iaxis in range(dim)
    ]
    v2_tangent_der = sum(tangent[iaxis] * grad_v2[iaxis]
                         for iaxis in range(dim))

    from pytential.symbolic.pde.scalar import NeumannOperator
    from sumpy.kernel import LaplaceKernel
    operator_v1 = NeumannOperator(LaplaceKernel(dim),
                                  loc_sign=qbx_forced_limit)
    bound_op_v1 = bind(qbx, operator_v1.operator(var("sigma")))
    # FIXME: the positive sign works here
    rhs_v1 = operator_v1.prepare_rhs(1 * v2_tangent_der)
    gmres_result = gmres(bound_op_v1.scipy_op(queue, "sigma",
                                              dtype=np.float64),
                         rhs_v1,
                         tol=1e-9,
                         progress=True,
                         stall_iterations=0,
                         hard_failure=True)
    sigma = gmres_result.solution
    qbx_stick_out = qbx.copy(
        target_association_tolerance=target_association_tolerance)
    v1 = bind((qbx_stick_out, target_discr),
              operator_v1.representation(var("sigma"),
                                         qbx_forced_limit=None))(queue,
                                                                 sigma=sigma)
    grad_v1 = bind(
        (qbx_stick_out, target_discr),
        operator_v1.representation(
            var("sigma"),
            qbx_forced_limit=None,
            map_potentials=lambda pot: sym.grad(dim, pot)))(queue, sigma=sigma)
    v1_bdry = bind(
        qbx,
        operator_v1.representation(var("sigma"),
                                   qbx_forced_limit=qbx_forced_limit))(
                                       queue, sigma=sigma)

    z_conj = target_discr.nodes()[0] - 1j * target_discr.nodes()[1]
    z_conj_bdry = density_discr.nodes().with_queue(queue)[0] \
            - 1j * density_discr.nodes().with_queue(queue)[1]
    int_rho = 1 / (8 * np.pi) * bind(
        qbx, sym.integral(dim, dim - 1, density_rho_sym))(queue, mu=mu)

    omega_S1 = bind(  # noqa: N806
        (qbx_stick_out, target_discr), GS1)(queue, mu=mu).real
    omega_S2 = -1 * bind(  # noqa: N806
        (qbx_stick_out, target_discr), GS2)(queue, mu=mu).real
    omega_S3 = (z_conj * int_rho).real  # noqa: N806
    omega_S = -(omega_S1 + omega_S2 + omega_S3)  # noqa: N806

    grad_omega_S1 = bind(  # noqa: N806
        (qbx_stick_out, target_discr), sym.grad(dim, GS1))(queue, mu=mu).real
    grad_omega_S2 = -1 * bind(  # noqa: N806
        (qbx_stick_out, target_discr), sym.grad(dim, GS2))(queue, mu=mu).real
    grad_omega_S3 = (int_rho * make_obj_array([1., -1.])).real  # noqa: N806
    grad_omega_S = -(grad_omega_S1 + grad_omega_S2 + grad_omega_S3
                     )  # noqa: N806

    omega_S1_bdry = bind(qbx, GS1_bdry)(queue, mu=mu).real  # noqa: N806
    omega_S2_bdry = -1 * bind(qbx, GS2_bdry)(queue, mu=mu).real  # noqa: N806
    omega_S3_bdry = (z_conj_bdry * int_rho).real  # noqa: N806
    omega_S_bdry = -(omega_S1_bdry + omega_S2_bdry + omega_S3_bdry
                     )  # noqa: N806

    omega_D1 = bind(  # noqa: N806
        (qbx_stick_out, target_discr),
        GD1)(queue,
             mu=mu,
             arclength_parametrization_derivatives=make_obj_array([xp,
                                                                   yp])).real
    omega_D = (omega_D1 + v1)  # noqa: N806

    grad_omega_D1 = bind(  # noqa: N806
        (qbx_stick_out, target_discr), sym.grad(dim, GD1))(
            queue,
            mu=mu,
            arclength_parametrization_derivatives=make_obj_array([xp,
                                                                  yp])).real
    grad_omega_D = grad_omega_D1 + grad_v1  # noqa: N806

    omega_D1_bdry = bind(  # noqa: N806
        qbx, GD1_bdry)(queue,
                       mu=mu,
                       arclength_parametrization_derivatives=make_obj_array(
                           [xp, yp])).real
    omega_D_bdry = (omega_D1_bdry + v1_bdry)  # noqa: N806

    int_bdry_mu = bind(
        qbx, sym.integral(dim, dim - 1, sym.make_sym_vector("mu", dim)))(queue,
                                                                         mu=mu)
    omega_W = (  # noqa: N806
        int_bdry_mu[0] * target_discr.nodes()[1] -
        int_bdry_mu[1] * target_discr.nodes()[0])
    grad_omega_W = make_obj_array(  # noqa: N806
        [-int_bdry_mu[1], int_bdry_mu[0]])
    omega_W_bdry = (  # noqa: N806
        int_bdry_mu[0] * density_discr.nodes().with_queue(queue)[1] -
        int_bdry_mu[1] * density_discr.nodes().with_queue(queue)[0])

    int_bdry = bind(qbx, sym.integral(dim, dim - 1, var("integrand")))(
        queue, integrand=omega_S_bdry + omega_D_bdry + omega_W_bdry)

    debugging_info = {}
    debugging_info['omega_S'] = omega_S
    debugging_info['omega_D'] = omega_D
    debugging_info['omega_W'] = omega_W
    debugging_info['omega_v1'] = v1
    debugging_info['omega_D1'] = omega_D1

    int_interior_func_bdry = bind(qbx,
                                  sym.integral(2, 1,
                                               var("integrand")))(queue,
                                                                  integrand=f)

    path_length = get_path_length(queue, density_discr)
    ext_f = omega_S + omega_D + omega_W + (int_interior_func_bdry -
                                           int_bdry) / path_length
    grad_f = grad_omega_S + grad_omega_D + grad_omega_W

    return ext_f, grad_f[0], grad_f[1], debugging_info
예제 #12
0
    np.random.seed(22)
    source_charges = np.random.randn(point_source.ndofs)
    source_charges[-1] = -np.sum(source_charges[:-1])
    source_charges = source_charges.astype(dtype)
    assert np.sum(source_charges) < 1.0e-15

    source_charges_dev = actx.from_numpy(source_charges)

    # }}}

    # {{{ establish BCs

    pot_src = sym.IntG(
        # FIXME: qbx_forced_limit--really?
        knl,
        sym_charges,
        qbx_forced_limit=None,
        **case.knl_sym_kwargs)

    test_direct = bind(places,
                       pot_src,
                       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,