svMultiPhysics
Loading...
Searching...
No Matches
LagrangeBasis.h
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_LAGRANGEBASIS_H
5#define SVMP_FE_BASIS_LAGRANGEBASIS_H
6
7#include "BasisFunction.h"
8#include "BasisTraits.h"
9
10#include <array>
11#include <cstddef>
12#include <span>
13
14namespace svmp::FE::basis {
15
16/**
17 * @defgroup FE_LagrangeBasis LagrangeBasis
18 * @ingroup FE_Basis
19 * @brief Construction and evaluation API for nodal Lagrange finite-element bases.
20 *
21 * @details This group documents the complete nodal Lagrange basis evaluator
22 * used by the FE library. The implementation covers tensor-product,
23 * simplex, and wedge reference topologies with exact analytical first and
24 * second derivatives in reference coordinates.
25 * @{
26 */
27
28/**
29 * @brief Nodal Lagrange basis on supported reference finite elements.
30 *
31 * @details LagrangeBasis represents the complete (full-degree) nodal
32 * interpolation basis on a reference topology. It supports point, line,
33 * quadrilateral, hexahedron, triangle, tetrahedron, and wedge reference
34 * topologies. The primary constructor takes a BasisTopology and an explicit
35 * polynomial order, so an arbitrary order carries no node-count assumption
36 * (an order-2 hexahedron is BasisTopology::Hexahedron with order 2). A named
37 * ElementType such as Line3, Quad9, Tetra10, or Hex27 is a fixed-order
38 * shorthand: it maps to the same (topology, order) pair and the requested order
39 * must equal the order baked into that layout (1 for the linear elements, 2 for
40 * the complete-quadratic aliases, 0 for Point1).
41 *
42 * ## Reference-node distribution
43 *
44 * The interpolation nodes are not a single distribution across topologies; each
45 * family uses the node set its evaluator is built for:
46 * - **Tensor-product (line, quadrilateral, hexahedron):** the shared
47 * Gauss-Lobatto-Legendre (GLL) tensor-axis nodes -- see line_coord_pm_one for
48 * the distribution and its conditioning -- not an equispaced layout.
49 * - **Simplex (triangle, tetrahedron):** the equispaced barycentric lattice
50 * (each barycentric coordinate at @f$i/p@f$). The closed-form evaluator below
51 * is specific to this equispaced lattice.
52 * - **Wedge:** the tensor product of an equispaced triangle cross-section with a
53 * GLL through-axis.
54 *
55 * Because GLL coincides with the equispaced layout at orders 1 and 2
56 * (line_coord_pm_one), the linear and quadratic tensor elements -- Line2/Line3,
57 * Quad4/Quad9, Hex8/Hex27, and the wedge through-axis -- are built on equispaced
58 * nodes, and the GLL/equispaced distinction appears only for order >= 3.
59 *
60 * ## Evaluation
61 *
62 * Tensor-product elements use the one-dimensional nodal polynomials
63 * @f[
64 * l_i(x) = \prod_{j \ne i} \frac{x - x_j}{x_i - x_j}
65 * @f]
66 * on the per-axis GLL coordinates @f$x_j \in [-1, 1]@f$ (the barycentric-weight
67 * form, valid for any distinct node set). Multi-dimensional basis functions are
68 * products of the active axis polynomials, for example
69 * @f$N_{ijk}(r,s,t) = l_i(r)l_j(s)l_k(t)@f$ on a hexahedron.
70 *
71 * Simplex elements use barycentric coordinates and integer lattice
72 * exponents on the equispaced lattice. For a node with exponent tuple
73 * @f$\alpha@f$, where
74 * @f$\sum_a \alpha_a = p@f$, the basis is assembled from scaled
75 * falling-factorial factors,
76 * @f[
77 * N_\alpha(\lambda) =
78 * \prod_a \prod_{m=0}^{\alpha_a-1}
79 * \frac{p\lambda_a - m}{m + 1}.
80 * @f]
81 * Gradients and Hessians are evaluated analytically by differentiating these
82 * factors and applying the barycentric-coordinate chain rule.
83 *
84 * Wedge elements are treated as a tensor product between a triangle simplex
85 * basis and a one-dimensional through-axis basis:
86 * @f$N_{a k}(r,s,t) = T_a(r,s)l_k(t)@f$.
87 *
88 * ## Conditioning and the supported order range
89 *
90 * Interpolation conditioning is governed by the node distribution and so differs
91 * by topology:
92 * - **Tensor-product topologies stay well-conditioned at high order.** GLL nodes
93 * have a logarithmic Lebesgue constant, so line/quadrilateral/hexahedron bases
94 * remain trustworthy well beyond the production orders.
95 * - **Simplex topologies degrade at high order.** The equispaced barycentric
96 * lattice has a Lebesgue constant that grows roughly exponentially with order
97 * (the Runge phenomenon), so triangle and tetrahedron bases are reliable
98 * through low orders but become increasingly ill-conditioned beyond them. The
99 * wedge inherits this through its equispaced triangle cross-section.
100 *
101 * The vector-returning evaluators are convenient API wrappers. The `*_to`
102 * methods write to caller-provided spans and are intended for assembly paths
103 * that avoid temporary allocations.
104 */
105class LagrangeBasis final : public BasisFunction {
106public:
107 /** @brief Axis-index tuple for tensor-product reference nodes. */
108 using TensorNodeIndex = std::array<std::size_t, 3>;
109
110 /** @brief Barycentric exponent tuple for simplex reference nodes. */
111 using SimplexExponent = std::array<int, 4>;
112
113 /** @brief Triangle-node and axis-node tuple for wedge reference nodes. */
114 using WedgeNodeIndex = std::array<std::size_t, 2>;
115
116 /**
117 * @brief Construct a Lagrange basis on a reference topology at a polynomial order.
118 *
119 * @details This is the primary, arbitrary-order entry point: a BasisTopology
120 * carries no node-count assumption, so any supported order is requested
121 * explicitly (e.g. an order-5 hexahedron is BasisTopology::Hexahedron with
122 * order 5). The constructor builds the reference node coordinates and the
123 * topology-specific lookup data used by evaluation. Tensor-product bases
124 * store per-axis node indices, simplex bases store barycentric exponent
125 * tuples, and wedge bases store the triangle-node/axis-node decomposition.
126 *
127 * Reference nodes follow the per-topology distribution described in the class
128 * documentation (Reference-node distribution). Unlike SerendipityBasis, this
129 * constructor does not reject ill-conditioned high-order simplex/wedge requests
130 * (where the equispaced barycentric lattice degrades); that choice is the
131 * caller's.
132 *
133 * @param topology Reference topology; Point through the volume topologies.
134 * @param order Polynomial order; must be non-negative. Point is order 0.
135 * @throws BasisConfigurationException If the order is negative, or if Point
136 * is requested with a nonzero order.
137 * @throws BasisElementCompatibilityException If the topology is Unknown.
138 */
140
141 /**
142 * @brief Construct a Lagrange basis from a named element layout.
143 *
144 * @details Convenience overload for a named mesh element. The order is baked
145 * into the layout (0 for Point1, 1 for the linear elements, 2 for the
146 * complete-quadratic aliases such as Hex27/Tetra10) and the requested
147 * @p order must match it; arbitrary orders must be requested through the
148 * BasisTopology overload. Serendipity and pyramid layouts are rejected.
149 *
150 * @param type Named element type used to determine topology and baked-in order.
151 * @param order Requested order; must equal the element's baked-in order.
152 * @throws BasisConfigurationException If @p order does not match the element's baked-in order.
153 * @throws BasisElementCompatibilityException If the element type is unsupported.
154 */
156
157 /**
158 * @brief Construct a Lagrange basis from a named element layout at its baked-in order.
159 *
160 * @details Single-argument convenience overload: the polynomial order is the
161 * one baked into the layout (0 for Point1, 1 for the linear elements, 2 for
162 * the complete-quadratic aliases such as Hex27/Tetra10), so the caller does
163 * not repeat it. Equivalent to LagrangeBasis(type, <baked-in order>).
164 * Serendipity and pyramid layouts are rejected, as for the two-argument
165 * overload.
166 *
167 * @param type Named element type; determines both topology and order.
168 * @throws BasisElementCompatibilityException If the element type is unsupported.
169 */
170 explicit LagrangeBasis(ElementType type);
171
172 /** @copydoc BasisFunction::basis_type() */
173 BasisType basis_type() const noexcept final { return BasisType::Lagrange; }
174
175 /** @copydoc BasisFunction::topology() */
176 BasisTopology topology() const noexcept final { return topology_; }
177
178 /** @copydoc BasisFunction::dimension() */
179 int dimension() const noexcept final { return dimension_; }
180
181 /** @copydoc BasisFunction::order() */
182 int order() const noexcept final { return order_; }
183
184 /** @copydoc BasisFunction::size() */
185 std::size_t size() const noexcept final { return nodes_.size(); }
186
187 /**
188 * @brief Return the reference interpolation nodes in basis ordering.
189 *
190 * @details The returned node order matches the basis-function order used by
191 * all evaluators; the coordinates follow the per-topology distribution
192 * described in the class documentation (Reference-node distribution).
193 *
194 * @return Reference node coordinates, one per basis function.
195 */
196 const std::vector<math::Vector<double, 3>>& nodes() const noexcept final { return nodes_; }
197
198 /**
199 * @brief Evaluate Lagrange basis values into caller-provided storage.
200 *
201 * @details This is the low-allocation API intended for element assembly
202 * loops. The span is filled in basis-node order and no vector resizing is
203 * performed.
204 *
205 * @param xi Reference coordinate. Lower-dimensional elements use the active prefix components.
206 * @param values_out Output span with at least size() entries.
207 */
209 std::span<double> values_out) const final;
210
211 /**
212 * @brief Evaluate Lagrange basis gradients into caller-provided storage.
213 *
214 * @details Gradients are written in basis-node order with one
215 * three-component gradient per node.
216 *
217 * @param xi Reference coordinate. Lower-dimensional elements use the active prefix components.
218 * @param gradients_out Output span with at least size() entries.
219 */
221 std::span<Gradient> gradients_out) const final;
222
223 /**
224 * @brief Evaluate Lagrange basis Hessians into caller-provided storage.
225 *
226 * @details Hessians are written in basis-node order with one 3-by-3
227 * Hessian per node.
228 *
229 * @param xi Reference coordinate. Lower-dimensional elements use the active prefix components.
230 * @param hessians_out Output span with at least size() entries.
231 */
233 std::span<Hessian> hessians_out) const final;
234
235private:
237 int dimension_{0};
238 int order_{0};
239
240 // Topology-specific construction data. nodes_ (the reference nodes in basis
241 // order) is populated for every topology and backs size(); each remaining
242 // vector is filled only for the topologies that use it and stays empty
243 // otherwise:
244 // line/quad/hex : nodes_1d_, nodes_1d_weights_, tensor_indices_
245 // triangle/tetra: simplex_exponents_
246 // wedge : nodes_1d_, nodes_1d_weights_, wedge_indices_, and
247 // simplex_exponents_ (the triangle cross-section exponents)
248 // point : nodes_ only
249 std::vector<double> nodes_1d_;
250 std::vector<double> nodes_1d_weights_;
251 std::vector<math::Vector<double, 3>> nodes_;
252 std::vector<TensorNodeIndex> tensor_indices_;
253 std::vector<SimplexExponent> simplex_exponents_;
254 std::vector<WedgeNodeIndex> wedge_indices_;
255
256 void init_nodes();
257 void build_point_nodes();
258 void build_tensor_product_nodes();
259 void build_simplex_nodes();
260 void build_wedge_nodes();
261 void init_tensor_axis_nodes();
262
263 void evaluate_all_to(const math::Vector<double, 3>& xi,
264 std::span<double> values_out,
265 std::span<Gradient> gradients_out,
266 std::span<Hessian> hessians_out) const override;
267 void evaluate_point_to(std::span<double> values_out,
268 std::span<Gradient> gradients_out,
269 std::span<Hessian> hessians_out) const;
270 void evaluate_tensor_product_to(const math::Vector<double, 3>& xi,
271 std::span<double> values_out,
272 std::span<Gradient> gradients_out,
273 std::span<Hessian> hessians_out) const;
274 void evaluate_simplex_to(const math::Vector<double, 3>& xi,
275 std::span<double> values_out,
276 std::span<Gradient> gradients_out,
277 std::span<Hessian> hessians_out) const;
278 void evaluate_wedge_to(const math::Vector<double, 3>& xi,
279 std::span<double> values_out,
280 std::span<Gradient> gradients_out,
281 std::span<Hessian> hessians_out) const;
282};
283
284/** @} */
285
286} // namespace svmp::FE::basis
287
288#endif // SVMP_FE_BASIS_LAGRANGEBASIS_H
Reference-topology vocabulary (BasisTopology) and the internal ElementType/topology/order maps.
Abstract interface for finite-element basis-function families.
Definition BasisFunction.h:166
Nodal Lagrange basis on supported reference finite elements.
Definition LagrangeBasis.h:105
std::size_t size() const noexcept final
Return the number of basis functions and reference nodes.
Definition LagrangeBasis.h:185
int order() const noexcept final
Return the polynomial order represented by this basis.
Definition LagrangeBasis.h:182
std::array< int, 4 > SimplexExponent
Barycentric exponent tuple for simplex reference nodes.
Definition LagrangeBasis.h:111
int dimension() const noexcept final
Return the reference-space dimension of the basis.
Definition LagrangeBasis.h:179
std::array< std::size_t, 3 > TensorNodeIndex
Axis-index tuple for tensor-product reference nodes.
Definition LagrangeBasis.h:108
void evaluate_values_to(const math::Vector< double, 3 > &xi, std::span< double > values_out) const final
Evaluate Lagrange basis values into caller-provided storage.
Definition LagrangeBasis.cpp:578
BasisTopology topology() const noexcept final
Return the reference topology of this basis.
Definition LagrangeBasis.h:176
std::array< std::size_t, 2 > WedgeNodeIndex
Triangle-node and axis-node tuple for wedge reference nodes.
Definition LagrangeBasis.h:114
void evaluate_gradients_to(const math::Vector< double, 3 > &xi, std::span< Gradient > gradients_out) const final
Evaluate Lagrange basis gradients into caller-provided storage.
Definition LagrangeBasis.cpp:584
BasisType basis_type() const noexcept final
Return the concrete basis family.
Definition LagrangeBasis.h:173
void evaluate_hessians_to(const math::Vector< double, 3 > &xi, std::span< Hessian > hessians_out) const final
Evaluate Lagrange basis Hessians into caller-provided storage.
Definition LagrangeBasis.cpp:590
const std::vector< math::Vector< double, 3 > > & nodes() const noexcept final
Return the reference interpolation nodes in basis ordering.
Definition LagrangeBasis.h:196
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
@ Lagrange
Standard nodal Lagrange basis.
Eigen::Matrix< T, static_cast< int >(N), 1 > Vector
Fixed-size column vector for element-level computations.
Definition Vector.h:51