示例#1
0
def test_modal_mass_matrix_for_face(dims, shape_cls, order=3):
    vol_shape = shape_cls(dims)
    vol_space = mp.space_for_shape(vol_shape, order)
    vol_basis = mp.basis_for_space(vol_space, vol_shape)

    from modepy.matrices import modal_mass_matrix_for_face
    for face in mp.faces_for_shape(vol_shape):
        face_space = mp.space_for_shape(face, order)
        face_basis = mp.basis_for_space(face_space, face)
        face_quad = mp.quadrature_for_space(mp.space_for_shape(face, 2*order), face)
        face_quad2 = mp.quadrature_for_space(
                mp.space_for_shape(face, 2*order+2), face)
        fmm = modal_mass_matrix_for_face(
                face, face_quad, face_basis.functions, vol_basis.functions)
        fmm2 = modal_mass_matrix_for_face(
                face, face_quad2, face_basis.functions, vol_basis.functions)

        error = la.norm(fmm - fmm2, np.inf) / la.norm(fmm2, np.inf)
        logger.info("fmm error: %.5e", error)
        assert error < 1e-11, f"error {error:.5e} on face {face.face_index}"

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

        logger.info("fmm: nnz %d\n%s", nnz, fmm)
示例#2
0
def test_deprecated_nodal_face_mass_matrix(dims, order=3):
    # FIXME DEPRECATED remove along with nodal_face_mass_matrix (>=2022)
    vol_shape = mp.Simplex(dims)
    vol_space = mp.space_for_shape(vol_shape, order)

    vertices = mp.unit_vertices_for_shape(vol_shape)
    volume_nodes = mp.edge_clustered_nodes_for_space(vol_space, vol_shape)
    volume_basis = mp.basis_for_space(vol_space, vol_shape)

    from modepy.matrices import nodal_face_mass_matrix
    for face in mp.faces_for_shape(vol_shape):
        face_space = mp.space_for_shape(face, order)
        face_nodes = mp.edge_clustered_nodes_for_space(face_space, face)
        face_vertices = vertices[:, face.volume_vertex_indices]

        fmm = nodal_face_mass_matrix(
                volume_basis.functions, volume_nodes,
                face_nodes, order, face_vertices)
        fmm2 = nodal_face_mass_matrix(
                volume_basis.functions,
                volume_nodes, face_nodes, order+1, face_vertices)

        error = la.norm(fmm - fmm2, np.inf) / la.norm(fmm2, np.inf)
        logger.info("fmm error: %.5e", error)
        assert error < 5e-11, f"error {error:.5e} on face {face.face_index}"

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

        logger.info("fmm: nnz %d\n%s", nnz, fmm)

        logger.info("mass matrix:\n%s", mp.mass_matrix(
            mp.basis_for_space(face_space, face).functions,
            mp.edge_clustered_nodes_for_space(face_space, face)))
示例#3
0
def test_deprecated_modal_face_mass_matrix(dims, order=3):
    # FIXME DEPRECATED remove along with modal_face_mass_matrix (>=2022)
    shape = mp.Simplex(dims)
    space = mp.space_for_shape(shape, order)

    vertices = mp.unit_vertices_for_shape(shape)
    basis = mp.basis_for_space(space, shape)

    from modepy.matrices import modal_face_mass_matrix
    for face in mp.faces_for_shape(shape):
        face_vertices = vertices[:, face.volume_vertex_indices]

        fmm = modal_face_mass_matrix(
                basis.functions, order, face_vertices)
        fmm2 = modal_face_mass_matrix(
                basis.functions, order+1, face_vertices)

        error = la.norm(fmm - fmm2, np.inf) / la.norm(fmm2, np.inf)
        logger.info("fmm error: %.5e", error)
        assert error < 1e-11, f"error {error:.5e} on face {face.face_index}"

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

        logger.info("fmm: nnz %d\n%s", nnz, fmm)
示例#4
0
def test_normals(shape):
    vol_vertices = mp.unit_vertices_for_shape(shape)
    vol_centroid = np.mean(vol_vertices, axis=1)

    for face in mp.faces_for_shape(shape):
        face_vertices = vol_vertices[:, face.volume_vertex_indices]
        face_centroid = np.mean(face_vertices, axis=1)
        normal = mp.face_normal(face)

        assert normal @ (face_centroid-vol_centroid) > 0

        for i in range(len(face_vertices)-1):
            assert abs(
                (face_vertices[:, i+1] - face_vertices[:, 0]) @ normal) < 1e-13

        assert abs(la.norm(normal, 2) - 1) < 1e-13
