示例#1
0
def test_circle_mesh(visualize=False):
    from meshmode.mesh.io import generate_gmsh, FileSource
    logger.info("BEGIN GEN")
    mesh = generate_gmsh(
        FileSource("circle.step"),
        2,
        order=2,
        force_ambient_dim=2,
        other_options=["-string", "Mesh.CharacteristicLengthMax = 0.05;"],
        target_unit="MM",
    )
    logger.info("END GEN")
    logger.info("nelements: %d", mesh.nelements)

    from meshmode.mesh.processing import affine_map
    mesh = affine_map(mesh, A=3 * np.eye(2))

    if visualize:
        from meshmode.mesh.visualization import draw_2d_mesh
        draw_2d_mesh(mesh,
                     fill=None,
                     draw_vertex_numbers=False,
                     draw_nodal_adjacency=True,
                     set_bounding_box=True)
        import matplotlib.pyplot as pt
        pt.axis("equal")
        pt.savefig("circle_mesh", dpi=300)
示例#2
0
def test_rect_mesh(visualize=False):
    mesh = mgen.generate_regular_rect_mesh(nelements_per_axis=(4, 4))

    if visualize:
        from meshmode.mesh.visualization import draw_2d_mesh
        draw_2d_mesh(mesh, fill=None, draw_nodal_adjacency=True)
        import matplotlib.pyplot as pt
        pt.show()
示例#3
0
def test_rect_mesh(do_plot=False):
    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh()

    if do_plot:
        from meshmode.mesh.visualization import draw_2d_mesh
        draw_2d_mesh(mesh, fill=None, draw_nodal_adjacency=True)
        import matplotlib.pyplot as pt
        pt.show()
示例#4
0
def test_rect_mesh(do_plot=False):
    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh()

    if do_plot:
        from meshmode.mesh.visualization import draw_2d_mesh
        draw_2d_mesh(mesh, fill=None, draw_connectivity=True)
        import matplotlib.pyplot as pt
        pt.show()
示例#5
0
def main():
    from meshmode.mesh.generation import (  # noqa
            make_curve_mesh, starfish)
    mesh1 = make_curve_mesh(starfish, np.linspace(0, 1, 20), 4)

    from meshmode.mesh.processing import affine_map, merge_disjoint_meshes
    mesh2 = affine_map(mesh1, b=np.array([2, 3]))

    mesh = merge_disjoint_meshes((mesh1, mesh2))

    from meshmode.mesh.visualization import draw_2d_mesh
    draw_2d_mesh(mesh, set_bounding_box=True)

    import matplotlib.pyplot as pt
    pt.show()
示例#6
0
def main():
    from meshmode.mesh.generation import (  # noqa
        make_curve_mesh, starfish)
    mesh1 = make_curve_mesh(starfish, np.linspace(0, 1, 20), 4)

    from meshmode.mesh.processing import affine_map, merge_disjoint_meshes
    mesh2 = affine_map(mesh1, b=np.array([2, 3]))

    mesh = merge_disjoint_meshes((mesh1, mesh2))

    from meshmode.mesh.visualization import draw_2d_mesh
    draw_2d_mesh(mesh, set_bounding_box=True)

    import matplotlib.pyplot as pt
    pt.show()
示例#7
0
def test_circle_mesh(do_plot=False):
    from meshmode.mesh.io import generate_gmsh, FileSource
    print("BEGIN GEN")
    mesh = generate_gmsh(
            FileSource("circle.step"), 2, order=2,
            force_ambient_dim=2,
            other_options=[
                "-string", "Mesh.CharacteristicLengthMax = 0.05;"]
            )
    print("END GEN")
    print(mesh.nelements)

    from meshmode.mesh.processing import affine_map
    mesh = affine_map(mesh, A=3*np.eye(2))

    if do_plot:
        from meshmode.mesh.visualization import draw_2d_mesh
        draw_2d_mesh(mesh, fill=None, draw_connectivity=True,
                set_bounding_box=True)
        import matplotlib.pyplot as pt
        pt.show()
示例#8
0
def test_circle_mesh(do_plot=False):
    from meshmode.mesh.io import generate_gmsh, FileSource
    print("BEGIN GEN")
    mesh = generate_gmsh(
            FileSource("circle.step"), 2, order=2,
            force_ambient_dim=2,
            other_options=[
                "-string", "Mesh.CharacteristicLengthMax = 0.05;"]
            )
    print("END GEN")
    print(mesh.nelements)

    from meshmode.mesh.processing import affine_map
    mesh = affine_map(mesh, A=3*np.eye(2))

    if do_plot:
        from meshmode.mesh.visualization import draw_2d_mesh
        draw_2d_mesh(mesh, fill=None, draw_nodal_adjacency=True,
                set_bounding_box=True)
        import matplotlib.pyplot as pt
        pt.show()
