Rodin/Variational/DirichletBC.h file

Essential (Dirichlet) boundary conditions, in two flavours.

Rodin's DirichletBC encodes a strongly-imposed essential constraint on a slave trial function $ u\in V_h^u $ over selected codimension-one mesh facets. With no .on(...) selector, this means the exterior boundary. With attributes, this also includes tagged interior facets such as FSI interfaces. Two flavours share the same template name and the same abstract base Rodin::Variational::DirichletBCBase, separated only by the type of the second argument:

  1. Value-prescribing BCDirichletBC(u, g) with g a FunctionBase (scalar, vector, or matrix-valued):

    \[ u(x) \;=\; g(x), \qquad x \in \Gamma_D. \]

    This is the classical inhomogeneous Dirichlet condition, including the homogeneous case $ g\equiv 0 $ .

  2. Identification BCDirichletBC(u, A(v)) with A(v) a ShapeFunctionBase expression linear in another (trial) shape function $ v\in V_h^v $ :

    \[ u(x) \;=\; A(v)(x), \qquad x \in \Gamma_D, \]

    where $ A $ is any operator producing a ShapeFunctionBase (the identity, a component selection $ v_x $ , a left product $ f\,v $ , a matrix product $ R\,v $ , sums of these, etc.). This is algebraic identification of the two unknowns' boundary DOFs: both sides of the constraint involve degrees of freedom that are still unknown at solve time, not pre-evaluated values.

    The optional three-argument spelling DirichletBC(u, A(v), d) keeps the same linear unknown-dependent part and adds a known defect:

    \[ u(x) \;=\; A(v)(x) + d(x), \qquad x \in \Gamma_D. \]

    This is the form used for exact Newton correction rows such as $ \delta u = A(\delta v) + d $ .

Mathematical model

Let $ V_h^u $ have basis $ \{\varphi_i^u\}_{i=1}^{N_u} $ and dual DOF functionals $ \{\ell_i^u\}_{i=1}^{N_u} $ satisfying $ \ell_i^u(\varphi_k^u) = \delta_{ik} $ . Likewise for $ V_h^v $ .

The DOF functionals are FE-local: for Lagrange they are nodal point evaluations $ \ell_i^u(w) = w(x_i^u) $ , for moment-based or non-nodal elements they are integrals or pairings against dual moments. Both flavours apply the same DOF functional on the slave side; they differ only in what they apply it to.

Value-prescribing. For each slave DOF $ s $ on $ \Gamma_D $

\[ \ell_s^u(u) \;=\; \ell_s^u(g) \quad\Longleftrightarrow\quad u_s = g_s, \]

where $ g_s := \ell_s^u(g) $ . The assembled object is a map $ s \mapsto g_s $ (the Rodin::Variational::DirichletBCBase::ValueDOFs alternative).

Identification. For each slave DOF $ s $ on $ \Gamma_D $ and with $ A $ linear,

\[ \ell_s^u(u) \;=\; \ell_s^u(A(v)) + \ell_s^u(d) \;=\; \sum_j \ell_s^u\!\bigl(A(\varphi_j^v)\bigr)\, v_j + d_s \;=\; \sum_j C_{sj}\, v_j + d_s, \]

with the constraint coefficients

\[ C_{sj} \;:=\; \ell_s^u\!\bigl(A(\varphi_j^v)\bigr), \qquad d_s \;:=\; \ell_s^u(d). \]

The assembled object is a map $ s \mapsto (\{j_k\}, \{C_{s,j_k}\}) $ over the non-zero coefficients (the Rodin::Variational::DirichletBCBase::IdentifiedDOFs alternative), plus an optional defect map for the known $ d_s $ values. The two-argument spelling is exactly the homogeneous case $ d\equiv 0 $ .

For Lagrange + same FES + $ A=\mathrm{id} $ : the dual property gives $ C_{sj}=\delta_{sj} $ , so each slave maps to the same DOF index of $ v $ with coefficient one. For $ A(v)=R(x)\,v $ on a vector FES at a Lagrange node $ x_s $ : $ C_{(s,\alpha),(s,\beta)} = R_{\alpha\beta}(x_s) $ — a multi-master row whose coefficients are exact entries of $ R $ at the slave node.

Exactness, by construction

Slave/master DOF pairings are determined entirely by the selected face and the FES's own connectivity (fes_u.getDOFs(faceDim, fi) and fes_v.getDOFs(faceDim, fi)). There is no geometric search and no tolerance anywhere in the assembly — the FE's DOF-functional contract (fe_u.getLinearForm(s) applied to a callable (Geometry::Point) -> value through the slave-FES pullback) is the only machinery used. Coefficient pruning uses strict c != 0 so that Lagrange-dual-induced sparsity is preserved bit-for-bit.

