Beispiel #1
0
def test_3d_orientation(ctx_factory, what, mesh_gen_func, visualize=False):
    pytest.importorskip("pytential")

    logging.basicConfig(level=logging.INFO)

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)

    mesh = mesh_gen_func()

    logger.info("%d elements" % mesh.nelements)

    from meshmode.discretization import Discretization
    discr = Discretization(ctx, mesh,
            PolynomialWarpAndBlendGroupFactory(1))

    from pytential import bind, sym

    # {{{ check normals point outward

    if what == "torus":
        nodes = sym.nodes(mesh.ambient_dim).as_vector()
        angle = sym.atan2(nodes[1], nodes[0])
        center_nodes = sym.make_obj_array([
                5*sym.cos(angle),
                5*sym.sin(angle),
                0*angle])
        normal_outward_expr = (
                sym.normal(mesh.ambient_dim) | (nodes-center_nodes))

    else:
        normal_outward_expr = (
                sym.normal(mesh.ambient_dim) | sym.nodes(mesh.ambient_dim))

    normal_outward_check = bind(discr, normal_outward_expr)(queue).as_scalar() > 0

    assert normal_outward_check.get().all(), normal_outward_check.get()

    # }}}

    normals = bind(discr, sym.normal(mesh.ambient_dim).xproject(1))(queue)

    if visualize:
        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(queue, discr, 1)

        vis.write_vtk_file("normals.vtu", [
            ("normals", normals),
            ])
Beispiel #2
0
def test_tangential_onb(actx_factory):
    actx = actx_factory()

    from meshmode.mesh.generation import generate_torus
    mesh = generate_torus(5, 2, order=3)

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

    tob = sym.tangential_onb(mesh.ambient_dim)
    nvecs = tob.shape[1]

    # make sure tangential_onb is mutually orthogonal and normalized
    orth_check = bind(discr, sym.make_obj_array([
        np.dot(tob[:, i], tob[:, j]) - (1 if i == j else 0)
        for i in range(nvecs) for j in range(nvecs)])
        )(actx)

    for orth_i in orth_check:
        assert actx.to_numpy(
                actx.np.all(actx.np.abs(orth_i) < 1e-13)
                )

    # make sure tangential_onb is orthogonal to normal
    orth_check = bind(discr, sym.make_obj_array([
        np.dot(tob[:, i], sym.normal(mesh.ambient_dim).as_vector())
        for i in range(nvecs)])
        )(actx)

    for orth_i in orth_check:
        assert actx.to_numpy(
                actx.np.all(actx.np.abs(orth_i) < 1e-13)
                )
Beispiel #3
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
Beispiel #4
0
def test_tangential_onb(ctx_factory):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.mesh.generation import generate_torus
    mesh = generate_torus(5, 2, order=3)

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

    tob = sym.tangential_onb(mesh.ambient_dim)
    nvecs = tob.shape[1]

    # make sure tangential_onb is mutually orthogonal and normalized
    orth_check = bind(
        discr,
        sym.make_obj_array([
            np.dot(tob[:, i], tob[:, j]) - (1 if i == j else 0)
            for i in range(nvecs) for j in range(nvecs)
        ]))(queue)

    for i, orth_i in enumerate(orth_check):
        assert (cl.clmath.fabs(orth_i) < 1e-13).get().all()

    # make sure tangential_onb is orthogonal to normal
    orth_check = bind(
        discr,
        sym.make_obj_array([
            np.dot(tob[:, i],
                   sym.normal(mesh.ambient_dim).as_vector())
            for i in range(nvecs)
        ]))(queue)

    for i, orth_i in enumerate(orth_check):
        assert (cl.clmath.fabs(orth_i) < 1e-13).get().all()
Beispiel #5
0
def test_tangential_onb(ctx_factory):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.mesh.generation import generate_torus
    mesh = generate_torus(5, 2, order=3)

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

    tob = sym.tangential_onb(mesh.ambient_dim)
    nvecs = tob.shape[1]

    # make sure tangential_onb is mutually orthogonal and normalized
    orth_check = bind(discr, sym.make_obj_array([
        np.dot(tob[:, i], tob[:, j]) - (1 if i == j else 0)
        for i in range(nvecs) for j in range(nvecs)])
        )(queue)

    for i, orth_i in enumerate(orth_check):
        assert (cl.clmath.fabs(orth_i) < 1e-13).get().all()

    # make sure tangential_onb is orthogonal to normal
    orth_check = bind(discr, sym.make_obj_array([
        np.dot(tob[:, i], sym.normal(mesh.ambient_dim).as_vector())
        for i in range(nvecs)])
        )(queue)

    for i, orth_i in enumerate(orth_check):
        assert (cl.clmath.fabs(orth_i) < 1e-13).get().all()
Beispiel #6
0
 def targets_from_sources(sign, dist, dim=2):
     nodes = dof_array_to_numpy(
         actx,
         bind(places, sym.nodes(dim, dofdesc=dd))(actx).as_vector(object))
     normals = dof_array_to_numpy(
         actx,
         bind(places, sym.normal(dim, dofdesc=dd))(actx).as_vector(object))
     return actx.from_numpy(nodes + normals * sign * dist)
Beispiel #7
0
def get_centers_on_side(lpot_src, sign):
    adim = lpot_src.density_discr.ambient_dim
    dim = lpot_src.density_discr.dim

    from pytential import sym, bind
    with cl.CommandQueue(lpot_src.cl_context) as queue:
        nodes = bind(lpot_src.density_discr, sym.nodes(adim))(queue)
        normals = bind(lpot_src.density_discr, sym.normal(adim, dim=dim))(queue)
        expansion_radii = lpot_src._expansion_radii("nsources").with_queue(queue)
        return (nodes + normals * sign * expansion_radii).as_vector(np.object)
    def targets_from_sources(sign, dist, dim=2):
        nodes = actx.to_numpy(
            flatten(
                bind(places, sym.nodes(dim, dofdesc=dd))(actx).as_vector(),
                actx)).reshape(dim, -1)
        normals = actx.to_numpy(
            flatten(
                bind(places, sym.normal(dim, dofdesc=dd))(actx).as_vector(),
                actx)).reshape(dim, -1)

        return actx.from_numpy(nodes + normals * sign * dist)
Beispiel #9
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
Beispiel #10
0
def _visualize_refinement(actx: PyOpenCLArrayContext,
                          discr,
                          niter,
                          stage_nr,
                          stage_name,
                          flags,
                          visualize=False):
    if not visualize:
        return

    if stage_nr not in (1, 2):
        raise ValueError("unexpected stage number")

    flags = flags.get()
    logger.info("for stage %s: splitting %d/%d stage-%d elements", stage_name,
                np.sum(flags), discr.mesh.nelements, stage_nr)

    from meshmode.discretization.visualization import make_visualizer
    vis = make_visualizer(actx, discr, 3)

    assert len(flags) == discr.mesh.nelements

    flags = flags.astype(bool)
    nodes_flags_template = discr.zeros(actx)
    nodes_flags = []
    for grp in discr.groups:
        meg = grp.mesh_el_group
        nodes_flags_grp = actx.to_numpy(nodes_flags_template[grp.index])
        nodes_flags_grp[flags[meg.element_nr_base:meg.nelements +
                              meg.element_nr_base]] = 1
        nodes_flags.append(actx.from_numpy(nodes_flags_grp))

    nodes_flags = DOFArray(actx, tuple(nodes_flags))

    vis_data = [
        ("refine_flags", nodes_flags),
    ]

    if 0:
        from pytential import sym, bind
        bdry_normals = bind(discr, sym.normal(
            discr.ambient_dim))(actx).as_vector(dtype=object)
        vis_data.append(("bdry_normals", bdry_normals), )

    vis.write_vtk_file(f"refinement-{stage_name}-{niter:03d}.vtu", vis_data)
Beispiel #11
0
    def visualize_refinement(niter, stage_nr, stage_name, flags):
        if not visualize:
            return

        if stage_nr == 1:
            discr = lpot_source.density_discr
        elif stage_nr == 2:
            discr = lpot_source.stage2_density_discr
        else:
            raise ValueError("unexpected stage number")

        flags = flags.get()
        logger.info("for stage %s: splitting %d/%d stage-%d elements",
                    stage_name, np.sum(flags), discr.mesh.nelements, stage_nr)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(wrangler.queue, discr, 3)

        assert len(flags) == discr.mesh.nelements

        flags = flags.astype(np.bool)
        nodes_flags = np.zeros(discr.nnodes)
        for grp in discr.groups:
            meg = grp.mesh_el_group
            grp.view(nodes_flags)[flags[meg.element_nr_base:meg.nelements +
                                        meg.element_nr_base]] = 1

        nodes_flags = cl.array.to_device(wrangler.queue, nodes_flags)
        vis_data = [
            ("refine_flags", nodes_flags),
        ]

        if 0:
            from pytential import sym, bind
            bdry_normals = bind(discr, sym.normal(discr.ambient_dim))(
                wrangler.queue).as_vector(dtype=object)
            vis_data.append(("bdry_normals", bdry_normals), )

        vis.write_vtk_file("refinement-%s-%03d.vtu" % (stage_name, niter),
                           vis_data)
Beispiel #12
0
    def visualize_refinement(niter, stage_nr, stage_name, flags):
        if not visualize:
            return

        if stage_nr == 1:
            discr = lpot_source.density_discr
        elif stage_nr == 2:
            discr = lpot_source.stage2_density_discr
        else:
            raise ValueError("unexpected stage number")

        flags = flags.get()
        logger.info("for stage %s: splitting %d/%d stage-%d elements",
                stage_name, np.sum(flags), discr.mesh.nelements, stage_nr)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(wrangler.queue, discr, 3)

        assert len(flags) == discr.mesh.nelements

        flags = flags.astype(np.bool)
        nodes_flags = np.zeros(discr.nnodes)
        for grp in discr.groups:
            meg = grp.mesh_el_group
            grp.view(nodes_flags)[
                    flags[meg.element_nr_base:meg.nelements+meg.element_nr_base]] = 1

        nodes_flags = cl.array.to_device(wrangler.queue, nodes_flags)
        vis_data = [
            ("refine_flags", nodes_flags),
            ]

        if 0:
            from pytential import sym, bind
            bdry_normals = bind(discr, sym.normal(discr.ambient_dim))(
                    wrangler.queue).as_vector(dtype=object)
            vis_data.append(("bdry_normals", bdry_normals),)

        vis.write_vtk_file("refinement-%s-%03d.vtu" % (stage_name, niter), vis_data)
Beispiel #13
0
if isinstance(kernel, HelmholtzKernel):
    sigma = sigma.astype(np.complex128)

bound_bdry_op = bind(qbx, op)
#mlab.figure(bgcolor=(1, 1, 1))
if 1:
    fplot = FieldPlotter(bbox_center, extent=1.5*bbox_size, npoints=150)

    from pytential.target import PointsTarget
    fld_in_vol = bind(
            (qbx, PointsTarget(fplot.points)),
            op)(queue, sigma=sigma, k=k).get()

    #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5)
    fplot.write_vtk_file(
            "potential.vts",
            [
                ("potential", fld_in_vol)
                ]
            )

    bdry_normals = bind(density_discr, sym.normal())(queue).as_vector(dtype=object)

    from meshmode.discretization.visualization import make_visualizer
    bdry_vis = make_visualizer(queue, density_discr, target_order)

    bdry_vis.write_vtk_file("source.vtu", [
        ("sigma", sigma),
        ("bdry_normals", bdry_normals),
        ])
Beispiel #14
0
 def targets_from_sources(sign, dist):
     from pytential import sym, bind
     dim = 2
     nodes = bind(lpot_source.density_discr, sym.nodes(dim))(queue)
     normals = bind(lpot_source.density_discr, sym.normal(dim))(queue)
     return (nodes + normals * sign * dist).as_vector(np.object)
Beispiel #15
0
                                              pde_test_repr.h, case.k)
        ]
        print("Maxwell residuals:", maxwell_residuals)

        eoc_rec_repr_maxwell.add_data_point(h_max, max(maxwell_residuals))

        # }}}

        # {{{ check PEC BC on total field

        bc_repr = EHField(
            mfie.scattered_volume_field(jt_sym,
                                        rho_sym,
                                        qbx_forced_limit=loc_sign))
        pec_bc_e = sym.n_cross(bc_repr.e + inc_xyz_sym.e)
        pec_bc_h = sym.normal(3).as_vector().dot(bc_repr.h + inc_xyz_sym.h)

        eh_bc_values = bind(qbx, sym.join_fields(pec_bc_e, pec_bc_h))(
            queue, jt=jt, rho=rho, inc_fld=inc_field_scat.field, **knl_kwargs)

        def scat_norm(f):
            return norm(qbx, queue, f, p=np.inf)

        e_bc_residual = scat_norm(eh_bc_values[:3]) / scat_norm(
            inc_field_scat.e)
        h_bc_residual = scat_norm(eh_bc_values[3]) / scat_norm(
            inc_field_scat.h)

        print("E/H PEC BC residuals:", h_max, e_bc_residual, h_bc_residual)

        eoc_pec_bc.add_data_point(h_max, max(e_bc_residual, h_bc_residual))
Beispiel #16
0
def main(mesh_name="ellipsoid"):
    import logging
    logger = logging.getLogger(__name__)
    logging.basicConfig(level=logging.WARNING)  # INFO for more progress info

    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    if mesh_name == "ellipsoid":
        cad_file_name = "geometries/ellipsoid.step"
        h = 0.6
    elif mesh_name == "two-cylinders":
        cad_file_name = "geometries/two-cylinders-smooth.step"
        h = 0.4
    else:
        raise ValueError("unknown mesh name: %s" % mesh_name)

    from meshmode.mesh.io import generate_gmsh, FileSource
    mesh = generate_gmsh(
        FileSource(cad_file_name),
        2,
        order=2,
        other_options=["-string",
                       "Mesh.CharacteristicLengthMax = %g;" % h],
        target_unit="MM")

    from meshmode.mesh.processing import perform_flips
    # Flip elements--gmsh generates inside-out geometry.
    mesh = perform_flips(mesh, np.ones(mesh.nelements))

    from meshmode.mesh.processing import find_bounding_box
    bbox_min, bbox_max = find_bounding_box(mesh)
    bbox_center = 0.5 * (bbox_min + bbox_max)
    bbox_size = max(bbox_max - bbox_min) / 2

    logger.info("%d elements" % mesh.nelements)

    from pytential.qbx import QBXLayerPotentialSource
    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory

    density_discr = Discretization(
        actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order))

    qbx = QBXLayerPotentialSource(density_discr,
                                  4 * target_order,
                                  qbx_order,
                                  fmm_order=qbx_order + 3,
                                  target_association_tolerance=0.15)

    from pytential.target import PointsTarget
    fplot = FieldPlotter(bbox_center, extent=3.5 * bbox_size, npoints=150)

    from pytential import GeometryCollection
    places = GeometryCollection(
        {
            "qbx": qbx,
            "targets": PointsTarget(fplot.points)
        }, auto_where="qbx")
    density_discr = places.get_discretization("qbx")

    nodes = thaw(actx, density_discr.nodes())
    angle = actx.np.arctan2(nodes[1], nodes[0])

    if k:
        kernel = HelmholtzKernel(3)
    else:
        kernel = LaplaceKernel(3)

    #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None))
    op = sym.D(kernel, sym.var("sigma"), qbx_forced_limit=None)
    #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None)

    sigma = actx.np.cos(mode_nr * angle)
    if 0:
        from meshmode.dof_array import flatten, unflatten
        sigma = flatten(0 * angle)
        from random import randrange
        for i in range(5):
            sigma[randrange(len(sigma))] = 1
        sigma = unflatten(actx, density_discr, sigma)

    if isinstance(kernel, HelmholtzKernel):
        for i, elem in np.ndenumerate(sigma):
            sigma[i] = elem.astype(np.complex128)

    fld_in_vol = actx.to_numpy(
        bind(places, op, auto_where=("qbx", "targets"))(actx, sigma=sigma,
                                                        k=k))

    #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5)
    fplot.write_vtk_file("layerpot-3d-potential.vts",
                         [("potential", fld_in_vol)])

    bdry_normals = bind(places, sym.normal(
        density_discr.ambient_dim))(actx).as_vector(dtype=object)

    from meshmode.discretization.visualization import make_visualizer
    bdry_vis = make_visualizer(actx, density_discr, target_order)
    bdry_vis.write_vtk_file("layerpot-3d-density.vtu", [
        ("sigma", sigma),
        ("bdry_normals", bdry_normals),
    ])
Beispiel #17
0
def main(nelements):
    import logging
    logging.basicConfig(level=logging.INFO)

    def get_obj_array(obj_array):
        from pytools.obj_array import make_obj_array
        return make_obj_array([
                ary.get()
                for ary in obj_array
                ])

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

    from meshmode.mesh.generation import (  # noqa
            make_curve_mesh, starfish, ellipse, drop)
    mesh = make_curve_mesh(
            lambda t: starfish(t),
            np.linspace(0, 1, nelements+1),
            target_order)
    coarse_density_discr = Discretization(
            cl_ctx, mesh,
            InterpolatoryQuadratureSimplexGroupFactory(target_order))

    from pytential.qbx import QBXLayerPotentialSource
    target_association_tolerance = 0.05
    qbx, _ = QBXLayerPotentialSource(
            coarse_density_discr, fine_order=ovsmp_target_order, qbx_order=qbx_order,
            fmm_order=fmm_order,
            target_association_tolerance=target_association_tolerance,
            ).with_refinement()

    density_discr = qbx.density_discr
    nodes = density_discr.nodes().with_queue(queue)

    # Get normal vectors for the density discretization -- used in integration with stresslet
    mv_normal = bind(density_discr, sym.normal(2))(queue)
    normal = mv_normal.as_vector(np.object)


    # {{{ describe bvp

    from sumpy.kernel import LaplaceKernel
    from pytential.symbolic.stokes import StressletWrapper
    from pytools.obj_array import make_obj_array
    dim=2
    cse = sym.cse

    nvec_sym = sym.make_sym_vector("normal", dim)
    sigma_sym = sym.make_sym_vector("sigma", dim)
    mu_sym = sym.var("mu")
    sqrt_w = sym.sqrt_jac_q_weight(2)
    inv_sqrt_w_sigma = cse(sigma_sym/sqrt_w)

    # -1 for interior Dirichlet
    # +1 for exterior Dirichlet
    loc_sign = -1

    # Create stresslet object
    stresslet_obj = StressletWrapper(dim=2)

    # Describe boundary operator
    bdry_op_sym = loc_sign * 0.5 * sigma_sym + sqrt_w * stresslet_obj.apply(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit='avg')

    # Bind to the qbx discretization
    bound_op = bind(qbx, bdry_op_sym)

    # }}}


    # {{{ fix rhs and solve

    def fund_soln(x, y, loc):
        #with direction (1,0) for point source
        r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2)
        scaling = 1./(4*np.pi*mu)
        xcomp = (-cl.clmath.log(r) + (x - loc[0])**2/r**2) * scaling
        ycomp = ((x - loc[0])*(y - loc[1])/r**2) * scaling
        return [ xcomp, ycomp ]

    def couette_soln(x, y, dp, h):
        scaling = 1./(2*mu)
        xcomp = scaling * dp * ((y+(h/2.))**2 - h * (y+(h/2.)))
        ycomp = scaling * 0*y
        return [xcomp, ycomp]



    if soln_type == 'fundamental':
        pt_loc = np.array([2.0, 0.0])
        bc = fund_soln(nodes[0], nodes[1], pt_loc)
    else:
        dp = -10.
        h = 2.5
        bc = couette_soln(nodes[0], nodes[1], dp, h)

    # Get rhs vector
    bvp_rhs = bind(qbx, sqrt_w*sym.make_sym_vector("bc",dim))(queue, bc=bc)

    from pytential.solve import gmres
    gmres_result = gmres(
             bound_op.scipy_op(queue, "sigma", np.float64, mu=mu, normal=normal),
             bvp_rhs, tol=1e-9, progress=True,
             stall_iterations=0,
             hard_failure=True)

    # }}}

    # {{{ postprocess/visualize
    sigma = gmres_result.solution

    # Describe representation of solution for evaluation in domain
    representation_sym = stresslet_obj.apply(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2)

    from sumpy.visualization import FieldPlotter
    nsamp = 10
    eval_points_1d = np.linspace(-1., 1., nsamp)
    eval_points = np.zeros((2, len(eval_points_1d)**2))
    eval_points[0,:] = np.tile(eval_points_1d, len(eval_points_1d))
    eval_points[1,:] = np.repeat(eval_points_1d, len(eval_points_1d))


    gamma_sym = sym.var("gamma")
    inv_sqrt_w_gamma = cse(gamma_sym/sqrt_w)
    constant_laplace_rep = sym.D(LaplaceKernel(dim=2), inv_sqrt_w_gamma, qbx_forced_limit=None)
    sqrt_w_vec = bind(qbx, sqrt_w)(queue)

    def general_mask(test_points):
        const_density = bind((qbx, PointsTarget(test_points)), constant_laplace_rep)(queue, gamma=sqrt_w_vec).get()
        return (abs(const_density) > 0.1)

    def inside_domain(test_points):
        mask = general_mask(test_points)
        return np.array([
            row[mask]
            for row in test_points])

    def stride_hack(arr):
        from numpy.lib.stride_tricks import as_strided
        return np.array(as_strided(arr, strides=(8 * len(arr[0]), 8)))

    eval_points = inside_domain(eval_points)
    eval_points_dev = cl.array.to_device(queue, eval_points)

    # Evaluate the solution at the evaluation points
    vel = bind(
            (qbx, PointsTarget(eval_points_dev)),
            representation_sym)(queue, sigma=sigma, mu=mu, normal=normal)
    print("@@@@@@@@")
    vel = get_obj_array(vel)


    if soln_type == 'fundamental':
        exact_soln = fund_soln(eval_points_dev[0], eval_points_dev[1], pt_loc)
    else:
        exact_soln = couette_soln(eval_points_dev[0], eval_points_dev[1], dp, h)
    err = vel - get_obj_array(exact_soln)

    print("@@@@@@@@")

    print("L2 error estimate: ", np.sqrt((2./(nsamp-1))**2*np.sum(err[0]*err[0]) + (2./(nsamp-1))**2*np.sum(err[1]*err[1])))
    max_error_loc = [abs(err[0]).argmax(), abs(err[1]).argmax()]
    print("max error at sampled points: ", max(abs(err[0])), max(abs(err[1])))
    print("exact velocity at max error points: x -> ", err[0][max_error_loc[0]], ", y -> ", err[1][max_error_loc[1]])

    from pytential.symbolic.mappers import DerivativeTaker
    rep_pressure = stresslet_obj.apply_pressure(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2)
    pressure = bind((qbx, PointsTarget(eval_points_dev)),
                     rep_pressure)(queue, sigma=sigma, mu=mu, normal=normal)
    pressure = pressure.get()
    print "pressure = ", pressure

    x_dir_vecs = np.zeros((2,len(eval_points[0])))
    x_dir_vecs[0,:] = 1.0
    y_dir_vecs = np.zeros((2, len(eval_points[0])))
    y_dir_vecs[1,:] = 1.0
    x_dir_vecs = cl.array.to_device(queue, x_dir_vecs)
    y_dir_vecs = cl.array.to_device(queue, y_dir_vecs)
    dir_vec_sym = sym.make_sym_vector("force_direction", dim)
    rep_stress = stresslet_obj.apply_stress(inv_sqrt_w_sigma, nvec_sym, dir_vec_sym, mu_sym, qbx_forced_limit=-2)

    applied_stress_x = bind((qbx, PointsTarget(eval_points_dev)),
                             rep_stress)(queue, sigma=sigma, normal=normal, force_direction=x_dir_vecs, mu=mu)
    applied_stress_x = get_obj_array(applied_stress_x)
    applied_stress_y = bind((qbx, PointsTarget(eval_points_dev)),
                             rep_stress)(queue, sigma=sigma, normal=normal, force_direction=y_dir_vecs, mu=mu)
    applied_stress_y = get_obj_array(applied_stress_y)

    print "stress applied to x direction: ", applied_stress_x
    print "stress applied to y direction: ", applied_stress_y


    import matplotlib.pyplot as plt
    plt.quiver(eval_points[0], eval_points[1], vel[0], vel[1], linewidth=0.1)
    file_name = "field-n%s.pdf"%(nelements)
    plt.savefig(file_name)

    return (max(abs(err[0])), max(abs(err[1])))