示例#9
0
def _make_cross_face_batches(
        queue, vol_discr, bdry_discr,
        i_tgt_grp, i_src_grp,
        i_face_tgt,
        adj_grp,
        vbc_tgt_grp_face_batch, src_grp_el_lookup):

    # {{{ index wrangling

    # Assert that the adjacency group and the restriction
    # interpolation batch and the adjacency group have the same
    # element ordering.

    adj_grp_tgt_flags = adj_grp.element_faces == i_face_tgt

    assert (
            np.array_equal(
                adj_grp.elements[adj_grp_tgt_flags],
                vbc_tgt_grp_face_batch.from_element_indices
                .get(queue=queue)))

    # find to_element_indices

    to_bdry_element_indices = (
            vbc_tgt_grp_face_batch.to_element_indices
            .get(queue=queue))

    # find from_element_indices

    from_vol_element_indices = adj_grp.neighbors[adj_grp_tgt_flags]
    from_element_faces = adj_grp.neighbor_faces[adj_grp_tgt_flags]

    from_bdry_element_indices = src_grp_el_lookup[
            from_vol_element_indices, from_element_faces]

    # }}}

    # {{{ visualization (for debugging)

    if 0:
        print("TVE", adj_grp.elements[adj_grp_tgt_flags])
        print("TBE", to_bdry_element_indices)
        print("FVE", from_vol_element_indices)
        from meshmode.mesh.visualization import draw_2d_mesh
        import matplotlib.pyplot as pt
        draw_2d_mesh(vol_discr.mesh, draw_element_numbers=True,
                set_bounding_box=True,
                draw_vertex_numbers=False,
                draw_face_numbers=True,
                fill=None)
        pt.figure()

        draw_2d_mesh(bdry_discr.mesh, draw_element_numbers=True,
                set_bounding_box=True,
                draw_vertex_numbers=False,
                draw_face_numbers=True,
                fill=None)

        pt.show()
    # }}}

    # {{{ invert face map (using Gauss-Newton)

    to_bdry_nodes = (
            # FIXME: This should view-then-transfer (but PyOpenCL doesn't do
            # non-contiguous transfers for now).
            bdry_discr.groups[i_tgt_grp].view(
                bdry_discr.nodes().get(queue=queue))
            [:, to_bdry_element_indices])

    tol = 1e4 * np.finfo(to_bdry_nodes.dtype).eps

    from_mesh_grp = bdry_discr.mesh.groups[i_src_grp]
    from_grp = bdry_discr.groups[i_src_grp]

    dim = from_grp.dim
    ambient_dim, nelements, nto_unit_nodes = to_bdry_nodes.shape

    initial_guess = np.mean(from_mesh_grp.vertex_unit_coordinates(), axis=0)
    from_unit_nodes = np.empty((dim, nelements, nto_unit_nodes))
    from_unit_nodes[:] = initial_guess.reshape(-1, 1, 1)

    import modepy as mp
    from_vdm = mp.vandermonde(from_grp.basis(), from_grp.unit_nodes)
    from_inv_t_vdm = la.inv(from_vdm.T)
    from_nfuncs = len(from_grp.basis())

    # (ambient_dim, nelements, nfrom_unit_nodes)
    from_bdry_nodes = (
            # FIXME: This should view-then-transfer (but PyOpenCL doesn't do
            # non-contiguous transfers for now).
            bdry_discr.groups[i_src_grp].view(
                bdry_discr.nodes().get(queue=queue))
            [:, from_bdry_element_indices])

    def apply_map(unit_nodes):
        # unit_nodes: (dim, nelements, nto_unit_nodes)

        # basis_at_unit_nodes
        basis_at_unit_nodes = np.empty((from_nfuncs, nelements, nto_unit_nodes))

        for i, f in enumerate(from_grp.basis()):
            basis_at_unit_nodes[i] = (
                    f(unit_nodes.reshape(dim, -1))
                    .reshape(nelements, nto_unit_nodes))

        intp_coeffs = np.einsum("fj,jet->fet", from_inv_t_vdm, basis_at_unit_nodes)

        # If we're interpolating 1, we had better get 1 back.
        one_deviation = np.abs(np.sum(intp_coeffs, axis=0) - 1)
        assert (one_deviation < tol).all(), np.max(one_deviation)

        return np.einsum("fet,aef->aet", intp_coeffs, from_bdry_nodes)

    def get_map_jacobian(unit_nodes):
        # unit_nodes: (dim, nelements, nto_unit_nodes)

        # basis_at_unit_nodes
        dbasis_at_unit_nodes = np.empty(
                (dim, from_nfuncs, nelements, nto_unit_nodes))

        for i, df in enumerate(from_grp.grad_basis()):
            df_result = df(unit_nodes.reshape(dim, -1))

            for rst_axis, df_r in enumerate(df_result):
                dbasis_at_unit_nodes[rst_axis, i] = (
                        df_r.reshape(nelements, nto_unit_nodes))

        dintp_coeffs = np.einsum(
                "fj,rjet->rfet", from_inv_t_vdm, dbasis_at_unit_nodes)

        return np.einsum("rfet,aef->raet", dintp_coeffs, from_bdry_nodes)

    # {{{ test map applier and jacobian

    if 0:
        u = from_unit_nodes
        f = apply_map(u)
        for h in [1e-1, 1e-2]:
            du = h*np.random.randn(*u.shape)

            f_2 = apply_map(u+du)

            jf = get_map_jacobian(u)

            f2_2 = f + np.einsum("raet,ret->aet", jf, du)

            print(h, la.norm((f_2-f2_2).ravel()))

    # }}}

    # {{{ visualize initial guess

    if 0:
        import matplotlib.pyplot as pt
        guess = apply_map(from_unit_nodes)
        goals = to_bdry_nodes

        from meshmode.discretization.visualization import draw_curve
        draw_curve(bdry_discr)

        pt.plot(guess[0].reshape(-1), guess[1].reshape(-1), "or")
        pt.plot(goals[0].reshape(-1), goals[1].reshape(-1), "og")
        pt.plot(from_bdry_nodes[0].reshape(-1), from_bdry_nodes[1].reshape(-1), "o",
                color="purple")
        pt.show()

    # }}}

    logger.info("make_opposite_face_connection: begin gauss-newton")

    niter = 0
    while True:
        resid = apply_map(from_unit_nodes) - to_bdry_nodes

        df = get_map_jacobian(from_unit_nodes)
        df_inv_resid = np.empty_like(from_unit_nodes)

        # For the 1D/2D accelerated versions, we'll use the normal
        # equations and Cramer's rule. If you're looking for high-end
        # numerics, look no further than meshmode.

        if dim == 1:
            # A is df.T
            ata = np.einsum("iket,jket->ijet", df, df)
            atb = np.einsum("iket,ket->iet", df, resid)

            df_inv_resid = atb / ata[0, 0]

        elif dim == 2:
            # A is df.T
            ata = np.einsum("iket,jket->ijet", df, df)
            atb = np.einsum("iket,ket->iet", df, resid)

            det = ata[0, 0]*ata[1, 1] - ata[0, 1]*ata[1, 0]

            df_inv_resid = np.empty_like(from_unit_nodes)
            df_inv_resid[0] = 1/det * (ata[1, 1] * atb[0] - ata[1, 0]*atb[1])
            df_inv_resid[1] = 1/det * (-ata[0, 1] * atb[0] + ata[0, 0]*atb[1])

        else:
            # The boundary of a 3D mesh is 2D, so that's the
            # highest-dimensional case we genuinely care about.
            #
            # This stinks, performance-wise, because it's not vectorized.
            # But we'll only hit it for boundaries of 4+D meshes, in which
            # case... good luck. :)
            for e in range(nelements):
                for t in range(nto_unit_nodes):
                    df_inv_resid[:, e, t], _, _, _ = \
                            la.lstsq(df[:, :, e, t].T, resid[:, e, t])

        from_unit_nodes = from_unit_nodes - df_inv_resid

        max_resid = np.max(np.abs(resid))
        logger.debug("gauss-newton residual: %g" % max_resid)

        if max_resid < tol:
            logger.info("make_opposite_face_connection: gauss-newton: done, "
                    "final residual: %g" % max_resid)
            break

        niter += 1
        if niter > 10:
            raise RuntimeError("Gauss-Newton (for finding opposite-face reference "
                    "coordinates) did not converge")

    # }}}

    # {{{ find groups of from_unit_nodes

    def to_dev(ary):
        return cl.array.to_device(queue, ary, array_queue=None)

    done_elements = np.zeros(nelements, dtype=np.bool)
    while True:
        todo_elements, = np.where(~done_elements)
        if not len(todo_elements):
            return

        template_unit_nodes = from_unit_nodes[:, todo_elements[0], :]

        unit_node_dist = np.max(np.max(np.abs(
                from_unit_nodes[:, todo_elements, :]
                -
                template_unit_nodes.reshape(dim, 1, -1)),
                axis=2), axis=0)

        close_els = todo_elements[unit_node_dist < tol]
        done_elements[close_els] = True

        unit_node_dist = np.max(np.max(np.abs(
                from_unit_nodes[:, todo_elements, :]
                -
                template_unit_nodes.reshape(dim, 1, -1)),
                axis=2), axis=0)

        from meshmode.discretization.connection import InterpolationBatch
        yield InterpolationBatch(
                from_group_index=i_src_grp,
                from_element_indices=to_dev(from_bdry_element_indices[close_els]),
                to_element_indices=to_dev(to_bdry_element_indices[close_els]),
                result_unit_nodes=template_unit_nodes,
                to_element_face=None)
