예제 #1
0
    def __init__(self, array_context, mesh, order=None,
            quad_tag_to_group_factory=None, mpi_communicator=None):
        """
        :param quad_tag_to_group_factory: A mapping from quadrature tags (typically
            strings--but may be any hashable/comparable object) to a
            :class:`~meshmode.discretization.poly_element.ElementGroupFactory`
            indicating with which quadrature discretization the operations are
            to be carried out, or *None* to indicate that operations with this
            quadrature tag should be carried out with the standard volume
            discretization.
        """

        self._setup_actx = array_context

        from meshmode.discretization.poly_element import \
                PolynomialWarpAndBlendGroupFactory

        if quad_tag_to_group_factory is None:
            if order is None:
                raise TypeError("one of 'order' and "
                        "'quad_tag_to_group_factory' must be given")

            quad_tag_to_group_factory = {
                    sym.QTAG_NONE: PolynomialWarpAndBlendGroupFactory(order=order)}
        else:
            if order is not None:
                quad_tag_to_group_factory = quad_tag_to_group_factory.copy()
                if sym.QTAG_NONE in quad_tag_to_group_factory:
                    raise ValueError("if 'order' is given, "
                            "'quad_tag_to_group_factory' must not have a "
                            "key of QTAG_NONE")

                quad_tag_to_group_factory[sym.QTAG_NONE] = \
                        PolynomialWarpAndBlendGroupFactory(order=order)

        self.quad_tag_to_group_factory = quad_tag_to_group_factory

        from meshmode.discretization import Discretization

        self._volume_discr = Discretization(array_context, mesh,
                self.group_factory_for_quadrature_tag(sym.QTAG_NONE))

        # {{{ management of discretization-scoped common subexpressions

        from pytools import UniqueNameGenerator
        self._discr_scoped_name_gen = UniqueNameGenerator()

        self._discr_scoped_subexpr_to_name = {}
        self._discr_scoped_subexpr_name_to_value = {}

        # }}}

        self._dist_boundary_connections = \
                self._set_up_distributed_communication(
                        mpi_communicator, array_context)

        self.mpi_communicator = mpi_communicator
예제 #2
0
def test_copy_visualizer(actx_factory, ambient_dim, visualize=True):
    actx = actx_factory()
    target_order = 4

    if ambient_dim == 2:
        nelements = 128
        mesh = mgen.make_curve_mesh(partial(mgen.ellipse, 1.0),
                                    np.linspace(0.0, 1.0, nelements + 1),
                                    target_order)
    elif ambient_dim == 3:
        mesh = mgen.generate_icosphere(1.0,
                                       target_order,
                                       uniform_refinement_rounds=2)
    else:
        raise ValueError(f"unsupported dimension: {ambient_dim}")

    from meshmode.mesh.processing import affine_map
    translated_mesh = affine_map(mesh,
                                 b=np.array([2.5, 0.0, 0.0][:ambient_dim]))

    from meshmode.discretization import Discretization
    discr = Discretization(actx, mesh,
                           PolynomialWarpAndBlendGroupFactory(target_order))
    translated_discr = Discretization(
        actx, translated_mesh,
        PolynomialWarpAndBlendGroupFactory(target_order))

    from meshmode.discretization.visualization import make_visualizer
    vis = make_visualizer(actx, discr, target_order, force_equidistant=True)
    assert vis._vtk_connectivity
    assert vis._vtk_lagrange_connectivity

    translated_vis = vis.copy_with_same_connectivity(actx, translated_discr)
    assert translated_vis._cached_vtk_connectivity is not None
    assert translated_vis._cached_vtk_lagrange_connectivity is not None

    assert translated_vis._vtk_connectivity \
            is vis._vtk_connectivity
    assert translated_vis._vtk_lagrange_connectivity \
            is vis._vtk_lagrange_connectivity

    if not visualize:
        return

    vis.write_vtk_file(f"visualizer_copy_{ambient_dim}d_orig.vtu", [],
                       overwrite=True)
    translated_vis.write_vtk_file(
        f"visualizer_copy_{ambient_dim}d_translated.vtu", [], overwrite=True)
예제 #3
0
def main():
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.mesh.generation import (  # noqa
        generate_icosphere, generate_icosahedron, generate_torus)
    #mesh = generate_icosphere(1, order=order)
    mesh = generate_icosahedron(1, order=order)
    #mesh = generate_torus(3, 1, order=order)

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

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

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

    vis.write_vtk_file("geometry.vtu", [
        ("f", discr.nodes()[0]),
    ])

    from meshmode.discretization.visualization import \
            write_nodal_adjacency_vtk_file

    write_nodal_adjacency_vtk_file("adjacency.vtu", mesh)
예제 #4
0
def test_flatten_unflatten(actx_factory):
    actx = actx_factory()

    ambient_dim = 2
    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim,
                                      b=(+0.5, ) * ambient_dim,
                                      n=(3, ) * ambient_dim,
                                      order=1)
    discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(3))
    a = np.random.randn(discr.ndofs)

    from meshmode.dof_array import flatten, unflatten
    a_round_trip = actx.to_numpy(
        flatten(unflatten(actx, discr, actx.from_numpy(a))))
    assert np.array_equal(a, a_round_trip)

    from meshmode.dof_array import flatten_to_numpy, unflatten_from_numpy
    a_round_trip = flatten_to_numpy(actx, unflatten_from_numpy(actx, discr, a))
    assert np.array_equal(a, a_round_trip)

    x = thaw(discr.nodes(), actx)
    avg_mass = DOFArray(
        actx,
        tuple([(np.pi + actx.zeros((grp.nelements, 1), a.dtype))
               for grp in discr.groups]))

    c = MyContainer(name="flatten",
                    mass=avg_mass,
                    momentum=make_obj_array([x, x, x]),
                    enthalpy=x)

    from meshmode.dof_array import unflatten_like
    c_round_trip = unflatten_like(actx, flatten(c), c)
    assert flat_norm(c - c_round_trip) < 1.0e-8
예제 #5
0
def test_merge_and_map(ctx_getter, visualize=False):
    from meshmode.mesh.io import generate_gmsh, FileSource

    mesh_order = 3

    mesh = generate_gmsh(
        FileSource("blob-2d.step"),
        2,
        order=mesh_order,
        force_ambient_dim=2,
        other_options=["-string", "Mesh.CharacteristicLengthMax = 0.02;"])

    from meshmode.mesh.processing import merge_disjoint_meshes, affine_map
    mesh2 = affine_map(mesh, A=np.eye(2), b=np.array([5, 0]))

    mesh3 = merge_disjoint_meshes((mesh2, mesh))

    if visualize:
        from meshmode.discretization import Discretization
        from meshmode.discretization.poly_element import \
                PolynomialWarpAndBlendGroupFactory
        cl_ctx = ctx_getter()
        queue = cl.CommandQueue(cl_ctx)

        discr = Discretization(cl_ctx, mesh3,
                               PolynomialWarpAndBlendGroupFactory(3))

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(queue, discr, 1)
        vis.write_vtk_file("merged.vtu", [])
예제 #6
0
    def __init__(self, actx, mesh, order):
        self.order = order

        from meshmode.discretization import Discretization
        from meshmode.discretization.poly_element import \
                PolynomialWarpAndBlendGroupFactory
        self.group_factory = PolynomialWarpAndBlendGroupFactory(order=order)
        self.volume_discr = Discretization(actx, mesh, self.group_factory)

        assert self.volume_discr.dim == 2
예제 #7
0
def make_visualizer(queue, discr, vis_order):
    from meshmode.discretization import Discretization
    from meshmode.discretization.poly_element import \
            PolynomialWarpAndBlendGroupFactory
    vis_discr = Discretization(discr.cl_context,
                               discr.mesh,
                               PolynomialWarpAndBlendGroupFactory(vis_order),
                               real_dtype=discr.real_dtype)
    from meshmode.discretization.connection import \
            make_same_mesh_connection

    return Visualizer(make_same_mesh_connection(vis_discr, discr))
