Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
11bd11f
make face mass matrices work on tensor products
alexfikl Nov 3, 2020
cfd8fbf
fix 0d case for tensor products
alexfikl Nov 4, 2020
ffcb91b
remove face index stuff
alexfikl Nov 4, 2020
47dec4d
simplify cube unit vertex construction
alexfikl Nov 4, 2020
56d7f13
simplify face maps a bit
alexfikl Nov 4, 2020
ddb7e6d
simplify test setup
alexfikl Nov 4, 2020
e9b52eb
update docs
alexfikl Nov 5, 2020
704e686
introduce a shapes module
alexfikl Nov 14, 2020
16180da
use shapes in estimate_lebesgue_constant
alexfikl Nov 14, 2020
3df2de1
add docs and some py3.6 fixes
alexfikl Nov 14, 2020
7acf2b0
move functions out of shapes module
alexfikl Nov 17, 2020
b014fbe
update docs and some fixes
alexfikl Nov 17, 2020
fe40713
add basis_with_mode_ids
alexfikl Nov 17, 2020
3b3bada
update docs
alexfikl Nov 18, 2020
b90c25c
bump version
alexfikl Nov 18, 2020
0a89725
estimate_lebesgue_constant: raise if dimensions do not match
alexfikl Nov 18, 2020
773bb2b
Merge branch 'master' into tensor-face-mass-matrix
inducer Nov 25, 2020
00488bd
Move shape-basd functions to bottom in modes/nodes
inducer Nov 25, 2020
f227cac
Move shapes docstring into shapes module
inducer Nov 25, 2020
f8209ce
Shapes: Add foldmethod comment
inducer Nov 25, 2020
7238c6c
Remove spurious blank line in modes docstring
inducer Nov 25, 2020
918342a
Use _cse in PKDO gradients
inducer Nov 25, 2020
acf4b34
Merge branch 'master' into tensor-face-mass-matrix
inducer Nov 26, 2020
59198d8
Deprecate current dimension-independent basis getters
inducer Nov 26, 2020
cf11d52
resampling_matrix: Impove count mismatch error message
inducer Nov 27, 2020
cd750b8
Refactor towards improved shape-based interface
inducer Nov 27, 2020
560a027
Refactor face information retrieval and face mass matrix computation
inducer Nov 27, 2020
598145f
Avoid log(0) warnings in test_basis_grad
inducer Nov 27, 2020
73e8d56
Reverse vertex/node order for hypercubes
inducer Nov 28, 2020
f6c5755
Export face query functionality in root namespace
inducer Nov 28, 2020
e7b8269
Add redundant @singledispatch.register arguments for Py3.6
inducer Nov 28, 2020
c15c453
Fix doc references
inducer Nov 28, 2020
a15fcfa
Fix quadrature_for_shape docstring
inducer Nov 28, 2020
8ffc3d4
Eliminate references to (removed) get_node_tuples
inducer Nov 28, 2020
9061bcc
Fix zerod_basis
inducer Nov 28, 2020
bceb113
Remove spurious import from modepy.nodes
inducer Nov 28, 2020
299b32f
Remove an extraneous import
inducer Nov 30, 2020
c75d799
Make new section for submeshes
inducer Nov 30, 2020
92e3e83
Doc suggestions for refactor-shapes from review by @alexfikl
inducer Nov 30, 2020
5e3550a
Cast volume_vertex_indices to tuple in _SimplexFace
inducer Nov 30, 2020
22ae991
Remove whitespace: placate flake8
inducer Nov 30, 2020
7f4e1a1
Generalize TensorProductBasis for nD inhomogeneity
inducer Nov 30, 2020
347027b
Make TensorProductBasis public in root module
inducer Nov 30, 2020
c872de9
Do not claim that Face subclasses Shape
inducer Nov 30, 2020
676d38a
Fix TensorProductBasis facepalm
inducer Nov 30, 2020
9a282c0
Introduce function spaces as first-class objects
inducer Dec 1, 2020
6bf5735
Move submesh functionality into shapes
inducer Dec 1, 2020
62524e2
Quadrature, notes: require space *and* shape arguments
inducer Dec 1, 2020
7f5ec1e
Drop a special case in node_tuples_for_space:Simplex
inducer Dec 1, 2020
b1f5de4
Bring back _for_space names for quadrature, nodes
inducer Dec 1, 2020
4917e62
Deprecate tools.unit_vertices, fix biunit_vertices_for_shape for simplex
inducer Dec 1, 2020
982ae2b
Merge pull request #1 from inducer/refactor-shapes
alexfikl Dec 2, 2020
0e04d2c
make face vertex index order positively oriented
alexfikl Dec 2, 2020
b60addc
flip hypercube node tuple order
alexfikl Dec 2, 2020
542b534
fix tensor_product_basis order
alexfikl Dec 2, 2020
991432f
fall back to equidistant nodes for simplex dim > 3
alexfikl Dec 2, 2020
752b3ae
fix sphinx directive
alexfikl Dec 2, 2020
97abd45
add shape to basis_for_space getters
alexfikl Dec 2, 2020
338e1aa
rename to unit_vertices_for_shape for consistency
alexfikl Dec 2, 2020
a6f8939
Add FIXMEs for order, dims arg order convention
inducer Dec 2, 2020
10b7d27
Bring back tools.UNIT_VERTICES to make unmodified meshmode happy
inducer Dec 2, 2020
368bd74
expand tensor_product_nodes
alexfikl Dec 3, 2020
ef01010
expand tensor product quadrature
alexfikl Dec 3, 2020
a17c544
update test_hypercube_submesh
alexfikl Dec 3, 2020
1fd772e
add a nicer repr to function spaces
alexfikl Dec 3, 2020
099e587
add some docs for exact_to on TensorProductQuadrature
alexfikl Dec 4, 2020
877018e
add force_dim_axis to 1d quadratures
alexfikl Dec 4, 2020
10a17d5
clarify exact_to
alexfikl Dec 4, 2020
231524f
handle missing exact_to in tensor product quadrature
alexfikl Dec 10, 2020
836ba97
quadrature_for_space doc tweak
inducer Dec 11, 2020
081077b
Better handle current limitations of _hypercube_face_to_vol_map
inducer Dec 11, 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
88 changes: 68 additions & 20 deletions modepy/matrices.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,42 +243,76 @@ def mass_matrix(basis, nodes):


