Skip to content

Commit 960b436

Browse files
committed
FunctionSpace: enable quad_scheme and docs
1 parent f14d0f5 commit 960b436

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+973
-340
lines changed

docker/Dockerfile.vanilla

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,7 @@ ENV SLEPC_DIR=$PETSC_DIR/$PETSC_ARCH
132132
ENV PATH="$PETSC_DIR/$PETSC_ARCH/bin:$PATH"
133133

134134
ENV HDF5_MPI=ON
135-
ENV CC=mpicc CXX=mpicxx
136-
ENV MPICC=$CC
135+
ENV MPICC=mpicc
137136
ENV CFLAGS="-O3 -mtune=generic" CPPFLAGS="-O3 -mtune=generic"
138137

139138
# Install Firedrake

docs/source/duals.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _duals:
2+
13
Dual spaces
24
=====================================
35

docs/source/element_list.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from finat.ufl.elementlist import ufl_elements
2-
# ~ from ufl.finiteelement.elementlist import ufl_elements
32
from finat.element_factory import supported_elements
43
import csv
54

docs/source/extruded-meshes.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ supports a more general syntax:
304304
305305
V = FunctionSpace(mesh, element)
306306
307-
where ``element`` is a UFL :py:class:`~ufl.finiteelement.finiteelement.FiniteElement` object. This
307+
where ``element`` is a UFL :py:class:`~finat.ufl.finiteelement.FiniteElement` object. This
308308
requires generation and manipulation of ``FiniteElement`` objects.
309309

310310
Geometrically, an extruded mesh cell is the *product* of a base, "horizontal",
@@ -319,7 +319,7 @@ The ``TensorProductElement`` operator
319319
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
320320

321321
To create an element compatible with an extruded mesh, one should use
322-
the :py:class:`~ufl.finiteelement.tensorproductelement.TensorProductElement`
322+
the :py:class:`~finat.ufl.tensorproductelement.TensorProductElement`
323323
operator. For example,
324324

325325
.. code-block:: python3
@@ -359,7 +359,7 @@ but is piecewise constant horizontally.
359359

360360
A more complicated element, like a Mini horizontal element with linear
361361
variation in the vertical direction, may be built using the
362-
:py:class:`~ufl.finiteelement.enrichedelement.EnrichedElement` functionality
362+
:py:class:`~finat.ufl.enrichedelement.EnrichedElement` functionality
363363
in either of the following ways:
364364

365365
.. code-block:: python3
@@ -392,7 +392,7 @@ The ``HDivElement`` and ``HCurlElement`` operators
392392
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
393393

394394
For moderately complicated vector-valued elements,
395-
:py:class:`~ufl.finiteelement.tensorproductelement.TensorProductElement`
395+
:py:class:`~finat.ufl.tensorproductelement.TensorProductElement`
396396
does not give enough information to unambiguously produce the desired
397397
space. As an example, consider the lowest-order *Raviart-Thomas* element on a
398398
quadrilateral. The degrees of freedom live on the facets, and consist of
@@ -417,7 +417,7 @@ However, this is only scalar-valued. There are two natural vector-valued
417417
elements that can be generated from this: one of them preserves tangential
418418
continuity between elements, and the other preserves normal continuity
419419
between elements. To obtain the Raviart-Thomas element, we must use the
420-
:py:class:`~ufl.finiteelement.hdivcurl.HDivElement` operator:
420+
:py:class:`~finat.ufl.hdivcurl.HDivElement` operator:
421421

422422
.. code-block:: python3
423423
@@ -433,7 +433,7 @@ between elements. To obtain the Raviart-Thomas element, we must use the
433433
:align: center
434434

435435
The RT quadrilateral element, requiring the use
436-
of :py:class:`~ufl.finiteelement.hdivcurl.HDivElement`
436+
of :py:class:`~finat.ufl.hdivcurl.HDivElement`
437437