예제 #8
0
def vtk_visualize_mesh(actx, mesh, filename, vtk_high_order=True):
    order = max(mgrp.order for mgrp in mesh.groups)

    from meshmode.discretization.poly_element import \
            PolynomialWarpAndBlendGroupFactory
    from meshmode.discretization import Discretization
    discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(order))

    from meshmode.discretization.visualization import make_visualizer
    vis = make_visualizer(actx, discr, order, force_equidistant=vtk_high_order)

    vis.write_vtk_file(filename, [], use_high_order=vtk_high_order)
예제 #9
0
파일: test_mesh.py 프로젝트: MTCam/meshmode
def test_box_mesh(actx_factory, visualize=False):
    mesh = mgen.generate_box_mesh(3 * (np.linspace(0, 1, 5), ))

    if visualize:
        from meshmode.discretization import Discretization

        actx = actx_factory()
        discr = Discretization(actx, mesh,
                               PolynomialWarpAndBlendGroupFactory(7))

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(actx, discr, 7)
        vis.write_vtk_file("box_mesh.vtu", [])
예제 #10
0
def test_merge_and_map(ctx_factory, visualize=False):
    from meshmode.mesh.io import generate_gmsh, FileSource
    from meshmode.mesh.generation import generate_box_mesh
    from meshmode.mesh import TensorProductElementGroup
    from meshmode.discretization.poly_element import (
        PolynomialWarpAndBlendGroupFactory,
        LegendreGaussLobattoTensorProductGroupFactory)

    mesh_order = 3

    if 1:
        mesh = generate_gmsh(
            FileSource("blob-2d.step"),
            2,
            order=mesh_order,
            force_ambient_dim=2,
            other_options=["-string", "Mesh.CharacteristicLengthMax = 0.02;"])

        discr_grp_factory = PolynomialWarpAndBlendGroupFactory(3)
    else:
        mesh = generate_box_mesh((
            np.linspace(0, 1, 4),
            np.linspace(0, 1, 4),
            np.linspace(0, 1, 4),
        ),
                                 10,
                                 group_factory=TensorProductElementGroup)

        discr_grp_factory = LegendreGaussLobattoTensorProductGroupFactory(3)

    from meshmode.mesh.processing import merge_disjoint_meshes, affine_map
    mesh2 = affine_map(mesh,
                       A=np.eye(mesh.ambient_dim),
                       b=np.array([5, 0, 0])[:mesh.ambient_dim])

    mesh3 = merge_disjoint_meshes((mesh2, mesh))
    mesh3.facial_adjacency_groups

    mesh3.copy()

    if visualize:
        from meshmode.discretization import Discretization
        cl_ctx = ctx_factory()
        queue = cl.CommandQueue(cl_ctx)

        discr = Discretization(cl_ctx, mesh3, discr_grp_factory)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(queue, discr, 3, element_shrink_factor=0.8)
        vis.write_vtk_file("merged.vtu", [])
예제 #11
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),
            ])
예제 #12
0
    def group_factory_for_quadrature_tag(self, quadrature_tag):
        """
        OK to override in user code to control mode/node choice.
        """

        if quadrature_tag is None:
            quadrature_tag = sym.QTAG_NONE

        from meshmode.discretization.poly_element import \
                PolynomialWarpAndBlendGroupFactory

        if quadrature_tag is not sym.QTAG_NONE:
            return self.quad_tag_to_group_factory[quadrature_tag]
        else:
            return PolynomialWarpAndBlendGroupFactory(order=self.order)
예제 #13
0
파일: test_mesh.py 프로젝트: MTCam/meshmode
def test_merge_and_map(actx_factory, group_cls, visualize=False):
    from meshmode.mesh.io import generate_gmsh, FileSource

    order = 3
    mesh_order = 3

    if group_cls is SimplexElementGroup:
        mesh = generate_gmsh(
            FileSource("blob-2d.step"),
            2,
            order=mesh_order,
            force_ambient_dim=2,
            other_options=["-string", "Mesh.CharacteristicLengthMax = 0.02;"],
            target_unit="MM",
        )

        discr_grp_factory = PolynomialWarpAndBlendGroupFactory(order)
    else:
        ambient_dim = 3
        mesh = mgen.generate_regular_rect_mesh(a=(0, ) * ambient_dim,
                                               b=(1, ) * ambient_dim,
                                               nelements_per_axis=(4, ) *
                                               ambient_dim,
                                               order=mesh_order,
                                               group_cls=group_cls)

        discr_grp_factory = LegendreGaussLobattoTensorProductGroupFactory(
            order)

    from meshmode.mesh.processing import merge_disjoint_meshes, affine_map
    mesh2 = affine_map(mesh,
                       A=np.eye(mesh.ambient_dim),
                       b=np.array([2, 0, 0])[:mesh.ambient_dim])

    mesh3 = merge_disjoint_meshes((mesh2, mesh))
    assert mesh3.facial_adjacency_groups

    mesh4 = mesh3.copy()

    if visualize:
        from meshmode.discretization import Discretization
        actx = actx_factory()
        discr = Discretization(actx, mesh4, discr_grp_factory)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(actx, discr, 3, element_shrink_factor=0.8)
        vis.write_vtk_file("merge_and_map.vtu", [])
예제 #14
0
def test_box_mesh(ctx_getter, visualize=False):
    from meshmode.mesh.generation import generate_box_mesh
    mesh = generate_box_mesh(3 * (np.linspace(0, 1, 5), ))

    if visualize:
        from meshmode.discretization import Discretization
        from meshmode.discretization.poly_element import \
                PolynomialWarpAndBlendGroupFactory
        cl_ctx = ctx_getter()
        queue = cl.CommandQueue(cl_ctx)

        discr = Discretization(cl_ctx, mesh,
                               PolynomialWarpAndBlendGroupFactory(1))

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(queue, discr, 1)
        vis.write_vtk_file("box.vtu", [])
예제 #15
0
def test_inverse_modal_connections_quadgrid(actx_factory):
    actx = actx_factory()
    order = 5

    def f(x):
        return 1 + 2 * x + 3 * x**2

    # Make a regular rectangle mesh
    mesh = mgen.generate_regular_rect_mesh(
        a=(0, 0),
        b=(5, 3),
        npoints_per_axis=(10, 6),
        order=order,
        group_cls=QuadratureSimplexGroupFactory.mesh_group_class)

    dcoll = DiscretizationCollection(
        actx,
        mesh,
        discr_tag_to_group_factory={
            dof_desc.DISCR_TAG_BASE: PolynomialWarpAndBlendGroupFactory(order),
            dof_desc.DISCR_TAG_QUAD: QuadratureSimplexGroupFactory(2 * order)
        })

    # Use dof descriptors on the quadrature grid
    dd_modal = dof_desc.DD_VOLUME_MODAL
    dd_quad = dof_desc.DOFDesc(dof_desc.DTAG_VOLUME_ALL,
                               dof_desc.DISCR_TAG_QUAD)

    x_quad = thaw(actx, dcoll.discr_from_dd(dd_quad).nodes()[0])
    quad_f = f(x_quad)

    # Map nodal coefficients of f to modal coefficients
    forward_conn = dcoll.connection_from_dds(dd_quad, dd_modal)
    modal_f = forward_conn(quad_f)
    # Now map the modal coefficients back to nodal
    backward_conn = dcoll.connection_from_dds(dd_modal, dd_quad)
    quad_f_2 = backward_conn(modal_f)

    # This error should be small since we composed a map with
    # its inverse
    err = actx.np.linalg.norm(quad_f - quad_f_2)

    assert err <= 1e-11