class _FaceMap:
def __init__(self, face_vertices):
vol_dim = face_vertices.shape[0]

self.origin = face_vertices[:, 0].reshape(-1, 1)
self.span = face_vertices[:, 1:vol_dim] - self.origin
self.face_dim = vol_dim - 1

def __call__(self, points):
return self.origin + np.einsum("ad,dn->an", self.span, points*0.5 + 0.5)


class _SimplexFaceMap(_FaceMap):
def __init__(self, face_vertices):
"""
:arg face_vertices: an array of shape ``[dim, npts]``, where *npts*
should equal *dim*.
should equal ``dim``.
"""
vol_dim, npts = face_vertices.shape
if npts != vol_dim:
raise ValueError("face_vertices has wrong shape")
raise ValueError("'face_vertices' has wrong shape")

self.origin = face_vertices[:, 0]
self.span = face_vertices[:, 1:] - self.origin[:, np.newaxis]
super().__init__(face_vertices)

self.face_dim = vol_dim - 1

def __call__(self, points):
return (self.origin[:, np.newaxis]
+ np.einsum("ad,dn->an", self.span, points*0.5 + 0.5))
class _HypercubeFaceMap(_FaceMap):
def __init__(self, face_vertices):
"""
:arg face_vertices: an array of shape ``[dim, npts]``, where *npts*
should equal ``2**(dim - 1)``.
"""
vol_dim, npts = face_vertices.shape
if npts != 2**(vol_dim-1):
raise ValueError("'face_vertices' has wrong shape")

super().__init__(face_vertices)


def modal_face_mass_matrix(trial_basis, order, face_vertices, test_basis=None):
def modal_face_mass_matrix(trial_basis, order, face_vertices,
test_basis=None, domain=None):
"""
:arg face_vertices: an array of shape ``[dim, npts]``, where *npts*
should equal *dim*.
:arg face_vertices: an array of shape ``[dim, npts]``.
:arg domain: identifier for the reference element, can be one of
`"simplex"` or `"hypercube"`.
Comment thread
inducer marked this conversation as resolved.
Outdated

.. versionadded :: 2016.1

.. versionchanged:: 2020.5
Comment thread
alexfikl marked this conversation as resolved.
Outdated

Added *domain* parameter and support for :math:`[-1, 1]^d` domains.
"""

if test_basis is None:
test_basis = trial_basis

fmap = _FaceMap(face_vertices)
if domain is None:
domain = "simplex"

if domain == "simplex":
from modepy.quadrature.grundmann_moeller import \
GrundmannMoellerSimplexQuadrature
fmap = _SimplexFaceMap(face_vertices)
quad = GrundmannMoellerSimplexQuadrature(order, fmap.face_dim)
elif domain == "hypercube":
from modepy.quadrature import LegendreGaussTensorProductQuadrature
fmap = _HypercubeFaceMap(face_vertices)
quad = LegendreGaussTensorProductQuadrature(fmap.face_dim, order)
Comment thread
inducer marked this conversation as resolved.
Outdated
else:
raise ValueError(f"unknown domain: '{domain}'")

from modepy.quadrature.grundmann_moeller import GrundmannMoellerSimplexQuadrature
quad = GrundmannMoellerSimplexQuadrature(order, fmap.face_dim)
assert quad.exact_to > order*2

mapped_nodes = fmap(quad.nodes)

nrows = len(test_basis)
Expand All @@ -296,24 +330,38 @@ def modal_face_mass_matrix(trial_basis, order, face_vertices, test_basis=None):


