def test_resampling_matrix(dims):
    ncoarse = 5
    nfine = 10

    coarse_nodes = mp.warp_and_blend_nodes(dims, ncoarse)
    fine_nodes = mp.warp_and_blend_nodes(dims, nfine)

    coarse_basis = mp.simplex_onb(dims, ncoarse)
    fine_basis = mp.simplex_onb(dims, nfine)

    my_eye = np.dot(
        mp.resampling_matrix(fine_basis, coarse_nodes, fine_nodes),
        mp.resampling_matrix(coarse_basis, fine_nodes, coarse_nodes))

    assert la.norm(my_eye - np.eye(len(my_eye))) < 1e-13

    my_eye_least_squares = np.dot(
        mp.resampling_matrix(coarse_basis,
                             coarse_nodes,
                             fine_nodes,
                             least_squares_ok=True),
        mp.resampling_matrix(coarse_basis, fine_nodes, coarse_nodes),
    )

    assert la.norm(my_eye_least_squares -
                   np.eye(len(my_eye_least_squares))) < 4e-13
Beispiel #2
0
def test_nodal_face_mass_matrix(dim, order=3):
    from modepy.tools import unit_vertices
    all_verts = unit_vertices(dim).T

    basis = mp.simplex_onb(dim, order)

    np.set_printoptions(linewidth=200)

    from modepy.matrices import nodal_face_mass_matrix
    volume_nodes = mp.warp_and_blend_nodes(dim, order)
    face_nodes = mp.warp_and_blend_nodes(dim-1, order)

    for iface in range(dim+1):
        verts = np.hstack([all_verts[:, :iface], all_verts[:, iface+1:]])

        fmm = nodal_face_mass_matrix(basis, volume_nodes, face_nodes, order,
                verts)
        fmm2 = nodal_face_mass_matrix(basis, volume_nodes, face_nodes, order+1,
                verts)

        assert la.norm(fmm-fmm2, np.inf) < 1e-11

        fmm[np.abs(fmm) < 1e-13] = 0

        print(fmm)
        nnz = np.sum(np.abs(fmm) > 0)
        print(nnz)

    print(mp.mass_matrix(
        mp.simplex_onb(dim-1, order),
        mp.warp_and_blend_nodes(dim-1, order), ))
def test_nodal_face_mass_matrix(dim, order=3):
    from modepy.tools import unit_vertices
    all_verts = unit_vertices(dim).T

    basis = mp.simplex_onb(dim, order)

    np.set_printoptions(linewidth=200)

    from modepy.matrices import nodal_face_mass_matrix
    volume_nodes = mp.warp_and_blend_nodes(dim, order)
    face_nodes = mp.warp_and_blend_nodes(dim - 1, order)

    for iface in range(dim + 1):
        verts = np.hstack([all_verts[:, :iface], all_verts[:, iface + 1:]])

        fmm = nodal_face_mass_matrix(basis, volume_nodes, face_nodes, order,
                                     verts)
        fmm2 = nodal_face_mass_matrix(basis, volume_nodes, face_nodes,
                                      order + 1, verts)

        assert la.norm(fmm - fmm2, np.inf) < 1e-11

        fmm[np.abs(fmm) < 1e-13] = 0

        print(fmm)
        nnz = np.sum(np.abs(fmm) > 0)
        print(nnz)

    print(
        mp.mass_matrix(
            mp.simplex_onb(dim - 1, order),
            mp.warp_and_blend_nodes(dim - 1, order),
        ))
Beispiel #4
0
def test_diff_matrix(dims, eltype):
    n = 5

    if eltype == "simplex":
        nodes = mp.warp_and_blend_nodes(dims, n)
        basis = mp.simplex_onb(dims, n)
        grad_basis = mp.grad_simplex_onb(dims, n)
    elif eltype == "tensor":
        nodes = mp.legendre_gauss_lobatto_tensor_product_nodes(dims, n)
        basis = mp.legendre_tensor_product_basis(dims, n)
        grad_basis = mp.grad_legendre_tensor_product_basis(dims, n)
    else:
        raise ValueError(f"unknown element type: {eltype}")

    diff_mat = mp.differentiation_matrices(basis, grad_basis, nodes)
    if isinstance(diff_mat, tuple):
        diff_mat = diff_mat[0]

    f = np.sin(nodes[0])

    df_dx = np.cos(nodes[0])
    df_dx_num = np.dot(diff_mat, f)

    error = la.norm(df_dx - df_dx_num) / la.norm(df_dx)
    logger.info("error: %.5e", error)
    assert error < 2.0e-4, error