예제 #16
0
def test_array_context_np_workalike(actx_factory):
    actx = actx_factory()

    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh(
            a=(-0.5,)*2, b=(0.5,)*2, n=(8,)*2, order=3)

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

    for sym_name, n_args in [
            ("sin", 1),
            ("exp", 1),
            ("arctan2", 2),
            ("minimum", 2),
            ("maximum", 2),
            ("where", 3),
            ("conj", 1),
            ]:
        args = [np.random.randn(discr.ndofs) for i in range(n_args)]
        ref_result = getattr(np, sym_name)(*args)

        # {{{ test DOFArrays

        actx_args = [unflatten(actx, discr, actx.from_numpy(arg)) for arg in args]

        actx_result = actx.to_numpy(
                flatten(getattr(actx.np, sym_name)(*actx_args)))

        assert np.allclose(actx_result, ref_result)

        # }}}

        # {{{ test object arrays of DOFArrays

        obj_array_args = [make_obj_array([arg]) for arg in actx_args]

        obj_array_result = actx.to_numpy(
                flatten(getattr(actx.np, sym_name)(*obj_array_args)[0]))

        assert np.allclose(obj_array_result, ref_result)
예제 #17
0
def _get_test_containers(actx, ambient_dim=2):
    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim,
                                      b=(+0.5, ) * ambient_dim,
                                      n=(3, ) * ambient_dim,
                                      order=1)
    discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(3))
    x = thaw(discr.nodes()[0], actx)

    # pylint: disable=unexpected-keyword-arg, no-value-for-parameter
    dataclass_of_dofs = MyContainer(name="container",
                                    mass=x,
                                    momentum=make_obj_array([x, x]),
                                    enthalpy=x)

    ary_dof = x
    ary_of_dofs = make_obj_array([x, x, x])
    mat_of_dofs = np.empty((2, 2), dtype=object)
    for i in np.ndindex(mat_of_dofs.shape):
        mat_of_dofs[i] = x

    return ary_dof, ary_of_dofs, mat_of_dofs, dataclass_of_dofs
예제 #18
0
def main(ctx_factory, dim=2, order=4, product_tag=None, visualize=False):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    # {{{ parameters

    # sphere radius
    radius = 1.0
    # sphere resolution
    resolution = 64 if dim == 2 else 1

    # cfl
    dt_factor = 2.0
    # final time
    final_time = np.pi

    # velocity field
    sym_x = sym.nodes(dim)
    c = make_obj_array([-sym_x[1], sym_x[0], 0.0])[:dim]
    # flux
    flux_type = "lf"

    # }}}

    # {{{ discretization

    if dim == 2:
        from meshmode.mesh.generation import make_curve_mesh, ellipse
        mesh = make_curve_mesh(lambda t: radius * ellipse(1.0, t),
                               np.linspace(0.0, 1.0, resolution + 1), order)
    elif dim == 3:
        from meshmode.mesh.generation import generate_icosphere
        mesh = generate_icosphere(radius,
                                  order=4 * order,
                                  uniform_refinement_rounds=resolution)
    else:
        raise ValueError("unsupported dimension")

    discr_tag_to_group_factory = {}
    if product_tag == "none":
        product_tag = None
    else:
        product_tag = dof_desc.DISCR_TAG_QUAD

    from meshmode.discretization.poly_element import \
            PolynomialWarpAndBlendGroupFactory, \
            QuadratureSimplexGroupFactory

    discr_tag_to_group_factory[dof_desc.DISCR_TAG_BASE] = \
        PolynomialWarpAndBlendGroupFactory(order)

    if product_tag:
        discr_tag_to_group_factory[product_tag] = \
            QuadratureSimplexGroupFactory(order=4*order)

    from grudge import DiscretizationCollection
    discr = DiscretizationCollection(
        actx, mesh, discr_tag_to_group_factory=discr_tag_to_group_factory)

    volume_discr = discr.discr_from_dd(dof_desc.DD_VOLUME)
    logger.info("ndofs:     %d", volume_discr.ndofs)
    logger.info("nelements: %d", volume_discr.mesh.nelements)

    # }}}

    # {{{ symbolic operators

    def f_initial_condition(x):
        return x[0]

    from grudge.models.advection import SurfaceAdvectionOperator
    op = SurfaceAdvectionOperator(c, flux_type=flux_type, quad_tag=product_tag)

    bound_op = bind(discr, op.sym_operator())
    u0 = bind(discr, f_initial_condition(sym_x))(actx, t=0)

    def rhs(t, u):
        return bound_op(actx, t=t, u=u)

    # check velocity is tangential
    sym_normal = sym.surface_normal(dim, dim=dim - 1,
                                    dd=dof_desc.DD_VOLUME).as_vector()
    error = bind(discr, sym.norm(2, c.dot(sym_normal)))(actx)
    logger.info("u_dot_n:   %.5e", error)

    # }}}

    # {{{ time stepping

    # compute time step
    h_min = bind(discr, sym.h_max_from_volume(discr.ambient_dim,
                                              dim=discr.dim))(actx)
    dt = dt_factor * h_min / order**2
    nsteps = int(final_time // dt) + 1
    dt = final_time / nsteps + 1.0e-15

    logger.info("dt:        %.5e", dt)
    logger.info("nsteps:    %d", nsteps)

    from grudge.shortcuts import set_up_rk4
    dt_stepper = set_up_rk4("u", dt, u0, rhs)
    plot = Plotter(actx, discr, order, visualize=visualize)

    norm = bind(discr, sym.norm(2, sym.var("u")))
    norm_u = norm(actx, u=u0)

    step = 0

    event = dt_stepper.StateComputed(0.0, 0, 0, u0)
    plot(event, "fld-surface-%04d" % 0)

    if visualize and dim == 3:
        from grudge.shortcuts import make_visualizer
        vis = make_visualizer(discr)
        vis.write_vtk_file("fld-surface-velocity.vtu",
                           [("u", bind(discr, c)(actx)),
                            ("n", bind(discr, sym_normal)(actx))],
                           overwrite=True)

        df = dof_desc.DOFDesc(FACE_RESTR_INTERIOR)
        face_discr = discr.connection_from_dds(dof_desc.DD_VOLUME, df).to_discr

        face_normal = bind(
            discr, sym.normal(df, face_discr.ambient_dim,
                              dim=face_discr.dim))(actx)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(actx, face_discr)
        vis.write_vtk_file("fld-surface-face-normals.vtu",
                           [("n", face_normal)],
                           overwrite=True)

    for event in dt_stepper.run(t_end=final_time, max_steps=nsteps + 1):
        if not isinstance(event, dt_stepper.StateComputed):
            continue

        step += 1
        if step % 10 == 0:
            norm_u = norm(actx, u=event.state_component)
            plot(event, "fld-surface-%04d" % step)

        logger.info("[%04d] t = %.5f |u| = %.5e", step, event.t, norm_u)

    plot(event, "fld-surface-%04d" % step)
예제 #19
0
def main():
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    dim = 2
    nel_1d = 16
    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                      b=(0.5, ) * dim,
                                      nelements_per_axis=(nel_1d, ) * dim)

    order = 3

    if dim == 2:
        # no deep meaning here, just a fudge factor
        dt = 0.75 / (nel_1d * order**2)
    elif dim == 3:
        # no deep meaning here, just a fudge factor
        dt = 0.45 / (nel_1d * order**2)
    else:
        raise ValueError("don't have a stable time step guesstimate")

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

    from meshmode.discretization.poly_element import \
            QuadratureSimplexGroupFactory, \
            PolynomialWarpAndBlendGroupFactory
    dcoll = DiscretizationCollection(
        actx,
        mesh,
        discr_tag_to_group_factory={
            DISCR_TAG_BASE: PolynomialWarpAndBlendGroupFactory(order),
            DISCR_TAG_QUAD: QuadratureSimplexGroupFactory(3 * order),
        })

    # bounded above by 1
    c = 0.2 + 0.8 * bump(actx, dcoll, center=np.zeros(3), width=0.5)

    fields = flat_obj_array(bump(
        actx,
        dcoll,
    ), [dcoll.zeros(actx) for i in range(dcoll.dim)])

    vis = make_visualizer(dcoll)

    def rhs(t, w):
        return wave_operator(dcoll, c=c, w=w)

    t = 0
    t_final = 3
    istep = 0
    while t < t_final:
        fields = rk4_step(fields, t, dt, rhs)

        if istep % 10 == 0:
            print(istep, t, op.norm(dcoll, fields[0], p=2))
            vis.write_vtk_file("fld-wave-eager-var-velocity-%04d.vtu" % istep,
                               [
                                   ("c", c),
                                   ("u", fields[0]),
                                   ("v", fields[1:]),
                               ])

        t += dt
        istep += 1