Beispiel #18
0
    def operator(self, unknown):
        result = np.zeros(4 * len(self.interfaces), dtype=object)

        unk_idx = self.unknown_index

        for i in range(len(self.interfaces)):
            idx_jt = unk_idx["jz", i]
            idx_jz = unk_idx["jt", i]
            idx_mt = unk_idx["mz", i]
            idx_mz = unk_idx["mt", i]

            phi1 = unknown[idx_jt]
            phi2 = unknown[idx_jz]
            phi3 = unknown[idx_mt]
            phi4 = unknown[idx_mz]

            ne = self.ne

            dom0i, dom1i, where = self.interfaces[i]

            tangent = self.tangent(where)
            normal = sym.cse(sym.normal(2, 1, where), "normal")

            S = self.S  # noqa
            D = self.D  # noqa
            T = self.T  # noqa

            def Tt(where, dom, density):  # noqa
                return sym.tangential_derivative(2, T(where, dom,
                                                      density)).xproject(0)

            def Sn(dom, density):  # noqa
                return sym.normal_derivative(
                    2, S(dom, density, qbx_forced_limit="avg"))

            def St(dom, density):  # noqa
                return sym.tangential_derivative(2, S(dom,
                                                      density)).xproject(0)

            n0 = self.domain_n_exprs[dom0i]
            n1 = self.domain_n_exprs[dom1i]

            a11 = sym.cse(n0**2 * D(dom0i, phi1) - n1**2 * D(dom1i, phi1),
                          "a11")
            a22 = sym.cse(-n0**2 * Sn(dom0i, phi2) + n1**2 * Sn(dom1i, phi2),
                          "a22")
            a33 = sym.cse(D(dom0i, phi3) - D(dom1i, phi3), "a33")
            a44 = sym.cse(-Sn(dom0i, phi4) + Sn(dom1i, phi4), "a44")

            a21 = sym.cse(
                -1j * ne *
                (n0**2 * tangent.scalar_product(S(dom0i, normal * phi1)) -
                 n1**2 * tangent.scalar_product(S(dom1i, normal * phi1))),
                "a21")

            a43 = sym.cse(
                -1j * ne * (tangent.scalar_product(S(dom0i, normal * phi3)) -
                            tangent.scalar_product(S(dom1i, normal * phi3))),
                "a43")

            a13 = +1 * sym.cse(
                ne * (T(where, dom0i, phi3) - T(where, dom1i, phi3)), "a13")
            a31 = -1 * sym.cse(
                ne * (T(where, dom0i, phi1) - T(where, dom1i, phi1)), "a31")

            a24 = +1 * sym.cse(ne * (St(dom0i, phi4) - St(dom1i, phi4)), "a24")
            a42 = -1 * sym.cse(ne * (St(dom0i, phi2) - St(dom1i, phi2)), "a42")

            a14 = sym.cse(
                1j * ((n0**2 - ne**2) * S(dom0i, phi4) -
                      (n1**2 - ne**2) * S(dom1i, phi4)), "a14")
            a32 = -sym.cse(
                1j * ((n0**2 - ne**2) * S(dom0i, phi2) -
                      (n1**2 - ne**2) * S(dom1i, phi2)), "a32")

            def a23_expr(phi):
                return (
                    1j * (Tt(where, dom0i, phi) - Tt(where, dom1i, phi)) - 1j *
                    (n0**2 * tangent.scalar_product(S(dom0i, tangent * phi)) -
                     n1**2 * tangent.scalar_product(S(dom1i, tangent * phi))))

            a23 = +1 * sym.cse(a23_expr(phi3), "a23")
            a41 = -1 * sym.cse(a23_expr(phi1), "a41")

            d1 = (n0**2 + n1**2) / 2 * phi1
            d2 = (n0**2 + n1**2) / 2 * phi2
            d3 = phi3
            d4 = phi4

            result[idx_jt] += d1 + a11 + 000 + a13 + a14
            result[idx_jz] += d2 + a21 + a22 + a23 + a24
            result[idx_mt] += d3 + a31 + a32 + a33 + 0
            result[idx_mz] += d4 + a41 + a42 + a43 + a44

            # TODO: L2 weighting
            # TODO: Add representation contributions to other boundaries
            # abutting the domain
            return result
Beispiel #19
0
def test_sanity_single_element(ctx_getter, dim, order, visualize=False):
    pytest.importorskip("pytential")

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

    from modepy.tools import unit_vertices
    vertices = unit_vertices(dim).T.copy()

    center = np.empty(dim, np.float64)
    center.fill(-0.5)

    import modepy as mp
    from meshmode.mesh import SimplexElementGroup, Mesh, BTAG_ALL
    mg = SimplexElementGroup(
        order=order,
        vertex_indices=np.arange(dim + 1, dtype=np.int32).reshape(1, -1),
        nodes=mp.warp_and_blend_nodes(dim, order).reshape(dim, 1, -1),
        dim=dim)

    mesh = Mesh(vertices, [mg],
                nodal_adjacency=None,
                facial_adjacency_groups=None)

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            PolynomialWarpAndBlendGroupFactory
    vol_discr = Discretization(cl_ctx, mesh,
                               PolynomialWarpAndBlendGroupFactory(order + 3))

    # {{{ volume calculation check

    vol_x = vol_discr.nodes().with_queue(queue)

    vol_one = vol_x[0].copy()
    vol_one.fill(1)
    from pytential import norm, integral  # noqa

    from pytools import factorial
    true_vol = 1 / factorial(dim) * 2**dim

    comp_vol = integral(vol_discr, queue, vol_one)
    rel_vol_err = abs(true_vol - comp_vol) / true_vol

    assert rel_vol_err < 1e-12

    # }}}

    # {{{ boundary discretization

    from meshmode.discretization.connection import make_face_restriction
    bdry_connection = make_face_restriction(
        vol_discr, PolynomialWarpAndBlendGroupFactory(order + 3), BTAG_ALL)
    bdry_discr = bdry_connection.to_discr

    # }}}

    # {{{ visualizers

    from meshmode.discretization.visualization import make_visualizer
    #vol_vis = make_visualizer(queue, vol_discr, 4)
    bdry_vis = make_visualizer(queue, bdry_discr, 4)

    # }}}

    from pytential import bind, sym
    bdry_normals = bind(bdry_discr,
                        sym.normal(dim))(queue).as_vector(dtype=object)

    if visualize:
        bdry_vis.write_vtk_file("boundary.vtu",
                                [("bdry_normals", bdry_normals)])

    from pytential import bind, sym
    normal_outward_check = bind(
        bdry_discr,
        sym.normal(dim)
        | (sym.nodes(dim) + 0.5 * sym.ones_vec(dim)),
    )(queue).as_scalar() > 0

    assert normal_outward_check.get().all(), normal_outward_check.get()
Beispiel #20
0
def test_sanity_single_element(actx_factory,
                               dim,
                               mesh_order,
                               group_cls,
                               visualize=False):
    pytest.importorskip("pytential")
    actx = actx_factory()

    if group_cls is SimplexElementGroup:
        group_factory = PolynomialWarpAndBlendGroupFactory(mesh_order + 3)
    elif group_cls is TensorProductElementGroup:
        group_factory = LegendreGaussLobattoTensorProductGroupFactory(
            mesh_order + 3)
    else:
        raise TypeError

    import modepy as mp
    shape = group_cls._modepy_shape_cls(dim)
    space = mp.space_for_shape(shape, mesh_order)

    vertices = mp.unit_vertices_for_shape(shape)
    nodes = mp.edge_clustered_nodes_for_space(space, shape).reshape(dim, 1, -1)
    vertex_indices = np.arange(shape.nvertices, dtype=np.int32).reshape(1, -1)

    center = np.empty(dim, np.float64)
    center.fill(-0.5)

    mg = group_cls(mesh_order, vertex_indices, nodes, dim=dim)
    mesh = Mesh(vertices, [mg], is_conforming=True)

    from meshmode.discretization import Discretization
    vol_discr = Discretization(actx, mesh, group_factory)

    # {{{ volume calculation check

    if isinstance(mg, SimplexElementGroup):
        from pytools import factorial
        true_vol = 1 / factorial(dim) * 2**dim
    elif isinstance(mg, TensorProductElementGroup):
        true_vol = 2**dim
    else:
        raise TypeError

    nodes = thaw(vol_discr.nodes(), actx)
    vol_one = 1 + 0 * nodes[0]

    from pytential import norm, integral  # noqa
    comp_vol = integral(vol_discr, vol_one)
    rel_vol_err = abs(true_vol - comp_vol) / true_vol

    assert rel_vol_err < 1e-12

    # }}}

    # {{{ boundary discretization

    from meshmode.discretization.connection import make_face_restriction
    bdry_connection = make_face_restriction(actx, vol_discr, group_factory,
                                            BTAG_ALL)
    bdry_discr = bdry_connection.to_discr

    # }}}

    from pytential import bind, sym
    bdry_normals = bind(bdry_discr, sym.normal(dim).as_vector())(actx)

    if visualize:
        from meshmode.discretization.visualization import make_visualizer
        bdry_vis = make_visualizer(actx, bdry_discr, 4)

        bdry_vis.write_vtk_file("sanity_single_element_boundary.vtu",
                                [("normals", bdry_normals)])

    normal_outward_check = bind(
        bdry_discr,
        sym.normal(dim)
        | (sym.nodes(dim) + 0.5 * sym.ones_vec(dim)),
    )(actx).as_scalar()

    normal_outward_check = flatten_to_numpy(actx, normal_outward_check > 0)
    assert normal_outward_check.all(), normal_outward_check
Beispiel #21
0
def test_3d_jump_relations(ctx_factory, relation, visualize=False):
    # logging.basicConfig(level=logging.INFO)

    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    if relation == "div_s":
        target_order = 3
    else:
        target_order = 4

    qbx_order = target_order

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for nel_factor in [6, 10, 14]:
        from meshmode.mesh.generation import generate_torus
        mesh = generate_torus(
                5, 2, order=target_order,
                n_major=2*nel_factor, n_minor=nel_factor)

        from meshmode.discretization import Discretization
        from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory
        pre_discr = Discretization(
                actx, mesh,
                InterpolatoryQuadratureSimplexGroupFactory(3))

        from pytential.qbx import QBXLayerPotentialSource
        qbx = QBXLayerPotentialSource(
                pre_discr, fine_order=4*target_order,
                qbx_order=qbx_order,
                fmm_order=qbx_order + 5,
                fmm_backend="fmmlib"
                )

        places = GeometryCollection(qbx)
        density_discr = places.get_discretization(places.auto_source.geometry)

        from sumpy.kernel import LaplaceKernel
        knl = LaplaceKernel(3)

        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)))

        from meshmode.dof_array import thaw
        x, y, z = thaw(actx, density_discr.nodes())
        m = actx.np

        if relation == "nxcurls":
            density_sym = sym.make_sym_vector("density", 2)

            jump_identity_sym = (
                    nxcurlS(+1)
                    - (nxcurlS("avg") + 0.5*sym.tangential_to_xyz(density_sym)))

            # The tangential coordinate system is element-local, so we can't just
            # conjure up some globally smooth functions, interpret their values
            # in the tangential coordinate system, and be done. Instead, generate
            # an XYZ function and project it.
            density = bind(places,
                    sym.xyz_to_tangential(sym.make_sym_vector("jxyz", 3)))(
                            actx,
                            jxyz=sym.make_obj_array([
                                m.cos(0.5*x) * m.cos(0.5*y) * m.cos(0.5*z),
                                m.sin(0.5*x) * m.cos(0.5*y) * m.sin(0.5*z),
                                m.sin(0.5*x) * m.cos(0.5*y) * m.cos(0.5*z),
                                ]))

        elif relation == "sp":

            density = m.cos(2*x) * m.cos(2*y) * m.cos(z)
            density_sym = sym.var("density")

            jump_identity_sym = (
                    sym.Sp(knl, density_sym, qbx_forced_limit=+1)
                    - (sym.Sp(knl, density_sym, qbx_forced_limit="avg")
                        - 0.5*density_sym))

        elif relation == "div_s":

            density = m.cos(2*x) * m.cos(2*y) * m.cos(z)
            density_sym = sym.var("density")

            jump_identity_sym = (
                    sym.div(sym.S(knl, sym.normal(3).as_vector()*density_sym,
                        qbx_forced_limit="avg"))
                    + sym.D(knl, density_sym, qbx_forced_limit="avg"))

        else:
            raise ValueError("unexpected value of 'relation': %s" % relation)

        bound_jump_identity = bind(places, jump_identity_sym)
        jump_identity = bound_jump_identity(actx, density=density)

        h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx)
        err = (
                norm(density_discr, jump_identity, np.inf)
                / norm(density_discr, density, np.inf))
        print("ERROR", h_max, err)

        eoc_rec.add_data_point(h_max, err)

        # {{{ visualization

        if visualize and relation == "nxcurls":
            nxcurlS_ext = bind(places, nxcurlS(+1))(actx, density=density)
            nxcurlS_avg = bind(places, nxcurlS("avg"))(actx, density=density)
            jtxyz = bind(places, sym.tangential_to_xyz(density_sym))(
                    actx, density=density)

            from meshmode.discretization.visualization import make_visualizer
            bdry_vis = make_visualizer(actx, qbx.density_discr, target_order+3)

            bdry_normals = bind(places, sym.normal(3))(actx)\
                    .as_vector(dtype=object)

            bdry_vis.write_vtk_file("source-%s.vtu" % nel_factor, [
                ("jt", jtxyz),
                ("nxcurlS_ext", nxcurlS_ext),
                ("nxcurlS_avg", nxcurlS_avg),
                ("bdry_normals", bdry_normals),
                ])

        if visualize and relation == "sp":
            op = sym.Sp(knl, density_sym, qbx_forced_limit=+1)
            sp_ext = bind(places, op)(actx, density=density)
            op = sym.Sp(knl, density_sym, qbx_forced_limit="avg")
            sp_avg = bind(places, op)(actx, density=density)

            from meshmode.discretization.visualization import make_visualizer
            bdry_vis = make_visualizer(actx, qbx.density_discr, target_order+3)

            bdry_normals = bind(places,
                    sym.normal(3))(actx).as_vector(dtype=object)

            bdry_vis.write_vtk_file("source-%s.vtu" % nel_factor, [
                ("density", density),
                ("sp_ext", sp_ext),
                ("sp_avg", sp_avg),
                ("bdry_normals", bdry_normals),
                ])

        # }}}

    print(eoc_rec)

    assert eoc_rec.order_estimate() >= qbx_order - 1.5
Beispiel #22
0
def test_sanity_balls(ctx_getter, src_file, dim, mesh_order,
        visualize=False):
    pytest.importorskip("pytential")

    logging.basicConfig(level=logging.INFO)

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

    from pytools.convergence import EOCRecorder
    vol_eoc_rec = EOCRecorder()
    surf_eoc_rec = EOCRecorder()

    # overkill
    quad_order = mesh_order

    from pytential import bind, sym

    for h in [0.2, 0.14, 0.1]:
        from meshmode.mesh.io import generate_gmsh, FileSource
        mesh = generate_gmsh(
                FileSource(src_file), dim, order=mesh_order,
                other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h],
                force_ambient_dim=dim)

        logger.info("%d elements" % mesh.nelements)

        # {{{ discretizations and connections

        from meshmode.discretization import Discretization
        from meshmode.discretization.poly_element import \
                InterpolatoryQuadratureSimplexGroupFactory
        vol_discr = Discretization(ctx, mesh,
                InterpolatoryQuadratureSimplexGroupFactory(quad_order))

        from meshmode.discretization.connection import make_boundary_restriction
        bdry_mesh, bdry_discr, bdry_connection = make_boundary_restriction(
                queue, vol_discr,
                InterpolatoryQuadratureSimplexGroupFactory(quad_order))

        # }}}

        # {{{ visualizers

        from meshmode.discretization.visualization import make_visualizer
        vol_vis = make_visualizer(queue, vol_discr, 20)
        bdry_vis = make_visualizer(queue, bdry_discr, 20)

        # }}}

        from math import gamma
        true_surf = 2*np.pi**(dim/2)/gamma(dim/2)
        true_vol = true_surf/dim

        vol_x = vol_discr.nodes().with_queue(queue)

        vol_one = vol_x[0].copy()
        vol_one.fill(1)
        from pytential import norm, integral  # noqa

        comp_vol = integral(vol_discr, queue, vol_one)
        rel_vol_err = abs(true_vol - comp_vol) / true_vol
        vol_eoc_rec.add_data_point(h, rel_vol_err)
        print("VOL", true_vol, comp_vol)

        bdry_x = bdry_discr.nodes().with_queue(queue)

        bdry_one_exact = bdry_x[0].copy()
        bdry_one_exact.fill(1)

        bdry_one = bdry_connection(queue, vol_one).with_queue(queue)
        intp_err = norm(bdry_discr, queue, bdry_one-bdry_one_exact)
        assert intp_err < 1e-14

        comp_surf = integral(bdry_discr, queue, bdry_one)
        rel_surf_err = abs(true_surf - comp_surf) / true_surf
        surf_eoc_rec.add_data_point(h, rel_surf_err)
        print("SURF", true_surf, comp_surf)

        if visualize:
            vol_vis.write_vtk_file("volume-h=%g.vtu" % h, [
                ("f", vol_one),
                ("area_el", bind(vol_discr, sym.area_element())(queue)),
                ])
            bdry_vis.write_vtk_file("boundary-h=%g.vtu" % h, [("f", bdry_one)])

        # {{{ check normals point outward

        normal_outward_check = bind(bdry_discr,
                sym.normal() | sym.Nodes(),
                )(queue).as_scalar() > 0

        assert normal_outward_check.get().all(), normal_outward_check.get()

        # }}}

    print("---------------------------------")
    print("VOLUME")
    print("---------------------------------")
    print(vol_eoc_rec)
    assert vol_eoc_rec.order_estimate() >= mesh_order

    print("---------------------------------")
    print("SURFACE")
    print("---------------------------------")
    print(surf_eoc_rec)
    assert surf_eoc_rec.order_estimate() >= mesh_order
Beispiel #23
0
    def center_info(self):
        """Return a :class:`CenterInfo`. |cached|

        """
        self_discr = self.lpot_source.density_discr

        ncenters = 0
        for el_group in self_discr.groups:
            kept_indices = self.kept_center_indices(el_group)
            # two: one for positive side, one for negative side
            ncenters += 2 * len(kept_indices) * el_group.nelements

        from pytential import sym, bind
        from pytools.obj_array import make_obj_array
        with cl.CommandQueue(self.cl_context) as queue:
            radii_sym = sym.cse(2*sym.area_element(), "radii")
            all_radii, all_pos_centers, all_neg_centers = bind(self_discr,
                    make_obj_array([
                        radii_sym,
                        sym.Nodes() + radii_sym*sym.normal(),
                        sym.Nodes() - radii_sym*sym.normal()
                        ]))(queue)

            # The centers are returned from the above as multivectors.
            all_pos_centers = all_pos_centers.as_vector(np.object)
            all_neg_centers = all_neg_centers.as_vector(np.object)

            # -1 for inside, +1 for outside
            sides = cl.array.empty(
                    self.cl_context, ncenters, np.int8)
            radii = cl.array.empty(
                    self.cl_context, ncenters, self.coord_dtype)
            centers = make_obj_array([
                cl.array.empty(self.cl_context, ncenters,
                    self.coord_dtype)
                for i in range(self_discr.ambient_dim)])

            ibase = 0
            for el_group in self_discr.groups:
                kept_center_indices = self.kept_center_indices(el_group)
                group_len = len(kept_indices) * el_group.nelements

                for side, all_centers in [
                        (+1, all_pos_centers),
                        (-1, all_neg_centers),
                        ]:

                    sides[ibase:ibase + group_len].fill(side, queue=queue)

                    radii_view = radii[ibase:ibase + group_len] \
                            .reshape(el_group.nelements, len(kept_indices))
                    centers_view = make_obj_array([
                        centers_i[ibase:ibase + group_len]
                        .reshape((el_group.nelements, len(kept_indices)))
                        for centers_i in centers
                        ])
                    all_centers_view = make_obj_array([
                        el_group.view(pos_centers_i)
                        for pos_centers_i in all_centers
                        ])
                    self.code_getter.pick_expansion_centers(queue,
                            centers=centers_view,
                            all_centers=all_centers_view,
                            radii=radii_view,
                            all_radii=el_group.view(all_radii),
                            kept_center_indices=kept_center_indices)

                    ibase += group_len

            assert ibase == ncenters

        return CenterInfo(
                sides=sides,
                radii=radii,
                centers=centers).with_queue(None)
            4 * target_order,
            case.qbx_order,
            fmm_order=case.fmm_order,
            fmm_backend=case.fmm_backend,
            _expansions_in_tree_have_extent=True,
            _expansion_stick_out_factor=getattr(case,
                                                "_expansion_stick_out_factor",
                                                0),
        ).with_refinement(**refiner_extra_kwargs)

        density_discr = qbx.density_discr

        # {{{ compute values of a solution to the PDE

        nodes_host = density_discr.nodes().get(queue)
        normal = bind(density_discr, sym.normal(d))(queue).as_vector(np.object)
        normal_host = [normal[j].get() for j in range(d)]

        if k != 0:
            if d == 2:
                angle = 0.3
                wave_vec = np.array([np.cos(angle), np.sin(angle)])
                u = np.exp(1j * k * np.tensordot(wave_vec, nodes_host, axes=1))
                grad_u = 1j * k * wave_vec[:, np.newaxis] * u
            elif d == 3:
                center = np.array([3, 1, 2])
                diff = nodes_host - center[:, np.newaxis]
                r = la.norm(diff, axis=0)
                u = np.exp(1j * k * r) / r
                grad_u = diff * (1j * k * u / r - u / r**2)
            else:
