Elliptic PDE Solving Methods
Ground truth for the stationary finite-difference path. Elliptic problems have no time variable, so the boundary conditions are the problem: the solution is the direct solve of
\[ -\mathcal{T} u + \rho(x) u = f \]
rather than a backward march from terminal data. Here T is the transport
operator built from Transport<N> and \(\rho\) is the reaction coefficient.
Relationship to the time-dependent contract
The parabolic and elliptic paths share the spatial discretization in
finite_difference/discretization.rs. Both consume DimensionKind to select
a stencil and Transport<N> to supply the per-dimension plus/minus
coefficients and local source. They differ only in the outer solve strategy:
PdeProblem<N>marches backward in time.EllipticProblem<N>assembles the operator once and solves it directly.
This keeps the stencils in one place while making the stationary strategy
explicit. The stationary work lives inside finite_difference, not as a
sibling module.
Elliptic problem contract
EllipticProblem<N> supplies:
dimension_kind(dim): the stencil kind for coordinatedim.transport(state, derivs): the plus/minus transport coefficients. The returnedsourceis ignored by the elliptic assembler; forcing belongs inrhs.rhs(state): the forcingf.reaction(state): a local zero-order coefficient added to the diagonal.boundary_conditions(): per-dimension lower and upper conditions.
The operator is assembled as
\[ -\sum_i \big[ a_i^{+} (u_{i,+} - u) + a_i^{-} (u_{i,-} - u) \big] + \rho(x)\, u = f(x), \]
where \(\rho\) is the reaction term. The negative sign follows the standard
elliptic convention: for diffusion coefficient \(D\), \(T u = D u''\) and the
problem reads \(-D u'' + \rho u = f\). The same DimensionKind stencil table as
in solver_pde.md is used for \(a_i^{+}\) and \(a_i^{-}\).
Elliptic control problem contract
For infinite-horizon stochastic control, the solver consumes
EllipticControlProblem<N>, which extends
crate::models::control::ControlProblem<N> with the same transport
/discretization data. Its stationary HJB equation is
\[ 0 = \sup_u \lbrace f(x,u) + \mathcal{L}^u V - r V \rbrace. \]
After optimizing over u, the equation is assembled in the same form as the
pure elliptic problem:
\[ -\mathcal{T}^{u^*} V + r V = s^{u^*}, \]
where \(T V + s = \sup_u \lbrace f + \mathcal{L}^u V \rbrace\). The transport
method returns plus, minus, and source = s; the discount \(r\) becomes
the reaction diagonal.
StationarySolver::solve_control performs policy iteration:
- Compute derivatives of the current value field.
- Optimize the control at every node.
- Assemble the operator and right-hand side from the optimized transport.
- Solve the linear system.
- Repeat until the value function stops changing.
The pure EllipticProblem path uses rhs for the forcing and ignores
Transport::source; the control path uses Transport::source as the
right-hand side.
Boundary conditions
BoundaryCondition is defined in discretization.rs:
Dirichlet(value): \(u = \text{value}\).Neumann(value): \(du/dx = \text{value}\), with the derivative taken along the increasing coordinate direction \(x\), not an outward normal.Robin { value, alpha, beta }: \(\alpha u + \beta\, du/dx = \text{value}\).
BoundaryConditions<N> bundles the lower and upper conditions for every
dimension. It defaults to Neumann(0) on every side.
Boundary condition implementation status
| Condition | Assembler support |
|---|---|
Dirichlet(value) | Implemented |
Neumann(value) | Implemented via ghost points |
Robin { value, alpha, beta } | Implemented via ghost points for beta != 0 |
Solution strategies
StationarySolver assembles a sparse CSR operator and solves it:
- 1D problems use the tridiagonal LAPACK solve.
- N-dimensional problems use successive over-relaxation.
Dirichlet conditions replace the boundary row with the identity. Neumann and
Robin conditions use a ghost point. The missing neighbour coefficient is
folded into the existing interior neighbour and produces a right-hand-side (and
diagonal, for Robin) correction. The derivative in Neumann and Robin is
taken along the increasing coordinate direction \(x\).
Reference problems
The implementation is validated against closed forms in
solver/tests/elliptic_benchmarks.rs (pure elliptic) and
solver/tests/elliptic_control.rs (the control path). The exact solutions
are stated once in Exact Solutions to PDEs; the
problems are:
- 1D Laplace (Dirichlet), Poisson, and reaction-diffusion;
- 2D Poisson with separable forcing;
- 1D Laplace with Neumann and Robin lower boundaries.
These six problems cover constant, polynomial, separable multi-dimensional, reaction-dominated, Neumann, and Robin boundary behaviour, and verify that the assembler solves the bare elliptic operator \(-\mathcal{T} u + \rho u = f\) rather than an identity-shifted operator.
The control path is validated against the stationary (algebraic Riccati) LQ solution in Exact Solutions in Stochastic Optimal Control, with \(a = -1\), \(b = 1\), \(q = r = 1\), \(\rho = 0.1\), and \(c = 0\). Dirichlet boundary conditions match the exact value at the grid endpoints, so the test isolates the interior operator and the policy-iteration loop.