示例#10
0
def main():
    # If can't import firedrake, do nothing
    #
    # filename MUST include "firedrake" (i.e. match *firedrake*.py) in order
    # to be run during CI
    try:
        import firedrake  # noqa : F401
    except ImportError:
        return 0

    from meshmode.interop.firedrake import build_connection_from_firedrake
    from firedrake import (UnitSquareMesh, FunctionSpace, SpatialCoordinate,
                           Function, cos)

    # Create a firedrake mesh and interpolate cos(x+y) onto it
    fd_mesh = UnitSquareMesh(10, 10)
    fd_fspace = FunctionSpace(fd_mesh, "DG", 2)
    spatial_coord = SpatialCoordinate(fd_mesh)
    fd_fntn = Function(fd_fspace).interpolate(cos(sum(spatial_coord)))

    # Make connections
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    fd_connection = build_connection_from_firedrake(actx, fd_fspace)
    fd_bdy_connection = \
        build_connection_from_firedrake(actx,
                                        fd_fspace,
                                        restrict_to_boundary="on_boundary")

    # Plot the meshmode meshes that the connections connect to
    import matplotlib.pyplot as plt
    from meshmode.mesh.visualization import draw_2d_mesh
    fig, (ax1, ax2) = plt.subplots(1, 2)
    ax1.set_title("FiredrakeConnection")
    plt.sca(ax1)
    draw_2d_mesh(fd_connection.discr.mesh,
                 draw_vertex_numbers=False,
                 draw_element_numbers=False,
                 set_bounding_box=True)
    ax2.set_title("FiredrakeConnection 'on_boundary'")
    plt.sca(ax2)
    draw_2d_mesh(fd_bdy_connection.discr.mesh,
                 draw_vertex_numbers=False,
                 draw_element_numbers=False,
                 set_bounding_box=True)
    plt.show()

    # Plot fd_fntn using unrestricted FiredrakeConnection
    from meshmode.discretization.visualization import make_visualizer
    discr = fd_connection.discr
    vis = make_visualizer(actx, discr, discr.groups[0].order + 3)
    field = fd_connection.from_firedrake(fd_fntn, actx=actx)

    fig = plt.figure()
    ax1 = fig.add_subplot(1, 2, 1, projection="3d")
    ax1.set_title("cos(x+y) in\nFiredrakeConnection")
    vis.show_scalar_in_matplotlib_3d(field, do_show=False)

    # Now repeat using FiredrakeConnection restricted to "on_boundary"
    bdy_discr = fd_bdy_connection.discr
    bdy_vis = make_visualizer(actx, bdy_discr, bdy_discr.groups[0].order + 3)
    bdy_field = fd_bdy_connection.from_firedrake(fd_fntn, actx=actx)

    ax2 = fig.add_subplot(1, 2, 2, projection="3d")
    plt.sca(ax2)
    ax2.set_title("cos(x+y) in\nFiredrakeConnection 'on_boundary'")
    bdy_vis.show_scalar_in_matplotlib_3d(bdy_field, do_show=False)

    import matplotlib.cm as cm
    fig.colorbar(cm.ScalarMappable())
    plt.show()