예제 #20
0
    def build_kernel_exterior_normalizer_table(self,
                                               cl_ctx,
                                               queue,
                                               pool=None,
                                               ncpus=None,
                                               mesh_order=5,
                                               quad_order=10,
                                               mesh_size=0.03,
                                               remove_tmp_files=True,
                                               **kwargs):
        r"""Build the kernel exterior normalizer table for fractional Laplacians.

        An exterior normalizer for kernel :math:`G(r)` and target
        :math:`x` is defined as

        .. math::

            \int_{B^c} G(\lVert x - y \rVert) dy

        where :math:`B` is the source box :math:`[0, source_box_extent]^dim`.
        """
        logger.warn("this method is currently under construction.")

        if not self.inverse_droste:
            raise ValueError()

        if ncpus is None:
            import multiprocessing
            ncpus = multiprocessing.cpu_count()

        if pool is None:
            from multiprocessing import Pool
            pool = Pool(ncpus)

        def fl_scaling(k, s):
            # scaling constant
            from scipy.special import gamma
            return (2**(2 * s) * s * gamma(s + k / 2)) / (np.pi**(k / 2) *
                                                          gamma(1 - s))

        # Directly compute and return in 1D
        if self.dim == 1:
            s = self.integral_knl.s

            targets = np.array(self.q_points).reshape(-1)
            r1 = targets
            r2 = self.source_box_extent - targets
            self.kernel_exterior_normalizers = 1 / (2 * s) * (
                1 / r1**(2 * s) + 1 / r2**(2 * s)) * fl_scaling(k=self.dim,
                                                                s=s)
            return

        from meshmode.array_context import PyOpenCLArrayContext
        from meshmode.dof_array import thaw, flatten
        from meshmode.mesh.io import read_gmsh
        from meshmode.discretization import Discretization
        from meshmode.discretization.poly_element import \
            PolynomialWarpAndBlendGroupFactory

        # {{{ gmsh processing

        import gmsh

        gmsh.initialize()
        gmsh.option.setNumber("General.Terminal", 1)

        # meshmode does not support other versions
        gmsh.option.setNumber("Mesh.MshFileVersion", 2)
        gmsh.option.setNumber("Mesh.CharacteristicLengthMax", mesh_size)

        gmsh.option.setNumber("Mesh.ElementOrder", mesh_order)
        if mesh_order > 1:
            gmsh.option.setNumber("Mesh.CharacteristicLengthFromCurvature", 1)

        # radius of source box
        hs = self.source_box_extent / 2
        # radius of bouding sphere
        r = hs * np.sqrt(self.dim)
        logger.debug("r_inner = %f, r_outer = %f" % (hs, r))

        if self.dim == 2:
            tag_box = gmsh.model.occ.addRectangle(x=0,
                                                  y=0,
                                                  z=0,
                                                  dx=2 * hs,
                                                  dy=2 * hs,
                                                  tag=-1)
        elif self.dim == 3:
            tag_box = gmsh.model.occ.addBox(x=0,
                                            y=0,
                                            z=0,
                                            dx=2 * hs,
                                            dy=2 * hs,
                                            dz=2 * hs,
                                            tag=-1)
        else:
            raise NotImplementedError()

        if self.dim == 2:
            tag_ball = gmsh.model.occ.addDisk(xc=hs,
                                              yc=hs,
                                              zc=0,
                                              rx=r,
                                              ry=r,
                                              tag=-1)
        elif self.dim == 3:
            tag_sphere = gmsh.model.occ.addSphere(xc=hs,
                                                  yc=hs,
                                                  zc=hs,
                                                  radius=r,
                                                  tag=-1)
            tag_ball = gmsh.model.occ.addVolume([tag_sphere], tag=-1)
        else:
            raise NotImplementedError()

        dimtags_ints, dimtags_map_ints = gmsh.model.occ.cut(
            objectDimTags=[(self.dim, tag_ball)],
            toolDimTags=[(self.dim, tag_box)],
            tag=-1,
            removeObject=True,
            removeTool=True)
        gmsh.model.occ.synchronize()
        gmsh.model.mesh.generate(self.dim)

        from tempfile import mkdtemp
        from os.path import join
        temp_dir = mkdtemp(prefix="tmp_volumential_nft")
        msh_filename = join(temp_dir, 'chinese_lucky_coin.msh')
        gmsh.write(msh_filename)
        gmsh.finalize()

        mesh = read_gmsh(msh_filename)
        if remove_tmp_files:
            import shutil
            shutil.rmtree(temp_dir)

        # }}} End gmsh processing

        arr_ctx = PyOpenCLArrayContext(queue)
        discr = Discretization(
            arr_ctx, mesh,
            PolynomialWarpAndBlendGroupFactory(order=quad_order))

        from pytential import bind, sym

        # {{{ optional checks

        if 1:
            if self.dim == 2:
                arerr = np.abs((np.pi * r**2 - (2 * hs)**2) -
                               bind(discr, sym.integral(self.dim, self.dim, 1))
                               (queue)) / (np.pi * r**2 - (2 * hs)**2)
                if arerr > 1e-12:
                    log_to = logger.warn
                else:
                    log_to = logger.debug
                log_to("the numerical error when computing the measure of a "
                       "unit ball is %e" % arerr)

            elif self.dim == 3:
                arerr = np.abs((4 / 3 * np.pi * r**3 - (2 * hs)**3) -
                               bind(discr, sym.integral(self.dim, self.dim, 1))
                               (queue)) / (4 / 3 * np.pi * r**3 - (2 * hs)**3)
                if arerr > 1e-12:
                    log_to = logger.warn
                else:
                    log_to = logger.debug
                logger.warn(
                    "The numerical error when computing the measure of a "
                    "unit ball is %e" % arerr)

        # }}} End optional checks

        # {{{ kernel evaluation

        # TODO: take advantage of symmetry if this is too slow

        from volumential.droste import InverseDrosteReduced

        # only for getting kernel evaluation related stuff
        drf = InverseDrosteReduced(self.integral_knl,
                                   self.quad_order,
                                   self.interaction_case_vecs,
                                   n_brick_quad_points=0,
                                   knl_symmetry_tags=[],
                                   auto_windowing=False)

        # uses "dist[dim]", assigned to "knl_val"
        knl_insns = drf.get_sumpy_kernel_insns()

        eval_kernel_insns = [
            insn.copy(within_inames=insn.within_inames | frozenset(["iqpt"]))
            for insn in knl_insns
        ]

        from sumpy.symbolic import SympyToPymbolicMapper
        sympy_conv = SympyToPymbolicMapper()

        scaling_assignment = lp.Assignment(
            id=None,
            assignee="knl_scaling",
            expression=sympy_conv(
                self.integral_knl.get_global_scaling_const()),
            temp_var_type=lp.Optional(),
        )

        extra_kernel_kwarg_types = ()
        if "extra_kernel_kwarg_types" in kwargs:
            extra_kernel_kwarg_types = kwargs["extra_kernel_kwarg_types"]

        lpknl = lp.make_kernel(  # NOQA
            "{ [iqpt, iaxis]: 0<=iqpt<n_q_points and 0<=iaxis<dim }",
            [
                """
                for iqpt
                    for iaxis
                        <> dist[iaxis] = (quad_points[iaxis, iqpt]
                            - target_point[iaxis])
                    end
                end
                """
            ] + eval_kernel_insns + [scaling_assignment] + [
                """
                for iqpt
                    result[iqpt] = knl_val * knl_scaling
                end
                """
            ],
            [
                lp.ValueArg("dim, n_q_points", np.int32),
                lp.GlobalArg("quad_points", np.float64, "dim, n_q_points"),
                lp.GlobalArg("target_point", np.float64, "dim")
            ] + list(extra_kernel_kwarg_types) + [
                "...",
            ],
            name="eval_kernel_lucky_coin",
            lang_version=(2018, 2),
        )

        lpknl = lp.fix_parameters(lpknl, dim=self.dim)
        lpknl = lp.set_options(lpknl, write_cl=False)
        lpknl = lp.set_options(lpknl, return_dict=True)

        # }}} End kernel evaluation

        node_coords = flatten(thaw(arr_ctx, discr.nodes()))
        nodes = cl.array.to_device(
            queue, np.vstack([crd.get() for crd in node_coords]))

        int_vals = []

        for target in self.q_points:
            evt, res = lpknl(queue, quad_points=nodes, target_point=target)
            knl_vals = res['result']

            integ = bind(
                discr, sym.integral(self.dim, self.dim,
                                    sym.var("integrand")))(queue,
                                                           integrand=knl_vals)
            queue.finish()
            int_vals.append(integ)

        int_vals_coins = np.array(int_vals)

        int_vals_inf = np.zeros(self.n_q_points)

        # {{{ integrate over the exterior of the ball

        if self.dim == 2:

            def rho_0(theta, target, radius):
                rho_x = np.linalg.norm(target, ord=2)
                return (-1 * rho_x * np.cos(theta) +
                        np.sqrt(radius**2 - rho_x**2 * (np.sin(theta)**2)))

            def ext_inf_integrand(theta, s, target, radius):
                _rho_0 = rho_0(theta, target=target, radius=radius)
                return _rho_0**(-2 * s)

            def compute_ext_inf_integral(target, s, radius):
                # target: target point
                # s: fractional order
                # radius: radius of the circle
                import scipy.integrate as sint
                val, _ = sint.quadrature(partial(ext_inf_integrand,
                                                 s=s,
                                                 target=target,
                                                 radius=radius),
                                         a=0,
                                         b=2 * np.pi)
                return val * (1 / (2 * s)) * fl_scaling(k=self.dim, s=s)

            if 1:
                # optional test
                target = [0, 0]
                s = 0.5
                radius = 1
                scaling = fl_scaling(k=self.dim, s=s)
                val = compute_ext_inf_integral(target, s, radius)
                test_err = np.abs(val - radius**(-2 * s) * 2 * np.pi *
                                  (1 /
                                   (2 * s)) * scaling) / (radius**(-2 * s) *
                                                          2 * np.pi *
                                                          (1 /
                                                           (2 * s)) * scaling)
                if test_err > 1e-12:
                    logger.warn("Error evaluating at origin = %f" % test_err)

            for tid, target in enumerate(self.q_points):
                # The formula assumes that the source box is centered at origin
                int_vals_inf[tid] = compute_ext_inf_integral(
                    target=target - hs, s=self.integral_knl.s, radius=r)

        elif self.dim == 3:
            # FIXME
            raise NotImplementedError("3D not yet implemented.")

        else:
            raise NotImplementedError("Unsupported dimension")

        # }}} End integrate over the exterior of the ball

        self.kernel_exterior_normalizers = int_vals_coins + int_vals_inf
        return