Beispiel #25
0
def get_green_error(geometry_getter,
                    lpot_kwargs,
                    center,
                    k,
                    vis_error_filename=None,
                    vis_order=TARGET_ORDER):
    """Return the Green identity error for a geometry.

    The density function for the Green error is the on-surface restriction of
    the potential due to a source charge in the exterior of the geometry, whose
    location is specified. The error is reported relative to the norm of the
    density.

    Params:

        geometry_getter: Geometry getter
        lpot_kwargs: Constructor args to QBXLayerPotentialSource
        center: Center of source charge used to obtain the constructed density
        k: Helmholtz parameter

    Returns:

        A dictionary containing Green identity errors in l^2 and l^infty norm
    """
    context = cl.create_some_context(interactive=False)
    queue = cl.CommandQueue(context)
    lpot_source = geometry_getter(queue, lpot_kwargs)

    d = lpot_source.ambient_dim

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

    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")}

    S_part = (sym.S(k_sym, dn_u_sym, qbx_forced_limit=-1, **knl_kwargs))

    D_part = (sym.D(k_sym, u_sym, qbx_forced_limit="avg", **knl_kwargs))

    sym_op = S_part - D_part - 0.5 * u_sym

    density_discr = lpot_source.density_discr

    # {{{ compute values of a solution to the PDE

    nodes_host = density_discr.nodes().get(queue)
    normal = bind(density_discr, sym.normal(d))(queue).as_vector(np.object)
    normal_host = [normal[j].get() for j in range(d)]

    if k != 0:
        if d == 2:
            angle = 0.3
            wave_vec = np.array([np.cos(angle), np.sin(angle)])
            u = np.exp(1j * k * np.tensordot(wave_vec, nodes_host, axes=1))
            grad_u = 1j * k * wave_vec[:, np.newaxis] * u
        else:
            diff = nodes_host - center[:, np.newaxis]
            r = la.norm(diff, axis=0)
            u = np.exp(1j * k * r) / r
            grad_u = diff * (1j * k * u / r - u / r**2)
    else:
        diff = nodes_host - center[:, np.newaxis]
        dist_squared = np.sum(diff**2, axis=0)
        dist = np.sqrt(dist_squared)
        if d == 2:
            u = np.log(dist)
            grad_u = diff / dist_squared
        elif d == 3:
            u = 1 / dist
            grad_u = -diff / dist**3
        else:
            assert False

    dn_u = 0
    for i in range(d):
        dn_u = dn_u + normal_host[i] * grad_u[i]

    # }}}

    u_dev = cl.array.to_device(queue, u)
    dn_u_dev = cl.array.to_device(queue, dn_u)
    grad_u_dev = cl.array.to_device(queue, grad_u)

    bound_op = bind(lpot_source, sym_op)
    error = bound_op(queue, u=u_dev, dn_u=dn_u_dev, grad_u=grad_u_dev, k=k)

    scaling_l2 = 1 / norm(density_discr, queue, u_dev, p=2)
    scaling_linf = 1 / norm(density_discr, queue, u_dev, p="inf")

    if vis_error_filename is not None:
        from meshmode.discretization.visualization import make_visualizer
        bdry_vis = make_visualizer(queue, lpot_source.density_discr, vis_order)
        bdry_vis.write_vtk_file(vis_error_filename, [
            ("green_zero", error),
            ("u_dev", u_dev),
        ])

    err_l2 = scaling_l2 * norm(density_discr, queue, error, p=2)
    err_linf = scaling_linf * norm(density_discr, queue, error, p="inf")

    return dict(err_l2=err_l2, err_linf=err_linf)
Beispiel #26
0
    def operator(self, unknown):
        result = np.zeros(4*len(self.interfaces), dtype=object)

        unk_idx = self.unknown_index

        for i in range(len(self.interfaces)):
            idx_jt = unk_idx["jz", i]
            idx_jz = unk_idx["jt", i]
            idx_mt = unk_idx["mz", i]
            idx_mz = unk_idx["mt", i]

            phi1 = unknown[idx_jt]
            phi2 = unknown[idx_jz]
            phi3 = unknown[idx_mt]
            phi4 = unknown[idx_mz]

            ne = self.ne

            dom0i, dom1i, where = self.interfaces[i]

            tangent = self.tangent(where)
            normal = sym.cse(
                    sym.normal(2, 1, where),
                    "normal")

            S = self.S  # noqa
            D = self.D  # noqa
            T = self.T  # noqa

            def Tt(where, dom, density):  # noqa
                return sym.tangential_derivative(
                        2, T(where, dom, density)).xproject(0)

            def Sn(dom, density):  # noqa
                return sym.normal_derivative(
                        2,
                        S(dom, density,
                            qbx_forced_limit="avg"))

            def St(dom, density):  # noqa
                return sym.tangential_derivative(2, S(dom, density)).xproject(0)

            n0 = self.domain_n_exprs[dom0i]
            n1 = self.domain_n_exprs[dom1i]

            a11 = sym.cse(n0**2 * D(dom0i, phi1) - n1**2 * D(dom1i, phi1), "a11")
            a22 = sym.cse(-n0**2 * Sn(dom0i, phi2) + n1**2 * Sn(dom1i, phi2), "a22")
            a33 = sym.cse(D(dom0i, phi3)-D(dom1i, phi3), "a33")
            a44 = sym.cse(-Sn(dom0i, phi4) + Sn(dom1i, phi4), "a44")

            a21 = sym.cse(-1j * ne * (
                    n0**2 * tangent.scalar_product(
                        S(dom0i, normal * phi1))
                    - n1**2 * tangent.scalar_product(
                        S(dom1i, normal * phi1))), "a21")

            a43 = sym.cse(-1j * ne * (
                    tangent.scalar_product(
                        S(dom0i, normal * phi3))
                    - tangent.scalar_product(
                        S(dom1i, normal * phi3))), "a43")

            a13 = +1*sym.cse(
                    ne*(T(where, dom0i, phi3) - T(where, dom1i, phi3)), "a13")
            a31 = -1*sym.cse(
                    ne*(T(where, dom0i, phi1) - T(where, dom1i, phi1)), "a31")

            a24 = +1*sym.cse(ne*(St(dom0i, phi4) - St(dom1i, phi4)), "a24")
            a42 = -1*sym.cse(ne*(St(dom0i, phi2) - St(dom1i, phi2)), "a42")

            a14 = sym.cse(1j*(
                    (n0**2 - ne**2) * S(dom0i, phi4)
                    - (n1**2 - ne**2) * S(dom1i, phi4)
                    ), "a14")
            a32 = -sym.cse(1j*(
                    (n0**2 - ne**2) * S(dom0i, phi2)
                    - (n1**2 - ne**2) * S(dom1i, phi2)
                    ), "a32")

            def a23_expr(phi):
                return (
                        1j * (Tt(where, dom0i, phi) - Tt(where, dom1i, phi))
                        - 1j * (
                            n0**2 * tangent.scalar_product(
                                S(dom0i, tangent * phi))
                            - n1**2 * tangent.scalar_product(
                                S(dom1i, tangent * phi))))

            a23 = +1*sym.cse(a23_expr(phi3), "a23")
            a41 = -1*sym.cse(a23_expr(phi1), "a41")

            d1 = (n0**2 + n1**2)/2 * phi1
            d2 = (n0**2 + n1**2)/2 * phi2
            d3 = phi3
            d4 = phi4

            result[idx_jt] += d1 + a11 + 000 + a13 + a14
            result[idx_jz] += d2 + a21 + a22 + a23 + a24
            result[idx_mt] += d3 + a31 + a32 + a33 + 0
            result[idx_mz] += d4 + a41 + a42 + a43 + a44

            # TODO: L2 weighting
            # TODO: Add representation contributions to other boundaries
            # abutting the domain
            return result
Beispiel #27
0
def run_exterior_stokes_2d(ctx_factory,
                           nelements,
                           mesh_order=4,
                           target_order=4,
                           qbx_order=4,
                           fmm_order=10,
                           mu=1,
                           circle_rad=1.5,
                           do_plot=False):

    # This program tests an exterior Stokes flow in 2D using the
    # compound representation given in Hsiao & Kress,
    # ``On an integral equation for the two-dimensional exterior Stokes problem,''
    # Applied Numerical Mathematics 1 (1985).

    logging.basicConfig(level=logging.INFO)

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

    ovsmp_target_order = 4 * target_order

    from meshmode.mesh.generation import (  # noqa
        make_curve_mesh, starfish, ellipse, drop)
    mesh = make_curve_mesh(lambda t: circle_rad * ellipse(1, t),
                           np.linspace(0, 1, nelements + 1), target_order)
    coarse_density_discr = Discretization(
        cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order))

    from pytential.qbx import QBXLayerPotentialSource
    target_association_tolerance = 0.05
    qbx, _ = QBXLayerPotentialSource(
        coarse_density_discr,
        fine_order=ovsmp_target_order,
        qbx_order=qbx_order,
        fmm_order=fmm_order,
        target_association_tolerance=target_association_tolerance,
        _expansions_in_tree_have_extent=True,
    ).with_refinement()

    density_discr = qbx.density_discr
    normal = bind(density_discr, sym.normal(2).as_vector())(queue)
    path_length = bind(density_discr, sym.integral(2, 1, 1))(queue)

    # {{{ describe bvp

    from pytential.symbolic.stokes import StressletWrapper, StokesletWrapper
    dim = 2
    cse = sym.cse

    sigma_sym = sym.make_sym_vector("sigma", dim)
    meanless_sigma_sym = cse(sigma_sym - sym.mean(2, 1, sigma_sym))
    int_sigma = sym.Ones() * sym.integral(2, 1, sigma_sym)

    nvec_sym = sym.make_sym_vector("normal", dim)
    mu_sym = sym.var("mu")

    # -1 for interior Dirichlet
    # +1 for exterior Dirichlet
    loc_sign = 1

    stresslet_obj = StressletWrapper(dim=2)
    stokeslet_obj = StokesletWrapper(dim=2)
    bdry_op_sym = (-loc_sign * 0.5 * sigma_sym - stresslet_obj.apply(
        sigma_sym, nvec_sym, mu_sym, qbx_forced_limit='avg') +
                   stokeslet_obj.apply(
                       meanless_sigma_sym, mu_sym, qbx_forced_limit='avg') -
                   (0.5 / np.pi) * int_sigma)

    # }}}

    bound_op = bind(qbx, bdry_op_sym)

    # {{{ fix rhs and solve

    def fund_soln(x, y, loc, strength):
        #with direction (1,0) for point source
        r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2)
        scaling = strength / (4 * np.pi * mu)
        xcomp = (-cl.clmath.log(r) + (x - loc[0])**2 / r**2) * scaling
        ycomp = ((x - loc[0]) * (y - loc[1]) / r**2) * scaling
        return [xcomp, ycomp]

    def rotlet_soln(x, y, loc):
        r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2)
        xcomp = -(y - loc[1]) / r**2
        ycomp = (x - loc[0]) / r**2
        return [xcomp, ycomp]

    def fund_and_rot_soln(x, y, loc, strength):
        #with direction (1,0) for point source
        r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2)
        scaling = strength / (4 * np.pi * mu)
        xcomp = ((-cl.clmath.log(r) + (x - loc[0])**2 / r**2) * scaling -
                 (y - loc[1]) * strength * 0.125 / r**2 + 3.3)
        ycomp = (((x - loc[0]) * (y - loc[1]) / r**2) * scaling +
                 (x - loc[0]) * strength * 0.125 / r**2 + 1.5)
        return [xcomp, ycomp]

    nodes = density_discr.nodes().with_queue(queue)
    fund_soln_loc = np.array([0.5, -0.2])
    strength = 100.
    bc = fund_and_rot_soln(nodes[0], nodes[1], fund_soln_loc, strength)

    omega_sym = sym.make_sym_vector("omega", dim)
    u_A_sym_bdry = stokeslet_obj.apply(  # noqa: N806
        omega_sym, mu_sym, qbx_forced_limit=1)

    omega = [
        cl.array.to_device(queue,
                           (strength / path_length) * np.ones(len(nodes[0]))),
        cl.array.to_device(queue, np.zeros(len(nodes[0])))
    ]
    bvp_rhs = bind(qbx,
                   sym.make_sym_vector("bc", dim) + u_A_sym_bdry)(queue,
                                                                  bc=bc,
                                                                  mu=mu,
                                                                  omega=omega)
    gmres_result = gmres(bound_op.scipy_op(queue,
                                           "sigma",
                                           np.float64,
                                           mu=mu,
                                           normal=normal),
                         bvp_rhs,
                         x0=bvp_rhs,
                         tol=1e-9,
                         progress=True,
                         stall_iterations=0,
                         hard_failure=True)

    # }}}

    # {{{ postprocess/visualize

    sigma = gmres_result.solution
    sigma_int_val_sym = sym.make_sym_vector("sigma_int_val", 2)
    int_val = bind(qbx, sym.integral(2, 1, sigma_sym))(queue, sigma=sigma)
    int_val = -int_val / (2 * np.pi)
    print("int_val = ", int_val)

    u_A_sym_vol = stokeslet_obj.apply(  # noqa: N806
        omega_sym, mu_sym, qbx_forced_limit=2)
    representation_sym = (
        -stresslet_obj.apply(sigma_sym, nvec_sym, mu_sym, qbx_forced_limit=2) +
        stokeslet_obj.apply(meanless_sigma_sym, mu_sym, qbx_forced_limit=2) -
        u_A_sym_vol + sigma_int_val_sym)

    nsamp = 30
    eval_points_1d = np.linspace(-3., 3., nsamp)
    eval_points = np.zeros((2, len(eval_points_1d)**2))
    eval_points[0, :] = np.tile(eval_points_1d, len(eval_points_1d))
    eval_points[1, :] = np.repeat(eval_points_1d, len(eval_points_1d))

    def circle_mask(test_points, radius):
        return (test_points[0, :]**2 + test_points[1, :]**2 > radius**2)

    def outside_circle(test_points, radius):
        mask = circle_mask(test_points, radius)
        return np.array([row[mask] for row in test_points])

    eval_points = outside_circle(eval_points, radius=circle_rad)
    from pytential.target import PointsTarget
    vel = bind((qbx, PointsTarget(eval_points)),
               representation_sym)(queue,
                                   sigma=sigma,
                                   mu=mu,
                                   normal=normal,
                                   sigma_int_val=int_val,
                                   omega=omega)
    print("@@@@@@@@")

    fplot = FieldPlotter(np.zeros(2), extent=6, npoints=100)
    plot_pts = outside_circle(fplot.points, radius=circle_rad)
    plot_vel = bind((qbx, PointsTarget(plot_pts)),
                    representation_sym)(queue,
                                        sigma=sigma,
                                        mu=mu,
                                        normal=normal,
                                        sigma_int_val=int_val,
                                        omega=omega)

    def get_obj_array(obj_array):
        return make_obj_array([ary.get() for ary in obj_array])

    exact_soln = fund_and_rot_soln(cl.array.to_device(queue, eval_points[0]),
                                   cl.array.to_device(queue, eval_points[1]),
                                   fund_soln_loc, strength)

    vel = get_obj_array(vel)
    err = vel - get_obj_array(exact_soln)

    # FIXME: Pointwise relative errors don't make sense!
    rel_err = err / (get_obj_array(exact_soln))

    if 0:
        print("@@@@@@@@")
        print("vel[0], err[0], rel_err[0] ***** vel[1], err[1], rel_err[1]: ")
        for i in range(len(vel[0])):
            print("%15.8e, %15.8e, %15.8e ***** %15.8e, %15.8e, %15.8e\n" %
                  (vel[0][i], err[0][i], rel_err[0][i], vel[1][i], err[1][i],
                   rel_err[1][i]))

        print("@@@@@@@@")

    l2_err = np.sqrt((6. / (nsamp - 1))**2 * np.sum(err[0] * err[0]) +
                     (6. / (nsamp - 1))**2 * np.sum(err[1] * err[1]))
    l2_rel_err = np.sqrt((6. /
                          (nsamp - 1))**2 * np.sum(rel_err[0] * rel_err[0]) +
                         (6. /
                          (nsamp - 1))**2 * np.sum(rel_err[1] * rel_err[1]))

    print("L2 error estimate: ", l2_err)
    print("L2 rel error estimate: ", l2_rel_err)
    print("max error at sampled points: ", max(abs(err[0])), max(abs(err[1])))
    print("max rel error at sampled points: ", max(abs(rel_err[0])),
          max(abs(rel_err[1])))

    if do_plot:
        import matplotlib
        matplotlib.use("Agg")
        import matplotlib.pyplot as plt

        full_pot = np.zeros_like(fplot.points) * float("nan")
        mask = circle_mask(fplot.points, radius=circle_rad)

        for i, vel in enumerate(plot_vel):
            full_pot[i, mask] = vel.get()

        plt.quiver(fplot.points[0],
                   fplot.points[1],
                   full_pot[0],
                   full_pot[1],
                   linewidth=0.1)
        plt.savefig("exterior-2d-field.pdf")

    # }}}

    h_max = bind(qbx, sym.h_max(qbx.ambient_dim))(queue)
    return h_max, l2_err
Beispiel #28
0
def test_ellipse_eigenvalues(ctx_getter, ellipse_aspect, mode_nr, qbx_order):
    logging.basicConfig(level=logging.INFO)

    print("ellipse_aspect: %s, mode_nr: %d, qbx_order: %d" % (
            ellipse_aspect, mode_nr, qbx_order))

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

    target_order = 7

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory
    from pytential.qbx import QBXLayerPotentialSource
    from pytools.convergence import EOCRecorder

    s_eoc_rec = EOCRecorder()
    d_eoc_rec = EOCRecorder()
    sp_eoc_rec = EOCRecorder()

    if ellipse_aspect != 1:
        nelements_values = [60, 100, 150, 200]
    else:
        nelements_values = [30, 70]

    # See
    #
    # [1] G. J. Rodin and O. Steinbach, "Boundary Element Preconditioners
    # for Problems Defined on Slender Domains", SIAM Journal on Scientific
    # Computing, Vol. 24, No. 4, pg. 1450, 2003.
    # http://dx.doi.org/10.1137/S1064827500372067

    for nelements in nelements_values:
        mesh = make_curve_mesh(partial(ellipse, ellipse_aspect),
                np.linspace(0, 1, nelements+1),
                target_order)

        fmm_order = qbx_order
        if fmm_order > 3:
            # FIXME: for now
            fmm_order = False

        density_discr = Discretization(
                cl_ctx, mesh,
                InterpolatoryQuadratureSimplexGroupFactory(target_order))
        qbx = QBXLayerPotentialSource(density_discr, 4*target_order,
                qbx_order, fmm_order=fmm_order)

        nodes = density_discr.nodes().with_queue(queue)

        if 0:
            # plot geometry, centers, normals
            centers = qbx.centers(density_discr, 1)
            nodes_h = nodes.get()
            centers_h = [centers[0].get(), centers[1].get()]
            pt.plot(nodes_h[0], nodes_h[1], "x-")
            pt.plot(centers_h[0], centers_h[1], "o")
            normal = bind(qbx, sym.normal())(queue).as_vector(np.object)
            pt.quiver(nodes_h[0], nodes_h[1],
                    normal[0].get(), normal[1].get())
            pt.gca().set_aspect("equal")
            pt.show()

        angle = cl.clmath.atan2(nodes[1]*ellipse_aspect, nodes[0])

        ellipse_fraction = ((1-ellipse_aspect)/(1+ellipse_aspect))**mode_nr

        # (2.6) in [1]
        J = cl.clmath.sqrt(  # noqa
                cl.clmath.sin(angle)**2
                + (1/ellipse_aspect)**2 * cl.clmath.cos(angle)**2)

        # {{{ single layer

        sigma = cl.clmath.cos(mode_nr*angle)/J

        s_sigma_op = bind(qbx, sym.S(0, sym.var("sigma")))
        s_sigma = s_sigma_op(queue=queue, sigma=sigma)

        # SIGN BINGO! :)
        s_eigval = 1/(2*mode_nr) * (1 + (-1)**mode_nr * ellipse_fraction)

        # (2.12) in [1]
        s_sigma_ref = s_eigval*J*sigma

        if 0:
            #pt.plot(s_sigma.get(), label="result")
            #pt.plot(s_sigma_ref.get(), label="ref")
            pt.plot((s_sigma_ref-s_sigma).get(), label="err")
            pt.legend()
            pt.show()

        s_err = (
                norm(density_discr, queue, s_sigma - s_sigma_ref)
                /
                norm(density_discr, queue, s_sigma_ref))
        s_eoc_rec.add_data_point(1/nelements, s_err)

        # }}}

        # {{{ double layer

        sigma = cl.clmath.cos(mode_nr*angle)

        d_sigma_op = bind(qbx, sym.D(0, sym.var("sigma")))
        d_sigma = d_sigma_op(queue=queue, sigma=sigma)

        # SIGN BINGO! :)
        d_eigval = -(-1)**mode_nr * 1/2*ellipse_fraction

        d_sigma_ref = d_eigval*sigma

        if 0:
            pt.plot(d_sigma.get(), label="result")
            pt.plot(d_sigma_ref.get(), label="ref")
            pt.legend()
            pt.show()

        if ellipse_aspect == 1:
            d_ref_norm = norm(density_discr, queue, sigma)
        else:
            d_ref_norm = norm(density_discr, queue, d_sigma_ref)

        d_err = (
                norm(density_discr, queue, d_sigma - d_sigma_ref)
                /
                d_ref_norm)
        d_eoc_rec.add_data_point(1/nelements, d_err)

        # }}}

        if ellipse_aspect == 1:
            # {{{ S'

            sigma = cl.clmath.cos(mode_nr*angle)

            sp_sigma_op = bind(qbx, sym.Sp(0, sym.var("sigma")))
            sp_sigma = sp_sigma_op(queue=queue, sigma=sigma)
            sp_eigval = 0

            sp_sigma_ref = sp_eigval*sigma

            sp_err = (
                    norm(density_discr, queue, sp_sigma - sp_sigma_ref)
                    /
                    norm(density_discr, queue, sigma))
            sp_eoc_rec.add_data_point(1/nelements, sp_err)

            # }}}

    print("Errors for S:")
    print(s_eoc_rec)
    required_order = qbx_order + 1
    assert s_eoc_rec.order_estimate() > required_order - 1.5

    print("Errors for D:")
    print(d_eoc_rec)
    required_order = qbx_order
    assert d_eoc_rec.order_estimate() > required_order - 1.5

    if ellipse_aspect == 1:
        print("Errors for S':")
        print(sp_eoc_rec)
        required_order = qbx_order
        assert sp_eoc_rec.order_estimate() > required_order - 1.5