示例#11
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])
示例#12
0
def make_opposite_face_connection(volume_to_bdry_conn):
    """Given a boundary restriction connection *volume_to_bdry_conn*,
    return a :class:`DirectDiscretizationConnection` that performs data
    exchange across opposite faces.
    """

    vol_discr = volume_to_bdry_conn.from_discr
    vol_mesh = vol_discr.mesh
    bdry_discr = volume_to_bdry_conn.to_discr

    # make sure we were handed a volume-to-boundary connection
    for i_tgrp, conn_grp in enumerate(volume_to_bdry_conn.groups):
        for batch in conn_grp.batches:
            assert batch.from_group_index == i_tgrp
            assert batch.to_element_face is not None

    ngrps = len(volume_to_bdry_conn.groups)
    assert ngrps == len(vol_discr.groups)
    assert ngrps == len(bdry_discr.groups)

    # One interpolation batch in this connection corresponds
    # to a key (i_tgt_grp,)  (i_src_grp, i_face_tgt,)

    with cl.CommandQueue(vol_discr.cl_context) as queue:
        # a list of batches for each group
        groups = [[] for i_tgt_grp in range(ngrps)]

        for i_src_grp in range(ngrps):
            src_grp_el_lookup = _make_bdry_el_lookup_table(
                queue, volume_to_bdry_conn, i_src_grp)

            for i_tgt_grp in range(ngrps):
                vbc_tgt_grp_batches = volume_to_bdry_conn.groups[
                    i_tgt_grp].batches

                adj = vol_mesh.facial_adjacency_groups[i_tgt_grp][i_src_grp]

                for i_face_tgt in range(vol_mesh.groups[i_tgt_grp].nfaces):
                    vbc_tgt_grp_face_batch = _find_ibatch_for_face(
                        vbc_tgt_grp_batches, i_face_tgt)

                    # {{{ index wrangling

                    # Assert that the adjacency group and the restriction
                    # interpolation batch and the adjacency group have the same
                    # element ordering.

                    adj_tgt_flags = adj.element_faces == i_face_tgt

                    assert (np.array_equal(
                        adj.elements[adj_tgt_flags],
                        vbc_tgt_grp_face_batch.from_element_indices.get(
                            queue=queue)))

                    # find to_element_indices

                    tgt_bdry_element_indices = (
                        vbc_tgt_grp_face_batch.to_element_indices.get(
                            queue=queue))

                    # find from_element_indices

                    src_vol_element_indices = adj.neighbors[adj_tgt_flags]
                    src_element_faces = adj.neighbor_faces[adj_tgt_flags]

                    src_bdry_element_indices = src_grp_el_lookup[
                        src_vol_element_indices, src_element_faces]

                    # }}}

                    # {{{ visualization (for debugging)

                    if 0:
                        print("TVE", adj.elements[adj_tgt_flags])
                        print("TBE", tgt_bdry_element_indices)
                        print("FVE", src_vol_element_indices)
                        from meshmode.mesh.visualization import draw_2d_mesh
                        import matplotlib.pyplot as pt
                        draw_2d_mesh(vol_discr.mesh,
                                     draw_element_numbers=True,
                                     set_bounding_box=True,
                                     draw_vertex_numbers=False,
                                     draw_face_numbers=True,
                                     fill=None)
                        pt.figure()

                        draw_2d_mesh(bdry_discr.mesh,
                                     draw_element_numbers=True,
                                     set_bounding_box=True,
                                     draw_vertex_numbers=False,
                                     draw_face_numbers=True,
                                     fill=None)

                        pt.show()

                    # }}}

                    groups[i_tgt_grp].extend(
                        _make_cross_face_batches(queue, bdry_discr, bdry_discr,
                                                 i_tgt_grp, i_src_grp,
                                                 tgt_bdry_element_indices,
                                                 src_bdry_element_indices))

    from meshmode.discretization.connection import (
        DirectDiscretizationConnection, DiscretizationConnectionElementGroup)
    return DirectDiscretizationConnection(
        from_discr=bdry_discr,
        to_discr=bdry_discr,
        groups=[
            DiscretizationConnectionElementGroup(batches=batches)
            for batches in groups
        ],
        is_surjective=True)