Beispiel #5
0
def plot_element_values(n, nodes, values, resample_n=None,
        node_tuples=None, show_nodes=False):
    dims = len(nodes)

    orig_nodes = nodes
    orig_values = values

    if resample_n is not None:
        import modepy as mp
        basis = mp.simplex_onb(dims, n)
        fine_nodes = mp.equidistant_nodes(dims, resample_n)

        values = np.dot(mp.resampling_matrix(basis, fine_nodes, nodes), values)
        nodes = fine_nodes
        n = resample_n

    from pytools import generate_nonnegative_integer_tuples_summing_to_at_most \
            as gnitstam

    if dims == 1:
        import matplotlib.pyplot as pt
        pt.plot(nodes[0], values)
        if show_nodes:
            pt.plot(orig_nodes[0], orig_values, "x")
        pt.show()
    elif dims == 2:
        import mayavi.mlab as mlab
        mlab.triangular_mesh(
                nodes[0], nodes[1], values, submesh(list(gnitstam(n, 2))))
        if show_nodes:
            mlab.points3d(orig_nodes[0], orig_nodes[1], orig_values,
                    scale_factor=0.05)
        mlab.show()
    else:
        raise RuntimeError("unsupported dimensionality %d" % dims)
Beispiel #6
0
    def _resample_matrix(self, elgroup_index, ibatch_index):
        import modepy as mp
        ibatch = self.groups[elgroup_index].batches[ibatch_index]
        from_grp = self.from_discr.groups[elgroup_index]

        return mp.resampling_matrix(
                mp.simplex_onb(self.from_discr.dim, from_grp.order),
                ibatch.result_unit_nodes, from_grp.unit_nodes)
    def estimate_resid(inner_n):
        nodes = mp.warp_and_blend_nodes(dims, inner_n)
        basis = mp.simplex_onb(dims, inner_n)
        vdm = mp.vandermonde(basis, nodes)

        f = test_func(nodes[0])
        coeffs = la.solve(vdm, f)

        from modepy.modal_decay import estimate_relative_expansion_residual
        return estimate_relative_expansion_residual(coeffs.reshape(1, -1),
                                                    dims, inner_n)
Beispiel #8
0
    def estimate_resid(inner_n):
        nodes = mp.warp_and_blend_nodes(dims, inner_n)
        basis = mp.simplex_onb(dims, inner_n)
        vdm = mp.vandermonde(basis, nodes)

        f = test_func(nodes[0])
        coeffs = la.solve(vdm, f)

        from modepy.modal_decay import estimate_relative_expansion_residual
        return estimate_relative_expansion_residual(
                coeffs.reshape(1, -1), dims, inner_n)
Beispiel #9
0
def test_resampling_matrix(dims):
    ncoarse = 5
    nfine = 10

    coarse_nodes = mp.warp_and_blend_nodes(dims, ncoarse)
    fine_nodes = mp.warp_and_blend_nodes(dims, nfine)

    coarse_basis = mp.simplex_onb(dims, ncoarse)
    fine_basis = mp.simplex_onb(dims, nfine)

    my_eye = np.dot(
            mp.resampling_matrix(fine_basis, coarse_nodes, fine_nodes),
            mp.resampling_matrix(coarse_basis, fine_nodes, coarse_nodes))

    assert la.norm(my_eye - np.eye(len(my_eye))) < 1e-13

    my_eye_least_squares = np.dot(
            mp.resampling_matrix(coarse_basis, coarse_nodes, fine_nodes,
                least_squares_ok=True),
            mp.resampling_matrix(coarse_basis, fine_nodes, coarse_nodes),
            )

    assert la.norm(my_eye_least_squares - np.eye(len(my_eye_least_squares))) < 4e-13
Beispiel #10
0
def test_resampling_matrix(dims, eltype):
    ncoarse = 5
    nfine = 10

    if eltype == "simplex":
        coarse_nodes = mp.warp_and_blend_nodes(dims, ncoarse)
        fine_nodes = mp.warp_and_blend_nodes(dims, nfine)

        coarse_basis = mp.simplex_onb(dims, ncoarse)
        fine_basis = mp.simplex_onb(dims, nfine)
    elif eltype == "tensor":
        coarse_nodes = mp.legendre_gauss_lobatto_tensor_product_nodes(
            dims, ncoarse)
        fine_nodes = mp.legendre_gauss_lobatto_tensor_product_nodes(
            dims, nfine)

        coarse_basis = mp.legendre_tensor_product_basis(dims, ncoarse)
        fine_basis = mp.legendre_tensor_product_basis(dims, nfine)
    else:
        raise ValueError(f"unknown element type: {eltype}")

    my_eye = np.dot(
        mp.resampling_matrix(fine_basis, coarse_nodes, fine_nodes),
        mp.resampling_matrix(coarse_basis, fine_nodes, coarse_nodes))

    assert la.norm(my_eye - np.eye(len(my_eye))) < 3e-13

    my_eye_least_squares = np.dot(
        mp.resampling_matrix(coarse_basis,
                             coarse_nodes,
                             fine_nodes,
                             least_squares_ok=True),
        mp.resampling_matrix(coarse_basis, fine_nodes, coarse_nodes),
    )

    assert la.norm(my_eye_least_squares -
                   np.eye(len(my_eye_least_squares))) < 4e-13
def test_diff_matrix(dims):
    n = 5
    nodes = mp.warp_and_blend_nodes(dims, n)

    f = np.sin(nodes[0])
    df_dx = np.cos(nodes[0])

    diff_mat = mp.differentiation_matrices(mp.simplex_onb(dims, n),
                                           mp.grad_simplex_onb(dims, n), nodes)
    if isinstance(diff_mat, tuple):
        diff_mat = diff_mat[0]
    df_dx_num = np.dot(diff_mat, f)

    print(la.norm(df_dx - df_dx_num))
    assert la.norm(df_dx - df_dx_num) < 1e-3