Beispiel #29
0
def test_sanity_single_element(ctx_getter, dim, order, visualize=False):
    pytest.importorskip("pytential")

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

    from modepy.tools import UNIT_VERTICES
    vertices = UNIT_VERTICES[dim].T.copy()

    center = np.empty(dim, np.float64)
    center.fill(-0.5)

    import modepy as mp
    from meshmode.mesh import SimplexElementGroup, Mesh
    mg = SimplexElementGroup(
            order=order,
            vertex_indices=np.arange(dim+1, dtype=np.int32).reshape(1, -1),
            nodes=mp.warp_and_blend_nodes(dim, order).reshape(dim, 1, -1),
            dim=dim)

    mesh = Mesh(vertices, [mg])

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            PolynomialWarpAndBlendGroupFactory
    vol_discr = Discretization(cl_ctx, mesh,
            PolynomialWarpAndBlendGroupFactory(order+3))

    # {{{ volume calculation check

    vol_x = vol_discr.nodes().with_queue(queue)

    vol_one = vol_x[0].copy()
    vol_one.fill(1)
    from pytential import norm, integral  # noqa

    from pytools import factorial
    true_vol = 1/factorial(dim) * 2**dim

    comp_vol = integral(vol_discr, queue, vol_one)
    rel_vol_err = abs(true_vol - comp_vol) / true_vol

    assert rel_vol_err < 1e-12

    # }}}

    # {{{ boundary discretization

    from meshmode.discretization.connection import make_boundary_restriction
    bdry_mesh, bdry_discr, bdry_connection = make_boundary_restriction(
            queue, vol_discr, PolynomialWarpAndBlendGroupFactory(order + 3))

    # }}}

    # {{{ visualizers

    from meshmode.discretization.visualization import make_visualizer
    #vol_vis = make_visualizer(queue, vol_discr, 4)
    bdry_vis = make_visualizer(queue, bdry_discr, 4)

    # }}}

    from pytential import bind, sym
    bdry_normals = bind(bdry_discr, sym.normal())(queue).as_vector(dtype=object)

    if visualize:
        bdry_vis.write_vtk_file("boundary.vtu", [
            ("bdry_normals", bdry_normals)
            ])

    from pytential import bind, sym
    normal_outward_check = bind(bdry_discr,
            sym.normal()
            |
            (sym.Nodes() + 0.5*sym.ones_vec(dim)),
            )(queue).as_scalar() > 0

    assert normal_outward_check.get().all(), normal_outward_check.get()
Beispiel #30
0
def run_int_eq_test(
        cl_ctx, queue, curve_f, nelements, qbx_order, bc_type, loc_sign, k,
        target_order, source_order):

    mesh = make_curve_mesh(curve_f,
            np.linspace(0, 1, nelements+1),
            target_order)

    if 0:
        from pytential.visualization import show_mesh
        show_mesh(mesh)

        pt.gca().set_aspect("equal")
        pt.show()

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

    if source_order is None:
        source_order = 4*target_order

    qbx = QBXLayerPotentialSource(
            density_discr, fine_order=source_order, qbx_order=qbx_order,
            # Don't use FMM for now
            fmm_order=False)

    # {{{ set up operator

    from pytential.symbolic.pde.scalar import (
            DirichletOperator,
            NeumannOperator)

    from sumpy.kernel import LaplaceKernel, HelmholtzKernel, AxisTargetDerivative
    if k:
        knl = HelmholtzKernel(2)
        knl_kwargs = {"k": k}
    else:
        knl = LaplaceKernel(2)
        knl_kwargs = {}

    if knl.is_complex_valued:
        dtype = np.complex128
    else:
        dtype = np.float64

    if bc_type == "dirichlet":
        op = DirichletOperator((knl, knl_kwargs), loc_sign, use_l2_weighting=True)
    elif bc_type == "neumann":
        op = NeumannOperator((knl, knl_kwargs), loc_sign, use_l2_weighting=True,
                 use_improved_operator=False)
    else:
        assert False

    op_u = op.operator(sym.var("u"))

    # }}}

    # {{{ set up test data

    inner_radius = 0.1
    outer_radius = 2

    if loc_sign < 0:
        test_src_geo_radius = outer_radius
        test_tgt_geo_radius = inner_radius
    else:
        test_src_geo_radius = inner_radius
        test_tgt_geo_radius = outer_radius

    point_sources = make_circular_point_group(10, test_src_geo_radius,
            func=lambda x: x**1.5)
    test_targets = make_circular_point_group(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

    # }}}

    if 0:
        # 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())(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()

    # {{{ establish BCs

    from sumpy.p2p import P2P
    pot_p2p = P2P(cl_ctx,
            [knl], exclude_self=False, value_dtypes=dtype)

    evt, (test_direct,) = pot_p2p(
            queue, test_targets, point_sources, [source_charges],
            out_host=False, **knl_kwargs)

    nodes = density_discr.nodes()

    evt, (src_pot,) = pot_p2p(
            queue, nodes, point_sources, [source_charges],
            **knl_kwargs)

    grad_p2p = P2P(cl_ctx,
            [AxisTargetDerivative(0, knl), AxisTargetDerivative(1, knl)],
            exclude_self=False, value_dtypes=dtype)
    evt, (src_grad0, src_grad1) = grad_p2p(
            queue, nodes, point_sources, [source_charges],
            **knl_kwargs)

    if bc_type == "dirichlet":
        bc = src_pot
    elif bc_type == "neumann":
        normal = bind(density_discr, sym.normal())(queue).as_vector(np.object)
        bc = (src_grad0*normal[0] + src_grad1*normal[1])

    # }}}

    # {{{ solve

    bound_op = bind(qbx, op_u)

    rhs = bind(density_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bc)

    from pytential.solve import gmres
    gmres_result = gmres(
            bound_op.scipy_op(queue, "u", k=k),
            rhs, tol=1e-14, progress=True,
            hard_failure=False)

    u = gmres_result.solution
    print("gmres state:", gmres_result.state)

    if 0:
        # {{{ build matrix for spectrum check

        from sumpy.tools import build_matrix
        mat = build_matrix(bound_op.scipy_op("u"))
        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()

        # }}}

    # }}}

    # {{{ error check

    from pytential.target import PointsTarget

    bound_tgt_op = bind((qbx, PointsTarget(test_targets)),
            op.representation(sym.var("u")))

    test_via_bdry = bound_tgt_op(queue, u=u, k=k)

    err = test_direct-test_via_bdry

    err = err.get()
    test_direct = test_direct.get()
    test_via_bdry = test_via_bdry.get()

    # {{{ remove effect of net source charge

    if k == 0 and 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))

    # {{{ test tangential derivative

    bound_t_deriv_op = bind(qbx,
            op.representation(
                sym.var("u"), map_potentials=sym.tangential_derivative,
                qbx_forced_limit=loc_sign))

    #print(bound_t_deriv_op.code)

    tang_deriv_from_src = bound_t_deriv_op(queue, u=u).as_scalar().get()

    tangent = bind(
            density_discr,
            sym.pseudoscalar()/sym.area_element())(queue).as_vector(np.object)

    tang_deriv_ref = (src_grad0 * tangent[0] + src_grad1 * tangent[1]).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)

    # }}}

    # {{{ plotting

    if 0:
        fplot = FieldPlotter(np.zeros(2),
                extent=1.25*2*max(test_src_geo_radius, test_tgt_geo_radius),
                npoints=200)

        #pt.plot(u)
        #pt.show()

        evt, (fld_from_src,) = pot_p2p(
                queue, fplot.points, point_sources, [source_charges],
                **knl_kwargs)
        fld_from_bdry = bind(
                (qbx, PointsTarget(fplot.points)),
                op.representation(sym.var("u"))
                )(queue, u=u, k=k)
        fld_from_src = fld_from_src.get()
        fld_from_bdry = fld_from_bdry.get()

        nodes = density_discr.nodes().get(queue=queue)

        def prep():
            pt.plot(point_sources[0], point_sources[1], "o",
                    label="Monopole 'Point Charges'")
            pt.plot(test_targets[0], test_targets[1], "v",
                    label="Observation Points")
            pt.plot(nodes[0], nodes[1], "k-",
                    label=r"$\Gamma$")

        from matplotlib.cm import get_cmap
        cmap = get_cmap()
        cmap._init()
        if 0:
            cmap._lut[(cmap.N*99)//100:, -1] = 0  # make last percent transparent?

        prep()
        if 1:
            pt.subplot(131)
            pt.title("Field error (loc_sign=%s)" % loc_sign)
            log_err = np.log10(1e-20+np.abs(fld_from_src-fld_from_bdry))
            log_err = np.minimum(-3, log_err)
            fplot.show_scalar_in_matplotlib(log_err, cmap=cmap)

            #from matplotlib.colors import Normalize
            #im.set_norm(Normalize(vmin=-6, vmax=1))

            cb = pt.colorbar(shrink=0.9)
            cb.set_label(r"$\log_{10}(\mathdefault{Error})$")

        if 1:
            pt.subplot(132)
            prep()
            pt.title("Source Field")
            fplot.show_scalar_in_matplotlib(
                    fld_from_src.real, max_val=3)

            pt.colorbar(shrink=0.9)
        if 1:
            pt.subplot(133)
            prep()
            pt.title("Solved Field")
            fplot.show_scalar_in_matplotlib(
                    fld_from_bdry.real, max_val=3)

            pt.colorbar(shrink=0.9)

        # total field
        #fplot.show_scalar_in_matplotlib(
        #fld_from_src.real+fld_from_bdry.real, max_val=0.1)

        #pt.colorbar()

        pt.legend(loc="best", prop=dict(size=15))
        from matplotlib.ticker import NullFormatter
        pt.gca().xaxis.set_major_formatter(NullFormatter())
        pt.gca().yaxis.set_major_formatter(NullFormatter())

        pt.gca().set_aspect("equal")

        if 0:
            border_factor_top = 0.9
            border_factor = 0.3

            xl, xh = pt.xlim()
            xhsize = 0.5*(xh-xl)
            pt.xlim(xl-border_factor*xhsize, xh+border_factor*xhsize)

            yl, yh = pt.ylim()
            yhsize = 0.5*(yh-yl)
            pt.ylim(yl-border_factor_top*yhsize, yh+border_factor*yhsize)

        #pt.savefig("helmholtz.pdf", dpi=600)
        pt.show()

        # }}}

    class Result(Record):
        pass

    return Result(
            rel_err_2=rel_err_2,
            rel_err_inf=rel_err_inf,
            rel_td_err_inf=rel_td_err_inf,
            gmres_result=gmres_result)
Beispiel #31
0
 def centers(self, target_discr, sign):
     from pytential import sym, bind
     with cl.CommandQueue(self.cl_context) as queue:
         return bind(target_discr,
                 sym.Nodes() + 2*sign*sym.area_element()*sym.normal())(queue) \
                         .as_vector(np.object)
Beispiel #32
0
def test_identities(ctx_getter, zero_op_name, curve_name, curve_f, qbx_order, k):
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    # prevent cache 'splosion
    from sympy.core.cache import clear_cache
    clear_cache()

    target_order = 7

    u_sym = sym.var("u")
    grad_u_sym = sym.VectorVariable("grad_u")
    dn_u_sym = sym.var("dn_u")

    if k == 0:
        k_sym = 0
    else:
        k_sym = "k"

    zero_op_table = {
            "green":
            sym.S(k_sym, dn_u_sym) - sym.D(k_sym, u_sym) - 0.5*u_sym,

            "green_grad":
            d1.nabla * d1(sym.S(k_sym, dn_u_sym))
            - d2.nabla * d2(sym.D(k_sym, u_sym))
            - 0.5*grad_u_sym,

            # only for k==0:
            "zero_calderon":
            -sym.Dp(0, sym.S(0, u_sym))
            - 0.25*u_sym + sym.Sp(0, sym.Sp(0, u_sym))
            }
    order_table = {
            "green": qbx_order,
            "green_grad": qbx_order-1,
            "zero_calderon": qbx_order-1,
            }

    zero_op = zero_op_table[zero_op_name]

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for nelements in [30, 50, 70]:
        mesh = make_curve_mesh(curve_f,
                np.linspace(0, 1, nelements+1),
                target_order)

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

        qbx = QBXLayerPotentialSource(density_discr, 4*target_order,
                qbx_order,
                # Don't use FMM for now
                fmm_order=False)

        # {{{ compute values of a solution to the PDE

        nodes_host = density_discr.nodes().get(queue)
        normal = bind(density_discr, sym.normal())(queue).as_vector(np.object)
        normal_host = [normal[0].get(), normal[1].get()]

        if k != 0:
            angle = 0.3
            wave_vec = np.array([np.cos(angle), np.sin(angle)])
            u = np.exp(1j*k*np.tensordot(wave_vec, nodes_host, axes=1))
            grad_u = 1j*k*wave_vec[:, np.newaxis]*u
        else:
            center = np.array([3, 1])
            diff = nodes_host - center[:, np.newaxis]
            dist_squared = np.sum(diff**2, axis=0)
            dist = np.sqrt(dist_squared)
            u = np.log(dist)
            grad_u = diff/dist_squared

        dn_u = normal_host[0]*grad_u[0] + normal_host[1]*grad_u[1]

        # }}}

        u_dev = cl.array.to_device(queue, u)
        dn_u_dev = cl.array.to_device(queue, dn_u)
        grad_u_dev = cl.array.to_device(queue, grad_u)

        key = (qbx_order, curve_name, nelements, zero_op_name)

        bound_op = bind(qbx, zero_op)
        error = bound_op(
                queue, u=u_dev, dn_u=dn_u_dev, grad_u=grad_u_dev, k=k)
        if 0:
            pt.plot(error)
            pt.show()

        l2_error_norm = norm(density_discr, queue, error)
        print(key, l2_error_norm)

        eoc_rec.add_data_point(1/nelements, l2_error_norm)

    print(eoc_rec)
    tgt_order = order_table[zero_op_name]
    assert eoc_rec.order_estimate() > tgt_order - 1.3
Beispiel #33
0
def test_sanity_balls(actx_factory,
                      src_file,
                      dim,
                      mesh_order,
                      visualize=False):
    pytest.importorskip("pytential")

    logging.basicConfig(level=logging.INFO)
    actx = actx_factory()

    from pytools.convergence import EOCRecorder
    vol_eoc_rec = EOCRecorder()
    surf_eoc_rec = EOCRecorder()

    # overkill
    quad_order = mesh_order

    from pytential import bind, sym

    for h in [0.2, 0.1, 0.05]:
        from meshmode.mesh.io import generate_gmsh, FileSource
        mesh = generate_gmsh(FileSource(src_file),
                             dim,
                             order=mesh_order,
                             other_options=[
                                 "-string",
                                 "Mesh.CharacteristicLengthMax = %g;" % h
                             ],
                             force_ambient_dim=dim,
                             target_unit="MM")

        logger.info("%d elements", mesh.nelements)

        # {{{ discretizations and connections

        from meshmode.discretization import Discretization
        vol_discr = Discretization(
            actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(quad_order))

        from meshmode.discretization.connection import make_face_restriction
        bdry_connection = make_face_restriction(
            actx, vol_discr,
            InterpolatoryQuadratureSimplexGroupFactory(quad_order), BTAG_ALL)
        bdry_discr = bdry_connection.to_discr

        # }}}

        from math import gamma
        true_surf = 2 * np.pi**(dim / 2) / gamma(dim / 2)
        true_vol = true_surf / dim

        vol_x = thaw(vol_discr.nodes(), actx)

        vol_one = vol_x[0] * 0 + 1
        from pytential import norm, integral  # noqa

        comp_vol = integral(vol_discr, vol_one)
        rel_vol_err = abs(true_vol - comp_vol) / true_vol
        vol_eoc_rec.add_data_point(h, rel_vol_err)
        print("VOL", true_vol, comp_vol)

        bdry_x = thaw(bdry_discr.nodes(), actx)

        bdry_one_exact = bdry_x[0] * 0 + 1

        bdry_one = bdry_connection(vol_one)
        intp_err = norm(bdry_discr, bdry_one - bdry_one_exact)
        assert intp_err < 1e-14

        comp_surf = integral(bdry_discr, bdry_one)
        rel_surf_err = abs(true_surf - comp_surf) / true_surf
        surf_eoc_rec.add_data_point(h, rel_surf_err)
        print("SURF", true_surf, comp_surf)

        if visualize:
            from meshmode.discretization.visualization import make_visualizer
            vol_vis = make_visualizer(actx, vol_discr, 7)
            bdry_vis = make_visualizer(actx, bdry_discr, 7)

            name = src_file.split("-")[0]
            vol_vis.write_vtk_file(f"sanity_balls_volume_{name}_{h:g}.vtu", [
                ("f", vol_one),
                ("area_el",
                 bind(vol_discr,
                      sym.area_element(mesh.ambient_dim,
                                       mesh.ambient_dim))(actx)),
            ])

            bdry_vis.write_vtk_file(f"sanity_balls_boundary_{name}_{h:g}.vtu",
                                    [("f", bdry_one)])

        # {{{ check normals point outward

        normal_outward_check = bind(
            bdry_discr,
            sym.normal(mesh.ambient_dim) | sym.nodes(mesh.ambient_dim),
        )(actx).as_scalar()

        normal_outward_check = flatten_to_numpy(actx, normal_outward_check > 0)
        assert normal_outward_check.all(), normal_outward_check

        # }}}

    print("---------------------------------")
    print("VOLUME")
    print("---------------------------------")
    print(vol_eoc_rec)
    assert vol_eoc_rec.order_estimate() >= mesh_order

    print("---------------------------------")
    print("SURFACE")
    print("---------------------------------")
    print(surf_eoc_rec)
    assert surf_eoc_rec.order_estimate() >= mesh_order
Beispiel #34
0
def run_dielectric_test(cl_ctx,
                        queue,
                        nelements,
                        qbx_order,
                        op_class,
                        mode,
                        k0=3,
                        k1=2.9,
                        mesh_order=10,
                        bdry_quad_order=None,
                        bdry_ovsmp_quad_order=None,
                        use_l2_weighting=False,
                        fmm_order=None,
                        visualize=False):

    if fmm_order is None:
        fmm_order = qbx_order * 2
    if bdry_quad_order is None:
        bdry_quad_order = mesh_order
    if bdry_ovsmp_quad_order is None:
        bdry_ovsmp_quad_order = 4 * bdry_quad_order

    from meshmode.mesh.generation import ellipse, make_curve_mesh
    from functools import partial
    mesh = make_curve_mesh(partial(ellipse, 3),
                           np.linspace(0, 1, nelements + 1), mesh_order)

    density_discr = Discretization(
        cl_ctx, mesh,
        InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order))

    logger.info("%d elements" % mesh.nelements)

    # from meshmode.discretization.visualization import make_visualizer
    # bdry_vis = make_visualizer(queue, density_discr, 20)

    # {{{ solve bvp

    from sumpy.kernel import HelmholtzKernel, AxisTargetDerivative
    kernel = HelmholtzKernel(2)

    beta = 2.5
    K0 = np.sqrt(k0**2 - beta**2)  # noqa
    K1 = np.sqrt(k1**2 - beta**2)  # noqa

    pde_op = op_class(mode,
                      k_vacuum=1,
                      interfaces=((0, 1, sym.DEFAULT_SOURCE), ),
                      domain_k_exprs=(k0, k1),
                      beta=beta,
                      use_l2_weighting=use_l2_weighting)

    op_unknown_sym = pde_op.make_unknown("unknown")

    representation0_sym = pde_op.representation(op_unknown_sym, 0)
    representation1_sym = pde_op.representation(op_unknown_sym, 1)

    from pytential.qbx import QBXLayerPotentialSource
    qbx = QBXLayerPotentialSource(density_discr,
                                  fine_order=bdry_ovsmp_quad_order,
                                  qbx_order=qbx_order,
                                  fmm_order=fmm_order).with_refinement()

    #print(sym.pretty(pde_op.operator(op_unknown_sym)))
    #1/0
    bound_pde_op = bind(qbx, pde_op.operator(op_unknown_sym))

    e_factor = float(pde_op.ez_enabled)
    h_factor = float(pde_op.hz_enabled)

    e_sources_0 = make_obj_array(list(np.array([[0.1, 0.2]]).T.copy()))
    e_strengths_0 = np.array([1 * e_factor])
    e_sources_1 = make_obj_array(list(np.array([[4, 4]]).T.copy()))
    e_strengths_1 = np.array([1 * e_factor])

    h_sources_0 = make_obj_array(list(np.array([[0.2, 0.1]]).T.copy()))
    h_strengths_0 = np.array([1 * h_factor])
    h_sources_1 = make_obj_array(list(np.array([[4, 5]]).T.copy()))
    h_strengths_1 = np.array([1 * h_factor])

    kernel_grad = [
        AxisTargetDerivative(i, kernel)
        for i in range(density_discr.ambient_dim)
    ]

    from sumpy.p2p import P2P
    pot_p2p = P2P(cl_ctx, [kernel], exclude_self=False)
    pot_p2p_grad = P2P(cl_ctx, kernel_grad, exclude_self=False)

    normal = bind(density_discr, sym.normal())(queue).as_vector(np.object)
    tangent = bind(density_discr,
                   sym.pseudoscalar() / sym.area_element())(queue).as_vector(
                       np.object)

    _, (E0, ) = pot_p2p(queue,
                        density_discr.nodes(),
                        e_sources_0, [e_strengths_0],
                        out_host=False,
                        k=K0)
    _, (E1, ) = pot_p2p(queue,
                        density_discr.nodes(),
                        e_sources_1, [e_strengths_1],
                        out_host=False,
                        k=K1)
    _, (grad0_E0, grad1_E0) = pot_p2p_grad(queue,
                                           density_discr.nodes(),
                                           e_sources_0, [e_strengths_0],
                                           out_host=False,
                                           k=K0)
    _, (grad0_E1, grad1_E1) = pot_p2p_grad(queue,
                                           density_discr.nodes(),
                                           e_sources_1, [e_strengths_1],
                                           out_host=False,
                                           k=K1)

    _, (H0, ) = pot_p2p(queue,
                        density_discr.nodes(),
                        h_sources_0, [h_strengths_0],
                        out_host=False,
                        k=K0)
    _, (H1, ) = pot_p2p(queue,
                        density_discr.nodes(),
                        h_sources_1, [h_strengths_1],
                        out_host=False,
                        k=K1)
    _, (grad0_H0, grad1_H0) = pot_p2p_grad(queue,
                                           density_discr.nodes(),
                                           h_sources_0, [h_strengths_0],
                                           out_host=False,
                                           k=K0)
    _, (grad0_H1, grad1_H1) = pot_p2p_grad(queue,
                                           density_discr.nodes(),
                                           h_sources_1, [h_strengths_1],
                                           out_host=False,
                                           k=K1)

    E0_dntarget = (grad0_E0 * normal[0] + grad1_E0 * normal[1])  # noqa
    E1_dntarget = (grad0_E1 * normal[0] + grad1_E1 * normal[1])  # noqa

    H0_dntarget = (grad0_H0 * normal[0] + grad1_H0 * normal[1])  # noqa
    H1_dntarget = (grad0_H1 * normal[0] + grad1_H1 * normal[1])  # noqa

    E0_dttarget = (grad0_E0 * tangent[0] + grad1_E0 * tangent[1])  # noqa
    E1_dttarget = (grad0_E1 * tangent[0] + grad1_E1 * tangent[1])  # noqa

    H0_dttarget = (grad0_H0 * tangent[0] + grad1_H0 * tangent[1])  # noqa
    H1_dttarget = (grad0_H1 * tangent[0] + grad1_H1 * tangent[1])  # noqa

    sqrt_w = bind(density_discr, sym.sqrt_jac_q_weight())(queue)

    bvp_rhs = np.zeros(len(pde_op.bcs), dtype=np.object)
    for i_bc, terms in enumerate(pde_op.bcs):
        for term in terms:
            assert term.i_interface == 0
            if term.field_kind == pde_op.field_kind_e:

                if term.direction == pde_op.dir_none:
                    bvp_rhs[i_bc] += (term.coeff_outer * E0 +
                                      term.coeff_inner * E1)
                elif term.direction == pde_op.dir_normal:
                    bvp_rhs[i_bc] += (term.coeff_outer * E0_dntarget +
                                      term.coeff_inner * E1_dntarget)
                elif term.direction == pde_op.dir_tangential:
                    bvp_rhs[i_bc] += (term.coeff_outer * E0_dttarget +
                                      term.coeff_inner * E1_dttarget)
                else:
                    raise NotImplementedError("direction spec in RHS")

            elif term.field_kind == pde_op.field_kind_h:
                if term.direction == pde_op.dir_none:
                    bvp_rhs[i_bc] += (term.coeff_outer * H0 +
                                      term.coeff_inner * H1)
                elif term.direction == pde_op.dir_normal:
                    bvp_rhs[i_bc] += (term.coeff_outer * H0_dntarget +
                                      term.coeff_inner * H1_dntarget)
                elif term.direction == pde_op.dir_tangential:
                    bvp_rhs[i_bc] += (term.coeff_outer * H0_dttarget +
                                      term.coeff_inner * H1_dttarget)
                else:
                    raise NotImplementedError("direction spec in RHS")

            if use_l2_weighting:
                bvp_rhs[i_bc] *= sqrt_w

    scipy_op = bound_pde_op.scipy_op(queue,
                                     "unknown",
                                     domains=[sym.DEFAULT_TARGET] *
                                     len(pde_op.bcs),
                                     K0=K0,
                                     K1=K1,
                                     dtype=np.complex128)

    if mode == "tem" or op_class is SRep:
        from sumpy.tools import vector_from_device, vector_to_device
        from pytential.solve import lu
        unknown = lu(scipy_op, vector_from_device(queue, bvp_rhs))
        unknown = vector_to_device(queue, unknown)

    else:
        from pytential.solve import gmres
        gmres_result = gmres(scipy_op,
                             bvp_rhs,
                             tol=1e-14,
                             progress=True,
                             hard_failure=True,
                             stall_iterations=0)

        unknown = gmres_result.solution

    # }}}

    targets_0 = make_obj_array(
        list(np.array([[3.2 + t, -4] for t in [0, 0.5, 1]]).T.copy()))
    targets_1 = make_obj_array(
        list(np.array([[t * -0.3, t * -0.2] for t in [0, 0.5, 1]]).T.copy()))

    from pytential.target import PointsTarget
    from sumpy.tools import vector_from_device
    F0_tgt = vector_from_device(
        queue,
        bind(  # noqa
            (qbx, PointsTarget(targets_0)),
            representation0_sym)(queue, unknown=unknown, K0=K0, K1=K1))
    F1_tgt = vector_from_device(
        queue,
        bind(  # noqa
            (qbx, PointsTarget(targets_1)),
            representation1_sym)(queue, unknown=unknown, K0=K0, K1=K1))

    _, (E0_tgt_true, ) = pot_p2p(queue,
                                 targets_0,
                                 e_sources_0, [e_strengths_0],
                                 out_host=True,
                                 k=K0)
    _, (E1_tgt_true, ) = pot_p2p(queue,
                                 targets_1,
                                 e_sources_1, [e_strengths_1],
                                 out_host=True,
                                 k=K1)

    _, (H0_tgt_true, ) = pot_p2p(queue,
                                 targets_0,
                                 h_sources_0, [h_strengths_0],
                                 out_host=True,
                                 k=K0)
    _, (H1_tgt_true, ) = pot_p2p(queue,
                                 targets_1,
                                 h_sources_1, [h_strengths_1],
                                 out_host=True,
                                 k=K1)

    err_F0_total = 0  # noqa
    err_F1_total = 0  # noqa

    i_field = 0

    def vec_norm(ary):
        return la.norm(ary.reshape(-1))

    def field_kind_to_string(field_kind):
        return {pde_op.field_kind_e: "E", pde_op.field_kind_h: "H"}[field_kind]

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

        if field_kind == pde_op.field_kind_e:
            F0_tgt_true = E0_tgt_true  # noqa
            F1_tgt_true = E1_tgt_true  # noqa
        elif field_kind == pde_op.field_kind_h:
            F0_tgt_true = H0_tgt_true  # noqa
            F1_tgt_true = H1_tgt_true  # noqa
        else:
            assert False

        abs_err_F0 = vec_norm(F0_tgt[i_field] - F0_tgt_true)  # noqa
        abs_err_F1 = vec_norm(F1_tgt[i_field] - F1_tgt_true)  # noqa

        rel_err_F0 = abs_err_F0 / vec_norm(F0_tgt_true)  # noqa
        rel_err_F1 = abs_err_F1 / vec_norm(F1_tgt_true)  # noqa

        err_F0_total = max(rel_err_F0, err_F0_total)  # noqa
        err_F1_total = max(rel_err_F1, err_F1_total)  # noqa

        print("Abs Err %s0" % field_kind_to_string(field_kind), abs_err_F0)
        print("Abs Err %s1" % field_kind_to_string(field_kind), abs_err_F1)

        print("Rel Err %s0" % field_kind_to_string(field_kind), rel_err_F0)
        print("Rel Err %s1" % field_kind_to_string(field_kind), rel_err_F1)

        i_field += 1

    if visualize:
        from sumpy.visualization import FieldPlotter
        fplot = FieldPlotter(np.zeros(2), extent=5, npoints=300)
        from pytential.target import PointsTarget
        fld0 = bind((qbx, PointsTarget(fplot.points)),
                    representation0_sym)(queue, unknown=unknown, K0=K0)
        fld1 = bind((qbx, PointsTarget(fplot.points)),
                    representation1_sym)(queue, unknown=unknown, K1=K1)

        comp_fields = []
        i_field = 0
        for field_kind in pde_op.field_kinds:
            if not pde_op.is_field_present(field_kind):
                continue

            fld_str = field_kind_to_string(field_kind)
            comp_fields.extend([
                ("%s_fld0" % fld_str, fld0[i_field].get()),
                ("%s_fld1" % fld_str, fld1[i_field].get()),
            ])

            i_field += 0

        low_order_qbx = QBXLayerPotentialSource(
            density_discr,
            fine_order=bdry_ovsmp_quad_order,
            qbx_order=2,
            fmm_order=3).with_refinement()
        from sumpy.kernel import LaplaceKernel
        from pytential.target import PointsTarget
        ones = (cl.array.empty(queue, (density_discr.nnodes, ),
                               dtype=np.float64).fill(1))
        ind_func = -bind(
            (low_order_qbx, PointsTarget(fplot.points)),
            sym.D(LaplaceKernel(2), sym.var("u")))(queue, u=ones).get()

        _, (e_fld0_true, ) = pot_p2p(queue,
                                     fplot.points,
                                     e_sources_0, [e_strengths_0],
                                     out_host=True,
                                     k=K0)
        _, (e_fld1_true, ) = pot_p2p(queue,
                                     fplot.points,
                                     e_sources_1, [e_strengths_1],
                                     out_host=True,
                                     k=K1)
        _, (h_fld0_true, ) = pot_p2p(queue,
                                     fplot.points,
                                     h_sources_0, [h_strengths_0],
                                     out_host=True,
                                     k=K0)
        _, (h_fld1_true, ) = pot_p2p(queue,
                                     fplot.points,
                                     h_sources_1, [h_strengths_1],
                                     out_host=True,
                                     k=K1)

        #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5)
        fplot.write_vtk_file("potential-n%d.vts" % nelements, [
            ("e_fld0_true", e_fld0_true),
            ("e_fld1_true", e_fld1_true),
            ("h_fld0_true", h_fld0_true),
            ("h_fld1_true", h_fld1_true),
            ("ind", ind_func),
        ] + comp_fields)

    return err_F0_total, err_F1_total