示例#13
0
def make_opposite_face_connection(actx, volume_to_bdry_conn):
    """Given a boundary restriction connection *volume_to_bdry_conn*,
    return a :class:`DirectDiscretizationConnection` that performs data
    exchange across opposite faces.
    """

    vol_discr = volume_to_bdry_conn.from_discr
    vol_mesh = vol_discr.mesh
    bdry_discr = volume_to_bdry_conn.to_discr

    # make sure we were handed a volume-to-boundary connection
    for i_tgrp, conn_grp in enumerate(volume_to_bdry_conn.groups):
        for batch in conn_grp.batches:
            assert batch.from_group_index == i_tgrp
            assert batch.to_element_face is not None

    ngrps = len(volume_to_bdry_conn.groups)
    assert ngrps == len(vol_discr.groups)
    assert ngrps == len(bdry_discr.groups)

    # One interpolation batch in this connection corresponds
    # to a key (i_tgt_grp,)  (i_src_grp, i_face_tgt,)

    # a list of batches for each group
    groups = [[] for i_tgt_grp in range(ngrps)]

    for i_src_grp in range(ngrps):
        src_grp_el_lookup = _make_bdry_el_lookup_table(actx,
                                                       volume_to_bdry_conn,
                                                       i_src_grp)

        for i_tgt_grp in range(ngrps):
            vbc_tgt_grp_batches = volume_to_bdry_conn.groups[i_tgt_grp].batches

            adj = vol_mesh.facial_adjacency_groups[i_tgt_grp][i_src_grp]

            for i_face_tgt in range(vol_mesh.groups[i_tgt_grp].nfaces):
                vbc_tgt_grp_face_batch = _find_ibatch_for_face(
                    vbc_tgt_grp_batches, i_face_tgt)

                # {{{ index wrangling

                # The elements in the adjacency group will be a subset of
                # the elements in the restriction interpolation batch:
                # Imagine an inter-group boundary. The volume-to-boundary
                # connection will include all faces as targets, whereas
                # there will be separate adjacency groups for intra- and
                # inter-group connections.

                adj_tgt_flags = adj.element_faces == i_face_tgt
                adj_els = adj.elements[adj_tgt_flags]
                if adj_els.size == 0:
                    # NOTE: this case can happen for inter-group boundaries
                    # when all elements are adjacent on the same face
                    # index, so all other ones will be empty
                    continue

                vbc_els = thaw_to_numpy(
                    actx, vbc_tgt_grp_face_batch.from_element_indices)

                if len(adj_els) == len(vbc_els):
                    # Same length: assert (below) that the two use the same
                    # ordering.
                    vbc_used_els = slice(None)

                else:
                    # Genuine subset: figure out an index mapping.
                    vbc_els_sort_idx = np.argsort(vbc_els)
                    vbc_used_els = vbc_els_sort_idx[np.searchsorted(
                        vbc_els, adj_els, sorter=vbc_els_sort_idx)]

                assert np.array_equal(vbc_els[vbc_used_els], adj_els)

                # find to_element_indices

                tgt_bdry_element_indices = thaw_to_numpy(
                    actx,
                    vbc_tgt_grp_face_batch.to_element_indices)[vbc_used_els]

                # find from_element_indices

                src_vol_element_indices = adj.neighbors[adj_tgt_flags]
                src_element_faces = adj.neighbor_faces[adj_tgt_flags]

                src_bdry_element_indices = src_grp_el_lookup[
                    src_vol_element_indices, src_element_faces]

                # }}}

                # {{{ visualization (for debugging)

                if 0:
                    print("TVE", adj.elements[adj_tgt_flags])
                    print("TBE", tgt_bdry_element_indices)
                    print("FVE", src_vol_element_indices)
                    from meshmode.mesh.visualization import draw_2d_mesh
                    import matplotlib.pyplot as pt
                    draw_2d_mesh(vol_discr.mesh,
                                 draw_element_numbers=True,
                                 set_bounding_box=True,
                                 draw_vertex_numbers=False,
                                 draw_face_numbers=True,
                                 fill=None)
                    pt.figure()

                    draw_2d_mesh(bdry_discr.mesh,
                                 draw_element_numbers=True,
                                 set_bounding_box=True,
                                 draw_vertex_numbers=False,
                                 draw_face_numbers=True,
                                 fill=None)

                    pt.show()

                # }}}

                batches = _make_cross_face_batches(actx, bdry_discr,
                                                   bdry_discr, i_tgt_grp,
                                                   i_src_grp,
                                                   tgt_bdry_element_indices,
                                                   src_bdry_element_indices)
                groups[i_tgt_grp].extend(batches)

    from meshmode.discretization.connection import (
        DirectDiscretizationConnection, DiscretizationConnectionElementGroup)
    return DirectDiscretizationConnection(
        from_discr=bdry_discr,
        to_discr=bdry_discr,
        groups=[
            DiscretizationConnectionElementGroup(batches=batches)
            for batches in groups
        ],
        is_surjective=True)
