In the finite element method, boundary conditions are classified by how they enter the discrete system:
Note Homogeneous Neumann conditions (
$ \partial u / \partial n = 0 $
) are the "default" boundary condition. If no Dirichlet or Neumann condition is imposed on a boundary segment, homogeneous Neumann is automatically satisfied by the weak formulation.
Dirichlet and periodic conditions are structural constraints: Rodin enforces them algebraically in the assembled system. Penalty terms are a different modeling choice. See Numerical contracts" for the shared constraint contract.
@section guides-bc-dirichlet Dirichlet Boundary Conditions
Dirichlet conditions specify the value of the solution on the boundary:
\iline 48 \iline 49 \_form#2077@_fakenl@_fakenl
@subsection guides-bc-dirichlet-homogeneous Homogeneous Dirichlet (@f$ g = 0 @f$)
The most common case sets the solution to zero on the boundary:
@code{.cpp}
Problem problem(u, v);
problem = Integral(Grad(u), Grad(v))
- Integral(f, v)
+ DirichletBC(u, Zero()); // u = 0 on entire boundary
@endcode
@subsection guides-bc-dirichlet-nonhomogeneous Non-Homogeneous Dirichlet
To prescribe a non-zero value:
@code{.cpp}
// Using a constant
DirichletBC(u, RealFunction(1.0))
// Using a spatial function
RealFunction g([](const Geometry::Point& p) {
return p.x() * p.x();
});
DirichletBC(u, g)
@endcode
@subsection guides-bc-dirichlet-partial Partial Boundary Conditions
To apply Dirichlet conditions only on a specific part of the boundary,
use the <tt>.on()</tt> method with a boundary attribute:
@code{.cpp}
// Apply u = 0 only on boundary with attribute 1
DirichletBC(u, Zero()).on(1)
// Apply u = g only on boundary with attribute 2
DirichletBC(u, g).on(2)
// Apply on multiple boundary attributes at once
DirichletBC(u, Zero()).on({1, 3})
@endcode
Boundary attributes are integers associated with boundary elements in
the mesh. They are typically set during mesh generation or loaded from
a mesh file.
@subsection guides-bc-dirichlet-vector Vector Dirichlet Conditions
For vector-valued problems (e.g., elasticity), use vector functions:
@code{.cpp}
// Fix displacement to zero (clamped boundary)
DirichletBC(u, VectorFunction{0, 0}).on(GammaD)
// Prescribe a specific displacement
VectorFunction prescribed{0.1, 0};
DirichletBC(u, prescribed).on(GammaD)
@endcode
@section guides-bc-neumann Neumann Boundary Conditions
Neumann conditions prescribe the normal derivative (or flux) on the
boundary:
\iline 115 \iline 116 \_form#2078@_fakenl@_fakenl
These arise naturally from integration by parts in the weak formulation
and appear as <strong>boundary integrals</strong>:
@code{.cpp}
// \int_\GammaN g v ds
BoundaryIntegral(g, v).over(GammaN)
@endcode
@subsection guides-bc-neumann-example Example: Neumann on One Side
@code{.cpp}
int GammaD = 1; // Dirichlet boundary
int GammaN = 2; // Neumann boundary
RealFunction g = 1.0; // Prescribed flux
Problem problem(u, v);
problem = Integral(Grad(u), Grad(v))
- Integral(f, v)
- BoundaryIntegral(g, v).over(GammaN)
+ DirichletBC(u, Zero()).on(GammaD);
@endcode
@subsection guides-bc-neumann-natural Homogeneous Neumann (Natural)
Homogeneous Neumann conditions ( \_form#2076) are
the "default" — they are automatically satisfied when no boundary integral
is added and no Dirichlet condition is imposed on that part of the boundary.
@subsection guides-bc-neumann-vector Vector Neumann (Traction)
In elasticity, a Neumann condition corresponds to an applied traction
(force per unit area). The traction vector \_form#2079 is
prescribed on the loaded boundary:
@code{.cpp}
VectorFunction traction{0, -1}; // Downward pull
Problem elasticity(u, v);
elasticity = LinearElasticityIntegral(u, v)(lambda, mu)
- BoundaryIntegral(traction, v).over(GammaN)
+ DirichletBC(u, VectorFunction{0, 0}).on(GammaD);
@endcode
@section guides-bc-periodic Periodic Boundary Conditions
Periodic conditions enforce that the solution on one boundary equals the
solution on the opposite boundary. They are used for problems on domains
that tile (e.g. unit cells in homogenization):
\iline 169 \iline 170 \iline 171 \_form#2080@_fakenl@_fakenl@_fakenl
In Rodin, periodic conditions are imposed by building an <tt>IndexMap</tt> that
pairs the DOF indices on opposite boundaries, then passing it to
<tt>PeriodicBC</tt>:
@code{.cpp}
const size_t n = 200;
Mesh mesh;
mesh = mesh.UniformGrid(Polytope::Type::Triangle, { n, n });
mesh.getConnectivity().compute(1, 2);
mesh.scale(1.0 / (n - 1));
mesh.scale(2 * M_PI); // Scale to [0, 2π]^2
P1 vh(mesh);
// Build DOF correspondence: left ↔ right, bottom ↔ top
IndexMap<IndexSet> dofs;
for (Index i = 0; i < vh.getSize(); i += n)
dofs[i].insert(i + n - 1); // left ↔ right
for (Index i = 0; i < n; i++)
dofs[i].insert(i + n * (n - 1)); // bottom ↔ top
TrialFunction u(vh);
TestFunction v(vh);
Problem problem(u, v);
problem = Integral(Grad(u), Grad(v))
- Integral(f, v)
+ PeriodicBC(u, dofs);
@endcode
See the @ref examples-pdes-periodic "periodic Poisson example" for a
complete walkthrough.
@section guides-bc-mixed Mixed Boundary Conditions
In practice, different parts of the boundary often have different
conditions. For example, in elasticity:
@code{.cpp}
int GammaD = 1; // Clamped (fixed) boundary
int GammaN = 2; // Loaded boundary
// Remaining boundary: traction-free (homogeneous Neumann)
VectorFunction load{0, -1}; // Downward force
Problem elasticity(u, v);
elasticity = LinearElasticityIntegral(u, v)(lambda, mu)
- BoundaryIntegral(load, v).over(GammaN)
+ DirichletBC(u, VectorFunction{0, 0}).on(GammaD);
@endcode
@section guides-bc-complete Complete Example
Here is a complete example with mixed boundary conditions:
@code{.cpp}
#include <Rodin/Solver.h>
#include <Rodin/Geometry.h>
#include <Rodin/Variational.h>
#include <Rodin/IO/XDMF.h>
using namespace Rodin;
using namespace Rodin::Geometry;
using namespace Rodin::Variational;
int main()
{
Mesh mesh;
mesh = mesh.UniformGrid(Polytope::Type::Triangle, {16, 16});
mesh.getConnectivity().compute(1, 2);
P1 Vh(mesh);
TrialFunction u(Vh);
TestFunction v(Vh);
RealFunction f = 1;
Problem problem(u, v);
problem = Integral(Grad(u), Grad(v))
- Integral(f, v)
+ DirichletBC(u, Zero());
Solver::CG(problem).solve();
// Export to XDMF
IO::XDMF xdmf("BoundaryConditions");
xdmf.grid().setMesh(mesh).add("u", u.getSolution());
xdmf.write();
return 0;
}
@endcode
@section guides-bc-summary Summary Table
<table class="markdownTable">
<tr class="markdownTableHead"> <th class="markdownTableHeadNone"> Type