Beispiel #35
0
def test_3d_jump_relations(ctx_factory, relation, visualize=False):
    # logging.basicConfig(level=logging.INFO)

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

    if relation == "div_s":
        target_order = 3
    else:
        target_order = 4

    qbx_order = target_order

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for nel_factor in [6, 10, 14]:
        from meshmode.mesh.generation import generate_torus
        mesh = generate_torus(
                5, 2, order=target_order,
                n_outer=2*nel_factor, n_inner=nel_factor)

        from meshmode.discretization import Discretization
        from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory
        pre_discr = Discretization(
                cl_ctx, mesh,
                InterpolatoryQuadratureSimplexGroupFactory(3))

        from pytential.qbx import QBXLayerPotentialSource
        qbx, _ = QBXLayerPotentialSource(
                pre_discr, fine_order=4*target_order,
                qbx_order=qbx_order,
                fmm_order=qbx_order + 5,
                fmm_backend="fmmlib"
                ).with_refinement()

        from sumpy.kernel import LaplaceKernel
        knl = LaplaceKernel(3)

        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)))

        x, y, z = qbx.density_discr.nodes().with_queue(queue)
        m = cl.clmath

        if relation == "nxcurls":
            density_sym = sym.make_sym_vector("density", 2)

            jump_identity_sym = (
                    nxcurlS(+1)
                    - (nxcurlS("avg") + 0.5*sym.tangential_to_xyz(density_sym)))

            # The tangential coordinate system is element-local, so we can't just
            # conjure up some globally smooth functions, interpret their values
            # in the tangential coordinate system, and be done. Instead, generate
            # an XYZ function and project it.
            density = bind(
                    qbx,
                    sym.xyz_to_tangential(sym.make_sym_vector("jxyz", 3)))(
                            queue,
                            jxyz=sym.make_obj_array([
                                m.cos(0.5*x) * m.cos(0.5*y) * m.cos(0.5*z),
                                m.sin(0.5*x) * m.cos(0.5*y) * m.sin(0.5*z),
                                m.sin(0.5*x) * m.cos(0.5*y) * m.cos(0.5*z),
                                ]))

        elif relation == "sp":

            density = m.cos(2*x) * m.cos(2*y) * m.cos(z)
            density_sym = sym.var("density")

            jump_identity_sym = (
                    sym.Sp(knl, density_sym, qbx_forced_limit=+1)
                    - (sym.Sp(knl, density_sym, qbx_forced_limit="avg")
                        - 0.5*density_sym))

        elif relation == "div_s":

            density = m.cos(2*x) * m.cos(2*y) * m.cos(z)
            density_sym = sym.var("density")

            jump_identity_sym = (
                    sym.div(sym.S(knl, sym.normal(3).as_vector()*density_sym,
                        qbx_forced_limit="avg"))
                    + sym.D(knl, density_sym, qbx_forced_limit="avg"))

        else:
            raise ValueError("unexpected value of 'relation': %s" % relation)

        bound_jump_identity = bind(qbx, jump_identity_sym)
        jump_identity = bound_jump_identity(queue, density=density)

        err = (
                norm(qbx, queue, jump_identity, np.inf)
                / norm(qbx, queue, density, np.inf))
        print("ERROR", qbx.h_max, err)

        eoc_rec.add_data_point(qbx.h_max, err)

        # {{{ visualization

        if visualize and relation == "nxcurls":
            nxcurlS_ext = bind(qbx, nxcurlS(+1))(queue, density=density)
            nxcurlS_avg = bind(qbx, nxcurlS("avg"))(queue, density=density)
            jtxyz = bind(qbx, sym.tangential_to_xyz(density_sym))(
                    queue, density=density)

            from meshmode.discretization.visualization import make_visualizer
            bdry_vis = make_visualizer(queue, qbx.density_discr, target_order+3)

            bdry_normals = bind(qbx, sym.normal(3))(queue)\
                    .as_vector(dtype=object)

            bdry_vis.write_vtk_file("source-%s.vtu" % nel_factor, [
                ("jt", jtxyz),
                ("nxcurlS_ext", nxcurlS_ext),
                ("nxcurlS_avg", nxcurlS_avg),
                ("bdry_normals", bdry_normals),
                ])

        if visualize and relation == "sp":
            sp_ext = bind(qbx, sym.Sp(knl, density_sym, qbx_forced_limit=+1))(
                    queue, density=density)
            sp_avg = bind(qbx, sym.Sp(knl, density_sym, qbx_forced_limit="avg"))(
                    queue, density=density)

            from meshmode.discretization.visualization import make_visualizer
            bdry_vis = make_visualizer(queue, qbx.density_discr, target_order+3)

            bdry_normals = bind(qbx, sym.normal(3))(queue)\
                    .as_vector(dtype=object)

            bdry_vis.write_vtk_file("source-%s.vtu" % nel_factor, [
                ("density", density),
                ("sp_ext", sp_ext),
                ("sp_avg", sp_avg),
                ("bdry_normals", bdry_normals),
                ])

        # }}}

    print(eoc_rec)

    assert eoc_rec.order_estimate() >= qbx_order - 1.5
Beispiel #36
0
                )
        places = GeometryCollection(qbx)

        from pytential.qbx.refinement import refine_geometry_collection
        kernel_length_scale = 5 / case.k if case.k else None
        places = refine_geometry_collection(places,
                kernel_length_scale=kernel_length_scale)

        # {{{ compute values of a solution to the PDE

        density_discr = places.get_discretization(places.auto_source.geometry)

        from meshmode.dof_array import thaw, flatten, unflatten
        nodes_host = [actx.to_numpy(axis)
                for axis in flatten(thaw(actx, density_discr.nodes()))]
        normal = bind(places, sym.normal(d))(actx).as_vector(object)
        normal_host = [actx.to_numpy(axis)for axis in flatten(normal)]

        if k != 0:
            if d == 2:
                angle = 0.3
                wave_vec = np.array([np.cos(angle), np.sin(angle)])
                u = np.exp(1j*k*np.tensordot(wave_vec, nodes_host, axes=1))
                grad_u = 1j*k*wave_vec[:, np.newaxis]*u
            elif d == 3:
                center = np.array([3, 1, 2])
                diff = nodes_host - center[:, np.newaxis]
                r = la.norm(diff, axis=0)
                u = np.exp(1j*k*r) / r
                grad_u = diff * (1j*k*u/r - u/r**2)
            else:
Beispiel #37
0
def main():
    # cl.array.to_device(queue, numpy_array)
    from meshmode.mesh.io import generate_gmsh, FileSource
    mesh = generate_gmsh(
            FileSource("ellipsoid.step"), 2, order=2,
            other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h])

    from meshmode.mesh.processing import perform_flips
    # Flip elements--gmsh generates inside-out geometry.
    mesh = perform_flips(mesh, np.ones(mesh.nelements))

    print("%d elements" % mesh.nelements)

    from meshmode.mesh.processing import find_bounding_box
    bbox_min, bbox_max = find_bounding_box(mesh)
    bbox_center = 0.5*(bbox_min+bbox_max)
    bbox_size = max(bbox_max-bbox_min) / 2

    logger.info("%d elements" % mesh.nelements)

    from pytential.qbx import QBXLayerPotentialSource
    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory

    density_discr = Discretization(
            cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order))

    qbx = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order,
            fmm_order=qbx_order + 10, fmm_backend="fmmlib")

    from pytential.symbolic.pde.maxwell import MuellerAugmentedMFIEOperator
    pde_op = MuellerAugmentedMFIEOperator(
            omega=0.4,
            epss=[1.4, 1.0],
            mus=[1.2, 1.0],
            )
    from pytential import bind, sym

    unk = pde_op.make_unknown("sigma")
    sym_operator = pde_op.operator(unk)
    sym_rhs = pde_op.rhs(
            sym.make_sym_vector("Einc", 3),
            sym.make_sym_vector("Hinc", 3))
    sym_repr = pde_op.representation(0, unk)

    if 1:
        expr = sym_repr
        print(sym.pretty(expr))

        print("#"*80)
        from pytential.target import PointsTarget

        tgt_points=np.zeros((3,1))
        tgt_points[0,0] = 100
        tgt_points[1,0] = -200
        tgt_points[2,0] = 300

        bound_op = bind((qbx, PointsTarget(tgt_points)), expr)
        print(bound_op.code)

    if 1:

        def green3e(x,y,z,source,strength,k):
        # electric field corresponding to dyadic green's function
        # due to monochromatic electric dipole located at "source".
        # "strength" is the the intensity of the dipole.
        #  E = (I + Hess)(exp(ikr)/r) dot (strength)
        #
            dx = x - source[0]
            dy = y - source[1]
            dz = z - source[2]
            rr = np.sqrt(dx**2 + dy**2 + dz**2)

            fout = np.exp(1j*k*rr)/rr
            evec = fout*strength
            qmat = np.zeros((3,3),dtype=np.complex128)

            qmat[0,0]=(2*dx**2-dy**2-dz**2)*(1-1j*k*rr)
            qmat[1,1]=(2*dy**2-dz**2-dx**2)*(1-1j*k*rr)
            qmat[2,2]=(2*dz**2-dx**2-dy**2)*(1-1j*k*rr)

            qmat[0,0]=qmat[0,0]+(-k**2*dx**2*rr**2)
            qmat[1,1]=qmat[1,1]+(-k**2*dy**2*rr**2)
            qmat[2,2]=qmat[2,2]+(-k**2*dz**2*rr**2)

            qmat[0,1]=(3-k**2*rr**2-3*1j*k*rr)*(dx*dy)
            qmat[1,2]=(3-k**2*rr**2-3*1j*k*rr)*(dy*dz)
            qmat[2,0]=(3-k**2*rr**2-3*1j*k*rr)*(dz*dx)

            qmat[1,0]=qmat[0,1]
            qmat[2,1]=qmat[1,2]
            qmat[0,2]=qmat[2,0]

            fout=np.exp(1j*k*rr)/rr**5/k**2

            fvec = fout*np.dot(qmat,strength)
            evec = evec + fvec
            return evec

        def green3m(x,y,z,source,strength,k):
        # magnetic field corresponding to dyadic green's function
        # due to monochromatic electric dipole located at "source".
        # "strength" is the the intensity of the dipole.
        #  H = curl((I + Hess)(exp(ikr)/r) dot (strength)) = 
        #  strength \cross \grad (exp(ikr)/r)
        #
            dx = x - source[0]
            dy = y - source[1]
            dz = z - source[2]
            rr = np.sqrt(dx**2 + dy**2 + dz**2)

            fout=(1-1j*k*rr)*np.exp(1j*k*rr)/rr**3
            fvec = np.zeros(3,dtype=np.complex128)
            fvec[0] = fout*dx
            fvec[1] = fout*dy
            fvec[2] = fout*dz

            hvec = np.cross(strength,fvec)

            return hvec

        def dipole3e(x,y,z,source,strength,k):
        #
        #  evalaute electric and magnetic field due
        #  to monochromatic electric dipole located at "source"
        #  with intensity "strength"

            evec = green3e(x,y,z,source,strength,k)
            evec = evec*1j*k
            hvec = green3m(x,y,z,source,strength,k)
            return evec,hvec
            
        def dipole3m(x,y,z,source,strength,k):
        #
        #  evalaute electric and magnetic field due
        #  to monochromatic magnetic dipole located at "source"
        #  with intensity "strength"
            evec = green3m(x,y,z,source,strength,k)
            hvec = green3e(x,y,z,source,strength,k)
            hvec = -hvec*1j*k
            return evec,hvec
            

        def dipole3eall(x,y,z,sources,strengths,k):
            ns = len(strengths)
            evec = np.zeros(3,dtype=np.complex128)
            hvec = np.zeros(3,dtype=np.complex128)

            for i in range(ns):
                evect,hvect = dipole3e(x,y,z,sources[i],strengths[i],k)
                evec = evec + evect
                hvec = hvec + hvect

        nodes = density_discr.nodes().with_queue(queue).get()
        source = [0.01,-0.03,0.02]
#        source = cl.array.to_device(queue,np.zeros(3))
#        source[0] = 0.01
#        source[1] =-0.03
#        source[2] = 0.02
        strength = np.ones(3)
       
#        evec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128))
#        hvec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128))

        evec = np.zeros((3,len(nodes[0])),dtype=np.complex128)
        hvec = np.zeros((3,len(nodes[0])),dtype=np.complex128)
        for i in range(len(nodes[0])):
            evec[:,i],hvec[:,i] = dipole3e(nodes[0][i],nodes[1][i],nodes[2][i],source,strength,k)
        print(np.shape(hvec))
        print(type(evec))
        print(type(hvec))

        evec = cl.array.to_device(queue,evec)
        hvec = cl.array.to_device(queue,hvec)

        bvp_rhs = bind(qbx, sym_rhs)(queue,Einc=evec,Hinc=hvec)
        print(np.shape(bvp_rhs))
        print(type(bvp_rhs))