예제 #21
0
def _test_mpi_boundary_swap(dim, order, num_groups):
    from meshmode.distributed import MPIMeshDistributor, MPIBoundaryCommSetupHelper

    from mpi4py import MPI
    mpi_comm = MPI.COMM_WORLD
    i_local_part = mpi_comm.Get_rank()
    num_parts = mpi_comm.Get_size()

    mesh_dist = MPIMeshDistributor(mpi_comm)

    if mesh_dist.is_mananger_rank():
        np.random.seed(42)
        from meshmode.mesh.generation import generate_warped_rect_mesh
        meshes = [
            generate_warped_rect_mesh(dim, order=order, n=4)
            for _ in range(num_groups)
        ]

        if num_groups > 1:
            from meshmode.mesh.processing import merge_disjoint_meshes
            mesh = merge_disjoint_meshes(meshes)
        else:
            mesh = meshes[0]

        part_per_element = np.random.randint(num_parts, size=mesh.nelements)

        local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element,
                                               num_parts)
    else:
        local_mesh = mesh_dist.receive_mesh_part()

    group_factory = PolynomialWarpAndBlendGroupFactory(order)

    from meshmode.array_context import PyOpenCLArrayContext
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

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

    from meshmode.distributed import get_connected_partitions
    connected_parts = get_connected_partitions(local_mesh)
    assert i_local_part not in connected_parts
    bdry_setup_helpers = {}
    local_bdry_conns = {}

    from meshmode.discretization.connection import make_face_restriction
    from meshmode.mesh import BTAG_PARTITION
    for i_remote_part in connected_parts:
        local_bdry_conns[i_remote_part] = make_face_restriction(
            actx, vol_discr, group_factory, BTAG_PARTITION(i_remote_part))

        setup_helper = bdry_setup_helpers[i_remote_part] = \
                MPIBoundaryCommSetupHelper(
                        mpi_comm, actx, local_bdry_conns[i_remote_part],
                        i_remote_part, bdry_grp_factory=group_factory)

        setup_helper.post_sends()

    remote_to_local_bdry_conns = {}
    from meshmode.discretization.connection import check_connection
    while bdry_setup_helpers:
        for i_remote_part, setup_helper in bdry_setup_helpers.items():
            if setup_helper.is_setup_ready():
                assert bdry_setup_helpers.pop(i_remote_part) is setup_helper
                conn = setup_helper.complete_setup()
                check_connection(actx, conn)
                remote_to_local_bdry_conns[i_remote_part] = conn
                break

        # FIXME: Not ideal, busy-waits

    _test_data_transfer(mpi_comm, actx, local_bdry_conns,
                        remote_to_local_bdry_conns, connected_parts)

    logger.debug("Rank %d exiting", i_local_part)