示例#14
0
def _make_cross_face_batches(queue, vol_discr, bdry_discr, i_tgt_grp,
                             i_src_grp, i_face_tgt, adj_grp,
                             vbc_tgt_grp_face_batch, src_grp_el_lookup):

    # {{{ index wrangling

    # Assert that the adjacency group and the restriction
    # interpolation batch and the adjacency group have the same
    # element ordering.

    adj_grp_tgt_flags = adj_grp.element_faces == i_face_tgt

    assert (np.array_equal(
        adj_grp.elements[adj_grp_tgt_flags],
        vbc_tgt_grp_face_batch.from_element_indices.get(queue=queue)))

    # find to_element_indices

    to_bdry_element_indices = (vbc_tgt_grp_face_batch.to_element_indices.get(
        queue=queue))

    # find from_element_indices

    from_vol_element_indices = adj_grp.neighbors[adj_grp_tgt_flags]
    from_element_faces = adj_grp.neighbor_faces[adj_grp_tgt_flags]

    from_bdry_element_indices = src_grp_el_lookup[from_vol_element_indices,
                                                  from_element_faces]

    # }}}

    # {{{ visualization (for debugging)

    if 0:
        print("TVE", adj_grp.elements[adj_grp_tgt_flags])
        print("TBE", to_bdry_element_indices)
        print("FVE", from_vol_element_indices)
        from meshmode.mesh.visualization import draw_2d_mesh
        import matplotlib.pyplot as pt
        draw_2d_mesh(vol_discr.mesh,
                     draw_element_numbers=True,
                     set_bounding_box=True,
                     draw_vertex_numbers=False,
                     draw_face_numbers=True,
                     fill=None)
        pt.figure()

        draw_2d_mesh(bdry_discr.mesh,
                     draw_element_numbers=True,
                     set_bounding_box=True,
                     draw_vertex_numbers=False,
                     draw_face_numbers=True,
                     fill=None)

        pt.show()
    # }}}

    # {{{ invert face map (using Gauss-Newton)

    to_bdry_nodes = (
        # FIXME: This should view-then-transfer (but PyOpenCL doesn't do
        # non-contiguous transfers for now).
        bdry_discr.groups[i_tgt_grp].view(bdry_discr.nodes().get(queue=queue))
        [:, to_bdry_element_indices])

    tol = 1e4 * np.finfo(to_bdry_nodes.dtype).eps

    from_mesh_grp = bdry_discr.mesh.groups[i_src_grp]
    from_grp = bdry_discr.groups[i_src_grp]

    dim = from_grp.dim
    ambient_dim, nelements, nto_unit_nodes = to_bdry_nodes.shape

    initial_guess = np.mean(from_mesh_grp.vertex_unit_coordinates(), axis=0)
    from_unit_nodes = np.empty((dim, nelements, nto_unit_nodes))
    from_unit_nodes[:] = initial_guess.reshape(-1, 1, 1)

    import modepy as mp
    from_vdm = mp.vandermonde(from_grp.basis(), from_grp.unit_nodes)
    from_inv_t_vdm = la.inv(from_vdm.T)
    from_nfuncs = len(from_grp.basis())

    # (ambient_dim, nelements, nfrom_unit_nodes)
    from_bdry_nodes = (
        # FIXME: This should view-then-transfer (but PyOpenCL doesn't do
        # non-contiguous transfers for now).
        bdry_discr.groups[i_src_grp].view(bdry_discr.nodes().get(queue=queue))
        [:, from_bdry_element_indices])

    def apply_map(unit_nodes):
        # unit_nodes: (dim, nelements, nto_unit_nodes)

        # basis_at_unit_nodes
        basis_at_unit_nodes = np.empty(
            (from_nfuncs, nelements, nto_unit_nodes))

        for i, f in enumerate(from_grp.basis()):
            basis_at_unit_nodes[i] = (f(unit_nodes.reshape(dim, -1)).reshape(
                nelements, nto_unit_nodes))

        intp_coeffs = np.einsum("fj,jet->fet", from_inv_t_vdm,
                                basis_at_unit_nodes)

        # If we're interpolating 1, we had better get 1 back.
        one_deviation = np.abs(np.sum(intp_coeffs, axis=0) - 1)
        assert (one_deviation < tol).all(), np.max(one_deviation)

        return np.einsum("fet,aef->aet", intp_coeffs, from_bdry_nodes)

    def get_map_jacobian(unit_nodes):
        # unit_nodes: (dim, nelements, nto_unit_nodes)

        # basis_at_unit_nodes
        dbasis_at_unit_nodes = np.empty(
            (dim, from_nfuncs, nelements, nto_unit_nodes))

        for i, df in enumerate(from_grp.grad_basis()):
            df_result = df(unit_nodes.reshape(dim, -1))

            for rst_axis, df_r in enumerate(df_result):
                dbasis_at_unit_nodes[rst_axis, i] = (df_r.reshape(
                    nelements, nto_unit_nodes))

        dintp_coeffs = np.einsum("fj,rjet->rfet", from_inv_t_vdm,
                                 dbasis_at_unit_nodes)

        return np.einsum("rfet,aef->raet", dintp_coeffs, from_bdry_nodes)

    # {{{ test map applier and jacobian

    if 0:
        u = from_unit_nodes
        f = apply_map(u)
        for h in [1e-1, 1e-2]:
            du = h * np.random.randn(*u.shape)

            f_2 = apply_map(u + du)

            jf = get_map_jacobian(u)

            f2_2 = f + np.einsum("raet,ret->aet", jf, du)

            print(h, la.norm((f_2 - f2_2).ravel()))

    # }}}

    # {{{ visualize initial guess

    if 0:
        import matplotlib.pyplot as pt
        guess = apply_map(from_unit_nodes)
        goals = to_bdry_nodes

        from meshmode.discretization.visualization import draw_curve
        draw_curve(bdry_discr)

        pt.plot(guess[0].reshape(-1), guess[1].reshape(-1), "or")
        pt.plot(goals[0].reshape(-1), goals[1].reshape(-1), "og")
        pt.plot(from_bdry_nodes[0].reshape(-1),
                from_bdry_nodes[1].reshape(-1),
                "o",
                color="purple")
        pt.show()

    # }}}

    logger.info("make_opposite_face_connection: begin gauss-newton")

    niter = 0
    while True:
        resid = apply_map(from_unit_nodes) - to_bdry_nodes

        df = get_map_jacobian(from_unit_nodes)
        df_inv_resid = np.empty_like(from_unit_nodes)

        # For the 1D/2D accelerated versions, we'll use the normal
        # equations and Cramer's rule. If you're looking for high-end
        # numerics, look no further than meshmode.

        if dim == 1:
            # A is df.T
            ata = np.einsum("iket,jket->ijet", df, df)
            atb = np.einsum("iket,ket->iet", df, resid)

            df_inv_resid = atb / ata[0, 0]

        elif dim == 2:
            # A is df.T
            ata = np.einsum("iket,jket->ijet", df, df)
            atb = np.einsum("iket,ket->iet", df, resid)

            det = ata[0, 0] * ata[1, 1] - ata[0, 1] * ata[1, 0]

            df_inv_resid = np.empty_like(from_unit_nodes)
            df_inv_resid[0] = 1 / det * (ata[1, 1] * atb[0] -
                                         ata[1, 0] * atb[1])
            df_inv_resid[1] = 1 / det * (-ata[0, 1] * atb[0] +
                                         ata[0, 0] * atb[1])

        else:
            # The boundary of a 3D mesh is 2D, so that's the
            # highest-dimensional case we genuinely care about.
            #
            # This stinks, performance-wise, because it's not vectorized.
            # But we'll only hit it for boundaries of 4+D meshes, in which
            # case... good luck. :)
            for e in range(nelements):
                for t in range(nto_unit_nodes):
                    df_inv_resid[:, e, t], _, _, _ = \
                            la.lstsq(df[:, :, e, t].T, resid[:, e, t])

        from_unit_nodes = from_unit_nodes - df_inv_resid

        max_resid = np.max(np.abs(resid))
        logger.debug("gauss-newton residual: %g" % max_resid)

        if max_resid < tol:
            logger.info("make_opposite_face_connection: gauss-newton: done, "
                        "final residual: %g" % max_resid)
            break

        niter += 1
        if niter > 10:
            raise RuntimeError(
                "Gauss-Newton (for finding opposite-face reference "
                "coordinates) did not converge")

    # }}}

    # {{{ find groups of from_unit_nodes

    def to_dev(ary):
        return cl.array.to_device(queue, ary, array_queue=None)

    done_elements = np.zeros(nelements, dtype=np.bool)
    while True:
        todo_elements, = np.where(~done_elements)
        if not len(todo_elements):
            return

        template_unit_nodes = from_unit_nodes[:, todo_elements[0], :]

        unit_node_dist = np.max(np.max(
            np.abs(from_unit_nodes[:, todo_elements, :] -
                   template_unit_nodes.reshape(dim, 1, -1)),
            axis=2),
                                axis=0)

        close_els = todo_elements[unit_node_dist < tol]
        done_elements[close_els] = True

        unit_node_dist = np.max(np.max(
            np.abs(from_unit_nodes[:, todo_elements, :] -
                   template_unit_nodes.reshape(dim, 1, -1)),
            axis=2),
                                axis=0)

        from meshmode.discretization.connection import InterpolationBatch
        yield InterpolationBatch(
            from_group_index=i_src_grp,
            from_element_indices=to_dev(from_bdry_element_indices[close_els]),
            to_element_indices=to_dev(to_bdry_element_indices[close_els]),
            result_unit_nodes=template_unit_nodes,
            to_element_face=None)