#        print(bvp_rhs)
        1/-1

        bound_op = bind(qbx, sym_operator)

        from pytential.solve import gmres
        if 0:
            gmres_result = gmres(
                bound_op.scipy_op(queue, "sigma", dtype=np.complex128, k=k),
                bvp_rhs, tol=1e-8, progress=True,
                stall_iterations=0,
                hard_failure=True)

            sigma = gmres_result.solution

        fld_at_tgt = bind((qbx, PointsTarget(tgt_points)), sym_repr)(queue,
        sigma=bvp_rhs,k=k)
        fld_at_tgt = np.array([
            fi.get() for fi in fld_at_tgt
            ])
        print(fld_at_tgt)
        1/0

    # }}}

    #mlab.figure(bgcolor=(1, 1, 1))
    if 1:
        from meshmode.discretization.visualization import make_visualizer
        bdry_vis = make_visualizer(queue, density_discr, target_order)

        bdry_normals = bind(density_discr, sym.normal(3))(queue)\
                .as_vector(dtype=object)

        bdry_vis.write_vtk_file("source.vtu", [
            ("sigma", sigma),
            ("bdry_normals", bdry_normals),
            ])

        fplot = FieldPlotter(bbox_center, extent=2*bbox_size, npoints=(150, 150, 1))

        qbx_tgt_tol = qbx.copy(target_association_tolerance=0.1)
        from pytential.target import PointsTarget
        from pytential.qbx import QBXTargetAssociationFailedException

        rho_sym = sym.var("rho")

        try:
            fld_in_vol = bind(
                    (qbx_tgt_tol, PointsTarget(fplot.points)),
                    sym.make_obj_array([
                        sym.S(pde_op.kernel, rho_sym, k=sym.var("k"),
                            qbx_forced_limit=None),
                        sym.d_dx(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"),
                            qbx_forced_limit=None)),
                        sym.d_dy(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"),
                            qbx_forced_limit=None)),
                        sym.d_dz(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"),
                            qbx_forced_limit=None)),
                        ])
                    )(queue, jt=jt, rho=rho, k=k)
        except QBXTargetAssociationFailedException as e:
            fplot.write_vtk_file(
                    "failed-targets.vts",
                    [
                        ("failed_targets", e.failed_target_flags.get(queue))
                        ])
            raise

        fld_in_vol = sym.make_obj_array(
            [fiv.get() for fiv in fld_in_vol])

        #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5)
        fplot.write_vtk_file(
                "potential.vts",
                [
                    ("potential", fld_in_vol[0]),
                    ("grad", fld_in_vol[1:]),
                    ]
                )
Beispiel #38
0
def test_3d_jump_relations(actx_factory, relation, visualize=False):
    # logging.basicConfig(level=logging.INFO)
    actx = actx_factory()

    if relation == "div_s":
        target_order = 3
    else:
        target_order = 4

    qbx_order = target_order

    if relation == "sp":
        resolutions = [10, 14, 18]
    else:
        resolutions = [6, 10, 14]

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for nel_factor in resolutions:
        from meshmode.mesh.generation import generate_torus
        mesh = generate_torus(
            5,
            2,
            n_major=2 * nel_factor,
            n_minor=nel_factor,
            order=target_order,
        )

        from meshmode.discretization import Discretization
        from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory
        pre_density_discr = Discretization(
            actx, mesh,
            InterpolatoryQuadratureSimplexGroupFactory(target_order))

        from pytential.qbx import QBXLayerPotentialSource
        qbx = QBXLayerPotentialSource(pre_density_discr,
                                      fine_order=5 * target_order,
                                      qbx_order=qbx_order,
                                      fmm_order=qbx_order + 5,
                                      fmm_backend="fmmlib")

        places = GeometryCollection(qbx)
        density_discr = places.get_discretization(places.auto_source.geometry)

        from sumpy.kernel import LaplaceKernel
        knl = LaplaceKernel(places.ambient_dim)

        def nxcurlS(qbx_forced_limit):
            sigma_sym = sym.cse(sym.tangential_to_xyz(density_sym), "jxyz")
            return sym.n_cross(
                sym.curl(
                    sym.S(knl, sigma_sym, qbx_forced_limit=qbx_forced_limit)))

        x, y, z = thaw(density_discr.nodes(), actx)
        if relation == "nxcurls":
            density_sym = sym.make_sym_vector("density", 2)
            jump_identity_sym = (nxcurlS(+1) - nxcurlS("avg") -
                                 0.5 * sym.tangential_to_xyz(density_sym))

            # The tangential coordinate system is element-local, so we can't just
            # conjure up some globally smooth functions, interpret their values
            # in the tangential coordinate system, and be done. Instead, generate
            # an XYZ function and project it.
            jxyz = sym.make_obj_array([
                actx.np.cos(0.5 * x) * actx.np.cos(0.5 * y) *
                actx.np.cos(0.5 * z),
                actx.np.sin(0.5 * x) * actx.np.cos(0.5 * y) *
                actx.np.sin(0.5 * z),
                actx.np.sin(0.5 * x) * actx.np.cos(0.5 * y) *
                actx.np.cos(0.5 * z),
            ])
            density = bind(
                places,
                sym.xyz_to_tangential(sym.make_sym_vector("jxyz",
                                                          3)))(actx, jxyz=jxyz)

        elif relation == "sp":
            density_sym = sym.var("density")
            jump_identity_sym = (
                0.5 * density_sym +
                sym.Sp(knl, density_sym, qbx_forced_limit=+1) -
                sym.Sp(knl, density_sym, qbx_forced_limit="avg"))

            density = actx.np.cos(2 * x) * actx.np.cos(2 * y) * actx.np.cos(z)

        elif relation == "div_s":
            density_sym = sym.var("density")
            sigma_sym = sym.normal(
                places.ambient_dim).as_vector() * density_sym
            jump_identity_sym = (
                sym.div(sym.S(knl, sigma_sym, qbx_forced_limit="avg")) +
                sym.D(knl, density_sym, qbx_forced_limit="avg"))

            density = actx.np.cos(2 * x) * actx.np.cos(2 * y) * actx.np.cos(z)

        else:
            raise ValueError(f"unexpected value of 'relation': '{relation}'")

        bound_jump_identity = bind(places, jump_identity_sym)
        jump_identity = bound_jump_identity(actx, density=density)

        h_max = actx.to_numpy(
            bind(places, sym.h_max(places.ambient_dim))(actx))
        err = actx.to_numpy(
            norm(density_discr, jump_identity, np.inf) /
            norm(density_discr, density, np.inf))
        eoc_rec.add_data_point(h_max, err)

        logging.info("error: nel %d h_max %.5e %.5e", nel_factor, h_max, err)

        # {{{ visualization

        if not visualize:
            continue

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(actx, density_discr, target_order)
        normals = bind(places,
                       sym.normal(places.ambient_dim).as_vector())(actx)
        error = actx.np.log10(actx.np.abs(jump_identity) + 1.0e-15)

        if relation == "nxcurls":
            nxcurlS_ext = bind(places, nxcurlS(+1))(actx, density=density)
            nxcurlS_avg = bind(places, nxcurlS("avg"))(actx, density=density)
            jtxyz = bind(places,
                         sym.tangential_to_xyz(density_sym))(actx,
                                                             density=density)

            vis.write_vtk_file(f"source-nxcurls-{nel_factor:03d}.vtu", [
                ("jt", jtxyz),
                ("nxcurlS_ext", nxcurlS_ext),
                ("nxcurlS_avg", nxcurlS_avg),
                ("bdry_normals", normals),
                ("error", error),
            ])

        elif relation == "sp":
            op = sym.Sp(knl, density_sym, qbx_forced_limit=+1)
            sp_ext = bind(places, op)(actx, density=density)
            op = sym.Sp(knl, density_sym, qbx_forced_limit="avg")
            sp_avg = bind(places, op)(actx, density=density)

            vis.write_vtk_file(f"source-sp-{nel_factor:03d}.vtu", [
                ("density", density),
                ("sp_ext", sp_ext),
                ("sp_avg", sp_avg),
                ("bdry_normals", normals),
                ("error", error),
            ])

        elif relation == "div_s":
            vis.write_vtk_file(f"source-div-{nel_factor:03d}.vtu", [
                ("density", density),
                ("bdry_normals", normals),
                ("error", error),
            ])

        # }}}

    logger.info("\n%s", str(eoc_rec))
    assert eoc_rec.order_estimate() >= qbx_order - 1.5
Beispiel #39
0
def test_sanity_balls(ctx_getter, src_file, dim, mesh_order, visualize=False):
    pytest.importorskip("pytential")

    logging.basicConfig(level=logging.INFO)

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

    from pytools.convergence import EOCRecorder
    vol_eoc_rec = EOCRecorder()
    surf_eoc_rec = EOCRecorder()

    # overkill
    quad_order = mesh_order

    from pytential import bind, sym

    for h in [0.2, 0.14, 0.1]:
        from meshmode.mesh.io import generate_gmsh, FileSource
        mesh = generate_gmsh(FileSource(src_file),
                             dim,
                             order=mesh_order,
                             other_options=[
                                 "-string",
                                 "Mesh.CharacteristicLengthMax = %g;" % h
                             ],
                             force_ambient_dim=dim)

        logger.info("%d elements" % mesh.nelements)

        # {{{ discretizations and connections

        from meshmode.discretization import Discretization
        vol_discr = Discretization(
            ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(quad_order))

        from meshmode.discretization.connection import make_face_restriction
        bdry_connection = make_face_restriction(
            vol_discr, InterpolatoryQuadratureSimplexGroupFactory(quad_order),
            BTAG_ALL)
        bdry_discr = bdry_connection.to_discr

        # }}}

        # {{{ visualizers

        from meshmode.discretization.visualization import make_visualizer
        vol_vis = make_visualizer(queue, vol_discr, 20)
        bdry_vis = make_visualizer(queue, bdry_discr, 20)

        # }}}

        from math import gamma
        true_surf = 2 * np.pi**(dim / 2) / gamma(dim / 2)
        true_vol = true_surf / dim

        vol_x = vol_discr.nodes().with_queue(queue)

        vol_one = vol_x[0].copy()
        vol_one.fill(1)
        from pytential import norm, integral  # noqa

        comp_vol = integral(vol_discr, queue, vol_one)
        rel_vol_err = abs(true_vol - comp_vol) / true_vol
        vol_eoc_rec.add_data_point(h, rel_vol_err)
        print("VOL", true_vol, comp_vol)

        bdry_x = bdry_discr.nodes().with_queue(queue)

        bdry_one_exact = bdry_x[0].copy()
        bdry_one_exact.fill(1)

        bdry_one = bdry_connection(queue, vol_one).with_queue(queue)
        intp_err = norm(bdry_discr, queue, bdry_one - bdry_one_exact)
        assert intp_err < 1e-14

        comp_surf = integral(bdry_discr, queue, bdry_one)
        rel_surf_err = abs(true_surf - comp_surf) / true_surf
        surf_eoc_rec.add_data_point(h, rel_surf_err)
        print("SURF", true_surf, comp_surf)

        if visualize:
            vol_vis.write_vtk_file("volume-h=%g.vtu" % h, [
                ("f", vol_one),
                ("area_el", bind(vol_discr, sym.area_element())(queue)),
            ])
            bdry_vis.write_vtk_file("boundary-h=%g.vtu" % h, [("f", bdry_one)])

        # {{{ check normals point outward

        normal_outward_check = bind(
            bdry_discr,
            sym.normal(mesh.ambient_dim) | sym.nodes(mesh.ambient_dim),
        )(queue).as_scalar() > 0

        assert normal_outward_check.get().all(), normal_outward_check.get()

        # }}}

    print("---------------------------------")
    print("VOLUME")
    print("---------------------------------")
    print(vol_eoc_rec)
    assert vol_eoc_rec.order_estimate() >= mesh_order

    print("---------------------------------")
    print("SURFACE")
    print("---------------------------------")
    print(surf_eoc_rec)
    assert surf_eoc_rec.order_estimate() >= mesh_order
        #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))
def test_ellipse_eigenvalues(ctx_factory,
                             ellipse_aspect,
                             mode_nr,
                             qbx_order,
                             force_direct,
                             visualize=False):
    logging.basicConfig(level=logging.INFO)

    print("ellipse_aspect: %s, mode_nr: %d, qbx_order: %d" %
          (ellipse_aspect, mode_nr, qbx_order))

    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    target_order = 8

    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory
    from pytential.qbx import QBXLayerPotentialSource
    from pytools.convergence import EOCRecorder

    s_eoc_rec = EOCRecorder()
    d_eoc_rec = EOCRecorder()
    sp_eoc_rec = EOCRecorder()

    if ellipse_aspect != 1:
        nelements_values = [60, 100, 150, 200]
    else:
        nelements_values = [30, 70]

    # See
    #
    # [1] G. J. Rodin and O. Steinbach, "Boundary Element Preconditioners
    # for Problems Defined on Slender Domains", SIAM Journal on Scientific
    # Computing, Vol. 24, No. 4, pg. 1450, 2003.
    # https://dx.doi.org/10.1137/S1064827500372067

    for nelements in nelements_values:
        mesh = make_curve_mesh(partial(ellipse, ellipse_aspect),
                               np.linspace(0, 1, nelements + 1), target_order)

        fmm_order = 12
        if force_direct:
            fmm_order = False

        pre_density_discr = Discretization(
            actx, mesh,
            InterpolatoryQuadratureSimplexGroupFactory(target_order))
        qbx = QBXLayerPotentialSource(
            pre_density_discr,
            4 * target_order,
            qbx_order,
            fmm_order=fmm_order,
            _expansions_in_tree_have_extent=True,
        )
        places = GeometryCollection(qbx)

        density_discr = places.get_discretization(places.auto_source.geometry)
        from meshmode.dof_array import thaw, flatten
        nodes = thaw(actx, density_discr.nodes())

        if visualize:
            # plot geometry, centers, normals
            centers = bind(places, sym.expansion_centers(qbx.ambient_dim,
                                                         +1))(actx)
            normals = bind(places,
                           sym.normal(qbx.ambient_dim))(actx).as_vector(object)

            nodes_h = np.array(
                [actx.to_numpy(axis) for axis in flatten(nodes)])
            centers_h = np.array(
                [actx.to_numpy(axis) for axis in flatten(centers)])
            normals_h = np.array(
                [actx.to_numpy(axis) for axis in flatten(normals)])

            pt.plot(nodes_h[0], nodes_h[1], "x-")
            pt.plot(centers_h[0], centers_h[1], "o")
            pt.quiver(nodes_h[0], nodes_h[1], normals_h[0], normals_h[1])
            pt.gca().set_aspect("equal")
            pt.show()

        angle = actx.np.arctan2(nodes[1] * ellipse_aspect, nodes[0])

        ellipse_fraction = ((1 - ellipse_aspect) /
                            (1 + ellipse_aspect))**mode_nr

        # (2.6) in [1]
        J = actx.np.sqrt(  # noqa
            actx.np.sin(angle)**2 +
            (1 / ellipse_aspect)**2 * actx.np.cos(angle)**2)

        from sumpy.kernel import LaplaceKernel
        lap_knl = LaplaceKernel(2)

        # {{{ single layer

        sigma_sym = sym.var("sigma")
        s_sigma_op = sym.S(lap_knl, sigma_sym, qbx_forced_limit=+1)

        sigma = actx.np.cos(mode_nr * angle) / J
        s_sigma = bind(places, s_sigma_op)(actx, sigma=sigma)

        # SIGN BINGO! :)
        s_eigval = 1 / (2 * mode_nr) * (1 + (-1)**mode_nr * ellipse_fraction)

        # (2.12) in [1]
        s_sigma_ref = s_eigval * J * sigma

        if 0:
            #pt.plot(s_sigma.get(), label="result")
            #pt.plot(s_sigma_ref.get(), label="ref")
            pt.plot(actx.to_numpy(flatten(s_sigma_ref - s_sigma)), label="err")
            pt.legend()
            pt.show()

        h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx)
        s_err = (norm(density_discr, s_sigma - s_sigma_ref) /
                 norm(density_discr, s_sigma_ref))
        s_eoc_rec.add_data_point(h_max, s_err)

        # }}}

        # {{{ double layer

        d_sigma_op = sym.D(lap_knl, sigma_sym, qbx_forced_limit="avg")

        sigma = actx.np.cos(mode_nr * angle)
        d_sigma = bind(places, d_sigma_op)(actx, sigma=sigma)

        # SIGN BINGO! :)
        d_eigval = -(-1)**mode_nr * 1 / 2 * ellipse_fraction

        d_sigma_ref = d_eigval * sigma

        if 0:
            pt.plot(actx.to_numpy(flatten(d_sigma)), label="result")
            pt.plot(actx.to_numpy(flatten(d_sigma_ref)), label="ref")
            pt.legend()
            pt.show()

        if ellipse_aspect == 1:
            d_ref_norm = norm(density_discr, sigma)
        else:
            d_ref_norm = norm(density_discr, d_sigma_ref)

        d_err = (norm(density_discr, d_sigma - d_sigma_ref) / d_ref_norm)
        d_eoc_rec.add_data_point(h_max, d_err)

        # }}}

        if ellipse_aspect == 1:
            # {{{ S'

            sp_sigma_op = sym.Sp(lap_knl,
                                 sym.var("sigma"),
                                 qbx_forced_limit="avg")

            sigma = actx.np.cos(mode_nr * angle)
            sp_sigma = bind(places, sp_sigma_op)(actx, sigma=sigma)
            sp_eigval = 0

            sp_sigma_ref = sp_eigval * sigma

            sp_err = (norm(density_discr, sp_sigma - sp_sigma_ref) /
                      norm(density_discr, sigma))
            sp_eoc_rec.add_data_point(h_max, sp_err)

            # }}}

    print("Errors for S:")
    print(s_eoc_rec)
    required_order = qbx_order + 1
    assert s_eoc_rec.order_estimate() > required_order - 1.5

    print("Errors for D:")
    print(d_eoc_rec)
    required_order = qbx_order
    assert d_eoc_rec.order_estimate() > required_order - 1.5

    if ellipse_aspect == 1:
        print("Errors for S':")
        print(sp_eoc_rec)
        required_order = qbx_order
        assert sp_eoc_rec.order_estimate() > required_order - 1.5
Beispiel #42
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)
def main(nelements):
    import logging
    logging.basicConfig(level=logging.INFO)

    def get_obj_array(obj_array):
        from pytools.obj_array import make_obj_array
        return make_obj_array([ary.get() for ary in obj_array])

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

    from meshmode.mesh.generation import (  # noqa
        make_curve_mesh, starfish, ellipse, drop)
    mesh = make_curve_mesh(lambda t: starfish(t),
                           np.linspace(0, 1, nelements + 1), target_order)
    coarse_density_discr = Discretization(
        cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order))

    from pytential.qbx import QBXLayerPotentialSource
    target_association_tolerance = 0.05
    qbx, _ = QBXLayerPotentialSource(
        coarse_density_discr,
        fine_order=ovsmp_target_order,
        qbx_order=qbx_order,
        fmm_order=fmm_order,
        target_association_tolerance=target_association_tolerance,
    ).with_refinement()

    density_discr = qbx.density_discr
    nodes = density_discr.nodes().with_queue(queue)

    # Get normal vectors for the density discretization -- used in integration with stresslet
    mv_normal = bind(density_discr, sym.normal(2))(queue)
    normal = mv_normal.as_vector(np.object)

    # {{{ describe bvp

    from sumpy.kernel import LaplaceKernel
    from pytential.symbolic.stokes import StressletWrapper
    from pytools.obj_array import make_obj_array
    dim = 2
    cse = sym.cse

    nvec_sym = sym.make_sym_vector("normal", dim)
    sigma_sym = sym.make_sym_vector("sigma", dim)
    mu_sym = sym.var("mu")
    sqrt_w = sym.sqrt_jac_q_weight(2)
    inv_sqrt_w_sigma = cse(sigma_sym / sqrt_w)

    # -1 for interior Dirichlet
    # +1 for exterior Dirichlet
    loc_sign = -1

    # Create stresslet object
    stresslet_obj = StressletWrapper(dim=2)

    # Describe boundary operator
    bdry_op_sym = loc_sign * 0.5 * sigma_sym + sqrt_w * stresslet_obj.apply(
        inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit='avg')

    # Bind to the qbx discretization
    bound_op = bind(qbx, bdry_op_sym)

    # }}}

    # {{{ fix rhs and solve

    def fund_soln(x, y, loc):
        #with direction (1,0) for point source
        r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2)
        scaling = 1. / (4 * np.pi * mu)
        xcomp = (-cl.clmath.log(r) + (x - loc[0])**2 / r**2) * scaling
        ycomp = ((x - loc[0]) * (y - loc[1]) / r**2) * scaling
        return [xcomp, ycomp]

    def couette_soln(x, y, dp, h):
        scaling = 1. / (2 * mu)
        xcomp = scaling * dp * ((y + (h / 2.))**2 - h * (y + (h / 2.)))
        ycomp = scaling * 0 * y
        return [xcomp, ycomp]

    if soln_type == 'fundamental':
        pt_loc = np.array([2.0, 0.0])
        bc = fund_soln(nodes[0], nodes[1], pt_loc)
    else:
        dp = -10.
        h = 2.5
        bc = couette_soln(nodes[0], nodes[1], dp, h)

    # Get rhs vector
    bvp_rhs = bind(qbx, sqrt_w * sym.make_sym_vector("bc", dim))(queue, bc=bc)

    from pytential.solve import gmres
    gmres_result = gmres(bound_op.scipy_op(queue,
                                           "sigma",
                                           np.float64,
                                           mu=mu,
                                           normal=normal),
                         bvp_rhs,
                         tol=1e-9,
                         progress=True,
                         stall_iterations=0,
                         hard_failure=True)

    # }}}

    # {{{ postprocess/visualize
    sigma = gmres_result.solution

    # Describe representation of solution for evaluation in domain
    representation_sym = stresslet_obj.apply(inv_sqrt_w_sigma,
                                             nvec_sym,
                                             mu_sym,
                                             qbx_forced_limit=-2)

    from sumpy.visualization import FieldPlotter
    nsamp = 10
    eval_points_1d = np.linspace(-1., 1., nsamp)
    eval_points = np.zeros((2, len(eval_points_1d)**2))
    eval_points[0, :] = np.tile(eval_points_1d, len(eval_points_1d))
    eval_points[1, :] = np.repeat(eval_points_1d, len(eval_points_1d))

    gamma_sym = sym.var("gamma")
    inv_sqrt_w_gamma = cse(gamma_sym / sqrt_w)
    constant_laplace_rep = sym.D(LaplaceKernel(dim=2),
                                 inv_sqrt_w_gamma,
                                 qbx_forced_limit=None)
    sqrt_w_vec = bind(qbx, sqrt_w)(queue)

    def general_mask(test_points):
        const_density = bind((qbx, PointsTarget(test_points)),
                             constant_laplace_rep)(queue,
                                                   gamma=sqrt_w_vec).get()
        return (abs(const_density) > 0.1)

    def inside_domain(test_points):
        mask = general_mask(test_points)
        return np.array([row[mask] for row in test_points])

    def stride_hack(arr):
        from numpy.lib.stride_tricks import as_strided
        return np.array(as_strided(arr, strides=(8 * len(arr[0]), 8)))

    eval_points = inside_domain(eval_points)
    eval_points_dev = cl.array.to_device(queue, eval_points)

    # Evaluate the solution at the evaluation points
    vel = bind((qbx, PointsTarget(eval_points_dev)),
               representation_sym)(queue, sigma=sigma, mu=mu, normal=normal)
    print("@@@@@@@@")
    vel = get_obj_array(vel)

    if soln_type == 'fundamental':
        exact_soln = fund_soln(eval_points_dev[0], eval_points_dev[1], pt_loc)
    else:
        exact_soln = couette_soln(eval_points_dev[0], eval_points_dev[1], dp,
                                  h)
    err = vel - get_obj_array(exact_soln)

    print("@@@@@@@@")

    print(
        "L2 error estimate: ",
        np.sqrt((2. / (nsamp - 1))**2 * np.sum(err[0] * err[0]) +
                (2. / (nsamp - 1))**2 * np.sum(err[1] * err[1])))
    max_error_loc = [abs(err[0]).argmax(), abs(err[1]).argmax()]
    print("max error at sampled points: ", max(abs(err[0])), max(abs(err[1])))
    print("exact velocity at max error points: x -> ",
          err[0][max_error_loc[0]], ", y -> ", err[1][max_error_loc[1]])

    from pytential.symbolic.mappers import DerivativeTaker
    rep_pressure = stresslet_obj.apply_pressure(inv_sqrt_w_sigma,
                                                nvec_sym,
                                                mu_sym,
                                                qbx_forced_limit=-2)
    pressure = bind((qbx, PointsTarget(eval_points_dev)),
                    rep_pressure)(queue, sigma=sigma, mu=mu, normal=normal)
    pressure = pressure.get()
    print "pressure = ", pressure

    x_dir_vecs = np.zeros((2, len(eval_points[0])))
    x_dir_vecs[0, :] = 1.0
    y_dir_vecs = np.zeros((2, len(eval_points[0])))
    y_dir_vecs[1, :] = 1.0
    x_dir_vecs = cl.array.to_device(queue, x_dir_vecs)
    y_dir_vecs = cl.array.to_device(queue, y_dir_vecs)
    dir_vec_sym = sym.make_sym_vector("force_direction", dim)
    rep_stress = stresslet_obj.apply_stress(inv_sqrt_w_sigma,
                                            nvec_sym,
                                            dir_vec_sym,
                                            mu_sym,
                                            qbx_forced_limit=-2)

    applied_stress_x = bind((qbx, PointsTarget(eval_points_dev)),
                            rep_stress)(queue,
                                        sigma=sigma,
                                        normal=normal,
                                        force_direction=x_dir_vecs,
                                        mu=mu)
    applied_stress_x = get_obj_array(applied_stress_x)
    applied_stress_y = bind((qbx, PointsTarget(eval_points_dev)),
                            rep_stress)(queue,
                                        sigma=sigma,
                                        normal=normal,
                                        force_direction=y_dir_vecs,
                                        mu=mu)
    applied_stress_y = get_obj_array(applied_stress_y)

    print "stress applied to x direction: ", applied_stress_x
    print "stress applied to y direction: ", applied_stress_y

    import matplotlib.pyplot as plt
    plt.quiver(eval_points[0], eval_points[1], vel[0], vel[1], linewidth=0.1)
    file_name = "field-n%s.pdf" % (nelements)
    plt.savefig(file_name)

    return (max(abs(err[0])), max(abs(err[1])))