예제 #22
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()
예제 #23
0
def test_diffusion_accuracy(actx_factory,
                            problem,
                            nsteps,
                            dt,
                            scales,
                            order,
                            visualize=False):
    """
    Checks the accuracy of the diffusion operator by solving the heat equation for a
    given problem setup.
    """
    actx = actx_factory()

    p = problem

    sym_diffusion_u = sym_diffusion(p.dim, p.sym_alpha, p.sym_u)

    # In order to support manufactured solutions, we modify the heat equation
    # to add a source term f. If the solution is exact, this term should be 0.
    sym_t = pmbl.var("t")
    sym_f = sym.diff(sym_t)(p.sym_u) - sym_diffusion_u

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for n in scales:
        mesh = p.get_mesh(n)

        from grudge.eager import EagerDGDiscretization
        from meshmode.discretization.poly_element import \
                QuadratureSimplexGroupFactory, \
                PolynomialWarpAndBlendGroupFactory
        discr = EagerDGDiscretization(
            actx,
            mesh,
            discr_tag_to_group_factory={
                DISCR_TAG_BASE: PolynomialWarpAndBlendGroupFactory(order),
                DISCR_TAG_QUAD: QuadratureSimplexGroupFactory(3 * order),
            })

        nodes = thaw(actx, discr.nodes())

        def sym_eval(expr, t):
            return sym.EvaluationMapper({"x": nodes, "t": t})(expr)

        alpha = sym_eval(p.sym_alpha, 0.)

        if isinstance(alpha, DOFArray):
            discr_tag = DISCR_TAG_QUAD
        else:
            discr_tag = DISCR_TAG_BASE

        def get_rhs(t, u):
            return (
                diffusion_operator(discr,
                                   quad_tag=discr_tag,
                                   alpha=alpha,
                                   boundaries=p.get_boundaries(discr, actx, t),
                                   u=u) + sym_eval(sym_f, t))

        t = 0.

        u = sym_eval(p.sym_u, t)

        from mirgecom.integrators import rk4_step

        for _ in range(nsteps):
            u = rk4_step(u, t, dt, get_rhs)
            t += dt

        expected_u = sym_eval(p.sym_u, t)

        rel_linf_err = (discr.norm(u - expected_u, np.inf) /
                        discr.norm(expected_u, np.inf))
        eoc_rec.add_data_point(1. / n, rel_linf_err)

        if visualize:
            from grudge.shortcuts import make_visualizer
            vis = make_visualizer(discr, discr.order + 3)
            vis.write_vtk_file(
                "diffusion_accuracy_{order}_{n}.vtu".format(order=order, n=n),
                [
                    ("u", u),
                    ("expected_u", expected_u),
                ])

    print("L^inf error:")
    print(eoc_rec)
    # Expected convergence rates from Hesthaven/Warburton book
    expected_order = order + 1 if order % 2 == 0 else order
    assert (eoc_rec.order_estimate() >= expected_order - 0.5
            or eoc_rec.max_error() < 1e-11)
