Date: 2026-04-14 Module: src/fem/interpolation/nedelec Purpose: Theory, interface, and implementation conventions for BELFEM's Nédélec (edge) finite elements. This document covers the content that applies to all edge elements — their role in H(curl) formulations, the EdgeFunction base class, the lifecycle, the factory pattern, and the volume-element implementations (TRI3, TRI6, TET4, TET10, LINE3). The thin-shell variants (QUAD4TS, PENTA6TS) are specialized and documented separately in nedelec_thinshell.md.
BELFEM's magnetodynamic solver uses the H-phi formulation (Messe et al. 2023, Arsenault et al. 2023). In conducting subdomains, the unknown is the magnetic field strength H, which must be curl-conforming (continuous tangentially across interfaces, discontinuous normally) and whose curl is the current density J = ∇ × H. Standard Lagrange (nodal) interpolation is H¹-conforming and imposes continuity of every component across element faces; it over-constrains the tangential-only continuity that H actually needs and produces spurious curl-free modes in multiply connected domains.
Nédélec's (1980) edge elements solve both problems. Their DOFs are edge circulations
which make tangential continuity automatic across element faces (because adjacent elements share the same edge DOF) while leaving normal components free to jump. The interpolation space lies in H(curl) rather than H¹. For a systematic treatment see Monk (2003) and Nédélec (1980).
In BELFEM, Nédélec elements are used for every conducting block (plus cohomology-cut DOFs at the interface with scalar-phi regions). Air, ferromagnetic, and buffer regions use scalar Lagrange elements for φ. The coupling at the H-φ interface is handled through static condensation of edge DOFs onto nodal values (see src/fem/kernel/doc/).
All BELFEM edge elements derive from the abstract base EdgeFunction at `cl_EF_EdgeFunction.hpp`. The class owns the usual FEM-element state and a small public API:
| Member | Type | Meaning |
|---|---|---|
| mJ | Matrix<real> | Geometry Jacobian, transposed (mJ(i,j) = ∂x_j / ∂ξ_i) |
| mInvJ | Matrix<real> | Inverse of the transposed Jacobian. Column j of mInvJ is the physical-space gradient of reference coordinate j (∇ξ_j) |
| mDetJ | real | Determinant of the Jacobian (may be signed) |
| mAbsDetJ | real | Absolute value of mDetJ, used as the integration weight |
| mE | Matrix<real> | Edge basis values at current integration point, shape (ndim × nDOFs) |
| mC | Matrix<real> | Curl of the edge basis at current integration point, same shape as mE |
| mSumW | real | Sum of integration weights over the reference element |
| mNumDofs | uint | Number of edge DOFs this element carries |
The transposed-Jacobian convention is the same as the rest of BELFEM's interpolation module. A consequence is that the columns (not rows) of mInvJ are physical-space gradients of reference coordinates — useful to remember when reading basis construction code.
A typical assembly loop in an IWG looks like:
The edgeFn and integration objects are cached by element type outside the loop — see src/fem/kernel/cl_FEM_Group for BELFEM's calculator machinery that does this caching at the block level.
Edge functions are created through EdgeFunctionFactory::create_edge_function(ElementType) at `cl_EdgeFunctionFactory.hpp`. The factory is stateless; each call constructs a fresh edge function. Current dispatch:
| ElementType | Edge function class | Category | Status |
|---|---|---|---|
| TRI3 | EF_TRI3 | Volume (2D) | Production |
| TRI6 | EF_TRI6 | Volume (2D), 2nd order | ⚠️ Proof of concept (see §6.5) |
| TET4 | EF_TET4 | Volume (3D) | Production |
| TET10 | EF_TET10 | Volume (3D), 2nd order | ⚠️ Proof of concept (see §6.5) |
| LINE3 | EF_LINE3 | Higher-order edge (1D), 2nd order | ⚠️ Proof of concept (see §6.5) |
| QUAD4TS | EF_QUAD4TS | Thin shell — see nedelec_thinshell.md | Production |
| PENTA6TS | EF_PENTA6TS | Thin shell — see nedelec_thinshell.md | Production |
| HEX8 | EF_HEX8 | Volume (3D) | ⚠️ Rectangular bricks only (see §6.6) |
| HEX8TS | EF_HEX8TS | Thin shell — see nedelec_thinshell.md | Production |
| HEX8TB | EF_HEX8TB | Side-connector wall element | Production |
The DOF count per element type is also reported through the helper num_nedelec_dofs(ElementType) in `fn_num_nedelec_dofs.hpp`:
| ElementType | DOF count | Notes |
|---|---|---|
| LINE2 | 1 | Circulation along the line |
| LINE3 | 2 | Linear + quadratic |
| TRI3 | 3 | One per edge |
| TRI6 | 8 | Six edges + two face bubbles |
| TET4 | 6 | One per edge |
| TET10 | 20 | Lowest order + quadratic edge + face |
| QUAD4TS | 2 | Tangential-only, per thin-shell convention |
| PENTA6TS | 6 | Three bottom + three top |
num_nedelec_dofs is consulted by the DOF allocation code when the IWG needs to know how many edge DOFs a given block contributes. When adding a new edge element type, update both the factory switch and this helper.
BELFEM's meshes use global edges (shared by multiple elements), so each Nédélec basis function needs a sign for the element's local edge direction. The sign is retrieved with aElement->edge_directions(mS) inside link(). mS is a small fixed-size array (one real per edge) containing +1 if the element's local edge direction matches the global edge direction, -1 otherwise. All volume edge elements use this convention uniformly; see e.g. EF_TET4::link() at cl_EF_TET4.cpp:94.
The sign enters the basis construction as an explicit factor. Without it, the circulation integral ∫ E_k · dℓ would return the wrong sign on half of the shared edges, breaking tangential continuity. The orientation information comes from the mesh's edge construction (ordering of edge endpoints by node ID or similar); users don't need to touch it directly.
Every BELFEM edge element is normalized so that the DOF value equals the edge circulation. Concretely, for basis function E_k associated with edge k,
where s_k is the edge's orientation sign. With this normalization, the discrete H field is the simple linear combination
One documented exception: TRI6. The normalization above holds for the first-order elements. TRI6's two parent-edge functions each carry circulation s/2 rather than unity — the hand integrals H_0 - G_0 = 2 - 3t and H_1 - G_1 = 3t - 1 both give 1/2, and the implementation agrees (nedelec_derivation.md §3.3, nedelec/cl_EF_TRI6.cpp). This does not extend to TET10, whose edge polynomials are twice the TRI6 pair and do integrate to unit circulation (nedelec_derivation.md §4.1). Do not renormalise one without the other.
with coefficients h_k that are directly the edge circulations of H along each edge. Interpretation is unambiguous, and post-processing (current computation, line integrals, cut coefficients) doesn't need to carry around basis normalization factors.
When two elements share an edge, the shared DOF must mean the same thing from both sides. If element A's basis were normalized so that ∫ E_k · dℓ = 1 and element B's basis were normalized so that ∫ E_k · dℓ = 2, a DOF value of 1.0 would correspond to different physical H fields on the two sides — the assembled system would be inconsistent.
All BELFEM edge functions adhere to the unit-circulation convention. When adding a new edge element, verify this by hand (compute the circulation of its basis on a reference element) before wiring it into the factory. This is particularly important for reduced or custom bases such as the thin-shell elements in nedelec_thinshell.md, where the basis normalization must be chosen specifically to reach unit circulation.
The curl operator C = ∇ × E gives the current density basis:
The stiffness matrix entry from ∫ ρ (∇×H)·(∇×H) dV is therefore trans(C) * ρ * C * dV at each integration point, which is the form used in BELFEM's conductor IWG kernels in src/fem/maxwell/matrices/mt_maxwell_h.cpp.
BELFEM's volume Nédélec elements follow the canonical Whitney construction:
where N_a, N_b are the linear Lagrange shape functions of the two end vertices. This construction has unit circulation on its own edge, zero on every other edge, and zero curl on degenerate edges. The sign convention matches s_k from edge_directions().
The lowest-order 3D edge element: four vertices, six edges, six DOFs. The Whitney basis expands to closed-form polynomials in (ξ, η, ζ) plus a barycentric τ = 1 − ξ − η − ζ. Both basis and curl are constant over the element (because ∇N_a is constant), so the element is exactly integrated by a single-point Gauss rule — mSumW = 1/6 (the reference tetrahedron volume). See cl_EF_TET4.cpp.
The quadratic counterpart of TET4: ten nodes (four vertices + six edge midpoints), 20 DOFs. Twelve edge DOFs (two per geometric edge: a lowest-order plus a quadratic refinement) and eight face DOFs. The increased richness of the basis pays off in convergence order when the H field has significant variation inside an element.
The 2D analogs. In BELFEM's 2D H-phi formulation, the conductor's H field is in-plane (H_x, H_y) while φ is scalar, and cohomology cuts provide the transport current coupling. TRI3 and TRI6 implement the Whitney and quadratic Nédélec bases on a triangle. EF_TRI6 has eight DOFs: six edge (two per geometric edge) plus two interior, per the standard quadratic Nédélec count on a triangle.
The 1D edge element used for higher-order 1D refinements. Rarely appears directly in the magnetic solve — it's used by the cohomology-cut machinery and in certain interface constructions.
The second-order Nédélec elements — TRI6, TET10, and LINE3 — are present in the codebase as proof-of-concept implementations. They are not currently part of BELFEM's tested and supported feature set.
Concretely:
In practice, production runs use lowest-order elements (TRI3, TET4) for the conducting volumes plus the dedicated thin-shell elements for the tape stack. If you need higher-order accuracy on the volume side, plan for additional validation work before relying on results — at minimum a manufactured-solution patch test on a simple geometry, plus careful inspection of the assembled Jacobian for the specific problem class. Treat the existing EF_TRI6, EF_TET10, and EF_LINE3 implementations as a starting point, not as a guaranteed-correct black box.
The hexahedral edge element EF_HEX8 (and any future quadrilateral one) has one geometry restriction that simplex elements do not: use it only on perfectly rectangular elements, meaning rectangles in 2D and bricks in 3D, either axis-aligned or rigidly rotated. Do not use trapezoidal, sheared, or otherwise distorted shapes. This is not a BELFEM implementation limit. It is a known property of tensor-product H(curl)/H(div) elements, and the failure is silent.
The mechanism. On triangles and tetrahedra, the reference-to-physical map is affine, so the covariant (Piola) transformation carries the reference Nédélec space onto a physical polynomial space with the same approximation power. On general quadrilaterals and hexahedra, the map is bi-/trilinear rather than affine. The transform then stops preserving the polynomial space: the mapped basis loses completeness, along with the interpolation estimates used by the convergence theory. Monk 2003 builds the hexahedral Nédélec theory on the affine case (Monk, §6.1) and warns that non-affine hexahedral maps can give non-optimal convergence, or even non-convergence, in H(curl; Ω) (Monk, §8.2–8.3).
How bad it gets. Arnold, Boffi & Falk and Falk, Gatto & Monk are the key studies. They show that standard mapped families on general, non-affine quadrilateral meshes lose approximation order, with the lowest-order elements, the ones BELFEM uses in production, hit hardest. In the H(div) counterpart to this problem, Boffi et al. 2013, Remark 2.5.5, state that the divergence does not converge for k = 0 on general quadrilateral meshes. Falk et al. 2011 extend the negative results to 3D hexahedral H(curl) elements. Arnold et al. 2001 and 2002 give the underlying approximation theory, including the scalar serendipity case, and Arnold et al. 2005 treats H(div).
Why this is dangerous in practice. Nothing asserts. A distorted-hex h-φ model can assemble, solve, and produce plausible fields. The fields are still wrong, or they converge at a reduced rate that refinement along the same distorted mesh family will not repair. Treat this as a meshing rule:
Scalar (Lagrange) elements are far more forgiving: bilinear/trilinear scalar elements keep their first-order energy-norm convergence on arbitrary non-degenerate quads/hexes, which is why thermal problems on such meshes are acceptable. The restriction here is specific to the edge (and face) element spaces of the magnetic solve.
References: Monk 2003, §6.1 and §8.2–8.3; Boffi et al. 2013, §2.2.4 and §2.5.5 (Remark 2.5.5); Arnold et al. 2001, 2002, 2005; Falk et al. 2011. Full citations with DOIs in doc/literature_references.md.
When adding a new volume Nédélec element type:
For thin-shell variants, see nedelec_thinshell.md for the additional considerations around dimensional reduction, pseudo-inverse Jacobians, and shared-edge compatibility.
For thin-shell element theory specifically, see nedelec_thinshell.md. For the interpolation module in general — including non-Nédélec shape functions, integration data, and the InterpolationFunction factory — see the module index and interpolation_usage_guide.md.