Beispiel #12
0
def flip_simplex_element_group(vertices, grp, grp_flip_flags):
    from modepy.tools import barycentric_to_unit, unit_to_barycentric

    from meshmode.mesh import SimplexElementGroup

    if not isinstance(grp, SimplexElementGroup):
        raise NotImplementedError("flips only supported on "
                "exclusively SimplexElementGroup-based meshes")

    # Swap the first two vertices on elements to be flipped.

    new_vertex_indices = grp.vertex_indices.copy()
    new_vertex_indices[grp_flip_flags, 0] \
            = grp.vertex_indices[grp_flip_flags, 1]
    new_vertex_indices[grp_flip_flags, 1] \
            = grp.vertex_indices[grp_flip_flags, 0]

    # Generate a resampling matrix that corresponds to the
    # first two barycentric coordinates being swapped.

    bary_unit_nodes = unit_to_barycentric(grp.unit_nodes)

    flipped_bary_unit_nodes = bary_unit_nodes.copy()
    flipped_bary_unit_nodes[0, :] = bary_unit_nodes[1, :]
    flipped_bary_unit_nodes[1, :] = bary_unit_nodes[0, :]
    flipped_unit_nodes = barycentric_to_unit(flipped_bary_unit_nodes)

    flip_matrix = mp.resampling_matrix(
            mp.simplex_onb(grp.dim, grp.order),
            flipped_unit_nodes, grp.unit_nodes)

    flip_matrix[np.abs(flip_matrix) < 1e-15] = 0

    # Flipping twice should be the identity
    assert la.norm(
            np.dot(flip_matrix, flip_matrix)
            - np.eye(len(flip_matrix))) < 1e-13

    # Apply the flip matrix to the nodes.
    new_nodes = grp.nodes.copy()
    new_nodes[:, grp_flip_flags] = np.einsum(
            "ij,dej->dei",
            flip_matrix, grp.nodes[:, grp_flip_flags])

    return SimplexElementGroup(
            grp.order, new_vertex_indices, new_nodes,
            unit_nodes=grp.unit_nodes)
Beispiel #13
0
def test_diff_matrix(dims):
    n = 5
    nodes = mp.warp_and_blend_nodes(dims, n)

    f = np.sin(nodes[0])
    df_dx = np.cos(nodes[0])

    diff_mat = mp.differentiation_matrices(
            mp.simplex_onb(dims, n),
            mp.grad_simplex_onb(dims, n),
            nodes)
    if isinstance(diff_mat, tuple):
        diff_mat = diff_mat[0]
    df_dx_num = np.dot(diff_mat, f)

    print((la.norm(df_dx-df_dx_num)))
    assert la.norm(df_dx-df_dx_num) < 1e-3
def test_modal_decay(case_name, test_func, dims, n, expected_expn):
    nodes = mp.warp_and_blend_nodes(dims, n)
    basis = mp.simplex_onb(dims, n)
    vdm = mp.vandermonde(basis, nodes)

    f = test_func(nodes[0])
    coeffs = la.solve(vdm, f)

    if 0:
        from modepy.tools import plot_element_values
        plot_element_values(n, nodes, f, resample_n=70, show_nodes=True)

    from modepy.modal_decay import fit_modal_decay
    expn, _ = fit_modal_decay(coeffs.reshape(1, -1), dims, n)
    expn = expn[0]

    print(f"{case_name}: computed: {expn:g}, expected: {expected_expn:g}")
    assert abs(expn - expected_expn) < 0.1
def test_diff_matrix_permutation(dims):
    order = 5

    from pytools import \
            generate_nonnegative_integer_tuples_summing_to_at_most as gnitstam
    node_tuples = list(gnitstam(order, dims))

    simplex_onb = mp.simplex_onb(dims, order)
    grad_simplex_onb = mp.grad_simplex_onb(dims, order)
    nodes = np.array(
        mp.warp_and_blend_nodes(dims, order, node_tuples=node_tuples))
    diff_matrices = mp.differentiation_matrices(simplex_onb, grad_simplex_onb,
                                                nodes)

    for iref_axis in range(dims):
        perm = mp.diff_matrix_permutation(node_tuples, iref_axis)

        assert la.norm(diff_matrices[iref_axis] -
                       diff_matrices[0][perm][:, perm]) < 1e-10
Beispiel #16
0
def test_modal_decay(case_name, test_func, dims, n, expected_expn):
    nodes = mp.warp_and_blend_nodes(dims, n)
    basis = mp.simplex_onb(dims, n)
    vdm = mp.vandermonde(basis, nodes)

    f = test_func(nodes[0])
    coeffs = la.solve(vdm, f)

    if 0:
        from modepy.tools import plot_element_values
        plot_element_values(n, nodes, f, resample_n=70,
                show_nodes=True)

    from modepy.modal_decay import fit_modal_decay
    expn, _ = fit_modal_decay(coeffs.reshape(1, -1), dims, n)
    expn = expn[0]

    print(("%s: computed: %g, expected: %g" % (case_name, expn, expected_expn)))
    assert abs(expn-expected_expn) < 0.1