def nodal_face_mass_matrix(trial_basis, volume_nodes, face_nodes, order,
face_vertices, test_basis=None):
face_vertices, test_basis=None, domain=None):
"""
:arg face_vertices: an array of shape ``[dim, npts]``, where *npts*
should equal *dim*.
:arg face_vertices: an array of shape ``[dim, npts]``.
:arg domain: identifier for the reference element, can be one of
`"simplex"` or `"hypercube"`.

.. versionadded :: 2016.1

.. versionchanged:: 2020.5

Added *domain* parameter and support for :math:`[-1, 1]^d` domains.
"""

if test_basis is None:
test_basis = trial_basis

fmap = _FaceMap(face_vertices)
if domain is None:
domain = "simplex"

if domain == "simplex":
fmap = _SimplexFaceMap(face_vertices)
elif domain == "hypercube":
fmap = _HypercubeFaceMap(face_vertices)
else:
raise ValueError(f"unknown domain: '{domain}'")

face_vdm = vandermonde(trial_basis, fmap(face_nodes)) # /!\ non-square
vol_vdm = vandermonde(test_basis, volume_nodes)

modal_fmm = modal_face_mass_matrix(
trial_basis, order, face_vertices, test_basis=test_basis)
trial_basis, order, face_vertices,
test_basis=test_basis, domain=domain)
return la.inv(vol_vdm.T).dot(modal_fmm).dot(la.pinv(face_vdm))


Expand Down
8 changes: 8 additions & 0 deletions modepy/modes.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,10 @@ def tensor_product_basis(dims, basis_1d):

.. versionadded:: 2017.1
"""
if dims == 0:
# NOTE: using to maintain consistency in the 0d case
return simplex_onb(dims, len(basis_1d))
Comment thread
alexfikl marked this conversation as resolved.
Outdated

from pytools import generate_nonnegative_integer_tuples_below as gnitb
return tuple(
_TensorProductBasisFunction(order, [basis_1d[i] for i in order])
Expand All @@ -673,6 +677,10 @@ def grad_tensor_product_basis(dims, basis_1d, grad_basis_1d):

.. versionadded:: 2020.2
"""
if dims == 0:
# NOTE: using to maintain consistency in the 0d case
return grad_simplex_onb(dims, len(basis_1d))
Comment thread
alexfikl marked this conversation as resolved.
Outdated

from pytools import (
wandering_element,
generate_nonnegative_integer_tuples_below as gnitb)
Expand Down
4 changes: 4 additions & 0 deletions modepy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ def tensor_product_nodes(dims, nodes_1d):

.. versionadded:: 2017.1
"""
if dims == 0:
# NOTE: using this to maintain consistency in the 0d case
return warp_and_blend_nodes(dims, 1)

Comment thread
alexfikl marked this conversation as resolved.
Outdated
nnodes_1d = len(nodes_1d)
result = np.empty((dims,) + (nnodes_1d,) * dims)
for d in range(dims):
Expand Down
26 changes: 26 additions & 0 deletions modepy/quadrature/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,29 @@ def __init__(self, quad, left, right):
Quadrature.__init__(self,
left + (quad.nodes+1) / 2 * length,
quad.weights * half_length)


class TensorProductQuadrature(Quadrature):
Comment thread
inducer marked this conversation as resolved.
def __init__(self, dims, quad):
Comment thread
inducer marked this conversation as resolved.
Outdated
"""
:arg quad: a :class:`Quadrature` class for one-dimensional intervals.
"""

from modepy.nodes import tensor_product_nodes
x = tensor_product_nodes(dims, quad.nodes)
from itertools import product
w = np.fromiter(
(np.prod(w) for w in product(quad.weights, repeat=dims)),
dtype=np.float,
count=quad.weights.size**dims)
assert w.size == x.shape[1]

super().__init__(x, w)
self.exact_to = quad.exact_to


class LegendreGaussTensorProductQuadrature(TensorProductQuadrature):
def __init__(self, dims, N, backend=None): # noqa: N803
Comment thread
alexfikl marked this conversation as resolved.
Outdated
from modepy.quadrature.jacobi_gauss import LegendreGaussQuadrature
super().__init__(
dims, LegendreGaussQuadrature(N, backend=backend))
13 changes: 13 additions & 0 deletions modepy/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ def inverse(self):
"""The inverse :class:`AffineMap` of *self*."""
return AffineMap(la.inv(self.a), -la.solve(self.a, self.b))

# }}}


# {{{ simplex coordinate mapping

EQUILATERAL_TO_UNIT_MAP = {
1: AffineMap([[1]], [0]),
Expand Down Expand Up @@ -229,6 +233,15 @@ def barycentric_to_equilateral(bary):
# }}}


# {{{ hypercube coordinate mapping

def hypercube_unit_vertices(dims):
from modepy.nodes import tensor_product_nodes
return tensor_product_nodes(dims, np.array([-1.0, 1.0])).T
Comment thread
alexfikl marked this conversation as resolved.
Outdated

# }}}


def pick_random_simplex_unit_coordinate(rng, dims):
offset = 0.05
base = -1 + offset
Expand Down
Loading