示例#5
0
    def get_local_face_mass_matrix(self, afgrp, volgrp, dtype):
        nfaces = volgrp.mesh_el_group.nfaces
        assert afgrp.nelements == nfaces * volgrp.nelements

        matrix = np.empty((volgrp.nunit_dofs, nfaces, afgrp.nunit_dofs),
                          dtype=dtype)

        import modepy as mp
        shape = mp.Simplex(volgrp.dim)
        unit_vertices = mp.unit_vertices_for_shape(shape).T

        for face in mp.faces_for_shape(shape):
            face_vertices = unit_vertices[np.array(
                face.volume_vertex_indices)].T
            matrix[:, face.face_index, :] = mp.nodal_face_mass_matrix(
                volgrp.basis_obj().functions, volgrp.unit_nodes,
                afgrp.unit_nodes, volgrp.order, face_vertices)

        actx = self._setup_actx
        return actx.freeze(actx.from_numpy(matrix))
示例#6
0
def test_nodal_mass_matrix_for_face(dims, shape_cls, order=3):
    vol_shape = shape_cls(dims)
    vol_space = mp.space_for_shape(vol_shape, order)

    volume_nodes = mp.edge_clustered_nodes_for_space(vol_space, vol_shape)
    volume_basis = mp.basis_for_space(vol_space, vol_shape)

    from modepy.matrices import (nodal_mass_matrix_for_face,
        nodal_quad_mass_matrix_for_face)
    for face in mp.faces_for_shape(vol_shape):
        face_space = mp.space_for_shape(face, order)
        face_basis = mp.basis_for_space(face_space, face)
        face_nodes = mp.edge_clustered_nodes_for_space(face_space, face)
        face_quad = mp.quadrature_for_space(mp.space_for_shape(face, 2*order), face)
        face_quad2 = mp.quadrature_for_space(
                mp.space_for_shape(face, 2*order+2), face)
        fmm = nodal_mass_matrix_for_face(
                face, face_quad, face_basis.functions, volume_basis.functions,
                volume_nodes, face_nodes)
        fmm2 = nodal_quad_mass_matrix_for_face(
                face, face_quad2, volume_basis.functions, volume_nodes)

        for f_face in face_basis.functions:
            fval_nodal = f_face(face_nodes)
            fval_quad = f_face(face_quad2.nodes)
            assert (
                    la.norm(fmm@fval_nodal - fmm2@fval_quad, np.inf)
                    / la.norm(fval_quad)) < 3e-15

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

        logger.info("fmm: nnz %d\n%s", nnz, fmm)

        logger.info("mass matrix:\n%s",
                mp.mass_matrix(face_basis.functions, face_nodes))
示例#7
0
    def matrix(self, afgrp, volgrp, dtype):
        nfaces = volgrp.mesh_el_group.nfaces
        assert afgrp.nelements == nfaces * volgrp.nelements

        matrix = np.empty((volgrp.nunit_dofs, nfaces, afgrp.nunit_dofs),
                          dtype=dtype)

        import modepy as mp
        from meshmode.discretization import ElementGroupWithBasis
        from meshmode.discretization.poly_element import \
            QuadratureSimplexElementGroup

        n = volgrp.order
        m = afgrp.order
        vol_basis = volgrp.basis_obj()
        faces = mp.faces_for_shape(volgrp.shape)

        for iface, face in enumerate(faces):
            # If the face group is defined on a higher-order
            # quadrature grid, use the underlying quadrature rule
            if isinstance(afgrp, QuadratureSimplexElementGroup):
                face_quadrature = afgrp.quadrature_rule()
                if face_quadrature.exact_to < m:
                    raise ValueError(
                        "The face quadrature rule is only exact for polynomials "
                        f"of total degree {face_quadrature.exact_to}. Please "
                        "ensure a quadrature rule is used that is at least "
                        f"exact for degree {m}.")
            else:
                # NOTE: This handles the general case where
                # volume and surface quadrature rules may have different
                # integration orders
                face_quadrature = mp.quadrature_for_space(
                    mp.space_for_shape(face, 2 * max(n, m)), face)

            # If the group has a nodal basis and is unisolvent,
            # we use the basis on the face to compute the face mass matrix
            if (isinstance(afgrp, ElementGroupWithBasis)
                    and afgrp.space.space_dim == afgrp.nunit_dofs):

                face_basis = afgrp.basis_obj()

                # Sanity check for face quadrature accuracy. Not integrating
                # degree N + M polynomials here is asking for a bad time.
                if face_quadrature.exact_to < m + n:
                    raise ValueError(
                        "The face quadrature rule is only exact for polynomials "
                        f"of total degree {face_quadrature.exact_to}. Please "
                        "ensure a quadrature rule is used that is at least "
                        f"exact for degree {n+m}.")

                matrix[:, iface, :] = mp.nodal_mass_matrix_for_face(
                    face,
                    face_quadrature,
                    face_basis.functions,
                    vol_basis.functions,
                    volgrp.unit_nodes,
                    afgrp.unit_nodes,
                )
            else:
                # Otherwise, we use a routine that is purely quadrature-based
                # (no need for explicit face basis functions)
                matrix[:, iface, :] = mp.nodal_quad_mass_matrix_for_face(
                    face,
                    face_quadrature,
                    vol_basis.functions,
                    volgrp.unit_nodes,
                )

        return matrix
示例#8
0
 def _modepy_faces(self):
     return mp.faces_for_shape(self._modepy_shape)