Beispiel #44
0
def test_pec_mfie_extinction(ctx_getter, case, visualize=False):
    """For (say) is_interior=False (the 'exterior' MFIE), this test verifies
    extinction of the combined (incoming + scattered) field on the interior
    of the scatterer.
    """
    logging.basicConfig(level=logging.INFO)

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

    np.random.seed(12)

    knl_kwargs = {"k": case.k}

    # {{{ come up with a solution to Maxwell's equations

    j_sym = sym.make_sym_vector("j", 3)
    jt_sym = sym.make_sym_vector("jt", 2)
    rho_sym = sym.var("rho")

    from pytential.symbolic.pde.maxwell import (
            PECChargeCurrentMFIEOperator,
            get_sym_maxwell_point_source,
            get_sym_maxwell_plane_wave)
    mfie = PECChargeCurrentMFIEOperator()

    test_source = case.get_source(queue)

    calc_patch = CalculusPatch(np.array([-3, 0, 0]), h=0.01)
    calc_patch_tgt = PointsTarget(cl.array.to_device(queue, calc_patch.points))

    rng = cl.clrandom.PhiloxGenerator(cl_ctx, seed=12)
    src_j = rng.normal(queue, (3, test_source.nnodes), dtype=np.float64)

    def eval_inc_field_at(tgt):
        if 0:
            # plane wave
            return bind(
                    tgt,
                    get_sym_maxwell_plane_wave(
                        amplitude_vec=np.array([1, 1, 1]),
                        v=np.array([1, 0, 0]),
                        omega=case.k)
                    )(queue)
        else:
            # point source
            return bind(
                    (test_source, tgt),
                    get_sym_maxwell_point_source(mfie.kernel, j_sym, mfie.k)
                    )(queue, j=src_j, k=case.k)

    pde_test_inc = EHField(
            vector_from_device(queue, eval_inc_field_at(calc_patch_tgt)))

    source_maxwell_resids = [
            calc_patch.norm(x, np.inf) / calc_patch.norm(pde_test_inc.e, np.inf)
            for x in frequency_domain_maxwell(
                calc_patch, pde_test_inc.e, pde_test_inc.h, case.k)]
    print("Source Maxwell residuals:", source_maxwell_resids)
    assert max(source_maxwell_resids) < 1e-6

    # }}}

    loc_sign = -1 if case.is_interior else +1

    from pytools.convergence import EOCRecorder

    eoc_rec_repr_maxwell = EOCRecorder()
    eoc_pec_bc = EOCRecorder()
    eoc_rec_e = EOCRecorder()
    eoc_rec_h = EOCRecorder()

    from pytential.qbx import QBXLayerPotentialSource
    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory
    from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder

    for resolution in case.resolutions:
        scat_mesh = case.get_mesh(resolution, case.target_order)
        observation_mesh = case.get_observation_mesh(case.target_order)

        pre_scat_discr = Discretization(
                cl_ctx, scat_mesh,
                InterpolatoryQuadratureSimplexGroupFactory(case.target_order))
        qbx, _ = QBXLayerPotentialSource(
                pre_scat_discr, fine_order=4*case.target_order,
                qbx_order=case.qbx_order,
                fmm_level_to_order=SimpleExpansionOrderFinder(
                    case.fmm_tolerance),
                fmm_backend=case.fmm_backend
                ).with_refinement(_expansion_disturbance_tolerance=0.05)
        h_max = qbx.h_max

        scat_discr = qbx.density_discr
        obs_discr = Discretization(
                cl_ctx, observation_mesh,
                InterpolatoryQuadratureSimplexGroupFactory(case.target_order))

        inc_field_scat = EHField(eval_inc_field_at(scat_discr))
        inc_field_obs = EHField(eval_inc_field_at(obs_discr))

        # {{{ system solve

        inc_xyz_sym = EHField(sym.make_sym_vector("inc_fld", 6))

        bound_j_op = bind(qbx, mfie.j_operator(loc_sign, jt_sym))
        j_rhs = bind(qbx, mfie.j_rhs(inc_xyz_sym.h))(
                queue, inc_fld=inc_field_scat.field, **knl_kwargs)

        gmres_settings = dict(
                tol=case.gmres_tol,
                progress=True,
                hard_failure=True,
                stall_iterations=50, no_progress_factor=1.05)
        from pytential.solve import gmres
        gmres_result = gmres(
                bound_j_op.scipy_op(queue, "jt", np.complex128, **knl_kwargs),
                j_rhs, **gmres_settings)

        jt = gmres_result.solution

        bound_rho_op = bind(qbx, mfie.rho_operator(loc_sign, rho_sym))
        rho_rhs = bind(qbx, mfie.rho_rhs(jt_sym, inc_xyz_sym.e))(
                queue, jt=jt, inc_fld=inc_field_scat.field, **knl_kwargs)

        gmres_result = gmres(
                bound_rho_op.scipy_op(queue, "rho", np.complex128, **knl_kwargs),
                rho_rhs, **gmres_settings)

        rho = gmres_result.solution

        # }}}

        jxyz = bind(qbx, sym.tangential_to_xyz(jt_sym))(queue, jt=jt)

        # {{{ volume eval

        sym_repr = mfie.scattered_volume_field(jt_sym, rho_sym)

        def eval_repr_at(tgt, source=None):
            if source is None:
                source = qbx

            return bind((source, tgt), sym_repr)(queue, jt=jt, rho=rho, **knl_kwargs)

        pde_test_repr = EHField(
                vector_from_device(queue, eval_repr_at(calc_patch_tgt)))

        maxwell_residuals = [
                calc_patch.norm(x, np.inf) / calc_patch.norm(pde_test_repr.e, np.inf)
                for x in frequency_domain_maxwell(
                    calc_patch, pde_test_repr.e, pde_test_repr.h, case.k)]
        print("Maxwell residuals:", maxwell_residuals)

        eoc_rec_repr_maxwell.add_data_point(h_max, max(maxwell_residuals))

        # }}}

        # {{{ check PEC BC on total field

        bc_repr = EHField(mfie.scattered_volume_field(
            jt_sym, rho_sym, qbx_forced_limit=loc_sign))
        pec_bc_e = sym.n_cross(bc_repr.e + inc_xyz_sym.e)
        pec_bc_h = sym.normal(3).as_vector().dot(bc_repr.h + inc_xyz_sym.h)

        eh_bc_values = bind(qbx, sym.join_fields(pec_bc_e, pec_bc_h))(
                    queue, jt=jt, rho=rho, inc_fld=inc_field_scat.field,
                    **knl_kwargs)

        def scat_norm(f):
            return norm(qbx, queue, f, p=np.inf)

        e_bc_residual = scat_norm(eh_bc_values[:3]) / scat_norm(inc_field_scat.e)
        h_bc_residual = scat_norm(eh_bc_values[3]) / scat_norm(inc_field_scat.h)

        print("E/H PEC BC residuals:", h_max, e_bc_residual, h_bc_residual)

        eoc_pec_bc.add_data_point(h_max, max(e_bc_residual, h_bc_residual))

        # }}}

        # {{{ visualization

        if visualize:
            from meshmode.discretization.visualization import make_visualizer
            bdry_vis = make_visualizer(queue, scat_discr, case.target_order+3)

            bdry_normals = bind(scat_discr, sym.normal(3))(queue)\
                    .as_vector(dtype=object)

            bdry_vis.write_vtk_file("source-%s.vtu" % resolution, [
                ("j", jxyz),
                ("rho", rho),
                ("Einc", inc_field_scat.e),
                ("Hinc", inc_field_scat.h),
                ("bdry_normals", bdry_normals),
                ("e_bc_residual", eh_bc_values[:3]),
                ("h_bc_residual", eh_bc_values[3]),
                ])

            fplot = make_field_plotter_from_bbox(
                    find_bounding_box(scat_discr.mesh), h=(0.05, 0.05, 0.3),
                    extend_factor=0.3)

            from pytential.qbx import QBXTargetAssociationFailedException

            qbx_tgt_tol = qbx.copy(target_association_tolerance=0.2)

            fplot_tgt = PointsTarget(cl.array.to_device(queue, fplot.points))
            try:
                fplot_repr = eval_repr_at(fplot_tgt, source=qbx_tgt_tol)
            except QBXTargetAssociationFailedException as e:
                fplot.write_vtk_file(
                        "failed-targets.vts",
                        [
                            ("failed_targets", e.failed_target_flags.get(queue))
                            ])
                raise

            fplot_repr = EHField(vector_from_device(queue, fplot_repr))

            fplot_inc = EHField(
                    vector_from_device(queue, eval_inc_field_at(fplot_tgt)))

            fplot.write_vtk_file(
                    "potential-%s.vts" % resolution,
                    [
                        ("E", fplot_repr.e),
                        ("H", fplot_repr.h),
                        ("Einc", fplot_inc.e),
                        ("Hinc", fplot_inc.h),
                        ]
                    )

        # }}}

        # {{{ error in E, H

        obs_repr = EHField(eval_repr_at(obs_discr))

        def obs_norm(f):
            return norm(obs_discr, queue, f, p=np.inf)

        rel_err_e = (obs_norm(inc_field_obs.e + obs_repr.e)
                / obs_norm(inc_field_obs.e))
        rel_err_h = (obs_norm(inc_field_obs.h + obs_repr.h)
                / obs_norm(inc_field_obs.h))

        # }}}

        print("ERR", h_max, rel_err_h, rel_err_e)

        eoc_rec_h.add_data_point(h_max, rel_err_h)
        eoc_rec_e.add_data_point(h_max, rel_err_e)

    print("--------------------------------------------------------")
    print("is_interior=%s" % case.is_interior)
    print("--------------------------------------------------------")

    good = True
    for which_eoc, eoc_rec, order_tol in [
            ("maxwell", eoc_rec_repr_maxwell, 1.5),
            ("PEC BC", eoc_pec_bc, 1.5),
            ("H", eoc_rec_h, 1.5),
            ("E", eoc_rec_e, 1.5)]:
        print(which_eoc)
        print(eoc_rec.pretty_print())

        if len(eoc_rec.history) > 1:
            if eoc_rec.order_estimate() < case.qbx_order - order_tol:
                good = False

    assert good
Beispiel #45
0
                                              pde_test_repr.h, case.k)
        ]
        print("Maxwell residuals:", maxwell_residuals)

        eoc_rec_repr_maxwell.add_data_point(h_max, max(maxwell_residuals))

        # }}}

        # {{{ check PEC BC on total field

        bc_repr = EHField(
            mfie.scattered_volume_field(jt_sym,
                                        rho_sym,
                                        qbx_forced_limit=loc_sign))
        pec_bc_e = sym.n_cross(bc_repr.e + inc_xyz_sym.e)
        pec_bc_h = sym.normal(3).as_vector().dot(bc_repr.h + inc_xyz_sym.h)

        eh_bc_values = bind(places, sym.flat_obj_array(pec_bc_e, pec_bc_h))(
            actx, jt=jt, rho=rho, inc_fld=inc_field_scat.field, **knl_kwargs)

        def scat_norm(f):
            return norm(density_discr, f, p=np.inf)

        e_bc_residual = scat_norm(eh_bc_values[:3]) / scat_norm(
            inc_field_scat.e)
        h_bc_residual = scat_norm(eh_bc_values[3]) / scat_norm(
            inc_field_scat.h)

        print("E/H PEC BC residuals:", h_max, e_bc_residual, h_bc_residual)

        eoc_pec_bc.add_data_point(h_max, max(e_bc_residual, h_bc_residual))
def run_dielectric_test(cl_ctx, queue, nelements, qbx_order,
        op_class, mode,
        k0=3, k1=2.9, mesh_order=10,
        bdry_quad_order=None, bdry_ovsmp_quad_order=None,
        use_l2_weighting=False,
        fmm_order=None, visualize=False):

    if fmm_order is None:
        fmm_order = qbx_order * 2
    if bdry_quad_order is None:
        bdry_quad_order = mesh_order
    if bdry_ovsmp_quad_order is None:
        bdry_ovsmp_quad_order = 4*bdry_quad_order

    from meshmode.mesh.generation import ellipse, make_curve_mesh
    from functools import partial
    mesh = make_curve_mesh(
            partial(ellipse, 3),
            np.linspace(0, 1, nelements+1),
            mesh_order)

    density_discr = Discretization(
            cl_ctx, mesh,
            InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order))

    logger.info("%d elements" % mesh.nelements)

    # from meshmode.discretization.visualization import make_visualizer
    # bdry_vis = make_visualizer(queue, density_discr, 20)

    # {{{ solve bvp

    from sumpy.kernel import HelmholtzKernel, AxisTargetDerivative
    kernel = HelmholtzKernel(2)

    beta = 2.5
    K0 = np.sqrt(k0**2-beta**2)  # noqa
    K1 = np.sqrt(k1**2-beta**2)  # noqa

    pde_op = op_class(
            mode,
            k_vacuum=1,
            interfaces=((0, 1, sym.DEFAULT_SOURCE),),
            domain_k_exprs=(k0, k1),
            beta=beta,
            use_l2_weighting=use_l2_weighting)

    op_unknown_sym = pde_op.make_unknown("unknown")

    representation0_sym = pde_op.representation(op_unknown_sym, 0)
    representation1_sym = pde_op.representation(op_unknown_sym, 1)

    from pytential.qbx import QBXLayerPotentialSource
    qbx = QBXLayerPotentialSource(
            density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order,
            fmm_order=fmm_order
            ).with_refinement()

    #print(sym.pretty(pde_op.operator(op_unknown_sym)))
    #1/0
    bound_pde_op = bind(qbx, pde_op.operator(op_unknown_sym))

    e_factor = float(pde_op.ez_enabled)
    h_factor = float(pde_op.hz_enabled)

    e_sources_0 = make_obj_array(list(np.array([
        [0.1, 0.2]
        ]).T.copy()))
    e_strengths_0 = np.array([1*e_factor])
    e_sources_1 = make_obj_array(list(np.array([
        [4, 4]
        ]).T.copy()))
    e_strengths_1 = np.array([1*e_factor])

    h_sources_0 = make_obj_array(list(np.array([
        [0.2, 0.1]
        ]).T.copy()))
    h_strengths_0 = np.array([1*h_factor])
    h_sources_1 = make_obj_array(list(np.array([
        [4, 5]
        ]).T.copy()))
    h_strengths_1 = np.array([1*h_factor])

    kernel_grad = [
        AxisTargetDerivative(i, kernel) for i in range(density_discr.ambient_dim)]

    from sumpy.p2p import P2P
    pot_p2p = P2P(cl_ctx, [kernel], exclude_self=False)
    pot_p2p_grad = P2P(cl_ctx, kernel_grad, exclude_self=False)

    normal = bind(density_discr, sym.normal())(queue).as_vector(np.object)
    tangent = bind(
        density_discr,
        sym.pseudoscalar()/sym.area_element())(queue).as_vector(np.object)

    _, (E0,) = pot_p2p(queue, density_discr.nodes(), e_sources_0, [e_strengths_0],
                    out_host=False, k=K0)
    _, (E1,) = pot_p2p(queue, density_discr.nodes(), e_sources_1, [e_strengths_1],
                    out_host=False, k=K1)
    _, (grad0_E0, grad1_E0) = pot_p2p_grad(
        queue, density_discr.nodes(), e_sources_0, [e_strengths_0],
        out_host=False, k=K0)
    _, (grad0_E1, grad1_E1) = pot_p2p_grad(
        queue, density_discr.nodes(), e_sources_1, [e_strengths_1],
        out_host=False, k=K1)

    _, (H0,) = pot_p2p(queue, density_discr.nodes(), h_sources_0, [h_strengths_0],
                    out_host=False, k=K0)
    _, (H1,) = pot_p2p(queue, density_discr.nodes(), h_sources_1, [h_strengths_1],
                    out_host=False, k=K1)
    _, (grad0_H0, grad1_H0) = pot_p2p_grad(
        queue, density_discr.nodes(), h_sources_0, [h_strengths_0],
        out_host=False, k=K0)
    _, (grad0_H1, grad1_H1) = pot_p2p_grad(
        queue, density_discr.nodes(), h_sources_1, [h_strengths_1],
        out_host=False, k=K1)

    E0_dntarget = (grad0_E0*normal[0] + grad1_E0*normal[1])  # noqa
    E1_dntarget = (grad0_E1*normal[0] + grad1_E1*normal[1])  # noqa

    H0_dntarget = (grad0_H0*normal[0] + grad1_H0*normal[1])  # noqa
    H1_dntarget = (grad0_H1*normal[0] + grad1_H1*normal[1])  # noqa

    E0_dttarget = (grad0_E0*tangent[0] + grad1_E0*tangent[1])  # noqa
    E1_dttarget = (grad0_E1*tangent[0] + grad1_E1*tangent[1])  # noqa

    H0_dttarget = (grad0_H0*tangent[0] + grad1_H0*tangent[1])  # noqa
    H1_dttarget = (grad0_H1*tangent[0] + grad1_H1*tangent[1])  # noqa

    sqrt_w = bind(density_discr, sym.sqrt_jac_q_weight())(queue)

    bvp_rhs = np.zeros(len(pde_op.bcs), dtype=np.object)
    for i_bc, terms in enumerate(pde_op.bcs):
        for term in terms:
            assert term.i_interface == 0
            if term.field_kind == pde_op.field_kind_e:

                if term.direction == pde_op.dir_none:
                    bvp_rhs[i_bc] += (
                        term.coeff_outer * E0
                        + term.coeff_inner * E1)
                elif term.direction == pde_op.dir_normal:
                    bvp_rhs[i_bc] += (
                        term.coeff_outer * E0_dntarget
                        + term.coeff_inner * E1_dntarget)
                elif term.direction == pde_op.dir_tangential:
                    bvp_rhs[i_bc] += (
                        term.coeff_outer * E0_dttarget
                        + term.coeff_inner * E1_dttarget)
                else:
                    raise NotImplementedError("direction spec in RHS")

            elif term.field_kind == pde_op.field_kind_h:
                if term.direction == pde_op.dir_none:
                    bvp_rhs[i_bc] += (
                        term.coeff_outer * H0
                        + term.coeff_inner * H1)
                elif term.direction == pde_op.dir_normal:
                    bvp_rhs[i_bc] += (
                        term.coeff_outer * H0_dntarget
                        + term.coeff_inner * H1_dntarget)
                elif term.direction == pde_op.dir_tangential:
                    bvp_rhs[i_bc] += (
                        term.coeff_outer * H0_dttarget
                        + term.coeff_inner * H1_dttarget)
                else:
                    raise NotImplementedError("direction spec in RHS")

            if use_l2_weighting:
                bvp_rhs[i_bc] *= sqrt_w

    scipy_op = bound_pde_op.scipy_op(queue, "unknown",
            domains=[sym.DEFAULT_TARGET]*len(pde_op.bcs), K0=K0, K1=K1,
            dtype=np.complex128)

    if mode == "tem" or op_class is SRep:
        from sumpy.tools import vector_from_device, vector_to_device
        from pytential.solve import lu
        unknown = lu(scipy_op, vector_from_device(queue, bvp_rhs))
        unknown = vector_to_device(queue, unknown)

    else:
        from pytential.solve import gmres
        gmres_result = gmres(scipy_op,
                bvp_rhs, tol=1e-14, progress=True,
                hard_failure=True, stall_iterations=0)

        unknown = gmres_result.solution

    # }}}

    targets_0 = make_obj_array(list(np.array([
        [3.2 + t, -4]
        for t in [0, 0.5, 1]
        ]).T.copy()))
    targets_1 = make_obj_array(list(np.array([
        [t*-0.3, t*-0.2]
        for t in [0, 0.5, 1]
        ]).T.copy()))

    from pytential.target import PointsTarget
    from sumpy.tools import vector_from_device
    F0_tgt = vector_from_device(queue, bind(  # noqa
            (qbx, PointsTarget(targets_0)),
            representation0_sym)(queue, unknown=unknown, K0=K0, K1=K1))
    F1_tgt = vector_from_device(queue, bind(  # noqa
            (qbx, PointsTarget(targets_1)),
            representation1_sym)(queue, unknown=unknown, K0=K0, K1=K1))

    _, (E0_tgt_true,) = pot_p2p(queue, targets_0, e_sources_0, [e_strengths_0],
                    out_host=True, k=K0)
    _, (E1_tgt_true,) = pot_p2p(queue, targets_1, e_sources_1, [e_strengths_1],
                    out_host=True, k=K1)

    _, (H0_tgt_true,) = pot_p2p(queue, targets_0, h_sources_0, [h_strengths_0],
                    out_host=True, k=K0)
    _, (H1_tgt_true,) = pot_p2p(queue, targets_1, h_sources_1, [h_strengths_1],
                    out_host=True, k=K1)

    err_F0_total = 0  # noqa
    err_F1_total = 0  # noqa

    i_field = 0

    def vec_norm(ary):
        return la.norm(ary.reshape(-1))

    def field_kind_to_string(field_kind):
        return {pde_op.field_kind_e: "E", pde_op.field_kind_h: "H"}[field_kind]

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

        if field_kind == pde_op.field_kind_e:
            F0_tgt_true = E0_tgt_true  # noqa
            F1_tgt_true = E1_tgt_true  # noqa
        elif field_kind == pde_op.field_kind_h:
            F0_tgt_true = H0_tgt_true  # noqa
            F1_tgt_true = H1_tgt_true  # noqa
        else:
            assert False

        abs_err_F0 = vec_norm(F0_tgt[i_field] - F0_tgt_true)  # noqa
        abs_err_F1 = vec_norm(F1_tgt[i_field] - F1_tgt_true)  # noqa

        rel_err_F0 = abs_err_F0/vec_norm(F0_tgt_true)  # noqa
        rel_err_F1 = abs_err_F1/vec_norm(F1_tgt_true)  # noqa

        err_F0_total = max(rel_err_F0, err_F0_total)  # noqa
        err_F1_total = max(rel_err_F1, err_F1_total)  # noqa

        print("Abs Err %s0" % field_kind_to_string(field_kind), abs_err_F0)
        print("Abs Err %s1" % field_kind_to_string(field_kind), abs_err_F1)

        print("Rel Err %s0" % field_kind_to_string(field_kind), rel_err_F0)
        print("Rel Err %s1" % field_kind_to_string(field_kind), rel_err_F1)

        i_field += 1

    if visualize:
        from sumpy.visualization import FieldPlotter
        fplot = FieldPlotter(np.zeros(2), extent=5, npoints=300)
        from pytential.target import PointsTarget
        fld0 = bind(
                (qbx, PointsTarget(fplot.points)),
                representation0_sym)(queue, unknown=unknown, K0=K0)
        fld1 = bind(
                (qbx, PointsTarget(fplot.points)),
                representation1_sym)(queue, unknown=unknown, K1=K1)

        comp_fields = []
        i_field = 0
        for field_kind in pde_op.field_kinds:
            if not pde_op.is_field_present(field_kind):
                continue

            fld_str = field_kind_to_string(field_kind)
            comp_fields.extend([
                ("%s_fld0" % fld_str, fld0[i_field].get()),
                ("%s_fld1" % fld_str, fld1[i_field].get()),
                ])

            i_field += 0

        low_order_qbx = QBXLayerPotentialSource(
                density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=2,
                fmm_order=3).with_refinement()
        from sumpy.kernel import LaplaceKernel
        from pytential.target import PointsTarget
        ones = (cl.array.empty(queue, (density_discr.nnodes,), dtype=np.float64)
                .fill(1))
        ind_func = - bind((low_order_qbx, PointsTarget(fplot.points)),
                sym.D(LaplaceKernel(2), sym.var("u")))(
                        queue, u=ones).get()

        _, (e_fld0_true,) = pot_p2p(
                queue, fplot.points, e_sources_0, [e_strengths_0],
                out_host=True, k=K0)
        _, (e_fld1_true,) = pot_p2p(
                queue, fplot.points, e_sources_1, [e_strengths_1],
                out_host=True, k=K1)
        _, (h_fld0_true,) = pot_p2p(
                queue, fplot.points, h_sources_0, [h_strengths_0],
                out_host=True, k=K0)
        _, (h_fld1_true,) = pot_p2p(
                queue, fplot.points, h_sources_1, [h_strengths_1],
                out_host=True, k=K1)

        #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5)
        fplot.write_vtk_file(
                "potential-n%d.vts" % nelements,
                [
                    ("e_fld0_true", e_fld0_true),
                    ("e_fld1_true", e_fld1_true),
                    ("h_fld0_true", h_fld0_true),
                    ("h_fld1_true", h_fld1_true),
                    ("ind", ind_func),
                    ] + comp_fields
                )

    return err_F0_total, err_F1_total