示例#15
0
def test_box_boundary_tags(dim, nelem, mesh_type, group_cls, visualize=False):
    if group_cls is TensorProductElementGroup and mesh_type is not None:
        pytest.skip("mesh type not supported on tensor product elements")

    from meshmode.mesh import is_boundary_tag_empty
    from meshmode.mesh import check_bc_coverage

    if dim == 1:
        a = (0, )
        b = (1, )
        nelements_per_axis = (nelem, )
        btag_to_face = {"btag_test_1": ["+x"], "btag_test_2": ["-x"]}
    elif dim == 2:
        a = (0, -1)
        b = (1, 1)
        nelements_per_axis = (nelem, ) * 2
        btag_to_face = {
            "btag_test_1": ["+x", "-y"],
            "btag_test_2": ["+y", "-x"]
        }
    elif dim == 3:
        a = (0, -1, -1)
        b = (1, 1, 1)
        nelements_per_axis = (nelem, ) * 3
        btag_to_face = {
            "btag_test_1": ["+x", "-y", "-z"],
            "btag_test_2": ["+y", "-x", "+z"]
        }
    mesh = mgen.generate_regular_rect_mesh(
        a=a,
        b=b,
        nelements_per_axis=nelements_per_axis,
        order=3,
        boundary_tag_to_face=btag_to_face,
        group_cls=group_cls,
        mesh_type=mesh_type)

    if visualize and dim == 2:
        from meshmode.mesh.visualization import draw_2d_mesh
        draw_2d_mesh(mesh,
                     draw_element_numbers=False,
                     draw_vertex_numbers=False)
        import matplotlib.pyplot as plt
        plt.show()

    # correct answer
    if dim == 1:
        num_on_bdy = 1
    elif group_cls is TensorProductElementGroup:
        num_on_bdy = dim * nelem**(dim - 1)
    elif group_cls is SimplexElementGroup:
        num_on_bdy = dim * (dim - 1) * nelem**(dim - 1)
    else:
        raise AssertionError()

    assert not is_boundary_tag_empty(mesh, "btag_test_1")
    assert not is_boundary_tag_empty(mesh, "btag_test_2")
    check_bc_coverage(mesh, ["btag_test_1", "btag_test_2"])

    # check how many elements are marked on each boundary
    num_marked_bdy_1 = 0
    num_marked_bdy_2 = 0
    btag_1_bit = mesh.boundary_tag_bit("btag_test_1")
    btag_2_bit = mesh.boundary_tag_bit("btag_test_2")
    for igrp in range(len(mesh.groups)):
        bdry_fagrp = mesh.facial_adjacency_groups[igrp].get(None, None)

        if bdry_fagrp is None:
            continue

        for nbrs in bdry_fagrp.neighbors:
            if (-nbrs) & btag_1_bit:
                num_marked_bdy_1 += 1
            if (-nbrs) & btag_2_bit:
                num_marked_bdy_2 += 1

    # raise errors if wrong number of elements marked
    if num_marked_bdy_1 != num_on_bdy:
        raise ValueError("%i marked on custom boundary 1, should be %i" %
                         (num_marked_bdy_1, num_on_bdy))
    if num_marked_bdy_2 != num_on_bdy:
        raise ValueError("%i marked on custom boundary 2, should be %i" %
                         (num_marked_bdy_2, num_on_bdy))
