Finite element interpolations from the DefElement encyclopedia for use with Ferrite.jl.
The implementations are, to a large extent, automated/robot translations of the element tabulations in DefElement (through its reference implementation symfem) into Ferrite's conventions: reference cells, entity numbering, DOF ordering, and orientation handling. Every implemented basis is cross-checked against symfem in the test suite, except where an element deliberately follows its original paper instead of DefElement (Fortin–Soulie, Crouzeix–Falk; see the table).
This package implements elements that Ferrite does not (yet) provide itself. Elements that already exist in Ferrite are deliberately not re-implemented here — see Implemented in Ferrite for that list, including notes on degrees/cells Ferrite covers and gaps.
Element names link to their DefElement entries. The Type column gives the interpolation type to use; "-" means the element is not available.
Interpolations implemented in this package.
| Element | Type | Notes |
|---|---|---|
| bernstein | Bernstein |
line 1–3, triangle 1–3, tetrahedron 1–2 (tet ≥ 3 needs #5) |
| brezzi-douglas-fortin-marini | BrezziDouglasFortinMarini |
triangle, degrees 1–2 |
| brezzi-douglas-marini | BDM |
triangle, degree 2 (degree 1 is Ferrite's BrezziDouglasMarini, see below) |
| bubble | Bubble |
line 2–3, triangle 3–4, tetrahedron 4 |
| conforming-crouzeix-raviart | ConformingCrouzeixRaviart |
triangle, degrees 2–4 (degree 1 coincides with P1 Lagrange) |
| crouzeix-falk | CrouzeixFalk |
triangle (degree 3), as in the original paper: edge DOFs at the three Gauss–Legendre points of each edge. Differs from DefElement, which uses the equispaced points 1/4, 1/2, 3/4; with those the patch test fails and the method loses two orders of convergence. Only the span (full P3) is cross-checked against symfem |
| dPc | DPC |
quadrilateral 1–3, hexahedron 1–2, with the L2 Piola mapping; on the interval it coincides with DiscontinuousLagrange |
| enriched-galerkin | EnrichedGalerkin |
every cell/degree Ferrite's Lagrange supports |
| fortin-soulie | FortinSoulie |
triangle (degree 2), as in the original paper: continuous P2 plus one neutral function per cell, continuous at the Gauss–Legendre points of each edge (spans the full Gauss-continuous space on simply connected domains; a proper subspace on domains with holes). Differs from DefElement's definition, which uses an asymmetric local element (and, in symfem up to 2025.12, the edge points 1/3 and 2/3, see mscroggs/symfem#344); see the file header and #33 |
| gauss-legendre | GaussLegendre |
line/quadrilateral/hexahedron, any degree (modal basis, following symfem) |
| nedelec2 | NedelecSecondKind |
triangle, degrees 1–2 |
| radau | Radau |
interval degree 2 (degree ≥ 3 has no symfem reference; quad/hex need #2) |
| taylor | Taylor |
line/triangle, degrees 1–2, with the cell-dependent TaylorMapping |
| tnt-curl | TNTCurl |
quadrilateral, degree 1 |
| tnt-div | TNTDiv |
quadrilateral, degree 1 |
| transition | Transition |
triangle, interior order 2, per-edge orders 1–2 (tuple type parameter) |
| trimmed-serendipity-curl | TrimmedSerendipityCurl |
quadrilateral, degree 1 |
| trimmed-serendipity-div | TrimmedSerendipityDiv |
quadrilateral, degree 1 |
| vector dPc | DPC^vdim |
vectorized DPC (VectorizedInterpolation) |
Elements that cannot currently be implemented against Ferrite (each linked issue describes the required upstream changes), or that are out of scope.
| Element | Type | Notes |
|---|---|---|
| alfeld-sorokina | - | blocked (macro split + derivative DOFs): #21 |
| argyris | - | blocked (derivative DOFs): #7 |
| arnold-boffi-falk | - | blocked (Kirby mapping): #14 |
| arnold-winther | - | blocked (matrix-valued): #25 |
| bell | - | blocked (derivative DOFs): #8 |
| bernardi-raugel | - | blocked (geometry-dependent facet DOFs): #13 |
| bogner-fox-schmitt | - | blocked (derivative DOFs): #12 |
| brezzi-douglas-duran-fortin | - | blocked (3D face DOF orientation): #28 |
| buffa-christiansen | - | out of scope (dual polygon element) |
| direct-serendipity | - | blocked (basis built on the physical cell): #29 |
| dual | - | out of scope (dual polygon element) |
| gopalakrishnan-lederer-schoberl | - | blocked (matrix-valued): #27 |
| guzman-neilan (first kind) | - | blocked (macro split): #22 |
| guzman-neilan (second kind) | - | blocked (macro split): #22 |
| hellan-herrmann-johnson | - | blocked (matrix-valued): #26 |
| hermite | - | blocked (derivative DOFs): #6 |
| hsieh-clough-tocher | - | blocked (macro split): #18 |
| huang-zhang | - | blocked (tangential edge moments): #16 |
| johnson-mercier | - | blocked (macro split, matrix-valued): #23 |
| mardal-tai-winther | - | blocked (tangential edge moments): #15 |
| morley | - | blocked (normal-derivative DOFs): #9 |
| morley-wang-xu | - | blocked (normal-derivative DOFs): #10 |
| nonconforming-arnold-winther | - | blocked (matrix-valued): #25 |
| p1-iso-p2 | - | blocked (macro split): #19 |
| p1-macro | - | blocked (macro split): #20 |
| reduced-hsieh-clough-tocher | - | blocked (macro split): #18 |
| regge | - | blocked (matrix-valued): #24 |
| rotated-buffa-christiansen | - | out of scope (dual polygon element) |
| tnt (scalar) | - | blocked (sign-flipping edge moment weights): #17 |
These DefElement entries are not re-implemented in this package because Ferrite.jl (v1.6) already provides them, possibly for a subset of the degrees and reference cells that DefElement defines. Extending their coverage belongs upstream in Ferrite — except where a note says a gap is filled here under a different type name.
Degrees are given in Ferrite's numbering. For Raviart–Thomas and Nédélec
(first kind), DefElement degree k corresponds to Ferrite degree k + 1.
| Element | Type | Notes |
|---|---|---|
| brezzi-douglas-marini | BrezziDouglasMarini |
triangle 1. Degree 2 is BDM in this package (distinct name to avoid clashing with Ferrite's type); triangle ≥ 3 missing; tetrahedron blocked upstream (face-orientation DOF transformations) |
| bubble-enriched-lagrange | BubbleEnrichedLagrange |
triangle 1; DefElement degree 2 missing |
| crouzeix-raviart | CrouzeixRaviart |
triangle 1, tetrahedron 1; higher odd degrees missing |
| crouzeix-raviart (quad/hex) | RannacherTurek |
quadrilateral 1, hexahedron 1 |
| lagrange | Lagrange |
line 1–2, triangle 1–5, quadrilateral 1–3, tetrahedron 1–4, hexahedron 1–3, prism 1–2, pyramid 1–2; higher degrees missing on all cells (DefElement is unbounded) |
| lagrange (discontinuous) | DiscontinuousLagrange |
as Lagrange, plus degree 0 on every cell |
| nedelec1 | Nedelec |
triangle 1–2, quadrilateral 1, tetrahedron 1, hexahedron 1; same gaps as RaviartThomas, prism missing entirely |
| raviart-thomas | RaviartThomas |
triangle 1–2, quadrilateral 1, tetrahedron 1, hexahedron 1; triangle ≥ 3 and quadrilateral ≥ 2 missing; tet/hex ≥ 2 additionally blocked upstream (> 1 DOF per face needs face-orientation DOF transformations) |
| serendipity | Serendipity |
quadrilateral 2, hexahedron 2. Ferrite uses edge-midpoint point evaluations instead of DefElement's integral moments (same span, different basis). Degree ≥ 3 missing (edge DOFs become integral moments; the edge-reversal permutation no longer applies — needs upstream DOF transformations) |
| vector-bubble-enriched-lagrange | BubbleEnrichedLagrange^2 |
via vectorization; follows the scalar element |
| vector-lagrange | Lagrange^vdim |
via vectorization; follows Lagrange |
| vector-q | Lagrange^vdim |
via vectorization; follows Lagrange |
The elements are defined on a single cell; how boundary conditions are applied
in a mesh depends on what the DOFs on the boundary facets determine. Natural
(Neumann) conditions are applied as usual (facet integrals with FacetValues)
for every element. For Dirichlet conditions, the elements fall into these
classes (each is tested by solving a model problem whose exact solution lies in
the discrete space, see test/test_utils.jl):
| Class | How to apply Dirichlet conditions | Where the boundary condition holds | Elements |
|---|---|---|---|
| Nodal, conforming | Dirichlet |
on the whole boundary facet (for data in the trace space; otherwise the facet interpolant of the data) | ConformingCrouzeixRaviart, Radau, Transition (on order-1 edges the trace is the linear interpolant) |
| Nonconforming | Dirichlet |
at the points where the global space is continuous: the Gauss–Legendre points of the boundary edges | CrouzeixFalk, FortinSoulie (the conditions act on the vertex/midpoint DOFs; the neutral cell function is nonzero on the boundary except at the Gauss points) |
| H(div) / H(curl) | ProjectedDirichlet (facet L2 projection of the normal / tangential component) |
normal / tangential trace on the whole boundary facet (for data in the trace space) | BDM, BrezziDouglasFortinMarini, TrimmedSerendipityDiv, TNTDiv; NedelecSecondKind, TrimmedSerendipityCurl, TNTCurl |
| Discontinuous / no boundary DOFs | weakly, e.g. Nitsche / symmetric interior penalty (Dirichlet constrains nothing or errors) |
weakly | DPC, GaussLegendre, Taylor, EnrichedGalerkin (the per-cell constant is nonzero on the boundary, so constraining the Lagrange DOFs would not fix the trace) |
| Vanishes on the boundary | nothing to apply (homogeneous by construction) | everywhere on the boundary | Bubble (used as an enrichment) |
| Not supported | weakly, or through AffineConstraints with the Bernstein coefficients of the data (Dirichlet needs point-evaluation DOFs, ProjectedDirichlet is H(div)/H(curl) only) |
– | Bernstein |
For Ferrite's own interpolations the same classes apply: Lagrange,
Serendipity and BubbleEnrichedLagrange are nodal and conforming;
RaviartThomas, BrezziDouglasMarini and Nedelec use ProjectedDirichlet;
CrouzeixRaviart is nonconforming (Dirichlet acts at the facet midpoints);
DiscontinuousLagrange accepts Dirichlet on the nodes of the boundary facets
but is typically used with weak conditions.
- One source file per element in
src/, defining an interpolation type in Ferrite's style (e.g.Bernstein{RefTriangle, 2}()). - Elements that cannot currently be implemented against Ferrite (they need upstream changes, e.g. general DOF transformations, matrix-valued interpolations, or macro-element support) also get one file each, containing a description of the required upstream changes and a placeholder type whose constructor throws. These are not exported.
- One test file per element in
test/, with interpolation-level tests (properties, reference tabulation tables) and integration tests viaCellValues/FacetValues. - Elements that exist in Ferrite also get one test file each, with symfem
cross-checks only (Ferrite's own test suite covers the rest). Their bases
agree with symfem up to a signed permutation (scaled by the Piola factor of
the reference-cell map for
RaviartThomas/Nedelecon hypercubes), exceptSerendipity, where only the spans agree since Ferrite uses edge-midpoint point evaluations instead of integral moments.
The package is developed against a local Ferrite checkout (sibling directory
../Ferrite):
julia --project=. -e 'using Pkg; Pkg.develop(path="../Ferrite"); Pkg.instantiate()'
julia --project=. -e 'using Pkg; Pkg.test()'
Manifest.toml is intentionally not committed.
- Ferrite's interpolation interface is unexported and documented as not fully
stable; this package implements
Ferrite.-qualified internal methods and pinsFerrite = "1.6"in[compat]as a guard. - The test suite cross-checks every basis against
symfem (DefElement's reference
implementation), imported live via PythonCall — a test-only dependency;
test/CondaPkg.tomlprovisions Python and symfem automatically. Note that symfem/DefElement and Ferrite differ in reference cell coordinates and in entity numbering/ordering —test_symfem_referencemaps the coordinates, and each element's test file documents its DOF permutation.