def test_modal_face_mass_matrix(dim, order=3):
    from modepy.tools import unit_vertices
    all_verts = unit_vertices(dim).T

    basis = mp.simplex_onb(dim, order)

    # np.set_printoptions(linewidth=200)

    from modepy.matrices import modal_face_mass_matrix
    for iface in range(dim + 1):
        verts = np.hstack([all_verts[:, :iface], all_verts[:, iface + 1:]])

        fmm = modal_face_mass_matrix(basis, order, verts)
        fmm2 = modal_face_mass_matrix(basis, order + 1, verts)

        assert la.norm(fmm - fmm2, np.inf) < 1e-11

        fmm[np.abs(fmm) < 1e-13] = 0

        print(fmm)
        nnz = np.sum(fmm > 0)
        print(nnz)
Beispiel #18
0
def test_modal_face_mass_matrix(dim, order=3):
    from modepy.tools import unit_vertices
    all_verts = unit_vertices(dim).T

    basis = mp.simplex_onb(dim, order)

    # np.set_printoptions(linewidth=200)

    from modepy.matrices import modal_face_mass_matrix
    for iface in range(dim+1):
        verts = np.hstack([all_verts[:, :iface], all_verts[:, iface+1:]])

        fmm = modal_face_mass_matrix(basis, order, verts)
        fmm2 = modal_face_mass_matrix(basis, order+1, verts)

        assert la.norm(fmm-fmm2, np.inf) < 1e-11

        fmm[np.abs(fmm) < 1e-13] = 0

        print(fmm)
        nnz = np.sum(fmm > 0)
        print(nnz)