Beispiel #47
0
def main():
    import logging
    logger = logging.getLogger(__name__)
    logging.basicConfig(level=logging.WARNING)  # INFO for more progress info

    from meshmode.mesh.io import generate_gmsh, FileSource
    mesh = generate_gmsh(
            FileSource(cad_file_name), 2, order=2,
            other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h])

    from meshmode.mesh.processing import perform_flips
    # Flip elements--gmsh generates inside-out geometry.
    mesh = perform_flips(mesh, np.ones(mesh.nelements))

    from meshmode.mesh.processing import find_bounding_box
    bbox_min, bbox_max = find_bounding_box(mesh)
    bbox_center = 0.5*(bbox_min+bbox_max)
    bbox_size = max(bbox_max-bbox_min) / 2

    logger.info("%d elements" % mesh.nelements)

    from pytential.qbx import QBXLayerPotentialSource
    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory

    density_discr = Discretization(
            cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order))

    qbx, _ = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order,
            fmm_order=qbx_order + 3,
            target_association_tolerance=0.15).with_refinement()

    nodes = density_discr.nodes().with_queue(queue)

    angle = cl.clmath.atan2(nodes[1], nodes[0])

    from pytential import bind, sym
    #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None))
    op = sym.D(kernel, sym.var("sigma"), qbx_forced_limit=None)
    #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None)

    sigma = cl.clmath.cos(mode_nr*angle)
    if 0:
        sigma = 0*angle
        from random import randrange
        for i in range(5):
            sigma[randrange(len(sigma))] = 1

    if isinstance(kernel, HelmholtzKernel):
        sigma = sigma.astype(np.complex128)

    fplot = FieldPlotter(bbox_center, extent=3.5*bbox_size, npoints=150)

    from pytential.target import PointsTarget
    fld_in_vol = bind(
            (qbx, PointsTarget(fplot.points)),
            op)(queue, sigma=sigma, k=k).get()

    #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5)
    fplot.write_vtk_file(
            "potential-3d.vts",
            [
                ("potential", fld_in_vol)
                ]
            )

    bdry_normals = bind(
            density_discr,
            sym.normal(density_discr.ambient_dim))(queue).as_vector(dtype=object)

    from meshmode.discretization.visualization import make_visualizer
    bdry_vis = make_visualizer(queue, density_discr, target_order)

    bdry_vis.write_vtk_file("source-3d.vtu", [
        ("sigma", sigma),
        ("bdry_normals", bdry_normals),
        ])
Beispiel #48
0
def main():
    # cl.array.to_device(queue, numpy_array)
    from meshmode.mesh.io import generate_gmsh, FileSource
    mesh = generate_gmsh(
        FileSource("ellipsoid.step"),
        2,
        order=2,
        other_options=["-string",
                       "Mesh.CharacteristicLengthMax = %g;" % h])

    from meshmode.mesh.processing import perform_flips
    # Flip elements--gmsh generates inside-out geometry.
    mesh = perform_flips(mesh, np.ones(mesh.nelements))

    print("%d elements" % mesh.nelements)

    from meshmode.mesh.processing import find_bounding_box
    bbox_min, bbox_max = find_bounding_box(mesh)
    bbox_center = 0.5 * (bbox_min + bbox_max)
    bbox_size = max(bbox_max - bbox_min) / 2

    logger.info("%d elements" % mesh.nelements)

    from pytential.qbx import QBXLayerPotentialSource
    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            InterpolatoryQuadratureSimplexGroupFactory

    density_discr = Discretization(
        cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order))

    qbx = QBXLayerPotentialSource(density_discr,
                                  4 * target_order,
                                  qbx_order,
                                  fmm_order=qbx_order + 10,
                                  fmm_backend="fmmlib")

    from pytential.symbolic.pde.maxwell import MuellerAugmentedMFIEOperator
    pde_op = MuellerAugmentedMFIEOperator(
        omega=0.4,
        epss=[1.4, 1.0],
        mus=[1.2, 1.0],
    )
    from pytential import bind, sym

    unk = pde_op.make_unknown("sigma")
    sym_operator = pde_op.operator(unk)
    sym_rhs = pde_op.rhs(sym.make_sym_vector("Einc", 3),
                         sym.make_sym_vector("Hinc", 3))
    sym_repr = pde_op.representation(0, unk)

    if 1:
        expr = sym_repr
        print(sym.pretty(expr))

        print("#" * 80)
        from pytential.target import PointsTarget

        tgt_points = np.zeros((3, 1))
        tgt_points[0, 0] = 100
        tgt_points[1, 0] = -200
        tgt_points[2, 0] = 300

        bound_op = bind((qbx, PointsTarget(tgt_points)), expr)
        print(bound_op.code)

    if 1:

        def green3e(x, y, z, source, strength, k):
            # electric field corresponding to dyadic green's function
            # due to monochromatic electric dipole located at "source".
            # "strength" is the the intensity of the dipole.
            #  E = (I + Hess)(exp(ikr)/r) dot (strength)
            #
            dx = x - source[0]
            dy = y - source[1]
            dz = z - source[2]
            rr = np.sqrt(dx**2 + dy**2 + dz**2)

            fout = np.exp(1j * k * rr) / rr
            evec = fout * strength
            qmat = np.zeros((3, 3), dtype=np.complex128)

            qmat[0, 0] = (2 * dx**2 - dy**2 - dz**2) * (1 - 1j * k * rr)
            qmat[1, 1] = (2 * dy**2 - dz**2 - dx**2) * (1 - 1j * k * rr)
            qmat[2, 2] = (2 * dz**2 - dx**2 - dy**2) * (1 - 1j * k * rr)

            qmat[0, 0] = qmat[0, 0] + (-k**2 * dx**2 * rr**2)
            qmat[1, 1] = qmat[1, 1] + (-k**2 * dy**2 * rr**2)
            qmat[2, 2] = qmat[2, 2] + (-k**2 * dz**2 * rr**2)

            qmat[0, 1] = (3 - k**2 * rr**2 - 3 * 1j * k * rr) * (dx * dy)
            qmat[1, 2] = (3 - k**2 * rr**2 - 3 * 1j * k * rr) * (dy * dz)
            qmat[2, 0] = (3 - k**2 * rr**2 - 3 * 1j * k * rr) * (dz * dx)

            qmat[1, 0] = qmat[0, 1]
            qmat[2, 1] = qmat[1, 2]
            qmat[0, 2] = qmat[2, 0]

            fout = np.exp(1j * k * rr) / rr**5 / k**2

            fvec = fout * np.dot(qmat, strength)
            evec = evec + fvec
            return evec

        def green3m(x, y, z, source, strength, k):
            # magnetic field corresponding to dyadic green's function
            # due to monochromatic electric dipole located at "source".
            # "strength" is the the intensity of the dipole.
            #  H = curl((I + Hess)(exp(ikr)/r) dot (strength)) =
            #  strength \cross \grad (exp(ikr)/r)
            #
            dx = x - source[0]
            dy = y - source[1]
            dz = z - source[2]
            rr = np.sqrt(dx**2 + dy**2 + dz**2)

            fout = (1 - 1j * k * rr) * np.exp(1j * k * rr) / rr**3
            fvec = np.zeros(3, dtype=np.complex128)
            fvec[0] = fout * dx
            fvec[1] = fout * dy
            fvec[2] = fout * dz

            hvec = np.cross(strength, fvec)

            return hvec

        def dipole3e(x, y, z, source, strength, k):
            #
            #  evalaute electric and magnetic field due
            #  to monochromatic electric dipole located at "source"
            #  with intensity "strength"

            evec = green3e(x, y, z, source, strength, k)
            evec = evec * 1j * k
            hvec = green3m(x, y, z, source, strength, k)
            return evec, hvec

        def dipole3m(x, y, z, source, strength, k):
            #
            #  evalaute electric and magnetic field due
            #  to monochromatic magnetic dipole located at "source"
            #  with intensity "strength"
            evec = green3m(x, y, z, source, strength, k)
            hvec = green3e(x, y, z, source, strength, k)
            hvec = -hvec * 1j * k
            return evec, hvec

        def dipole3eall(x, y, z, sources, strengths, k):
            ns = len(strengths)
            evec = np.zeros(3, dtype=np.complex128)
            hvec = np.zeros(3, dtype=np.complex128)

            for i in range(ns):
                evect, hvect = dipole3e(x, y, z, sources[i], strengths[i], k)
                evec = evec + evect
                hvec = hvec + hvect

        nodes = density_discr.nodes().with_queue(queue).get()
        source = [0.01, -0.03, 0.02]
        #        source = cl.array.to_device(queue,np.zeros(3))
        #        source[0] = 0.01
        #        source[1] =-0.03
        #        source[2] = 0.02
        strength = np.ones(3)

        #        evec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128))
        #        hvec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128))

        evec = np.zeros((3, len(nodes[0])), dtype=np.complex128)
        hvec = np.zeros((3, len(nodes[0])), dtype=np.complex128)
        for i in range(len(nodes[0])):
            evec[:, i], hvec[:, i] = dipole3e(nodes[0][i], nodes[1][i],
                                              nodes[2][i], source, strength, k)
        print(np.shape(hvec))
        print(type(evec))
        print(type(hvec))

        evec = cl.array.to_device(queue, evec)
        hvec = cl.array.to_device(queue, hvec)

        bvp_rhs = bind(qbx, sym_rhs)(queue, Einc=evec, Hinc=hvec)
        print(np.shape(bvp_rhs))
        print(type(bvp_rhs))
        #        print(bvp_rhs)
        1 / -1

        bound_op = bind(qbx, sym_operator)

        from pytential.solve import gmres
        if 0:
            gmres_result = gmres(bound_op.scipy_op(queue,
                                                   "sigma",
                                                   dtype=np.complex128,
                                                   k=k),
                                 bvp_rhs,
                                 tol=1e-8,
                                 progress=True,
                                 stall_iterations=0,
                                 hard_failure=True)

            sigma = gmres_result.solution

        fld_at_tgt = bind((qbx, PointsTarget(tgt_points)),
                          sym_repr)(queue, sigma=bvp_rhs, k=k)
        fld_at_tgt = np.array([fi.get() for fi in fld_at_tgt])
        print(fld_at_tgt)
        1 / 0

    # }}}

    #mlab.figure(bgcolor=(1, 1, 1))
    if 1:
        from meshmode.discretization.visualization import make_visualizer
        bdry_vis = make_visualizer(queue, density_discr, target_order)

        bdry_normals = bind(density_discr, sym.normal(3))(queue)\
                .as_vector(dtype=object)

        bdry_vis.write_vtk_file("source.vtu", [
            ("sigma", sigma),
            ("bdry_normals", bdry_normals),
        ])

        fplot = FieldPlotter(bbox_center,
                             extent=2 * bbox_size,
                             npoints=(150, 150, 1))

        qbx_tgt_tol = qbx.copy(target_association_tolerance=0.1)
        from pytential.target import PointsTarget
        from pytential.qbx import QBXTargetAssociationFailedException

        rho_sym = sym.var("rho")

        try:
            fld_in_vol = bind((qbx_tgt_tol, PointsTarget(fplot.points)),
                              sym.make_obj_array([
                                  sym.S(pde_op.kernel,
                                        rho_sym,
                                        k=sym.var("k"),
                                        qbx_forced_limit=None),
                                  sym.d_dx(
                                      3,
                                      sym.S(pde_op.kernel,
                                            rho_sym,
                                            k=sym.var("k"),
                                            qbx_forced_limit=None)),
                                  sym.d_dy(
                                      3,
                                      sym.S(pde_op.kernel,
                                            rho_sym,
                                            k=sym.var("k"),
                                            qbx_forced_limit=None)),
                                  sym.d_dz(
                                      3,
                                      sym.S(pde_op.kernel,
                                            rho_sym,
                                            k=sym.var("k"),
                                            qbx_forced_limit=None)),
                              ]))(queue, jt=jt, rho=rho, k=k)
        except QBXTargetAssociationFailedException as e:
            fplot.write_vtk_file(
                "failed-targets.vts",
                [("failed_targets", e.failed_target_flags.get(queue))])
            raise

        fld_in_vol = sym.make_obj_array([fiv.get() for fiv in fld_in_vol])

        #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5)
        fplot.write_vtk_file("potential.vts", [
            ("potential", fld_in_vol[0]),
            ("grad", fld_in_vol[1:]),
        ])
                                          sym.QBX_SOURCE_QUAD_STAGE2)
        logger.info("quad stage-2 elements have %d nodes",
                    discr.groups[0].nunit_dofs)

    # }}}

    # {{{ plot geometry

    if visualize and ambient_dim == 2:
        try:
            import matplotlib.pyplot as pt
        except ImportError:
            visualize = False

    if visualize:
        normals = bind(places, sym.normal(ambient_dim).as_vector())(actx)

        # show geometry, centers, normals
        if ambient_dim == 2:
            nodes = actx.to_numpy(flatten(density_discr.nodes(),
                                          actx)).reshape(ambient_dim, -1)
            normals = actx.to_numpy(flatten(normals,
                                            actx)).reshape(ambient_dim, -1)

            pt.plot(nodes[0], nodes[1], "x-")
            pt.quiver(nodes[0], nodes[1], normals[0], normals[1])
            pt.gca().set_aspect("equal")
            pt.savefig(f"pre-solve-source-{resolution}", dpi=300)
        elif ambient_dim == 3:
            bdry_vis = make_visualizer(actx, density_discr,
                                       case.target_order + 3)
def test_identity_convergence(ctx_getter,  case, visualize=False):
    logging.basicConfig(level=logging.INFO)

    case.check()

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

    # prevent cache 'splosion
    from sympy.core.cache import clear_cache
    clear_cache()

    target_order = 8

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for resolution in (
            getattr(case, "resolutions", None)
            or case.geometry.resolutions
            ):
        mesh = case.geometry.get_mesh(resolution, target_order)
        if mesh is None:
            break

        d = mesh.ambient_dim
        k = case.k

        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")}

        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))

        refiner_extra_kwargs = {}

        if case.k != 0:
            refiner_extra_kwargs["kernel_length_scale"] = 5/case.k

        qbx, _ = QBXLayerPotentialSource(
                pre_density_discr, 4*target_order,
                case.qbx_order,
                fmm_order=case.fmm_order,
                fmm_backend=case.fmm_backend,
                _expansions_in_tree_have_extent=True,
                _expansion_stick_out_factor=getattr(
                    case, "_expansion_stick_out_factor", 0),
                ).with_refinement(**refiner_extra_kwargs)

        density_discr = qbx.density_discr

        # {{{ compute values of a solution to the PDE

        nodes_host = density_discr.nodes().get(queue)
        normal = bind(density_discr, sym.normal(d))(queue).as_vector(np.object)
        normal_host = [normal[j].get() for j in range(d)]

        if k != 0:
            if d == 2:
                angle = 0.3
                wave_vec = np.array([np.cos(angle), np.sin(angle)])
                u = np.exp(1j*k*np.tensordot(wave_vec, nodes_host, axes=1))
                grad_u = 1j*k*wave_vec[:, np.newaxis]*u
            elif d == 3:
                center = np.array([3, 1, 2])
                diff = nodes_host - center[:, np.newaxis]
                r = la.norm(diff, axis=0)
                u = np.exp(1j*k*r) / r
                grad_u = diff * (1j*k*u/r - u/r**2)
            else:
                raise ValueError("invalid dim")
        else:
            center = np.array([3, 1, 2])[:d]
            diff = nodes_host - center[:, np.newaxis]
            dist_squared = np.sum(diff**2, axis=0)
            dist = np.sqrt(dist_squared)
            if d == 2:
                u = np.log(dist)
                grad_u = diff/dist_squared
            elif d == 3:
                u = 1/dist
                grad_u = -diff/dist**3
            else:
                assert False

        dn_u = 0
        for i in range(d):
            dn_u = dn_u + normal_host[i]*grad_u[i]

        # }}}

        u_dev = cl.array.to_device(queue, u)
        dn_u_dev = cl.array.to_device(queue, dn_u)
        grad_u_dev = cl.array.to_device(queue, grad_u)

        key = (case.qbx_order, case.geometry.mesh_name, resolution,
                case.expr.zero_op_name)

        bound_op = bind(qbx, case.expr.get_zero_op(k_sym, **knl_kwargs))
        error = bound_op(
                queue, u=u_dev, dn_u=dn_u_dev, grad_u=grad_u_dev, k=case.k)
        if 0:
            pt.plot(error)
            pt.show()

        linf_error_norm = norm(density_discr, queue, error, p=np.inf)
        print("--->", key, linf_error_norm)

        eoc_rec.add_data_point(qbx.h_max, linf_error_norm)

        if visualize:
            from meshmode.discretization.visualization import make_visualizer
            bdry_vis = make_visualizer(queue, density_discr, target_order)

            bdry_normals = bind(density_discr, sym.normal(mesh.ambient_dim))(queue)\
                    .as_vector(dtype=object)

            bdry_vis.write_vtk_file("source-%s.vtu" % resolution, [
                ("u", u_dev),
                ("bdry_normals", bdry_normals),
                ("error", error),
                ])

    print(eoc_rec)
    tgt_order = case.qbx_order - case.expr.order_drop
    assert eoc_rec.order_estimate() > tgt_order - 1.6