svMultiPhysics
Loading...
Searching...
No Matches
SerendipityBasis.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Stanford University, The Regents of the University of California, and others.
2// SPDX-License-Identifier: BSD-3-Clause
3
4#ifndef SVMP_FE_BASIS_SERENDIPITYBASIS_H
5#define SVMP_FE_BASIS_SERENDIPITYBASIS_H
6
7/**
8 * @file SerendipityBasis.h
9 * @brief Reduced-degree-of-freedom serendipity bases
10 */
11
12#include "BasisFunction.h"
13
14#include <array>
15#include <span>
16
17namespace svmp::FE::basis {
18
19/**
20 * @defgroup FE_SerendipityBasis SerendipityBasis
21 * @ingroup FE_Basis
22 * @brief Construction and evaluation API for reduced serendipity finite-element bases.
23 *
24 * @details This group documents reduced degree-of-freedom basis families that
25 * preserve nodal interpolation on supported element boundaries while omitting
26 * selected interior tensor-product modes. These bases are used for standard
27 * serendipity elements and geometry-mode mappings that intentionally use a
28 * lower-order interpolation space.
29 * @{
30 */
31
32/**
33 * @brief Reduced-degree-of-freedom serendipity basis on supported reference elements.
34 *
35 * @details SerendipityBasis implements nodal bases for the quadrilateral and
36 * hexahedral serendipity families at arbitrary order, plus the Wedge15 prism
37 * layout. Compared with a complete tensor-product Lagrange basis of the same
38 * nominal order, a serendipity basis removes selected interior modes while
39 * retaining nodal interpolation on the supported node layout. The named layouts
40 * Quad8, Hex8, and Hex20 are the fixed-order instances of these families
41 * (quadrilateral order 2, hexahedron orders 1 and 2).
42 *
43 * The quadrilateral serendipity polynomial space is described by monomials
44 * @f$x^{a_x}y^{a_y}@f$ whose superlinear degree is at most the requested
45 * order. The implementation evaluates this space through tensor Legendre
46 * modes, which span the same polynomial space but give a better-conditioned
47 * Vandermonde. The superlinear degree is
48 * @f[
49 * sldeg(x^{a_x}y^{a_y}) =
50 * \begin{cases} a_x, & a_x > 1 \\ 0, & a_x \le 1 \end{cases}
51 * +
52 * \begin{cases} a_y, & a_y > 1 \\ 0, & a_y \le 1 \end{cases}.
53 * @f]
54 * The nodal basis is recovered by inverting the generalized Vandermonde
55 * interpolation matrix at the selected reference nodes. Values, gradients, and
56 * Hessians are then evaluated by differentiating the modal vector and applying
57 * the inverse Vandermonde coefficients.
58 * For order @f$p \ge 1@f$, this space has @f$4p@f$ boundary modes for
59 * @f$p \le 3@f$ and
60 * @f[
61 * 4p + \frac{(p - 3)(p - 2)}{2}
62 * @f]
63 * modes for @f$p \ge 4@f$.
64 *
65 * The quadrilateral node set is unisolvent by construction. If
66 * @f$s(x,y)@f$ in this space vanishes at the @f$p + 1@f$ distinct nodes on
67 * every edge, each edge restriction is a degree-@f$p@f$ one-variable
68 * polynomial with @f$p + 1@f$ roots, so all edge restrictions vanish. Thus
69 * @f$s@f$ is divisible by the boundary bubble
70 * @f$(1 - x^2)(1 - y^2)@f$, and the quotient lies in
71 * @f$P_{p-4}@f$ (with no quotient for @f$p < 4@f$). For @f$p \ge 4@f$, the
72 * interior nodes form triangular rows for @f$P_{p-4}@f$: the first row has
73 * @f$m + 1@f$ distinct @f$x@f$ values, the next row has @f$m@f$, and so on
74 * for @f$m = p - 4@f$. A total-degree polynomial that vanishes on those rows
75 * is zero by induction over rows, because each vanished row factors out one
76 * linear term in @f$y@f$. The interpolation Vandermonde is therefore
77 * nonsingular for the implemented quadrilateral serendipity space.
78 *
79 * Hexahedral serendipity generalizes the same construction to the cube. The
80 * polynomial space is described by every monomial
81 * @f$r^{a_r}s^{a_s}t^{a_t}@f$ whose superlinear degree (the three-axis form of
82 * the rule above) is at most @f$p@f$, and the nodal basis is again the inverse
83 * Vandermonde at the reference nodes. Those nodes are
84 * distributed by boundary stratum: 8 corners, @f$12(p-1)@f$ edge nodes,
85 * @f$6\,q(p)@f$ face-interior nodes -- each face carries the 2D quadrilateral
86 * serendipity interior, since the trace of the cube space on a face is the
87 * square space -- and a volume interior that is empty until @f$p \ge 6@f$.
88 * Unisolvence follows the same factorization: a function vanishing on every
89 * boundary node vanishes on each face by the quadrilateral result above, hence
90 * is divisible by the cube bubble @f$(1 - r^2)(1 - s^2)(1 - t^2)@f$ with quotient
91 * in @f$P_{p-6}@f$; the volume-interior nodes form a tetrahedral staircase that
92 * is unisolvent for @f$P_{p-6}@f$ by induction over @f$t@f$-layers, so the cube
93 * Vandermonde is nonsingular.
94 *
95 * `SerendipityBasis(BasisTopology::Quadrilateral, p)` and
96 * `SerendipityBasis(BasisTopology::Hexahedron, p)` are the arbitrary-order entry
97 * points (@f$p \ge 1@f$; orders below one are rejected). Reference nodes for both
98 * the arbitrary-order and the named paths come from the single
99 * ReferenceNodeLayout serendipity generator, in a VTK-consistent stratified
100 * order; for @f$p \ge 3@f$ the interior ordering is an implementation convention
101 * rather than a public layout. The named fixed layouts -- `ElementType::Quad8`
102 * (order 2), `Hex8` (order 1), and `Hex20` (order 2) -- are the same construction
103 * at those orders; the named overload only pins the order, so the named and
104 * topology constructions produce identical objects and share the single public
105 * node ordering the solver permutes against (order 1 and order 2 reuse the VTK
106 * corner/edge ordering exactly). Wedge serendipity remains a single fixed layout
107 * (Wedge15), constructed only from its named ElementType. Solver-default basis
108 * selection is separate: `basis_factory` maps the complete Quad4 layout to the
109 * default linear Lagrange basis and maps Quad8/Hex20 to serendipity unless a
110 * caller explicitly requests a different supported basis.
111 *
112 * Every supported family -- quadrilateral, hexahedral, and Wedge15 -- is built by
113 * inverting the generalized Vandermonde of its mode space at the public-order
114 * reference nodes. Quadrilateral and hexahedral bases use tensor Legendre modes;
115 * the fixed Wedge15 table uses monomial modes. Values, gradients, and Hessians
116 * are evaluated by differentiating the matching mode vector and applying the
117 * inverse-Vandermonde coefficients. Because the tables are generated in public
118 * node order, evaluation needs no output reordering, and there is no hand-written
119 * special case -- the Hex8 basis is the order-1 instance of the generated
120 * hexahedral space, not a separate trilinear evaluator.
121 *
122 * ## Conditioning and the well-conditioned order range
123 *
124 * High-order nodal interpolation is governed by two conditioning factors, both
125 * addressed so that arbitrary orders produce trustworthy shape functions:
126 * - **Node distribution.** The quadrilateral and hexahedral families place their
127 * nodes on the shared Gauss-Lobatto-Legendre (GLL) distribution -- edges, faces,
128 * and the interior staircase all use the GLL 1D nodes (line_coord_pm_one), whose
129 * logarithmic Lebesgue constant keeps high-order interpolation well-conditioned.
130 * The named production layouts are unaffected, since GLL coincides with the
131 * equispaced layout at orders 1 and 2 (so Quad8/Hex8/Hex20 keep their exact
132 * public coordinates); the layout is this module's own convention only for
133 * order >= 3.
134 * - **Modal basis.** The quadrilateral and hexahedral Vandermondes are assembled
135 * in a tensor **Legendre** basis rather than raw monomials. The serendipity
136 * exponent set is downward-closed, so the Legendre and monomial spans are
137 * identical (the change of basis is triangular) -- the nodal shape functions are
138 * unchanged -- but the Legendre Vandermonde is far better conditioned. (The
139 * fixed Wedge15 layout, order 2, keeps the monomial form; it is trivially
140 * well-conditioned.)
141 */
142class SerendipityBasis final : public BasisFunction {
143public:
144 /**
145 * @brief Construct an arbitrary-order quadrilateral or hexahedral serendipity basis.
146 *
147 * @details This is the arbitrary-order entry point for the serendipity
148 * families with a free order: the quadrilateral and the hexahedron. The
149 * topology carries no node-count assumption; the serendipity polynomial
150 * space, reference nodes (generated here in VTK-consistent stratified order),
151 * and nodal coefficient table are built from the requested order (which must
152 * be @f$p \ge 1@f$). Wedge serendipity is a single fixed layout and is not
153 * constructed this way -- use the named ElementType overload (Wedge15).
154 *
155 * @param topology Must be BasisTopology::Quadrilateral or BasisTopology::Hexahedron.
156 * @param order Polynomial order @f$p \ge 1@f$; orders below 1 are rejected.
157 * @throws BasisConfigurationException If @p order is less than 1.
158 * @throws BasisElementCompatibilityException If @p topology is not Quadrilateral or Hexahedron.
159 */
161
162 /**
163 * @brief Construct a serendipity basis from a named element layout.
164 *
165 * @details Convenience overload for the named, fixed serendipity layouts.
166 * Each layout is the fixed-order instance of its family, built through the
167 * same generated construction as the arbitrary-order path and taking its
168 * nodes from ReferenceNodeLayout: Quad8 is the quadrilateral at order 2, Hex8
169 * and Hex20 are the hexahedron at orders 1 and 2, and Wedge15 is the prism
170 * layout. Each layout carries an inferred fixed order (Hex8 to 1; Quad8,
171 * Hex20, and Wedge15 to 2); the requested @p order must equal that inferred
172 * order and is never adjusted to fit, so a mismatched request (including
173 * order 0 or negative) is rejected. Arbitrary-order quadrilateral and
174 * hexahedral serendipity is requested through the BasisTopology overload.
175 *
176 * @param type Named serendipity element type (Quad8, Hex8, Hex20, or Wedge15).
177 * @param order Requested order; must equal the layout's inferred fixed order
178 * (1 for Hex8; 2 for Quad8, Hex20, and Wedge15).
179 * @throws BasisConfigurationException If @p order does not match the layout's inferred order.
180 * @throws BasisElementCompatibilityException If the element type is unsupported.
181 */
183
184 /**
185 * @brief Construct a serendipity basis from a named layout at its fixed order.
186 *
187 * @details Single-argument convenience overload for the named serendipity
188 * layouts: the order is the one fixed by the layout (1 for Hex8; 2 for Quad8,
189 * Hex20, and Wedge15), so the caller does not repeat it. Equivalent to
190 * SerendipityBasis(type, <fixed order>).
191 *
192 * @param type Named serendipity element type (Quad8, Hex8, Hex20, or Wedge15).
193 * @throws BasisElementCompatibilityException If the element type is unsupported.
194 */
195 explicit SerendipityBasis(ElementType type);
196
197 /** @copydoc BasisFunction::basis_type() */
198 BasisType basis_type() const noexcept final { return BasisType::Serendipity; }
199
200 /** @copydoc BasisFunction::topology() */
201 BasisTopology topology() const noexcept final { return topology_; }
202
203 /** @copydoc BasisFunction::dimension() */
204 int dimension() const noexcept final { return dimension_; }
205
206 /** @copydoc BasisFunction::order() */
207 int order() const noexcept final { return order_; }
208
209 /** @copydoc BasisFunction::size() */
210 std::size_t size() const noexcept final { return size_; }
211
212 /**
213 * @brief Return the reference interpolation nodes in basis ordering.
214 *
215 * @details Node coordinates are the points at which the serendipity basis
216 * satisfies the nodal interpolation property. All families take their nodes
217 * from ReferenceNodeLayout, the public node-ordering source the solver adapter
218 * permutes against: the fixed Wedge15 layout and the quadrilateral/hexahedral
219 * families (named or arbitrary-order) alike, in VTK-consistent stratified
220 * order -- corners and edges first (matching the public Quad8/Hex8/Hex20
221 * ordering at the named orders), then the face and volume interior points
222 * needed to make the reduced polynomial space unisolvent. For @f$p \ge 3@f$
223 * that interior ordering is an implementation convention; callers should pair
224 * it with basis values from the same object rather than assume an external
225 * mesh ordering contract beyond the supported named production layouts.
226 *
227 * @return Reference node coordinates, one per basis function.
228 */
229 const std::vector<math::Vector<double, 3>>& nodes() const noexcept final { return nodes_; }
230
231 /**
232 * @brief Evaluate serendipity basis values into caller-provided storage.
233 * @param xi Reference coordinate. Lower-dimensional elements use the active prefix components.
234 * @param values_out Output span with at least size() entries.
235 */
237 std::span<double> values_out) const final;
238
239 /**
240 * @brief Evaluate serendipity basis gradients into caller-provided storage.
241 * @param xi Reference coordinate. Lower-dimensional elements use the active prefix components.
242 * @param gradients_out Output span with at least size() entries.
243 */
245 std::span<Gradient> gradients_out) const final;
246
247 /**
248 * @brief Evaluate serendipity basis Hessians into caller-provided storage.
249 * @param xi Reference coordinate. Lower-dimensional elements use the active prefix components.
250 * @param hessians_out Output span with at least size() entries.
251 */
253 std::span<Hessian> hessians_out) const final;
254
255private:
257 int dimension_{0};
258 int order_{0};
259 std::size_t size_{0};
260 std::vector<math::Vector<double, 3>> nodes_;
261 // Per-axis degrees (a, b, c) of the tensor modes spanning the family's
262 // polynomial space. Interpreted as monomial powers r^a s^b t^c or, when
263 // uses_legendre_modes_ is set, as tensor Legendre degrees P_a(r) P_b(s) P_c(t)
264 // (the same space; see ModalAxisKind in SerendipityBasis.cpp).
265 std::vector<std::array<int, 3>> mode_exponents_;
266 // Row-major inverse (generalized) Vandermonde, indexed as [mode, basis].
267 std::vector<double> inv_vandermonde_;
268 // Whether the tensor modes are Legendre polynomials (quadrilateral/hexahedral
269 // families) or plain monomials (the fixed Wedge15 layout). Evaluation must use
270 // the same family the coefficient table was built with.
271 bool uses_legendre_modes_{false};
272
273 // Build the quadrilateral serendipity mode set, nodes, and Legendre
274 // coefficient table for the given order. (Details at the definition.)
275 void init_quadrilateral(int order);
276 // Build the hexahedral serendipity mode set, nodes, and Legendre coefficient
277 // table for the given order; Hex8/Hex20 are its order-1/order-2 instances.
278 void init_hexahedron(int order);
279 // Build the fixed Wedge15 layout from its tabulated monomial mode space.
280 void init_fixed_named(ElementType type);
281
282 void evaluate_all_to(const math::Vector<double, 3>& xi,
283 std::span<double> values_out,
284 std::span<Gradient> gradients_out,
285 std::span<Hessian> hessians_out) const override;
286};
287
288/** @} */
289
290} // namespace svmp::FE::basis
291
292#endif // SVMP_FE_BASIS_SERENDIPITYBASIS_H
Abstract interface for finite-element basis-function families.
Definition BasisFunction.h:166
Reduced-degree-of-freedom serendipity basis on supported reference elements.
Definition SerendipityBasis.h:142
int order() const noexcept final
Return the polynomial order represented by this basis.
Definition SerendipityBasis.h:207
void evaluate_gradients_to(const math::Vector< double, 3 > &xi, std::span< Gradient > gradients_out) const final
Evaluate serendipity basis gradients into caller-provided storage.
Definition SerendipityBasis.cpp:527
std::size_t size() const noexcept final
Return the number of basis functions and reference nodes.
Definition SerendipityBasis.h:210
void evaluate_hessians_to(const math::Vector< double, 3 > &xi, std::span< Hessian > hessians_out) const final
Evaluate serendipity basis Hessians into caller-provided storage.
Definition SerendipityBasis.cpp:533
int dimension() const noexcept final
Return the reference-space dimension of the basis.
Definition SerendipityBasis.h:204
BasisTopology topology() const noexcept final
Return the reference topology of this basis.
Definition SerendipityBasis.h:201
const std::vector< math::Vector< double, 3 > > & nodes() const noexcept final
Return the reference interpolation nodes in basis ordering.
Definition SerendipityBasis.h:229
void evaluate_values_to(const math::Vector< double, 3 > &xi, std::span< double > values_out) const final
Evaluate serendipity basis values into caller-provided storage.
Definition SerendipityBasis.cpp:521
BasisType basis_type() const noexcept final
Return the concrete basis family.
Definition SerendipityBasis.h:198
BasisTopology
Reference-cell topology of a basis (the shape, independent of order).
Definition BasisTraits.h:28
@ Unknown
Unrecognized or uninitialized topology.
BasisType
Basis function families.
Definition Types.h:247
ElementType
Reference element types supported by the FE library.
Definition Types.h:215
@ Serendipity
Serendipity elements.
Eigen::Matrix< T, static_cast< int >(N), 1 > Vector
Fixed-size column vector for element-level computations.
Definition Vector.h:51