Beispiel #19
0
def make_face_restriction(discr, group_factory, boundary_tag,
        per_face_groups=False):
    """Create a mesh, a discretization and a connection to restrict
    a function on *discr* to its values on the edges of element faces
    denoted by *boundary_tag*.

    :arg boundary_tag: The boundary tag for which to create a face
        restriction. May be
        :class:`meshmode.discretization.connection.FRESTR_INTERIOR_FACES`
        to indicate interior faces, or
        :class:`meshmode.discretization.connection.FRESTR_ALL_FACES`
        to make a discretization consisting of all (interior and
        boundary) faces.

    :arg per_face_groups: If *True*, the resulting discretization is
        guaranteed to have groups organized as::

            (grp0, face0), (grp0, face1), ... (grp0, faceN),
            (grp1, face0), (grp1, face1), ... (grp1, faceN), ...

        each with the elements in the same order as the originating
        group. If *False*, volume and boundary groups correspond with
        each other one-to-one, and an interpolation batch is created
        per face.

    :return: a
        :class:`meshmode.discretization.connection.DirectDiscretizationConnection`
        representing the new connection. The new boundary discretization can be
        obtained from the
        :attr:`meshmode.discretization.connection.DirectDiscretizationConnection.to_discr`
        attribute of the return value, and the corresponding new boundary mesh
        from that.

    """

    if boundary_tag is None:
        boundary_tag = FACE_RESTR_INTERIOR
        from warnings import warn
        warn("passing *None* for boundary_tag is deprecated--pass "
                "FRESTR_INTERIOR_FACES instead",
                DeprecationWarning, stacklevel=2)

    logger.info("building face restriction: start")

    # {{{ gather boundary vertices

    bdry_vertex_vol_nrs = _get_face_vertices(discr.mesh, boundary_tag)

    vol_to_bdry_vertices = np.empty(
            discr.mesh.vertices.shape[-1],
            discr.mesh.vertices.dtype)
    vol_to_bdry_vertices.fill(-1)
    vol_to_bdry_vertices[bdry_vertex_vol_nrs] = np.arange(
            len(bdry_vertex_vol_nrs), dtype=np.intp)

    bdry_vertices = discr.mesh.vertices[:, bdry_vertex_vol_nrs]

    # }}}

    from meshmode.mesh import Mesh, SimplexElementGroup
    bdry_mesh_groups = []
    connection_data = {}

    btag_bit = discr.mesh.boundary_tag_bit(boundary_tag)

    for igrp, (grp, fagrp_map) in enumerate(
            zip(discr.groups, discr.mesh.facial_adjacency_groups)):

        mgrp = grp.mesh_el_group

        if not isinstance(mgrp, SimplexElementGroup):
            raise NotImplementedError("can only take boundary of "
                    "SimplexElementGroup-based meshes")

        # {{{ pull together per-group face lists

        group_boundary_faces = []

        if boundary_tag is FACE_RESTR_INTERIOR:
            for fagrp in six.itervalues(fagrp_map):
                if fagrp.ineighbor_group is None:
                    # boundary faces -> not looking for those
                    continue

                group_boundary_faces.extend(
                        zip(fagrp.elements, fagrp.element_faces))

        elif boundary_tag is FACE_RESTR_ALL:
            group_boundary_faces.extend(
                    (iel, iface)
                    for iface in range(grp.mesh_el_group.nfaces)
                    for iel in range(grp.nelements)
                    )

        else:
            bdry_grp = fagrp_map.get(None)
            if bdry_grp is not None:
                nb_el_bits = -bdry_grp.neighbors
                face_relevant_flags = (nb_el_bits & btag_bit) != 0

                group_boundary_faces.extend(
                            zip(
                                bdry_grp.elements[face_relevant_flags],
                                bdry_grp.element_faces[face_relevant_flags]))

        # }}}

        grp_face_vertex_indices = mgrp.face_vertex_indices()
        grp_vertex_unit_coordinates = mgrp.vertex_unit_coordinates()

        batch_base = 0

        # group by face_id

        for face_id in range(mgrp.nfaces):
            batch_boundary_el_numbers_in_grp = np.array(
                    [
                        ibface_el
                        for ibface_el, ibface_face in group_boundary_faces
                        if ibface_face == face_id],
                    dtype=np.intp)

            # {{{ preallocate arrays for mesh group

            nbatch_elements = len(batch_boundary_el_numbers_in_grp)

            if per_face_groups or face_id == 0:
                if per_face_groups:
                    ngroup_bdry_elements = nbatch_elements
                else:
                    ngroup_bdry_elements = len(group_boundary_faces)

                vertex_indices = np.empty(
                        (ngroup_bdry_elements, mgrp.dim+1-1),
                        mgrp.vertex_indices.dtype)

                bdry_unit_nodes = mp.warp_and_blend_nodes(mgrp.dim-1, mgrp.order)
                bdry_unit_nodes_01 = (bdry_unit_nodes + 1)*0.5

                vol_basis = mp.simplex_onb(mgrp.dim, mgrp.order)
                nbdry_unit_nodes = bdry_unit_nodes_01.shape[-1]
                nodes = np.empty(
                        (discr.ambient_dim, ngroup_bdry_elements, nbdry_unit_nodes),
                        dtype=np.float64)

            # }}}

            new_el_numbers = batch_base + np.arange(nbatch_elements)
            if not per_face_groups:
                batch_base += nbatch_elements

            # {{{ no per-element axes in these computations

            # Find boundary vertex indices
            loc_face_vertices = list(grp_face_vertex_indices[face_id])

            # Find unit nodes for boundary element
            face_vertex_unit_coordinates = \
                    grp_vertex_unit_coordinates[loc_face_vertices]

            # Find A, b such that A [e_1 e_2] + b = [r_1 r_2]
            # (Notation assumes that the volume is 3D and the face is 2D.
            # Code does not.)

            b = face_vertex_unit_coordinates[0]
            A = (  # noqa
                    face_vertex_unit_coordinates[1:]
                    - face_vertex_unit_coordinates[0]).T

            face_unit_nodes = (np.dot(A, bdry_unit_nodes_01).T + b).T

            resampling_mat = mp.resampling_matrix(
                    vol_basis,
                    face_unit_nodes, mgrp.unit_nodes)

            # }}}

            # {{{ build information for mesh element group

            # Find vertex_indices
            glob_face_vertices = mgrp.vertex_indices[
                    batch_boundary_el_numbers_in_grp][:, loc_face_vertices]
            vertex_indices[new_el_numbers] = \
                    vol_to_bdry_vertices[glob_face_vertices]

            # Find nodes
            nodes[:, new_el_numbers, :] = np.einsum(
                    "ij,dej->dei",
                    resampling_mat,
                    mgrp.nodes[:, batch_boundary_el_numbers_in_grp, :])

            # }}}

            connection_data[igrp, face_id] = _ConnectionBatchData(
                    group_source_element_indices=batch_boundary_el_numbers_in_grp,
                    group_target_element_indices=new_el_numbers,
                    A=A,
                    b=b,
                    )

            is_last_face = face_id + 1 == mgrp.nfaces

            if per_face_groups or is_last_face:
                bdry_mesh_group = SimplexElementGroup(
                        mgrp.order, vertex_indices, nodes,
                        unit_nodes=bdry_unit_nodes)
                bdry_mesh_groups.append(bdry_mesh_group)

    bdry_mesh = Mesh(bdry_vertices, bdry_mesh_groups)

    from meshmode.discretization import Discretization
    bdry_discr = Discretization(
            discr.cl_context, bdry_mesh, group_factory)

    with cl.CommandQueue(discr.cl_context) as queue:
        connection = _build_boundary_connection(
                queue, discr, bdry_discr, connection_data,
                per_face_groups)

    logger.info("building face restriction: done")

    return connection
Beispiel #20
0
import numpy as np
import modepy as mp

n = 17 # use this total degree
dimensions = 2

# Get a basis of orthonormal functions, and their derivatives.

basis = mp.simplex_onb(dimensions, n)
grad_basis = mp.grad_simplex_onb(dimensions, n)

nodes = mp.warp_and_blend_nodes(dimensions, n)
x, y = nodes

# We want to compute the x derivative of this function:

f = np.sin(5*x+y)
df_dx = 5*np.cos(5*x+y)

# The (generalized) Vandermonde matrix transforms coefficients into
# nodal values. So we can find basis coefficients by applying its
# inverse:

f_coefficients = np.linalg.solve(
        mp.vandermonde(basis, nodes), f)

# Now linearly combine the (x-)derivatives of the basis using
# f_coefficients to compute the numerical derivatives.

