From a5705393cd21ed12c54482c3166ed7e46ee4c6b9 Mon Sep 17 00:00:00 2001 From: Alexandru Fikl <alexfikl@gmail.com> Date: Tue, 12 May 2020 22:19:04 -0500 Subject: [PATCH] add check if mesh group is affine --- meshmode/discretization/__init__.py | 4 +++ meshmode/mesh/__init__.py | 28 ++++++++++++++++-- test/test_meshmode.py | 46 +++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/meshmode/discretization/__init__.py b/meshmode/discretization/__init__.py index 6a4fcda7..ea282587 100644 --- a/meshmode/discretization/__init__.py +++ b/meshmode/discretization/__init__.py @@ -78,6 +78,10 @@ class ElementGroupBase(object): self.order = order self.node_nr_base = node_nr_base + @property + def is_affine(self): + return self.mesh_el_group.is_affine + @property def nelements(self): return self.mesh_el_group.nelements diff --git a/meshmode/mesh/__init__.py b/meshmode/mesh/__init__.py index 211e764c..61ad5852 100644 --- a/meshmode/mesh/__init__.py +++ b/meshmode/mesh/__init__.py @@ -26,9 +26,10 @@ from six.moves import range import six import numpy as np -import modepy as mp import numpy.linalg as la -from pytools import Record + +import modepy as mp +from pytools import Record, memoize_method __doc__ = """ @@ -158,6 +159,7 @@ class MeshElementGroup(Record): *Not* the ambient dimension, see :attr:`Mesh.ambient_dim` for that. + .. automethod:: is_affine .. automethod:: face_vertex_indices .. automethod:: vertex_unit_coordinates @@ -223,6 +225,10 @@ class MeshElementGroup(Record): def nunit_nodes(self): return self.unit_nodes.shape[-1] + @memoize_method + def is_affine(self): + return is_affine_group(self) + def face_vertex_indices(self): """Return a tuple of tuples indicating which vertices (in mathematically positive ordering) make up each face @@ -1352,4 +1358,22 @@ def is_boundary_tag_empty(mesh, boundary_tag): # }}} +# {{{ + +def is_affine_group(group): + basis = mp.simplex_best_available_basis(group.dim, group.order) + grad_basis = mp.grad_simplex_best_available_basis(group.dim, group.order) + + diff_matrix = mp.differentiation_matrices(basis, grad_basis, group.unit_nodes) + vinv = la.inv(mp.vandermonde(basis, group.unit_nodes)) + + if not isinstance(diff_matrix, tuple): + diff_matrix = (diff_matrix,) + mat = tuple(vinv.dot(d.dot(d)) for d in diff_matrix) + + ddx_coeffs = np.einsum("aij,bj->abi", mat, group.nodes[:, 0, :]) + return np.max(np.abs(ddx_coeffs)) < 1.0e-13 + +# }}} + # vim: foldmethod=marker diff --git a/test/test_meshmode.py b/test/test_meshmode.py index e2ee1a81..1ae0b634 100644 --- a/test/test_meshmode.py +++ b/test/test_meshmode.py @@ -1205,6 +1205,52 @@ def test_open_curved_mesh(curve_name): closed=closed) +@pytest.mark.parametrize("mesh_name", [ + "box", "warped_box", + "circle", "ellipse", + "sphere", "torus" + ]) +def test_is_affine_group_check(mesh_name): + from meshmode.mesh.generation import ( + generate_regular_rect_mesh, generate_warped_rect_mesh, + make_curve_mesh, ellipse, + generate_icosphere, generate_torus) + + order = 4 + nelements = 32 + + if mesh_name == "box": + dim = 2 + is_affine = True + mesh = generate_regular_rect_mesh( + a=(-0.5,)*dim, b=(0.5,)*dim, + n=(nelements,)*dim, order=order) + elif mesh_name == "warped_box": + is_affine = False + dim = 2 + mesh = generate_warped_rect_mesh(dim, order, nelements) + elif mesh_name == "circle": + is_affine = False + mesh = make_curve_mesh( + lambda t: ellipse(1.0, t), + np.linspace(0.0, 1.0, nelements + 1), order=order) + elif mesh_name == "ellipse": + is_affine = False + mesh = make_curve_mesh( + lambda t: ellipse(2.0, t), + np.linspace(0.0, 1.0, nelements + 1), order=order) + elif mesh_name == "sphere": + is_affine = False + mesh = generate_icosphere(r=1.0, order=order) + elif mesh_name == "torus": + is_affine = False + mesh = generate_torus(10.0, 2.0, order=order) + else: + raise ValueError("unknown mesh name: {}".format(mesh_name)) + + assert all(grp.is_affine() for grp in mesh.groups) == is_affine + + if __name__ == "__main__": import sys if len(sys.argv) > 1: -- GitLab