Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
7dc2d82
refactor tensor products a bit
alexfikl Oct 24, 2020
7594971
implement face_vertex_indices for tensor products
alexfikl Oct 31, 2020
0164616
fix doc header
alexfikl Oct 31, 2020
fa414db
remove inappropriate uses of issubclass
alexfikl Oct 31, 2020
554214b
Implement tensor product face restrictions (with voodoo element basis…
inducer Nov 2, 2020
956da03
Merge pull request #1 from inducer/tp-face-restriction
alexfikl Nov 3, 2020
8dac59e
improve docs
alexfikl Nov 3, 2020
fa01334
underscore 1d tensor product methods
alexfikl Nov 3, 2020
07f315d
expand more tests to tensor products
alexfikl Nov 3, 2020
4dcb4c1
make ascii cube slightly larger
alexfikl Nov 3, 2020
13decc1
Merge branch 'master' into tensor-product-additions
alexfikl Nov 4, 2020
6bc483d
update comment
alexfikl Nov 5, 2020
02a3a48
use mesh order for resampling matrix
alexfikl Nov 6, 2020
673dd00
fix quad weights for tensor products
alexfikl Nov 6, 2020
a82685f
add back removed mesh (huh)
alexfikl Nov 6, 2020
06711ac
rework tensor product inheritance a bit
alexfikl Nov 6, 2020
3356de6
add gmsh quad test
alexfikl Nov 7, 2020
165b844
move vertex shuffle to separate function
alexfikl Nov 8, 2020
468a625
generate high-order gmsh quad mesh in test
alexfikl Nov 9, 2020
53e819e
use more elements in gmsh quad test
alexfikl Nov 9, 2020
1563970
fix typo in element group
alexfikl Nov 9, 2020
d6467f4
use mass matrix is quadrature weights are not provided
alexfikl Nov 13, 2020
72b2e51
use same order for the mesh and discr
alexfikl Nov 13, 2020
2efede8
Merge branch 'master' into tensor-product-additions
alexfikl Nov 13, 2020
90ffb1e
point back at gmsh_interop master
alexfikl Nov 13, 2020
73bea32
memoize tensor product weights
alexfikl Nov 13, 2020
5f27b78
fix typo in tensor product mass matrix
alexfikl Nov 18, 2020
24eae18
Merge branch 'master' into tensor-product-additions
alexfikl Nov 18, 2020
34c7e79
Merge branch 'master' into tensor-product-additions
inducer Nov 18, 2020
6ad559b
Explain the tensor product face restriction FIXME
inducer Nov 19, 2020
df303cb
Merge branch 'master' into tensor-product-additions
alexfikl Nov 22, 2020
e65545b
Merge branch 'master' into tensor-product-additions
alexfikl Nov 25, 2020
82be9e8
Make use of some shapes, spaces facilities from modepy in meshmode.mesh
inducer Dec 1, 2020
61d0b06
Merge pull request #2 from inducer/modern-modepy
alexfikl Dec 1, 2020
d79952d
add more shape checks to MeshElementGroup
alexfikl Dec 2, 2020
dae30bb
expand test_sanity_single_element for tensor products
alexfikl Dec 2, 2020
8cd7a38
use modepy unit nodes in gmsh reader
alexfikl Dec 2, 2020
5a06cbf
point requirements.txt to modepy branch
alexfikl Dec 2, 2020
bb5080e
update simple-dg example
alexfikl Dec 2, 2020
5912ccb
allow missing nodes for firedrake
alexfikl Dec 2, 2020
7d0d861
implement get_copy_kwargs
alexfikl Dec 2, 2020
d53887d
initialize MeshElementGroup fully on unpickling
alexfikl Dec 2, 2020
6fa04a8
update basis_for_space calls
alexfikl Dec 2, 2020
0520f71
rename biunit_vertices_for_space after modepy
alexfikl Dec 2, 2020
d775213
use more modern modepy in poly_element
alexfikl Dec 2, 2020
760d92b
update modern modepy in face restriction
alexfikl Dec 2, 2020
4ea8c45
fix MeshElementGroup subclass pickling
alexfikl Dec 3, 2020
63f2341
use modern modepy in visualization
alexfikl Dec 3, 2020
0f37a6a
use modern modepy in make_group_from_vertices
alexfikl Dec 3, 2020
4465d55
update MeshElementGroup docs
alexfikl Dec 3, 2020
f99d6eb
use new tensor_product_nodes in poly_element
alexfikl Dec 3, 2020
bef4afb
fix shadowing
alexfikl Dec 3, 2020
a3293b4
Merge branch 'master' into tensor-product-additions
inducer Dec 10, 2020
ec213e6
Point modepy back to master in req.txt
inducer Dec 11, 2020
821b326
Merge branch 'master' into tensor-product-additions
inducer Dec 20, 2020
79fcade
handle all cases in if condition
alexfikl Dec 21, 2020
adbc990
use stricter orthogonality check in tensor products
alexfikl Dec 21, 2020
e401f61
add comment for tensor product is_orthogonal check
alexfikl Dec 21, 2020
d9fbabb
take full unit_nodes in tensor product element groups
alexfikl Dec 21, 2020
f2b33e3
rename some variables
alexfikl Dec 21, 2020
0c10f6b
Tweak is_orthogonal_basis comment
inducer Dec 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 92 additions & 18 deletions meshmode/discretization/poly_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,25 @@
.. autoclass:: PolynomialRecursiveNodesElementGroup
.. autoclass:: PolynomialEquidistantSimplexElementGroup
.. autoclass:: PolynomialGivenNodesElementGroup

.. autoclass:: InterpolatoryQuadratureTensorProductElementGroup
.. autoclass:: LegendreGaussLobattoTensorProductElementGroup
.. autoclass:: EquidistantTensorProductElementGroup

Group factories
^^^^^^^^^^^^^^^

.. autoclass:: ElementGroupFactory
.. autoclass:: OrderAndTypeBasedGroupFactory

.. autoclass:: InterpolatoryQuadratureSimplexGroupFactory
.. autoclass:: QuadratureSimplexGroupFactory
.. autoclass:: PolynomialWarpAndBlendGroupFactory
.. autoclass:: PolynomialRecursiveNodesGroupFactory
.. autoclass:: PolynomialEquidistantSimplexGroupFactory
.. autoclass:: PolynomialGivenNodesGroupFactory

.. autoclass:: InterpolatoryQuadratureTensorProductGroupFactory
.. autoclass:: LegendreGaussLobattoTensorProductGroupFactory
"""

Expand Down Expand Up @@ -346,46 +352,103 @@ def unit_nodes(self):

# {{{ concrete element groups for tensor product elements

class LegendreGaussLobattoTensorProductElementGroup(PolynomialElementGroupBase):
class _TensorProductElementGroupBase(PolynomialElementGroupBase):
# {{{
Comment thread
alexfikl marked this conversation as resolved.
Outdated

def basis_1d(self):
from modepy.modes import jacobi
from functools import partial
return tuple(partial(jacobi, 0, 0, i) for i in range(self.order + 1))

def grad_basis_1d(self):
from modepy.modes import grad_jacobi
from functools import partial
return tuple(partial(grad_jacobi, 0, 0, i) for i in range(self.order + 1))

def unit_nodes_1d(self):
raise NotImplementedError
Comment thread
inducer marked this conversation as resolved.
Outdated

# }}}

def is_orthogonal_basis(self):
return True

def basis(self):
from modepy.modes import tensor_product_basis, jacobi
from functools import partial
return tensor_product_basis(
self.dim, tuple(
partial(jacobi, 0, 0, i)
for i in range(self.order+1)))
from modepy.modes import tensor_product_basis
return tensor_product_basis(self.dim, self.basis_1d())

def grad_basis(self):
raise NotImplementedError()
from modepy.modes import grad_tensor_product_basis
return grad_tensor_product_basis(self.dim,
Comment thread
inducer marked this conversation as resolved.
Outdated
self.basis_1d(), self.grad_basis_1d())

@property
@memoize_method
def unit_nodes(self):
from modepy.nodes import tensor_product_nodes
from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes
return tensor_product_nodes(
self.dim, legendre_gauss_lobatto_nodes(self.order))
return tensor_product_nodes(self.dim, self.unit_nodes_1d())

@memoize_method
def from_mesh_interp_matrix(self):
from modepy.modes import legendre_tensor_product_basis
meg = self.mesh_el_group
return mp.resampling_matrix(
self.basis(),
legendre_tensor_product_basis(self.dim, self.order),
self.unit_nodes,
meg.unit_nodes)


class EquidistantTensorProductElementGroup(
LegendreGaussLobattoTensorProductElementGroup):
class InterpolatoryQuadratureTensorProductElementGroup(
_TensorProductElementGroupBase):
"""Elemental discretization supplying a high-order quadrature rule
with a number of nodes matching the number of polynomials in the tensor
product basis, hence usable for differentiation and interpolation.

No interpolation nodes are present on the boundary of the hypercube.
"""

@memoize_method
def _quadrature_rule_1d(self):
from modepy.quadrature import LegendreGaussQuadrature
return LegendreGaussQuadrature(self.order)

def unit_nodes_1d(self):
return self._quadrature_rule().nodes

@property
@memoize_method
def unit_nodes(self):
from modepy.nodes import tensor_product_nodes, equidistant_nodes
return tensor_product_nodes(
self.dim, equidistant_nodes(1, self.order)[0])
def weights(self):
from modepy.nodes import tensor_product_nodes
return tensor_product_nodes(self.dim, self._quadrature_rule().weights)


class LegendreGaussLobattoTensorProductElementGroup(
_TensorProductElementGroupBase):
"""Elemental discretization supplying a high-order quadrature rule
with a number of nodes matching the number of polynomials in the tensor
product basis, hence usable for differentiation and interpolation.
Nodes are present on the boundary of the hypercube.
Comment thread
alexfikl marked this conversation as resolved.
Outdated

Uses :func:`~modepy.quadrature.jacobi_gauss.legendre_gauss_lobatto_nodes`.
"""

def unit_nodes_1d(self):
from modepy.quadrature.jacobi_gauss import legendre_gauss_lobatto_nodes
return legendre_gauss_lobatto_nodes(self.order)


class EquidistantTensorProductElementGroup(_TensorProductElementGroupBase):
"""Elemental discretization supplying a high-order quadrature rule
with a number of nodes matching the number of polynomials in the tensor
product basis, hence usable for differentiation and interpolation.
Nodes are present on the boundary of the hypercube.
Comment thread
alexfikl marked this conversation as resolved.
Outdated

Uses :func:`~modepy.equidistant_nodes`.
"""

def unit_nodes_1d(self):
from modepy.nodes import equidistant_nodes
return equidistant_nodes(1, self.order)[0]

# }}}

Expand Down Expand Up @@ -483,15 +546,26 @@ def __call__(self, mesh_el_group, index):

return PolynomialGivenNodesElementGroup(
mesh_el_group, self.order, self.unit_nodes, index)

# }}}


# {{{ group factories for tensor products

class InterpolatoryQuadratureTensorProductGroupFactory(
HomogeneousOrderBasedGroupFactory):
mesh_group_class = _MeshTensorProductElementGroup
group_class = InterpolatoryQuadratureTensorProductElementGroup


class LegendreGaussLobattoTensorProductGroupFactory(
HomogeneousOrderBasedGroupFactory):
mesh_group_class = _MeshTensorProductElementGroup
group_class = LegendreGaussLobattoTensorProductElementGroup

# }}}

# }}}


# vim: fdm=marker
44 changes: 37 additions & 7 deletions meshmode/mesh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ def face_vertex_indices(self):
(1, 2, 3)
)
else:
raise NotImplementedError("dim=%d" % self.dim)
raise NotImplementedError(f"dimension {self.dim}")

def vertex_unit_coordinates(self):
from modepy.tools import unit_vertices
Expand Down Expand Up @@ -412,10 +412,33 @@ def __init__(self, order, vertex_indices, nodes,
element_nr_base, node_nr_base, unit_nodes)

def face_vertex_indices(self):
raise NotImplementedError()
if self.dim == 1:
return (
(0,),
(1,),
)
elif self.dim == 2:
return (
(0, 1),
(3, 2),
(2, 0),
(1, 3),
)
elif self.dim == 3:
return (
(0, 2, 1, 3),
(4, 6, 5, 7),
(0, 4, 5, 1),
(2, 6, 7, 3),
(0, 4, 6, 2),
(1, 5, 7, 3),
Comment thread
alexfikl marked this conversation as resolved.
Outdated
)
else:
raise NotImplementedError(f"dimension {self.dim}")

def vertex_unit_coordinates(self):
raise NotImplementedError()
from pytools import generate_nonnegative_integer_tuples_below as gnitb
return np.array(list(gnitb(2, self.dim)), dtype=np.float64)*2.0 - 1.0

# }}}

Expand Down Expand Up @@ -971,15 +994,22 @@ def __ne__(self, other):

# {{{ node-vertex consistency test

def _test_node_vertex_consistency_simplex(mesh, mgrp, tol):
def _test_node_vertex_consistency_resampling(mesh, mgrp, tol):
if mesh.vertices is None:
return True

if mgrp.nelements == 0:
return True

if isinstance(mgrp, SimplexElementGroup):
basis = mp.simplex_best_available_basis(mgrp.dim, mgrp.order)
elif isinstance(mgrp, TensorProductElementGroup):
basis = mp.legendre_tensor_product_basis(mgrp.dim, mgrp.order)
else:
raise TypeError(f"unsupported group type: {type(mgrp).__name__}")

resampling_mat = mp.resampling_matrix(
mp.simplex_best_available_basis(mgrp.dim, mgrp.order),
basis,
mgrp.vertex_unit_coordinates().T,
mgrp.unit_nodes)

Expand Down Expand Up @@ -1013,8 +1043,8 @@ def _test_node_vertex_consistency(mesh, tol):
"""

for mgrp in mesh.groups:
if isinstance(mgrp, SimplexElementGroup):
assert _test_node_vertex_consistency_simplex(mesh, mgrp, tol)
if isinstance(mgrp, (SimplexElementGroup, TensorProductElementGroup)):
assert _test_node_vertex_consistency_resampling(mesh, mgrp, tol)
else:
from warnings import warn
warn("not implemented: node-vertex consistency check for '%s'"
Expand Down
11 changes: 6 additions & 5 deletions meshmode/mesh/generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ def generate_box_mesh(axis_coords, order=1, coord_dtype=np.float64,

if dim == 1:
if mesh_type is not None:
raise ValueError("unsupported mesh_type")
raise ValueError(f"unsupported mesh type: '{mesh_type}'")

for i in range(shape[0]-1):
# a--b
Expand Down Expand Up @@ -801,7 +801,7 @@ def generate_box_mesh(axis_coords, order=1, coord_dtype=np.float64,
pass

else:
raise ValueError("unsupported mesh_type")
raise ValueError(f"unsupported mesh type: '{mesh_type}'")

for i in range(shape[0]-1):
for j in range(shape[1]-1):
Expand Down Expand Up @@ -957,7 +957,8 @@ def generate_regular_rect_mesh(a=(0, 0), b=(1, 1), n=(5, 5), order=1,
on [a,b].
:param boundary_tag_to_face: an optional dictionary for tagging boundaries.
See :func:`generate_box_mesh`.
:param mesh_type: See :func:`generate_box_mesh`.
:param group_cls: see :func:`generate_box_mesh`.
:param mesh_type: see :func:`generate_box_mesh`.
"""
if min(n) < 2:
raise ValueError("need at least two points in each direction")
Expand All @@ -975,15 +976,15 @@ def generate_regular_rect_mesh(a=(0, 0), b=(1, 1), n=(5, 5), order=1,

# {{{ generate_warped_rect_mesh

def generate_warped_rect_mesh(dim, order, n):
def generate_warped_rect_mesh(dim, order, n, *, group_cls=None):
"""Generate a mesh of a warped line/square/cube. Mainly useful for testing
functionality with curvilinear meshes.
"""

assert dim in [1, 2, 3]
mesh = generate_regular_rect_mesh(
a=(-0.5,)*dim, b=(0.5,)*dim,
n=(n,)*dim, order=order)
n=(n,)*dim, order=order, group_cls=group_cls)

def m(x):
result = np.empty_like(x)
Expand Down
Loading