438438
Another reason to use these operators is when expanding a vector into a
439439
higher dimensional space. Consider the lowest-order Nedelec element of the
@@ -453,7 +453,7 @@ the product of this with a continuous element on an interval:
453453
454454
This element still only has two components. To expand this into a
455455
three-dimensional curl-conforming element, we must use the
456-
:py:class:`~ufl.finiteelement.hdivcurl.HCurlElement` operator; the syntax is:
456+
:py:class:`~finat.ufl.hdivcurl.HCurlElement` operator; the syntax is:
457457

458458
.. code-block:: python3
459459

docs/source/install.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ install Firedrake. To do this perform the following steps:
226226

227227
.. code-block:: text
228228
229-
CC=mpicc CXX=mpicxx PETSC_DIR=/path/to/petsc PETSC_ARCH=arch-firedrake-{default,complex} HDF5_MPI=ON
229+
PETSC_DIR=/path/to/petsc PETSC_ARCH=arch-firedrake-{default,complex} HDF5_MPI=ON
230230
231231
.. note::
232232
This command will only work if you have the right starting directory.

docs/source/interpolation.rst

Lines changed: 161 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Firedrake offers highly flexible capabilities for interpolating expressions
1111
(functions of space) into finite element :py:class:`~.Function`\s.
1212
Interpolation is often used to set up initial conditions and/or boundary
1313
conditions. Mathematically, if :math:`e(x)` is a function of space and
14-
:math:`V` is a finite element functionspace then
14+
:math:`V` is a finite element function space then
1515
:math:`\operatorname{interpolate}(e, V)` is the :py:class:`~.Function`
1616
:math:`v_i \phi_i\in V` such that:
1717

@@ -46,6 +46,9 @@ The basic syntax for interpolation is:
4646
:start-after: [test_interpolate_operator 1]
4747
:end-before: [test_interpolate_operator 2]
4848

49+
Here, the :py:func:`~.interpolate` function returned a **symbolic** UFL_ :py:class:`~ufl.Interpolate`
50+
expression. To calculate a concrete numerical result, we need to call :py:func:`~.assemble` on this expression.
51+
4952
It is also possible to interpolate an expression directly into an existing
5053
:py:class:`~.Function`:
5154

@@ -89,8 +92,7 @@ Here is an example demonstrating some of these features:
8992
:start-after: [test_interpolate_operator 7]
9093
:end-before: [test_interpolate_operator 8]
9194

92-
This also works as expected when interpolating into a a space defined on the facets
93-
of the mesh:
95+
This also works when interpolating into a space defined on the facets of the mesh:
9496

9597
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
9698
:language: python3
@@ -105,19 +107,170 @@ of the mesh:
105107
interpolate into spaces defined by higher-continuity elements such as
106108
Argyris and Hermite.
107109