예제 #24
0
def test_all_faces_interpolation(ctx_getter, mesh_name, dim, mesh_pars,
                                 per_face_groups):
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (
        make_face_restriction, make_face_to_all_faces_embedding,
        check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 4

    def f(x):
        return 0.1 * cl.clmath.sin(30 * x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "blob":
            assert dim == 2

            h = mesh_par

            from meshmode.mesh.io import generate_gmsh, FileSource
            print("BEGIN GEN")
            mesh = generate_gmsh(FileSource("blob-2d.step"),
                                 2,
                                 order=order,
                                 force_ambient_dim=2,
                                 other_options=[
                                     "-string",
                                     "Mesh.CharacteristicLengthMax = %s;" % h
                                 ])
            print("END GEN")
        elif mesh_name == "warp":
            from meshmode.mesh.generation import generate_warped_rect_mesh
            mesh = generate_warped_rect_mesh(dim, order=4, n=mesh_par)

            h = 1 / mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(cl_ctx, mesh,
                                   PolynomialWarpAndBlendGroupFactory(order))
        print("h=%s -> %d elements" %
              (h, sum(mgrp.nelements for mgrp in mesh.groups)))

        all_face_bdry_connection = make_face_restriction(
            vol_discr,
            PolynomialWarpAndBlendGroupFactory(order),
            FRESTR_ALL_FACES,
            per_face_groups=per_face_groups)
        all_face_bdry_discr = all_face_bdry_connection.to_discr

        for ito_grp, ceg in enumerate(all_face_bdry_connection.groups):
            for ibatch, batch in enumerate(ceg.batches):
                assert np.array_equal(batch.from_element_indices.get(queue),
                                      np.arange(vol_discr.mesh.nelements))

                if per_face_groups:
                    assert ito_grp == batch.to_element_face
                else:
                    assert ibatch == batch.to_element_face

        all_face_x = all_face_bdry_discr.nodes()[0].with_queue(queue)
        all_face_f = f(all_face_x)

        all_face_f_2 = all_face_bdry_discr.zeros(queue)

        for boundary_tag in [
                BTAG_ALL,
                FRESTR_INTERIOR_FACES,
        ]:
            bdry_connection = make_face_restriction(
                vol_discr,
                PolynomialWarpAndBlendGroupFactory(order),
                boundary_tag,
                per_face_groups=per_face_groups)
            bdry_discr = bdry_connection.to_discr

            bdry_x = bdry_discr.nodes()[0].with_queue(queue)
            bdry_f = f(bdry_x)

            all_face_embedding = make_face_to_all_faces_embedding(
                bdry_connection, all_face_bdry_discr)

            check_connection(all_face_embedding)

            all_face_f_2 += all_face_embedding(queue, bdry_f)

        err = la.norm((all_face_f - all_face_f_2).get(), np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-14)
예제 #25
0
    def __init__(
        self,
        array_context,
        mesh,
        order=None,
        discr_tag_to_group_factory=None,
        mpi_communicator=None,
        # FIXME: `quad_tag_to_group_factory` is deprecated
        quad_tag_to_group_factory=None):
        """
        :param discr_tag_to_group_factory: A mapping from discretization tags
            (typically one of: :class:`grudge.dof_desc.DISCR_TAG_BASE`,
            :class:`grudge.dof_desc.DISCR_TAG_MODAL`, or
            :class:`grudge.dof_desc.DISCR_TAG_QUAD`) to a
            :class:`~meshmode.discretization.poly_element.ElementGroupFactory`
            indicating with which type of discretization the operations are
            to be carried out, or *None* to indicate that operations with this
            discretization tag should be carried out with the standard volume
            discretization.
        """

        if (quad_tag_to_group_factory is not None
                and discr_tag_to_group_factory is not None):
            raise ValueError(
                "Both `quad_tag_to_group_factory` and `discr_tag_to_group_factory` "
                "are specified. Use `discr_tag_to_group_factory` instead.")

        # FIXME: `quad_tag_to_group_factory` is deprecated
        if (quad_tag_to_group_factory is not None
                and discr_tag_to_group_factory is None):
            warn(
                "`quad_tag_to_group_factory` is a deprecated kwarg and will "
                "be dropped in version 2022.x. Use `discr_tag_to_group_factory` "
                "instead.",
                DeprecationWarning,
                stacklevel=2)
            discr_tag_to_group_factory = quad_tag_to_group_factory

        self._setup_actx = array_context

        from meshmode.discretization.poly_element import \
                PolynomialWarpAndBlendGroupFactory

        if discr_tag_to_group_factory is None:
            if order is None:
                raise TypeError(
                    "one of 'order' and 'discr_tag_to_group_factory' must be given"
                )

            discr_tag_to_group_factory = {
                DISCR_TAG_BASE: PolynomialWarpAndBlendGroupFactory(order=order)
            }
        else:
            if order is not None:
                discr_tag_to_group_factory = discr_tag_to_group_factory.copy()
                if DISCR_TAG_BASE in discr_tag_to_group_factory:
                    raise ValueError(
                        "if 'order' is given, 'discr_tag_to_group_factory' must "
                        "not have a key of DISCR_TAG_BASE")

                discr_tag_to_group_factory[DISCR_TAG_BASE] = \
                        PolynomialWarpAndBlendGroupFactory(order=order)

        # Modal discr should always comes from the base discretization
        discr_tag_to_group_factory[DISCR_TAG_MODAL] = \
            _generate_modal_group_factory(
                discr_tag_to_group_factory[DISCR_TAG_BASE]
            )

        self.discr_tag_to_group_factory = discr_tag_to_group_factory

        from meshmode.discretization import Discretization

        self._volume_discr = Discretization(
            array_context, mesh,
            self.group_factory_for_discretization_tag(DISCR_TAG_BASE))

        # {{{ management of discretization-scoped common subexpressions

        from pytools import UniqueNameGenerator
        self._discr_scoped_name_gen = UniqueNameGenerator()

        self._discr_scoped_subexpr_to_name = {}
        self._discr_scoped_subexpr_name_to_value = {}

        # }}}

        self._dist_boundary_connections = \
                self._set_up_distributed_communication(
                        mpi_communicator, array_context)

        self.mpi_communicator = mpi_communicator
예제 #26
0
def _test_mpi_boundary_swap(dim, order, num_groups):
    from meshmode.distributed import MPIMeshDistributor, MPIBoundaryCommSetupHelper

    from mpi4py import MPI
    mpi_comm = MPI.COMM_WORLD
    i_local_part = mpi_comm.Get_rank()
    num_parts = mpi_comm.Get_size()

    mesh_dist = MPIMeshDistributor(mpi_comm)

    if mesh_dist.is_mananger_rank():
        np.random.seed(42)
        from meshmode.mesh.generation import generate_warped_rect_mesh
        meshes = [generate_warped_rect_mesh(dim, order=order, nelements_side=4)
                        for _ in range(num_groups)]

        if num_groups > 1:
            from meshmode.mesh.processing import merge_disjoint_meshes
            mesh = merge_disjoint_meshes(meshes)
        else:
            mesh = meshes[0]

        part_per_element = np.random.randint(num_parts, size=mesh.nelements)

        local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element, num_parts)
    else:
        local_mesh = mesh_dist.receive_mesh_part()

    group_factory = PolynomialWarpAndBlendGroupFactory(order)

    from arraycontext import PyOpenCLArrayContext
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

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

    from meshmode.distributed import get_connected_partitions
    connected_parts = get_connected_partitions(local_mesh)

    # Check that the connectivity makes sense before doing any communication
    _test_connected_parts(mpi_comm, connected_parts)

    from meshmode.discretization.connection import make_face_restriction
    from meshmode.mesh import BTAG_PARTITION
    local_bdry_conns = {}
    for i_remote_part in connected_parts:
        local_bdry_conns[i_remote_part] = make_face_restriction(
                actx, vol_discr, group_factory, BTAG_PARTITION(i_remote_part))

    remote_to_local_bdry_conns = {}
    with MPIBoundaryCommSetupHelper(mpi_comm, actx, local_bdry_conns,
            bdry_grp_factory=group_factory) as bdry_setup_helper:
        from meshmode.discretization.connection import check_connection
        while True:
            conns = bdry_setup_helper.complete_some()
            if not conns:
                break
            for i_remote_part, conn in conns.items():
                check_connection(actx, conn)
                remote_to_local_bdry_conns[i_remote_part] = conn

    _test_data_transfer(mpi_comm,
                        actx,
                        local_bdry_conns,
                        remote_to_local_bdry_conns,
                        connected_parts)

    logger.debug("Rank %d exiting", i_local_part)
예제 #27
0
def test_dof_array_arithmetic_same_as_numpy(actx_factory):
    actx = actx_factory()

    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh(
            a=(-0.5,)*2, b=(0.5,)*2, n=(3,)*2, order=1)

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

    def get_real(ary):
        return ary.real

    def get_imag(ary):
        return ary.real

    import operator
    from pytools import generate_nonnegative_integer_tuples_below as gnitb
    from random import uniform, randrange
    for op_func, n_args, use_integers in [
            (operator.add, 2, False),
            (operator.sub, 2, False),
            (operator.mul, 2, False),
            (operator.truediv, 2, False),
            (operator.pow, 2, False),
            # FIXME pyopencl.Array doesn't do mod.
            #(operator.mod, 2, True),
            #(operator.mod, 2, False),
            #(operator.imod, 2, True),
            #(operator.imod, 2, False),
            # FIXME: Two outputs
            #(divmod, 2, False),

            (operator.iadd, 2, False),
            (operator.isub, 2, False),
            (operator.imul, 2, False),
            (operator.itruediv, 2, False),

            (operator.and_, 2, True),
            (operator.xor, 2, True),
            (operator.or_, 2, True),

            (operator.iand, 2, True),
            (operator.ixor, 2, True),
            (operator.ior, 2, True),

            (operator.ge, 2, False),
            (operator.lt, 2, False),
            (operator.gt, 2, False),
            (operator.eq, 2, True),
            (operator.ne, 2, True),

            (operator.pos, 1, False),
            (operator.neg, 1, False),
            (operator.abs, 1, False),

            (get_real, 1, False),
            (get_imag, 1, False),
            ]:
        for is_array_flags in gnitb(2, n_args):
            if sum(is_array_flags) == 0:
                # all scalars, no need to test
                continue

            if is_array_flags[0] == 0 and op_func in [
                    operator.iadd, operator.isub,
                    operator.imul, operator.itruediv,
                    operator.iand, operator.ixor, operator.ior,
                    ]:
                # can't do in place operations with a scalar lhs
                continue

            args = [
                    (0.5+np.random.rand(discr.ndofs)
                        if not use_integers else
                        np.random.randint(3, 200, discr.ndofs))

                    if is_array_flag else
                    (uniform(0.5, 2)
                        if not use_integers
                        else randrange(3, 200))
                    for is_array_flag in is_array_flags]

            # {{{ get reference numpy result

            # make a copy for the in place operators
            ref_args = [
                    arg.copy() if isinstance(arg, np.ndarray) else arg
                    for arg in args]
            ref_result = op_func(*ref_args)

            # }}}

            # {{{ test DOFArrays

            actx_args = [
                    unflatten(actx, discr, actx.from_numpy(arg))
                    if isinstance(arg, np.ndarray) else arg
                    for arg in args]

            actx_result = actx.to_numpy(flatten(op_func(*actx_args)))

            assert np.allclose(actx_result, ref_result)

            # }}}

            # {{{ test object arrays of DOFArrays

            # It would be very nice if comparisons on object arrays behaved
            # consistently with everything else. Alas, they do not. Instead:
            #
            # 0.5 < obj_array(DOFArray) -> obj_array([True])
            #
            # because hey, 0.5 < DOFArray returned something truthy.

            if op_func not in [
                    operator.eq, operator.ne,
                    operator.le, operator.lt,
                    operator.ge, operator.gt,

                    operator.iadd, operator.isub,
                    operator.imul, operator.itruediv,
                    operator.iand, operator.ixor, operator.ior,

                    # All Python objects are real-valued, right?
                    get_imag,
                    ]:
                obj_array_args = [
                        make_obj_array([arg]) if isinstance(arg, DOFArray) else arg
                        for arg in actx_args]

                obj_array_result = actx.to_numpy(
                        flatten(op_func(*obj_array_args)[0]))

                assert np.allclose(obj_array_result, ref_result)
예제 #28
0
def test_mesh_multiple_groups(actx_factory, ambient_dim, visualize=False):
    actx = actx_factory()

    order = 4

    mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim,
                                           b=(0.5, ) * ambient_dim,
                                           nelements_per_axis=(8, ) *
                                           ambient_dim,
                                           order=order)
    assert len(mesh.groups) == 1

    from meshmode.mesh.processing import split_mesh_groups
    element_flags = np.any(
        mesh.vertices[0, mesh.groups[0].vertex_indices] < 0.0,
        axis=1).astype(np.int64)
    mesh = split_mesh_groups(mesh, element_flags)

    assert len(mesh.groups) == 2  # pylint: disable=no-member
    assert mesh.facial_adjacency_groups
    assert mesh.nodal_adjacency

    if visualize and ambient_dim == 2:
        from meshmode.mesh.visualization import draw_2d_mesh
        draw_2d_mesh(mesh,
                     draw_vertex_numbers=False,
                     draw_element_numbers=True,
                     draw_face_numbers=False,
                     set_bounding_box=True)

        import matplotlib.pyplot as plt
        plt.savefig("test_mesh_multiple_groups_2d_elements.png", dpi=300)

    from meshmode.discretization import Discretization
    discr = Discretization(actx, mesh,
                           PolynomialWarpAndBlendGroupFactory(order))

    if visualize:
        group_id = discr.empty(actx, dtype=np.int32)
        for igrp, vec in enumerate(group_id):
            vec.fill(igrp)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(actx, discr, vis_order=order)
        vis.write_vtk_file("mesh_multiple_groups.vtu",
                           [("group_id", group_id)],
                           overwrite=True)

    # check face restrictions
    from meshmode.discretization.connection import (
        make_face_restriction, make_face_to_all_faces_embedding,
        make_opposite_face_connection, check_connection)
    for boundary_tag in [BTAG_ALL, FACE_RESTR_INTERIOR, FACE_RESTR_ALL]:
        conn = make_face_restriction(
            actx,
            discr,
            group_factory=PolynomialWarpAndBlendGroupFactory(order),
            boundary_tag=boundary_tag,
            per_face_groups=False)
        check_connection(actx, conn)

        bdry_f = conn.to_discr.zeros(actx) + 1

        if boundary_tag == FACE_RESTR_INTERIOR:
            opposite = make_opposite_face_connection(actx, conn)
            check_connection(actx, opposite)

            op_bdry_f = opposite(bdry_f)
            error = flat_norm(bdry_f - op_bdry_f, np.inf)
            assert error < 1.0e-11, error

        if boundary_tag == FACE_RESTR_ALL:
            embedding = make_face_to_all_faces_embedding(
                actx, conn, conn.to_discr)
            check_connection(actx, embedding)

            em_bdry_f = embedding(bdry_f)
            error = flat_norm(bdry_f - em_bdry_f)
            assert error < 1.0e-11, error

    # check some derivatives (nb: flatten is a generator)
    import pytools
    ref_axes = pytools.flatten([[i] for i in range(ambient_dim)])

    from meshmode.discretization import num_reference_derivative
    x = thaw(discr.nodes(), actx)
    num_reference_derivative(discr, ref_axes, x[0])