示例#16
0
def make_opposite_face_connection(volume_to_bdry_conn):
    """Given a boundary restriction connection *volume_to_bdry_conn*,
    return a :class:`DirectDiscretizationConnection` that performs data
    exchange across opposite faces.
    """

    vol_discr = volume_to_bdry_conn.from_discr
    vol_mesh = vol_discr.mesh
    bdry_discr = volume_to_bdry_conn.to_discr

    # make sure we were handed a volume-to-boundary connection
    for i_tgrp, conn_grp in enumerate(volume_to_bdry_conn.groups):
        for batch in conn_grp.batches:
            assert batch.from_group_index == i_tgrp
            assert batch.to_element_face is not None

    ngrps = len(volume_to_bdry_conn.groups)
    assert ngrps == len(vol_discr.groups)
    assert ngrps == len(bdry_discr.groups)

    # One interpolation batch in this connection corresponds
    # to a key (i_tgt_grp,)  (i_src_grp, i_face_tgt,)

    with cl.CommandQueue(vol_discr.cl_context) as queue:
        # a list of batches for each group
        groups = [[] for i_tgt_grp in range(ngrps)]

        for i_src_grp in range(ngrps):
            src_grp_el_lookup = _make_bdry_el_lookup_table(
                    queue, volume_to_bdry_conn, i_src_grp)

            for i_tgt_grp in range(ngrps):
                vbc_tgt_grp_batches = volume_to_bdry_conn.groups[i_tgt_grp].batches

                adj = vol_mesh.facial_adjacency_groups[i_tgt_grp][i_src_grp]

                for i_face_tgt in range(vol_mesh.groups[i_tgt_grp].nfaces):
                    vbc_tgt_grp_face_batch = _find_ibatch_for_face(
                            vbc_tgt_grp_batches, i_face_tgt)

                    # {{{ index wrangling

                    # Assert that the adjacency group and the restriction
                    # interpolation batch and the adjacency group have the same
                    # element ordering.

                    adj_tgt_flags = adj.element_faces == i_face_tgt

                    assert (np.array_equal(
                                adj.elements[adj_tgt_flags],
                                vbc_tgt_grp_face_batch.from_element_indices
                                .get(queue=queue)))

                    # find to_element_indices

                    tgt_bdry_element_indices = (
                            vbc_tgt_grp_face_batch.to_element_indices
                            .get(queue=queue))

                    # find from_element_indices

                    src_vol_element_indices = adj.neighbors[adj_tgt_flags]
                    src_element_faces = adj.neighbor_faces[adj_tgt_flags]

                    src_bdry_element_indices = src_grp_el_lookup[
                            src_vol_element_indices, src_element_faces]

                    # }}}

                    # {{{ visualization (for debugging)

                    if 0:
                        print("TVE", adj.elements[adj_tgt_flags])
                        print("TBE", tgt_bdry_element_indices)
                        print("FVE", src_vol_element_indices)
                        from meshmode.mesh.visualization import draw_2d_mesh
                        import matplotlib.pyplot as pt
                        draw_2d_mesh(vol_discr.mesh, draw_element_numbers=True,
                                set_bounding_box=True,
                                draw_vertex_numbers=False,
                                draw_face_numbers=True,
                                fill=None)
                        pt.figure()

                        draw_2d_mesh(bdry_discr.mesh, draw_element_numbers=True,
                                set_bounding_box=True,
                                draw_vertex_numbers=False,
                                draw_face_numbers=True,
                                fill=None)

                        pt.show()

                    # }}}

                    groups[i_tgt_grp].extend(_make_cross_face_batches(queue,
                            bdry_discr, bdry_discr,
                            i_tgt_grp, i_src_grp,
                            tgt_bdry_element_indices,
                            src_bdry_element_indices))

    from meshmode.discretization.connection import (
            DirectDiscretizationConnection, DiscretizationConnectionElementGroup)
    return DirectDiscretizationConnection(
            from_discr=bdry_discr,
            to_discr=bdry_discr,
            groups=[
                DiscretizationConnectionElementGroup(batches=batches)
                for batches in groups],
            is_surjective=True)