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), ))
def __init__(self, cell): """ :arg cell: a :class:`fiat.FIAT.reference_element.Simplex`. """ # Ensure this cell is actually a simplex assert isinstance(cell, Simplex) super(SimplexCellAnalog, self).__init__(cell) # Stored as (dim, nunit_vertices) self._unit_vertices = tools.unit_vertices(cell.get_dimension()).T # Maps firedrake reference vertices to :mod:`meshmode` # unit vertices by x -> Ax + b, where A is :attr:`_mat` # and b is :attr:`_shift` reference_vertices = np.array(cell.vertices).T self._mat, self._shift = get_affine_mapping(reference_vertices, self._unit_vertices)
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)
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)
def test_sanity_single_element(ctx_getter, dim, order, visualize=False): pytest.importorskip("pytential") cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) from modepy.tools import unit_vertices vertices = unit_vertices(dim).T.copy() center = np.empty(dim, np.float64) center.fill(-0.5) import modepy as mp from meshmode.mesh import SimplexElementGroup, Mesh, BTAG_ALL mg = SimplexElementGroup( order=order, vertex_indices=np.arange(dim + 1, dtype=np.int32).reshape(1, -1), nodes=mp.warp_and_blend_nodes(dim, order).reshape(dim, 1, -1), dim=dim) mesh = Mesh(vertices, [mg], nodal_adjacency=None, facial_adjacency_groups=None) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ PolynomialWarpAndBlendGroupFactory vol_discr = Discretization(cl_ctx, mesh, PolynomialWarpAndBlendGroupFactory(order + 3)) # {{{ volume calculation check vol_x = vol_discr.nodes().with_queue(queue) vol_one = vol_x[0].copy() vol_one.fill(1) from pytential import norm, integral # noqa from pytools import factorial true_vol = 1 / factorial(dim) * 2**dim comp_vol = integral(vol_discr, queue, vol_one) rel_vol_err = abs(true_vol - comp_vol) / true_vol assert rel_vol_err < 1e-12 # }}} # {{{ boundary discretization from meshmode.discretization.connection import make_face_restriction bdry_connection = make_face_restriction( vol_discr, PolynomialWarpAndBlendGroupFactory(order + 3), BTAG_ALL) bdry_discr = bdry_connection.to_discr # }}} # {{{ visualizers from meshmode.discretization.visualization import make_visualizer #vol_vis = make_visualizer(queue, vol_discr, 4) bdry_vis = make_visualizer(queue, bdry_discr, 4) # }}} from pytential import bind, sym bdry_normals = bind(bdry_discr, sym.normal(dim))(queue).as_vector(dtype=object) if visualize: bdry_vis.write_vtk_file("boundary.vtu", [("bdry_normals", bdry_normals)]) from pytential import bind, sym normal_outward_check = bind( bdry_discr, sym.normal(dim) | (sym.nodes(dim) + 0.5 * sym.ones_vec(dim)), )(queue).as_scalar() > 0 assert normal_outward_check.get().all(), normal_outward_check.get()
def vertex_unit_coordinates(self): from modepy.tools import unit_vertices return unit_vertices(self.dim)
def test_sanity_single_element(ctx_getter, dim, order, visualize=False): pytest.importorskip("pytential") cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) from modepy.tools import unit_vertices vertices = unit_vertices(dim).T.copy() center = np.empty(dim, np.float64) center.fill(-0.5) import modepy as mp from meshmode.mesh import SimplexElementGroup, Mesh, BTAG_ALL mg = SimplexElementGroup( order=order, vertex_indices=np.arange(dim+1, dtype=np.int32).reshape(1, -1), nodes=mp.warp_and_blend_nodes(dim, order).reshape(dim, 1, -1), dim=dim) mesh = Mesh(vertices, [mg], nodal_adjacency=None, facial_adjacency_groups=None) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ PolynomialWarpAndBlendGroupFactory vol_discr = Discretization(cl_ctx, mesh, PolynomialWarpAndBlendGroupFactory(order+3)) # {{{ volume calculation check vol_x = vol_discr.nodes().with_queue(queue) vol_one = vol_x[0].copy() vol_one.fill(1) from pytential import norm, integral # noqa from pytools import factorial true_vol = 1/factorial(dim) * 2**dim comp_vol = integral(vol_discr, queue, vol_one) rel_vol_err = abs(true_vol - comp_vol) / true_vol assert rel_vol_err < 1e-12 # }}} # {{{ boundary discretization from meshmode.discretization.connection import make_face_restriction bdry_connection = make_face_restriction( vol_discr, PolynomialWarpAndBlendGroupFactory(order + 3), BTAG_ALL) bdry_discr = bdry_connection.to_discr # }}} # {{{ visualizers from meshmode.discretization.visualization import make_visualizer #vol_vis = make_visualizer(queue, vol_discr, 4) bdry_vis = make_visualizer(queue, bdry_discr, 4) # }}} from pytential import bind, sym bdry_normals = bind(bdry_discr, sym.normal())(queue).as_vector(dtype=object) if visualize: bdry_vis.write_vtk_file("boundary.vtu", [ ("bdry_normals", bdry_normals) ]) from pytential import bind, sym normal_outward_check = bind(bdry_discr, sym.normal() | (sym.Nodes() + 0.5*sym.ones_vec(dim)), )(queue).as_scalar() > 0 assert normal_outward_check.get().all(), normal_outward_check.get()
def get_affine_reference_simplex_mapping(ambient_dim, firedrake_to_meshmode=True): """ Returns a function which takes a numpy array points on one reference cell and maps each point to another using a positive affine map. :arg ambient_dim: The spatial dimension :arg firedrake_to_meshmode: If true, the returned function maps from the firedrake reference element to meshmode, if false maps from meshmode to firedrake. More specifically, :mod:`firedrake` uses the standard :mod:`FIAT` simplex and :mod:`meshmode` uses :mod:`modepy`'s `unit coordinates <https://documen.tician.de/modepy/nodes.html>`_. :return: A function which takes a numpy array of *n* points with shape *(dim, n)* on one reference cell and maps each point to another using a positive affine map. Note that the returned function performs no input validation. """ # validate input if not isinstance(ambient_dim, int): raise TypeError("'ambient_dim' must be an int, not " f"'{type(ambient_dim)}'") if ambient_dim < 0: raise ValueError("'ambient_dim' must be non-negative") if not isinstance(firedrake_to_meshmode, bool): raise TypeError("'firedrake_to_meshmode' must be a bool, not " f"'{type(firedrake_to_meshmode)}'") from FIAT.reference_element import ufc_simplex from modepy.tools import unit_vertices # Get the unit vertices from each system, # each stored with shape *(dim, nunit_vertices)* firedrake_unit_vertices = np.array(ufc_simplex(ambient_dim).vertices).T modepy_unit_vertices = unit_vertices(ambient_dim).T if firedrake_to_meshmode: from_verts = firedrake_unit_vertices to_verts = modepy_unit_vertices else: from_verts = modepy_unit_vertices to_verts = firedrake_unit_vertices # Compute matrix A and vector b so that A f_i + b -> t_i # for each "from" vertex f_i and corresponding "to" vertex t_i assert from_verts.shape == to_verts.shape dim, nvects = from_verts.shape # If we only have one vertex, have A = I and b = to_vert - from_vert if nvects == 1: shift = to_verts[:, 0] - from_verts[:, 0] def affine_map(points): return points + shift[:, np.newaxis] # Otherwise, we have to solve for A and b else: # span verts: v1 - v0, v2 - v0, ... from_span_verts = from_verts[:, 1:] - from_verts[:, 0, np.newaxis] to_span_verts = to_verts[:, 1:] - to_verts[:, 0, np.newaxis] # mat maps (fj - f0) -> (tj - t0), our "A" mat = la.solve(from_span_verts, to_span_verts) # A f0 + b -> t0 so b = t0 - A f0 shift = to_verts[:, 0] - np.matmul(mat, from_verts[:, 0]) # Explicitly ensure A is positive if la.det(mat) < 0: from meshmode.mesh.processing import get_simplex_element_flip_matrix flip_matrix = get_simplex_element_flip_matrix(1, to_verts) mat = np.matmul(flip_matrix, mat) def affine_map(points): return np.matmul(mat, points) + shift[:, np.newaxis] return affine_map