110+
111+
Semantics of symbolic interpolation
112+
--------------------------------------------
113+
114+
Let :math:`U` and :math:`V` be finite element spaces with DoFs :math:`\{\psi^{*}_{i}\}` and :math:`\{\phi^{*}_{i}\}`
115+
and basis functions :math:`\{\psi_{i}\}` and :math:`\{\phi_{i}\}`, respectively.
116+
The interpolation operator between :math:`U` and :math:`V` is defined
117+
118+
.. math::
119+
120+
\mathcal{I}_{V} : U &\to V \\ \mathcal{I}_{V}(u)(x) &= \phi^{*}_{i}(u)\phi_{i}(x).
121+
122+
We define the following bilinear form
123+
124+
.. math::
125+
126+
I : U \times V^{*} &\to \mathbb{R} \\ I(u, v^*) &= v^{*}(u)
127+
128+
where :math:`v^{*}\in V^{*}` is a linear functional in the dual space to :math:`V`, extended so that
129+
it can act on functions in :math:`U`. If we choose :math:`v^{*} = \phi^{*}_{i}` then
130+
:math:`I(u, \phi^{*}_{i}) = \phi^{*}_{i}(u)` gives the coefficients of the interpolation of :math:`u` into :math:`V`.
131+
This allows us to represent the interpolation as a form in UFL_. This is exactly the
132+
:py:class:`~ufl.Interpolate` UFL_ object. Note that this differs from typical bilinear forms since one of the
133+
arguments is in a dual space. For more information on dual spaces in Firedrake,
134+
see :ref:`the relevant section of the manual <duals>`.
135+
136+
Interpolation operators
137+
~~~~~~~~~~~~~~~~~~~~~~~
138+
139+
2-forms are assembled into matrices, and we can do the same with the interpolation form.
140+
If we let :math:`u` be a ``TrialFunction(U)`` (i.e. an argument in slot 1) and :math:`v^*` be a
141+
``TestFunction(V.dual())`` (i.e. a :py:class:`~ufl.Coargument` in slot 0) then
142+
143+
.. math::
144+
145+
I(u, v^*) = I(\psi_{j},\phi_{i}^*)=\phi_{i}^*(\psi_{j})=:A_{ij}
146+
147+
The matrix :math:`A` is the interpolation matrix from :math:`U` to :math:`V`. In Firedrake, we can
148+
assemble this matrix by doing
149+
150+
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
151+
:language: python3
152+
:dedent:
153+
:start-after: [test_interpolate_operator 11]
154+
:end-before: [test_interpolate_operator 12]
155+
156+
Passing a :py:class:`~.FunctionSpace` into the dual slot of :py:func:`~.interpolate` is
157+
syntactic sugar for ``TestFunction(V.dual())``.
158+
159+
If :math:`g\in U` is a :py:class:`~.Function`, then we can write it as :math:`g = g_j \psi_j` for
160+
some coefficients :math:`g_j`. Interpolating :math:`g` into :math:`V` gives
161+
162+
.. math::
163+
164+
I(g, v^*) = \phi^{*}_{i}(g_j \psi_j)= A_{ij} g_j,
165+
166+
so we can multiply the vector of coefficients of :math:`g` by the interpolation matrix to obtain the
167+
coefficients of the interpolated function. In Firedrake, we can do this by
168+
169+
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
170+
:language: python3
171+
:dedent:
172+
:start-after: [test_interpolate_operator 12]
173+
:end-before: [test_interpolate_operator 13]
174+
175+
:math:`h` is a :py:class:`~.Function` in :math:`V` representing the interpolation of :math:`g` into :math:`V`.
176+
177+
.. note::
178+
179+
When interpolating a :py:class:`~.Function` directly, for example
180+
181+
.. code-block:: python3
182+
183+
assemble(interpolate(Function(U), V))
184+
185+
Firedrake does not explicitly assemble the interpolation matrix. Instead, the interpolation
186+
is performed matrix-free.
187+
188+
Adjoint interpolation
189+
~~~~~~~~~~~~~~~~~~~~~
190+
The adjoint of the interpolation operator is defined as
191+
192+
.. math::
193+
194+
\mathcal{I}_{V}^{*} : V^{*} \to U^{*}.
195+
196+
This operator interpolates :py:class:`~.Cofunction`\s in the dual space :math:`V^{*}` into
197+
the dual space :math:`U^{*}`. The associated form is
198+
199+
.. math::
200+
201+
I^{*} : V^{*} \times U \to \mathbb{R}.
202+
203+
So to obtain the adjoint interpolation operator, we swap the arguments of the :py:class:`~ufl.Interpolate`
204+
form. In Firedrake, we can accomplish this in two ways. The first is to swap the argument numbers to the form:
205+
206+
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
207+
:language: python3
208+
:dedent:
209+
:start-after: [test_interpolate_operator 14]
210+
:end-before: [test_interpolate_operator 15]
211+
212+
The second way is to use UFL_'s :py:func:`~ufl.adjoint` operator, which takes a form and returns its adjoint:
213+
214+
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
215+
:language: python3
216+
:dedent:
217+
:start-after: [test_interpolate_operator 15]
218+
:end-before: [test_interpolate_operator 16]
219+
220+
If :math:`g^*` is a :py:class:`~.Cofunction` in :math:`V^{*}` then we can interpolate it into :math:`U^{*}` by doing
221+
222+
.. math::
223+
224+
I^{*}(g^*, u) = g^*_i \phi_i^*(\psi_j) = g^*_i A_{ij}.
225+
226+
This is the product of the adjoint interpolation matrix :math:`A^{*}` and the coefficients of :math:`g^*`.
227+
In Firedrake, we can do this by
228+
229+
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
230+
:language: python3
231+
:dedent:
232+
:start-after: [test_interpolate_operator 16]
233+
:end-before: [test_interpolate_operator 17]
234+
235+
Again, Firedrake does not explicitly assemble the adjoint interpolation matrix, but performs the
236+
interpolation matrix-free. To perform the interpolation with the assembled adjoint interpolation operator,
237+
we can take the :py:func:`~ufl.action` of the operator on the :py:class:`~.Cofunction`:
238+
239+
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
240+
:language: python3
241+
:dedent:
242+
:start-after: [test_interpolate_operator 17]
243+
:end-before: [test_interpolate_operator 18]
244+
245+
The final case is when we interpolate a :py:class:`~.Function` into :py:class:`~.Cofunction`:
246+
247+
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
248+
:language: python3
249+
:dedent:
250+
:start-after: [test_interpolate_operator 19]
251+
:end-before: [test_interpolate_operator 20]
252+
253+
This interpolation has zero arguments and hence is assembled into a number. Mathematically, we have
254+
255+
.. math::
256+
257+
I^{*}(g^*, u) = g^*_i \phi_i^*(u_{j}\psi_j) = g^*_i A_{ij} u_j.
258+
259+
which indeed contracts into a number.
260+
108261
Interpolation across meshes
109262
---------------------------
110263