df_dx_num = np.dot(
        mp.vandermonde(grad_basis, nodes)[0], f_coefficients)
Beispiel #21
0
def make_face_restriction(discr,
                          group_factory,
                          boundary_tag,
                          per_face_groups=False):
    """Create a mesh, a discretization and a connection to restrict
    a function on *discr* to its values on the edges of element faces
    denoted by *boundary_tag*.

    :arg boundary_tag: The boundary tag for which to create a face
        restriction. May be
        :class:`meshmode.discretization.connection.FRESTR_INTERIOR_FACES`
        to indicate interior faces, or
        :class:`meshmode.discretization.connection.FRESTR_ALL_FACES`
        to make a discretization consisting of all (interior and
        boundary) faces.

    :arg per_face_groups: If *True*, the resulting discretization is
        guaranteed to have groups organized as::

            (grp0, face0), (grp0, face1), ... (grp0, faceN),
            (grp1, face0), (grp1, face1), ... (grp1, faceN), ...

        each with the elements in the same order as the originating
        group. If *False*, volume and boundary groups correspond with
        each other one-to-one, and an interpolation batch is created
        per face.

    :return: a
        :class:`meshmode.discretization.connection.DirectDiscretizationConnection`
        representing the new connection. The new boundary discretization can be
        obtained from the
        :attr:`meshmode.discretization.connection.DirectDiscretizationConnection.to_discr`
        attribute of the return value, and the corresponding new boundary mesh
        from that.

    """

    if boundary_tag is None:
        boundary_tag = FACE_RESTR_INTERIOR
        from warnings import warn
        warn(
            "passing *None* for boundary_tag is deprecated--pass "
            "FRESTR_INTERIOR_FACES instead",
            DeprecationWarning,
            stacklevel=2)

    logger.info("building face restriction: start")

    # {{{ gather boundary vertices

    bdry_vertex_vol_nrs = _get_face_vertices(discr.mesh, boundary_tag)

    vol_to_bdry_vertices = np.empty(discr.mesh.vertices.shape[-1],
                                    discr.mesh.vertices.dtype)
    vol_to_bdry_vertices.fill(-1)
    vol_to_bdry_vertices[bdry_vertex_vol_nrs] = np.arange(
        len(bdry_vertex_vol_nrs), dtype=np.intp)

    bdry_vertices = discr.mesh.vertices[:, bdry_vertex_vol_nrs]

    # }}}

    from meshmode.mesh import Mesh, SimplexElementGroup
    bdry_mesh_groups = []
    connection_data = {}

    btag_bit = discr.mesh.boundary_tag_bit(boundary_tag)

    for igrp, (grp, fagrp_map) in enumerate(
            zip(discr.groups, discr.mesh.facial_adjacency_groups)):

        mgrp = grp.mesh_el_group

        if not isinstance(mgrp, SimplexElementGroup):
            raise NotImplementedError("can only take boundary of "
                                      "SimplexElementGroup-based meshes")

        # {{{ pull together per-group face lists

        group_boundary_faces = []

        if boundary_tag is FACE_RESTR_INTERIOR:
            for fagrp in six.itervalues(fagrp_map):
                if fagrp.ineighbor_group is None:
                    # boundary faces -> not looking for those
                    continue

                group_boundary_faces.extend(
                    zip(fagrp.elements, fagrp.element_faces))

        elif boundary_tag is FACE_RESTR_ALL:
            group_boundary_faces.extend(
                (iel, iface) for iface in range(grp.mesh_el_group.nfaces)
                for iel in range(grp.nelements))

        else:
            bdry_grp = fagrp_map.get(None)
            if bdry_grp is not None:
                nb_el_bits = -bdry_grp.neighbors
                face_relevant_flags = (nb_el_bits & btag_bit) != 0

                group_boundary_faces.extend(
                    zip(bdry_grp.elements[face_relevant_flags],
                        bdry_grp.element_faces[face_relevant_flags]))

        # }}}

        grp_face_vertex_indices = mgrp.face_vertex_indices()
        grp_vertex_unit_coordinates = mgrp.vertex_unit_coordinates()

        batch_base = 0

        # group by face_id

        for face_id in range(mgrp.nfaces):
            batch_boundary_el_numbers_in_grp = np.array([
                ibface_el for ibface_el, ibface_face in group_boundary_faces
                if ibface_face == face_id
            ],
                                                        dtype=np.intp)

            # {{{ preallocate arrays for mesh group

            nbatch_elements = len(batch_boundary_el_numbers_in_grp)

            if per_face_groups or face_id == 0:
                if per_face_groups:
                    ngroup_bdry_elements = nbatch_elements
                else:
                    ngroup_bdry_elements = len(group_boundary_faces)

                vertex_indices = np.empty(
                    (ngroup_bdry_elements, mgrp.dim + 1 - 1),
                    mgrp.vertex_indices.dtype)

                bdry_unit_nodes = mp.warp_and_blend_nodes(
                    mgrp.dim - 1, mgrp.order)
                bdry_unit_nodes_01 = (bdry_unit_nodes + 1) * 0.5

                vol_basis = mp.simplex_onb(mgrp.dim, mgrp.order)
                nbdry_unit_nodes = bdry_unit_nodes_01.shape[-1]
                nodes = np.empty((discr.ambient_dim, ngroup_bdry_elements,
                                  nbdry_unit_nodes),
                                 dtype=np.float64)

            # }}}

            new_el_numbers = batch_base + np.arange(nbatch_elements)
            if not per_face_groups:
                batch_base += nbatch_elements

            # {{{ no per-element axes in these computations

            # Find boundary vertex indices
            loc_face_vertices = list(grp_face_vertex_indices[face_id])

            # Find unit nodes for boundary element
            face_vertex_unit_coordinates = \
                    grp_vertex_unit_coordinates[loc_face_vertices]

            # Find A, b such that A [e_1 e_2] + b = [r_1 r_2]
            # (Notation assumes that the volume is 3D and the face is 2D.
            # Code does not.)

            b = face_vertex_unit_coordinates[0]
            A = (  # noqa
                face_vertex_unit_coordinates[1:] -
                face_vertex_unit_coordinates[0]).T

            face_unit_nodes = (np.dot(A, bdry_unit_nodes_01).T + b).T

            resampling_mat = mp.resampling_matrix(vol_basis, face_unit_nodes,
                                                  mgrp.unit_nodes)

            # }}}

            # {{{ build information for mesh element group

            # Find vertex_indices
            glob_face_vertices = mgrp.vertex_indices[
                batch_boundary_el_numbers_in_grp][:, loc_face_vertices]
            vertex_indices[new_el_numbers] = \
                    vol_to_bdry_vertices[glob_face_vertices]

            # Find nodes
            nodes[:, new_el_numbers, :] = np.einsum(
                "ij,dej->dei", resampling_mat,
                mgrp.nodes[:, batch_boundary_el_numbers_in_grp, :])

            # }}}

            connection_data[igrp, face_id] = _ConnectionBatchData(
                group_source_element_indices=batch_boundary_el_numbers_in_grp,
                group_target_element_indices=new_el_numbers,
                A=A,
                b=b,
            )

            is_last_face = face_id + 1 == mgrp.nfaces

            if per_face_groups or is_last_face:
                bdry_mesh_group = SimplexElementGroup(
                    mgrp.order,
                    vertex_indices,
                    nodes,
                    unit_nodes=bdry_unit_nodes)
                bdry_mesh_groups.append(bdry_mesh_group)

    bdry_mesh = Mesh(bdry_vertices, bdry_mesh_groups)

    from meshmode.discretization import Discretization
    bdry_discr = Discretization(discr.cl_context, bdry_mesh, group_factory)

    with cl.CommandQueue(discr.cl_context) as queue:
        connection = _build_boundary_connection(queue, discr, bdry_discr,
                                                connection_data,
                                                per_face_groups)

    logger.info("building face restriction: done")

    return connection
