Skip to content

Commit 6645341

Browse files
alexfiklinducer
authored andcommitted
Remove example and trim down overview
1 parent d7a87b7 commit 6645341

File tree

1 file changed

+48
-184
lines changed

1 file changed

+48
-184
lines changed

doc/paper/paper.md

Lines changed: 48 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -146,143 +146,80 @@ to any array type (including GPU or other high-performance arrays) as long as
146146

147147
# Overview
148148

149-
The high-level concepts available in `modepy` are shapes (i.e the geometry of a
149+
The high-level concepts available in `modepy` are shapes (i.e. a reference
150150
domain), modes (i.e. the basis functions), and nodes (i.e. the degrees of
151151
freedom). These are implemented in a user-extensible fashion using the
152152
`singledispatch` mechanism, with inspiration taken from common idiomatic usage
153-
in Julia [@Bezanson2017]. Given a function space `space` on a `shape`, a set of
154-
nodal degrees of freedom can be obtained via
155-
`edge_clustered_nodes_for_space(space, shape)`, with an implementation selected
156-
based on the type of `space`. While the example shows that multiple dispatch
157-
could be beneficial, we have decided to forgo it to avoid potential soundness
158-
issues [@Julia2018].
153+
in Julia [@Bezanson2017].
159154

160155
## Shapes
161156

162157
The geometry of a reference element is described in `modepy` by the `Shape`
163158
class. Built-in support exists for `Simplex` and `Hypercube` geometries,
164159
encompassing the commonly used interval, triangle, tetrahedron, quadrilateral,
165160
and hexahedral shapes (see \autoref{FigureSimplices}). `TensorProductShape` can
166-
be used to compose additional shapes, such as prisms, that are useful in
167-
specific applications and sometimes generated by meshing software (such as
168-
`gmsh` [@Geuzaine2009]). An example that constructs a prism and performs some
169-
standard operations on it is given in the next section.
161+
be used to compose additional shapes, that are useful in specific applications
162+
and sometimes generated by meshing software (such as `gmsh` [@Geuzaine2009]).
170163

171164
![Domains corresponding to the one-, two-, and three-dimensional simplices.](images/simplices.png){#FigureSimplices width="80%"}
172165

173-
To support a wide array of applications, shapes can be queried and manipulated
174-
in several ways. The `faces_for_shape` function can be used to return a list of
175-
faces, which are shapes themselves, that allow access to domain normals and
176-
mappings back to the reference element.
177-
178166
## Modes and Spaces
179167

180-
To perform calculus operations, each reference element can be equipped with
181-
function spaces described by the `FunctionSpace` class.
182-
These represent a finite-dimensional space of functions $\phi_i: D \to
183-
\mathbb{R}$, where $D$ is the reference element domain, but make no specific
184-
choice of basis. The function spaces mirror the shape definitions and are
185-
intended to work in tandem. In fact, the `space_for_shape` function provides a
186-
default choice of space for each shape. Predefined choices include the `PN`
187-
space, containing polynomials of total degree at most `order`, and the `QN`
188-
space, containing polynomials of maximum degree at most `order`. As with
189-
shapes, these spaces can also be combined using `TensorProductSpace` to
190-
describe functional spaces for other domains or in higher dimensions.
191-
192-
For calculations, each space can be equipped with a default basis using the
193-
`basis_for_space` function. `modepy` provides two special types of basis
194-
functions: orthonormal (accessed through `orthonormal_basis_for_space`) and
195-
monomial (accessed through `monomial_basis_for_space`). The basis is provided
196-
in the form of a `Basis` class, which allows access to the basis functions,
197-
their derivatives (per axis) and opaque `mode_ids`. As noted before, the basis
198-
functions and their derivatives can be evaluated directly or can be traced
199-
using the `pymbolic` library to aid in code generation.
168+
To perform calculus operations, each reference element can be equipped with a
169+
function space described by the `FunctionSpace` class. These represent a
170+
finite-dimensional space of functions $\phi_i: D \to \mathbb{R}$, where $D$ is
171+
the reference element domain, and no specific choice of basis. Predefined
172+
choices include the `PN` space, containing polynomials of total degree at most
173+
`order`, and the `QN` space, containing polynomials of maximum degree at most
174+
`order`. As with shapes, these spaces can be combined using
175+
`TensorProductSpace`.
176+
177+
The basis is provided in the form of a `Basis` class, which allows access to
178+
the basis functions, their derivatives (per axis) and opaque `mode_ids`. As
179+
noted before, the basis functions and their derivatives can be evaluated
180+
directly or can be traced using the `pymbolic` library to aid in code
181+
generation. Various standard basis functions are provided, such as the
182+
monomials, general Jacobi polynomials, and the
183+
Proriol-Koornwinder-Dubiner-Owens (PKDO) basis from [@Dubiner1991] (see
184+
\autoref{FigurePKDO}).
200185

201186
![PKDO basis functions for the triangle.](images/pkdo-2d.png){#FigurePKDO width="80%"}
202187

203-
By default, the `Simplex` shape is equipped with a `PN` functional space. This
204-
function space uses the Proriol-Koornwinder-Dubiner-Owens (PKDO) basis (see
205-
\autoref{FigurePKDO}) as defined in [@Dubiner1991] for dimensions up to 3. The
206-
`Hypercube` is equipped with the `QN` functional space that uses a tensor
207-
product of standard Legendre polynomials. Additionally, general Jacobi
208-
polynomials are available and can be used as a basis for variants of `QN` with
209-
different weights, depending on the application.
210-
211188
## Nodes
212189

213190
A final component in an FEM discretization (or 'Ciarlet triple' [@Brenner2007,
214-
Section 3.1]) is a set of 'degrees of freedom' ('DOFs'), that is, a vector of
215-
numbers (technically, functionals) that uniquely define a certain element in
216-
the span of a basis. The literature considers various types of degrees of
217-
freedom; the two most common are modal DOFs (i.e. basis coefficients) and nodal
218-
DOFs (i.e. function or derivative values at certain points). `modepy` provides
219-
easy access to both, while paying particular attention to their usability in
220-
the high-order setting. Due to Runge's phenomenon [@Trefethen2020], simple
221-
equispaced nodal DOFs rapidly become unusable with increasing polynomial order
222-
due to poor conditioning. As such, `modepy` offers access to many types of
223-
nodes with better properties for each reference element. There also exists an
224-
ability to construct one's own set of nodes given a set of functions in 2D via
225-
a procedure based on eigenvalues of multiplication operators [@Vioreanu2014].
226-
227-
On each shape, three default families of nodes are provided: equispaced
228-
(accessed through `equispaced_nodes_for_space`), edge-clustered (accessed
229-
through `edge_clustered_nodes_for_space`) and randomly distributed (accessed
230-
through `random_nodes_for_space`).
231-
232-
For more generality, `modepy` can directly interoperate with the
233-
`recursivenodes` library described in [@Isaac2020], which offers
234-
well-conditioned nodes on the simplex that obey a 'recursive' property, where
235-
nodes on a face of a higher-dimensional shape are exactly the lower-dimensional
236-
nodes. In addition, it offers many many tunable parameters (e.g. nodes on the
237-
boundary vs. not). On simplices, the "warp-and-blend" nodes [@Warburton2007]
238-
are also available for dimensions three and lower. On the hypercube, standard
239-
tensor product nodes are constructed from one-dimensional
240-
Legendre-Gauss-Lobatto nodes. As for the basis functions, the full family of
241-
Jacobi-Gauss and Jacobi-Gauss-Lobatto quadrature points is available for
242-
specific applications.
243-
244-
Taken together, the functionality described thus far provides comprehensive
245-
support for interpolation, that is, the evaluation of a polynomial defined by
246-
its nodal DOFs, at any point, and further the ability to obtain any derivative
247-
of the interpolating polynomial.
191+
Section 3.1]) is a set of 'degrees of freedom' ('DOFs') that uniquely define a
192+
certain function in the span of a basis. `modepy` provides easy access to modal
193+
DOFs (i.e. basis coefficients) and nodal DOFs (i.e. function or derivative
194+
values at a point). As equispaced nodal DOFs are not usable in the high-order
195+
setting [@Trefethen2020], `modepy` offers access to many types of nodes with
196+
better properties for each reference element. It can also construct custom
197+
nodes sets for a given set of basis functions in 2D via a procedure based on
198+
eigenvalues of multiplication operators [@Vioreanu2014].
199+
200+
On simplices, the "warp-and-blend" nodes [@Warburton2007] are available, and on
201+
the hypercube, standard tensor product nodes are constructed from
202+
one-dimensional Legendre-Gauss(-Lobatto) nodes. `modepy` can also directly
203+
interoperate with the `recursivenodes` library described in [@Isaac2020], which
204+
offers additional well-conditioned nodes on the simplex.
248205

249206
## Quadrature
250207

251-
While nodal degrees of freedom must be *unisolvent* or *interpolatory* (i.e.
252-
uniquely determine a function in a discrete function space), this requirement
253-
does not exist in the setting of quadrature, where the objective is to
254-
accurately approximate the value of an integral of a function on a shape. Using
255-
function values at points $\boldsymbol{x}_i$ ("nodes") and associated weights
256-
$w_i$, quadrature rules are generically expressed as
257-
$$
258-
\int_{D} f(\boldsymbol x) \mathrm{d}\boldsymbol{x} \approx
259-
\sum_{k = 0}^N f(\boldsymbol{x}_k) w_k.
260-
$$
261-
262-
Besides the standard building blocks consisting of domains, basis functions and
263-
node sets, `modepy` also offers a wide array of quadrature rules that can be
264-
used on each domain. The quadrature rules are provided as implementations of
265-
the `Quadrature` superclass.
266-
267-
For the interval, a broad selection of quadrature rules are present:
268-
Clenshaw--Curtis, Fejér, and Jacobi-Gauss. The latter class includes the
269-
commonly used Chebyshev and Legendre types, among others. Lobatto (that is,
270-
endpoint-included) variants of these are also available. The line segment
271-
quadratures can be used as part of the `TensorProductQuadrature` class to
272-
define different higher-dimensional rules. Additionally, several
273-
state-of-the-art higher-dimensional rules are available:
208+
Besides the standard building blocks above, `modepy` also offers a wide array
209+
of quadrature rules that can be used on each reference element. The quadrature
210+
rules are provided as implementations of the `Quadrature` superclass. For the
211+
interval, a broad selection of quadrature rules are present: Clenshaw--Curtis,
212+
Fejér, and Jacobi-Gauss(-Lobatto). Additionally, several state-of-the-art
213+
higher-dimensional rules are available:
274214

275215
* Grundmann--Möller [@Grundmann1978] rules for the $n$-simplex.
276216
* Vioreanu--Rokhlin [@Vioreanu2014] rules for the two- and
277-
three-dimensional simplex (see \autoref{FigureQuadrature}). The quadrature
278-
nodes from these rules are also suitable for interpolation.
217+
three-dimensional simplex (see \autoref{FigureQuadrature}).
279218
* Xiao--Gimbutas [@Xiao2010] rules for the two- and three-dimensional
280219
simplex.
281220
* Jáskowiec--Sukumar [@Jaskowiec2021] rules for the tetrahedron.
282221
* Witherden--Vincent [@Witherden2015] rules for the two- and
283-
three-dimensional hypercube (see \autoref{FigureQuadrature}). These rules
284-
have significantly fewer nodes than an equivalent tensor product rule, while
285-
maintaining positive weights.
222+
three-dimensional hypercube (see \autoref{FigureQuadrature}).
286223

287224
![(left) Vioreanu--Rokhlin quadrature points of order 11 and (right) Witherden--Vincent quadrature points of order 11.](images/quadrature_rules.png){#FigureQuadrature width="50%"}
288225

@@ -296,84 +233,11 @@ constructing desired quadrature nodes on a given domain. This can be found in
296233
While `modepy` is sufficiently flexible to accommodate different applications,
297234
it also provides functionality specific to FEM needs. In particular, it allows
298235
constructing a variety of matrix operators that define necessary resampling
299-
operators and bilinear forms used in FEM codes.
300-
301-
The Vandermonde matrix used in interpolation is provided by the `vandermonde`
302-
function. This can be used to obtain point-to-point interpolants using
303-
`resampling_matrix`. In a similar fashion, the `differentiation_matrices`
304-
function can be used to construct derivative operators along each reference
305-
axis.
306-
307-
A specific bilinear form matrix can be obtained using
308-
`nodal_quadrature_bilinear_form_matrix`, which requires providing the usual
309-
test functions, trial functions and corresponding nodes for the input and
310-
output. This allows constructing very general families of bilinear forms with
311-
or without oversampling. One such example is the standard mass matrix, which
312-
can be obtained more easily using the `mass_matrix` function. If the provided
313-
functions are derivatives of the basis functions, standard weak forms of
314-
differentiation operators can also be obtained.
315-
316-
# A Practical Example
317-
318-
In the following example, we demonstrate how to use the library to define a
319-
non-default tensor product shape --- the prism --- and construct a first
320-
derivative in the $x$ direction on this reference element. To produce the
321-
derivative matrix operator, we go through all the objects described in the
322-
previous section: nodes, modes, and quadrature rules.
323-
324-
```python
325-
import numpy as np
326-
import modepy as mp
327-
328-
# Define the shape on which we will operate
329-
line = mp.Simplex(1)
330-
triangle = mp.Simplex(2)
331-
prism = mp.TensorProductShape((triangle, line))
332-
333-
assert prism.dim == 3
334-
335-
# Define a function space for the prism of order 12
336-
n = 12
337-
space = mp.TensorProductSpace((mp.PN(triangle.dim, n), mp.PN(line.dim, n)))
338-
339-
assert space.order == n
340-
assert space.spatial_dim == 3
341-
assert space.space_dim == (n + 1) * (n + 1) * (n + 2) // 2
342-
343-
# Define a basis function for the prism
344-
basis = mp.orthonormal_basis_for_space(space, prism)
345-
346-
# Define a point set for the prism
347-
nodes = mp.edge_clustered_nodes_for_space(space, prism)
348-
349-
# Define a quadrature rule for the prism
350-
quadrature = mp.TensorProductQuadrature([
351-
mp.VioreanuRokhlinSimplexQuadrature(n, triangle.dim),
352-
mp.LegendreGaussQuadrature(n),
353-
])
354-
355-
# Define a bilinear form: weak derivative in the i=x direction
356-
i = 0
357-
weak_d = mp.nodal_quadrature_bilinear_form_matrix(
358-
quadrature,
359-
test_functions=basis.derivatives(i),
360-
trial_functions=basis.functions,
361-
nodal_interp_functions_test=basis.functions,
362-
nodal_interp_functions_trial=basis.functions,
363-
input_nodes=nodes,
364-
output_nodes=nodes,
365-
)
366-
inv_mass = mp.inverse_mass_matrix(basis, nodes)
367-
368-
# Compute derivative and check exact solution
369-
x = nodes[i]
370-
f = 1.0 - np.sin(x) ** 3
371-
f_ref = -3.0 * np.cos(x) * np.sin(x) ** 2
372-
f_approx = inv_mass @ weak_d.T @ f
373-
374-
error = np.linalg.norm(f_approx - f_ref) / np.linalg.norm(f_ref)
375-
assert error < 1.0e-4
376-
```
236+
operators and bilinear forms used in FEM codes. A specific bilinear form matrix
237+
can be obtained using `nodal_quadrature_bilinear_form_matrix`, which requires
238+
providing the usual test functions, trial functions and corresponding nodes for
239+
the input and output. This allows constructing very general families of
240+
bilinear forms with or without oversampling.
377241

378242
# Acknowledgements
379243

0 commit comments

Comments
 (0)