111264
The interpolation API supports interpolation between meshes where the target
112265
function space has finite elements (as given in the list of
113266
:ref:`supported elements <supported_elements>`)
114267

115-
* **Lagrange/CG** (also known a Continuous Galerkin or P elements),
268+
* **Lagrange/CG** (also known as Continuous Galerkin or P elements),
116269
* **Q** (i.e. Lagrange/CG on lines, quadrilaterals and hexahedra),
117270
* **Discontinuous Lagrange/DG** (also known as Discontinuous Galerkin or DP elements) and
118271
* **DQ** (i.e. Discontinuous Lagrange/DG on lines, quadrilaterals and hexahedra).
119272

120-
Vector, tensor and mixed function spaces can also be interpolated into from
273+
Vector, tensor, and mixed function spaces can also be interpolated into from
121274
other meshes as long as they are constructed from these spaces.
122275

123276
.. note::
@@ -142,7 +295,7 @@ of the source mesh. Volume, surface and line integrals can therefore be
142295
calculated by interpolating onto the mesh or
143296
:ref:`immersed manifold <immersed_manifolds>` which defines the volume,
144297
surface or line of interest in the domain. The integral itself is calculated
145-
by calling :py:func:`~.assemble` on an approriate form over the target mesh
298+
by calling :py:func:`~.assemble` on an appropriate form over the target mesh
146299
function space:
147300

148301
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
@@ -178,7 +331,7 @@ interpolation will raise a :py:class:`~.DofNotDefinedError`.
178331
:start-after: [test_cross_mesh 3]
179332
:end-before: [test_cross_mesh 4]
180333

181-
This can be overriden with the optional ``allow_missing_dofs`` keyword
334+
This can be overridden with the optional ``allow_missing_dofs`` keyword
182335
argument:
183336

184337
.. literalinclude:: ../../tests/firedrake/regression/test_interpolation_manual.py
@@ -248,7 +401,7 @@ Interpolation from external data
248401

249402
Unfortunately, UFL interpolation is not applicable if some of the
250403
source data is not yet available as a Firedrake :py:class:`~.Function`
251-
or UFL expression. Here we describe a recipe for moving external to
404+
or UFL expression. Here we describe a recipe for moving external data to
252405
Firedrake fields.
253406

254407
Let us assume that there is some function ``mydata(X)`` which takes as

docs/source/manual.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Manual
1919
duals
2020
interpolation
2121
point-evaluation
22+
quadrature
2223
external_operators
2324
adjoint
2425
visualisation

0 commit comments

Comments
 (0)