예제 #29
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
예제 #30
0
def build_connection_from_firedrake(actx, fdrake_fspace, grp_factory=None,
                                    restrict_to_boundary=None):

    """
    Create a :class:`FiredrakeConnection` from a :mod:`firedrake`
    ``"DG"`` function space by creates a corresponding
    meshmode discretization and facilitating
    transfer of functions to and from :mod:`firedrake`.

    :arg actx: A :class:`~meshmode.array_context.ArrayContext`
        used to instantiate :attr:`FiredrakeConnection.discr`.
    :arg fdrake_fspace: A :mod:`firedrake` ``"DG"``
        function space (of class
        :class:`~firedrake.functionspaceimpl.WithGeometry`) built on
        a mesh which is importable by
        :func:`~meshmode.interop.firedrake.mesh.import_firedrake_mesh`.
    :arg grp_factory: (optional) If not *None*, should be
        a :class:`~meshmode.discretization.poly_element.ElementGroupFactory`
        whose group class is a subclass of
        :class:`~meshmode.discretization.InterpolatoryElementGroupBase`.
        If *None*, and :mod:`recursivenodes` can be imported,
        a :class:`~meshmode.discretization.poly_element.\
PolynomialRecursiveNodesGroupFactory` with ``"lgl"`` nodes is used.
        Note that :mod:`recursivenodes` may not be importable
        as it uses :func:`math.comb`, which is new in Python 3.8.
        In the case that :mod:`recursivenodes` cannot be successfully
        imported, a :class:`~meshmode.discretization.poly_element.\
PolynomialWarpAndBlendGroupFactory` is used.
    :arg restrict_to_boundary: (optional)
        If not *None*, then must be a valid boundary marker for
        ``fdrake_fspace.mesh()``. In this case, creates a
        :class:`~meshmode.discretization.Discretization` on a submesh
        of ``fdrake_fspace.mesh()`` created from the cells with at least
        one vertex on a facet marked with the marker
        *restrict_to_boundary*.
    """
    # Ensure fdrake_fspace is a function space with appropriate reference
    # element.
    from firedrake.functionspaceimpl import WithGeometry
    if not isinstance(fdrake_fspace, WithGeometry):
        raise TypeError("'fdrake_fspace' must be of firedrake type "
                        "WithGeometry, not '%s'."
                        % type(fdrake_fspace))
    ufl_elt = fdrake_fspace.ufl_element()

    if ufl_elt.family() != "Discontinuous Lagrange":
        raise ValueError("the 'fdrake_fspace.ufl_element().family()' of "
                         "must be be "
                         "'Discontinuous Lagrange', not '%s'."
                         % ufl_elt.family())
    # Make sure grp_factory is the right type if provided, and
    # uses an interpolatory class.
    if grp_factory is not None:
        if not isinstance(grp_factory, ElementGroupFactory):
            raise TypeError("'grp_factory' must inherit from "
                            "meshmode.discretization.ElementGroupFactory,"
                            "but is instead of type "
                            "'%s'." % type(grp_factory))
        if not issubclass(grp_factory.group_class,
                          InterpolatoryElementGroupBase):
            raise TypeError("'grp_factory.group_class' must inherit from"
                            "meshmode.discretization."
                            "InterpolatoryElementGroupBase, but"
                            " is instead of type '%s'"
                            % type(grp_factory.group_class))
    # If not provided, make one
    else:
        degree = ufl_elt.degree()
        try:
            # recursivenodes is only importable in Python 3.8 since
            # it uses :func:`math.comb`, so need to check if it can
            # be imported
            import recursivenodes  # noqa : F401
            family = "lgl"  # L-G-Legendre
            grp_factory = PolynomialRecursiveNodesGroupFactory(degree, family)
        except ImportError:
            # If cannot be imported, uses warp-and-blend nodes
            grp_factory = PolynomialWarpAndBlendGroupFactory(degree)
    if restrict_to_boundary is not None:
        uniq_markers = fdrake_fspace.mesh().exterior_facets.unique_markers
        allowable_bdy_ids = list(uniq_markers) + ["on_boundary"]
        if restrict_to_boundary not in allowable_bdy_ids:
            raise ValueError("'restrict_to_boundary' must be one of"
                            " the following allowable boundary ids: "
                            f"{allowable_bdy_ids}, not "
                            f"'{restrict_to_boundary}'")

    # If only converting a portion of the mesh near the boundary, get
    # *cells_to_use* as described in
    # :func:`meshmode.interop.firedrake.mesh.import_firedrake_mesh`
    cells_to_use = _get_cells_to_use(fdrake_fspace.mesh(),
                                     restrict_to_boundary)

    # Create to_discr
    mm_mesh, orient = import_firedrake_mesh(fdrake_fspace.mesh(),
                                            cells_to_use=cells_to_use)
    to_discr = Discretization(actx, mm_mesh, grp_factory)

    # get firedrake unit nodes and map onto meshmode reference element
    group = to_discr.groups[0]
    fd_ref_cell_to_mm = get_affine_reference_simplex_mapping(group.dim,
                                                             True)
    fd_unit_nodes = get_finat_element_unit_nodes(fdrake_fspace.finat_element)
    fd_unit_nodes = fd_ref_cell_to_mm(fd_unit_nodes)
    # Flipping negative elements corresponds to reordering the nodes.
    # We handle reordering by storing the permutation explicitly as
    # a numpy array

    # Get the reordering fd->mm.
    flip_mat = get_simplex_element_flip_matrix(ufl_elt.degree(),
                                               fd_unit_nodes)
    fd_cell_node_list = fdrake_fspace.cell_node_list
    if cells_to_use is not None:
        fd_cell_node_list = fd_cell_node_list[cells_to_use]
    # flip fd_cell_node_list
    flipped_cell_node_list = _reorder_nodes(orient,
                                            fd_cell_node_list,
                                            flip_mat,
                                            unflip=False)

    assert np.size(np.unique(flipped_cell_node_list)) == \
        np.size(flipped_cell_node_list), \
        "A firedrake node in a 'DG' space got duplicated"

    return FiredrakeConnection(to_discr,
                               fdrake_fspace,
                               flipped_cell_node_list)