Beispiel #22
0
import numpy as np
import modepy as mp

n = 17  # use this total degree
dimensions = 2

# Get a basis of orthonormal functions, and their derivatives.

basis = mp.simplex_onb(dimensions, n)
grad_basis = mp.grad_simplex_onb(dimensions, n)

nodes = mp.warp_and_blend_nodes(dimensions, n)
x, y = nodes

# We want to compute the x derivative of this function:

f = np.sin(5 * x + y)
df_dx = 5 * np.cos(5 * x + y)

# The (generalized) Vandermonde matrix transforms coefficients into
# nodal values. So we can find basis coefficients by applying its
# inverse:

f_coefficients = np.linalg.solve(mp.vandermonde(basis, nodes), f)

# Now linearly combine the (x-)derivatives of the basis using
# f_coefficients to compute the numerical derivatives.

df_dx_num = np.dot(mp.vandermonde(grad_basis, nodes)[0], f_coefficients)

assert np.linalg.norm(df_dx - df_dx_num) < 1e-5
Beispiel #23
0
 def resampling_matrix(self):
     meg = self.mesh_el_group
     return mp.resampling_matrix(
             mp.simplex_onb(self.dim, meg.order),
             self.unit_nodes, meg.unit_nodes)
Beispiel #24
0
 def basis(self):
     return mp.simplex_onb(self.dim, self.order)
Beispiel #25
0
 def basis(self):
     if self.dim <= 3:
         return mp.simplex_onb(self.dim, self.order)
     else:
         return mp.simplex_monomial_basis(self.dim, self.order)