The identification assembler constructs a pointwise IntegrationPoint from each Geometry::Point and passes it to ShapeFunctionBase::setIntegrationPoint before querying ShapeFunctionBase::getBasis. The pointwise integration point has getQuadratureFormula() == nullptr, which selects direct reference-point evaluation without inventing a single-point quadrature rule. During integration, ShapeFunctionBase::setIntegrationPoint remains the preferred path with a non-null quadrature formula pointer and quadrature index so cached basis tabulations remain available.

Linear-system effect

Problem assembly handles the two flavours differently by visiting the variant returned from DirichletBCBase::getDOFs:

  • For DirichletBCBase::ValueDOFs at slave global index $ g_s $ :

    \[ A_{g_s,g_s} \leftarrow 1, \quad A_{g_s,k} \leftarrow 0 \;\forall k\neq g_s, \quad b_{g_s} \leftarrow g_s\text{ value}, \]

    with the column at $ g_s $ moved to the RHS as $ b_{r} \mathrel{-}= A_{r,g_s}\cdot g_{s} $ before being zeroed according to the current backend's classical essential-BC convention.

  • For DirichletBCBase::IdentifiedDOFs at slave global index $ g_s $ with masters $ \{g_{m_k}\} $ and coefficients $ \{c_k\} $ : define an expansion map

    \[ \operatorname{expand}(i)= \begin{cases} \{(i,1)\}, & i \text{ unconstrained},\\ \{(g_{m_k},c_k)\}_k, & i=g_s. \end{cases} \]

    Every matrix entry $ A_{ij}\mathrel{+}=a $ is assembled as

    \[ A_{r,c}\mathrel{+}= \alpha_r\,a\,\alpha_c \quad\forall(r,\alpha_r)\in\operatorname{expand}(i),\; (c,\alpha_c)\in\operatorname{expand}(j), \]

    and every vector entry $ b_i\mathrel{+}=f $ as

    \[ b_r\mathrel{+}= \alpha_r f \quad\forall(r,\alpha_r)\in\operatorname{expand}(i). \]

    For homogeneous identifications this is the variational transformation

    \[ A \leftarrow T^T A T,\qquad b \leftarrow T^T b. \]

    For affine identifications $ x = T\hat{x}+\hat{d} $ , the known defect also shifts the RHS:

    \[ A \leftarrow T^T A T,\qquad b \leftarrow T^T\!\left(b - A\hat{d}\right). \]

    If slave DOFs remain in the unknown vector, reconstruction rows are then written as

    \[ A_{g_s,g_s}\leftarrow 1,\quad A_{g_s,g_{m_k}}\leftarrow -c_k,\quad b_{g_s}\leftarrow d_{g_s}. \]

Identification mode is not zero-pinning, not row-only replacement, and not merely slave-column redirection. It is appropriate for tied fields, same-face linear identifications, periodic-like identifications, and monolithic FSI kinematic coupling where slave residuals/reactions must be transferred into the master equations.

Boundary specification

.on(attr) (or .on(attr1, attr2, ...)) selects the subset $ \Gamma_D $ from the mesh's codimension-one attribute set. If no attributes are given, only exterior boundary faces are selected; if attributes are given, tagged interior interface faces are selected too. Both slave and master DOFs are read from the same face polytopes — the assembler never matches DOFs across distinct faces (no geometric pairing). For a cross-face periodic relation use Rodin::Variational::PeriodicBC, which takes an explicit DOF adjacency map.

Usage examples

// Homogeneous Dirichlet BC: u = 0 on boundary
auto bc = DirichletBC(u, Zero());

// Inhomogeneous Dirichlet BC on attribute 1
RealFunction g = [](const Point& p) { return sin(p.x()); };
auto bc = DirichletBC(u, g).on(1);

// Identification: pin u on the boundary to v's DOFs
auto bc = DirichletBC(u, v).on(1);

// Identification: u = R(x) v on the boundary
auto bc = DirichletBC(u, R * v).on(1);

// Identification: scalar u equal to vector v's x-component
auto bc = DirichletBC(u, v.x()).on(1);

// Affine identification: u = A(v) + d
auto bc = DirichletBC(u, R * v, d).on(1);

Namespaces

namespace Rodin
The Rodin library for finite element methods and shape optimization.
namespace Rodin::Variational
Module which provides the necessary tools for constructing and solving variational problems.

Classes

template<class Scalar>
class Rodin::Variational::DirichletBCBase
Abstract base class for a Dirichlet boundary condition.
template<class Solution, class FES, class ValueDerived>
class Rodin::Variational::DirichletBC<TrialFunction<Solution, FES>, FunctionBase<ValueDerived>>
Value-prescribing Dirichlet boundary condition, $ u = g $ .
template<class Solution, class FES1, class Derived2, class FES2, ShapeFunctionSpaceType Sp>
class Rodin::Variational::DirichletBC<TrialFunction<Solution, FES1>, ShapeFunctionBase<Derived2, FES2, Sp>>
Identification Dirichlet boundary condition, $ u = A(v) $ or $ u = A(v) + d $ .