Beispiel #26
0
def make_boundary_restriction(queue, discr, group_factory):
    """
    :return: a tuple ``(bdry_mesh, bdry_discr, connection)``
    """

    logger.info("building boundary connection: start")

    # {{{ build face_map

    # maps (igrp, el_grp, face_id) to a frozenset of vertex IDs
    face_map = {}

    for igrp, mgrp in enumerate(discr.mesh.groups):
        grp_face_vertex_indices = mgrp.face_vertex_indices()

        for iel_grp in range(mgrp.nelements):
            for fid, loc_face_vertices in enumerate(grp_face_vertex_indices):
                face_vertices = frozenset(
                        mgrp.vertex_indices[iel_grp, fvi]
                        for fvi in loc_face_vertices
                        )
                face_map.setdefault(face_vertices, []).append(
                        (igrp, iel_grp, fid))

    del face_vertices

    # }}}

    boundary_faces = [
            face_ids[0]
            for face_vertices, face_ids in six.iteritems(face_map)
            if len(face_ids) == 1]

    from pytools import flatten
    bdry_vertex_vol_nrs = sorted(set(flatten(six.iterkeys(face_map))))

    vol_to_bdry_vertices = np.empty(
            discr.mesh.vertices.shape[-1],
            discr.mesh.vertices.dtype)
    vol_to_bdry_vertices.fill(-1)
    vol_to_bdry_vertices[bdry_vertex_vol_nrs] = np.arange(
            len(bdry_vertex_vol_nrs))

    bdry_vertices = discr.mesh.vertices[:, bdry_vertex_vol_nrs]

    from meshmode.mesh import Mesh, SimplexElementGroup
    bdry_mesh_groups = []
    connection_data = {}

    for igrp, grp in enumerate(discr.groups):
        mgrp = grp.mesh_el_group
        group_boundary_faces = [
                (ibface_el, ibface_face)
                for ibface_group, ibface_el, ibface_face in boundary_faces
                if ibface_group == igrp]

        if not isinstance(mgrp, SimplexElementGroup):
            raise NotImplementedError("can only take boundary of "
                    "SimplexElementGroup-based meshes")

        # {{{ Preallocate arrays for mesh group

        ngroup_bdry_elements = len(group_boundary_faces)
        vertex_indices = np.empty(
                (ngroup_bdry_elements, mgrp.dim+1-1),
                mgrp.vertex_indices.dtype)

        bdry_unit_nodes = mp.warp_and_blend_nodes(mgrp.dim-1, mgrp.order)
        bdry_unit_nodes_01 = (bdry_unit_nodes + 1)*0.5

        vol_basis = mp.simplex_onb(mgrp.dim, mgrp.order)
        nbdry_unit_nodes = bdry_unit_nodes_01.shape[-1]
        nodes = np.empty(
                (discr.ambient_dim, ngroup_bdry_elements, nbdry_unit_nodes),
                dtype=np.float64)

        # }}}

        grp_face_vertex_indices = mgrp.face_vertex_indices()
        grp_vertex_unit_coordinates = mgrp.vertex_unit_coordinates()

        # batch by face_id

        batch_base = 0

        for face_id in range(len(grp_face_vertex_indices)):
            batch_boundary_el_numbers_in_grp = np.array(
                    [
                        ibface_el
                        for ibface_el, ibface_face in group_boundary_faces
                        if ibface_face == face_id],
                    dtype=np.intp)

            new_el_numbers = np.arange(
                    batch_base,
                    batch_base + len(batch_boundary_el_numbers_in_grp))

            # {{{ no per-element axes in these computations

            # Find boundary vertex indices
            loc_face_vertices = list(grp_face_vertex_indices[face_id])

            # Find unit nodes for boundary element
            face_vertex_unit_coordinates = \
                    grp_vertex_unit_coordinates[loc_face_vertices]

            # Find A, b such that A [e_1 e_2] + b = [r_1 r_2]
            # (Notation assumes that the volume is 3D and the face is 2D.
            # Code does not.)

            b = face_vertex_unit_coordinates[0]
            A = (
                    face_vertex_unit_coordinates[1:]
                    - face_vertex_unit_coordinates[0]).T

            face_unit_nodes = (np.dot(A, bdry_unit_nodes_01).T + b).T

            resampling_mat = mp.resampling_matrix(
                    vol_basis,
                    face_unit_nodes, mgrp.unit_nodes)

            # }}}

            # {{{ build information for mesh element group

            # Find vertex_indices
            glob_face_vertices = mgrp.vertex_indices[
                    batch_boundary_el_numbers_in_grp][:, loc_face_vertices]
            vertex_indices[new_el_numbers] = \
                    vol_to_bdry_vertices[glob_face_vertices]

            # Find nodes
            nodes[:, new_el_numbers, :] = np.einsum(
                    "ij,dej->dei",
                    resampling_mat,
                    mgrp.nodes[:, batch_boundary_el_numbers_in_grp, :])

            # }}}

            connection_data[igrp, face_id] = _ConnectionBatchData(
                    group_source_element_indices=batch_boundary_el_numbers_in_grp,
                    group_target_element_indices=new_el_numbers,
                    A=A,
                    b=b,
                    )

            batch_base += len(batch_boundary_el_numbers_in_grp)

        bdry_mesh_group = SimplexElementGroup(
                mgrp.order, vertex_indices, nodes, unit_nodes=bdry_unit_nodes)
        bdry_mesh_groups.append(bdry_mesh_group)

    bdry_mesh = Mesh(bdry_vertices, bdry_mesh_groups)

    from meshmode.discretization import Discretization
    bdry_discr = Discretization(
            discr.cl_context, bdry_mesh, group_factory)

    connection = _build_boundary_connection(
            queue, discr, bdry_discr, connection_data)

    logger.info("building boundary connection: done")

    return bdry_mesh, bdry_discr, connection
Beispiel #27
0
 def basis(self):
     if self.dim <= 3:
         return mp.simplex_onb(self.dim, self.order)
     else:
         return mp.simplex_monomial_basis(self.dim, self.order)