pub enum BoundaryCondition<T: Clone> {
Show 19 variants
FixedValue(T),
FixedField(Field<T>),
ZeroGradient,
FixedGradient(T),
Mixed {
value_fraction: f64,
ref_value: T,
ref_grad: T,
},
MixedField {
value_fraction: Field<f64>,
ref_value: Field<T>,
ref_grad: Field<T>,
},
InletOutlet {
inlet_value: T,
},
OutletInlet {
outlet_value: T,
},
Symmetry,
Slip,
NoSlip,
Wedge,
Empty,
Calculated(Field<T>),
Freestream {
freestream_value: T,
},
PressureInletOutletVelocity,
FixedFluxPressure {
gradient: T,
},
TotalPressure {
p0: T,
},
FlowRateInletVelocity {
volumetric_flow_rate: f64,
},
}Expand description
Boundary condition variant for a single patch.
Covers the patch-field boundary conditions ported from OpenFOAM’s
finiteVolume/fields/fvPatchFields. The set is closed and dispatched by
enum (no dyn), so adding a variant forces every exhaustive match site to
be updated — the compiler flags each one.
§Units
The variants are unit-agnostic in T: T is whatever the field stores
(f64 for a scalar field, Vector3 for a vector field, …). Where a
variant stores a gradient (FixedGradient, Mixed::ref_grad) the value
is a normal gradient in units of field-value per metre ([T]·m⁻¹), because
the boundary face value is reconstructed as cell_value + gradient · delta
with delta the owner-cell-centre-to-face distance in metres.
§Status
The FixedGradient, Mixed, InletOutlet, OutletInlet, Slip,
NoSlip, and Wedge variants (added 2026-08-04) are an untrusted
AI-assisted draft pending human V&V review — verified against
analytic/limiting cases (see the vv_* tests) but not yet human-reviewed.
Wedge in particular is a zero-gradient stand-in, not the full rotation.
The flow-context variants Freestream, PressureInletOutletVelocity,
FixedFluxPressure, TotalPressure, and FlowRateInletVelocity (added
2026-08-04, Wave 4) are likewise an untrusted AI-assisted draft pending
human V&V review — verified against analytic/definition cases (the vv_*
tests) but not yet human-reviewed. Freestream is self-contained
(flux-switched by the convection operator like InletOutlet); the other
four are solver-driven — they depend on context the per-face BC update
cannot supply on its own (PressureInletOutletVelocity and
FixedFluxPressure on the face flux / momentum-predictor flux,
TotalPressure on the patch velocity and density, FlowRateInletVelocity
on the patch-area integral), so the solver must refresh their stored face
values / gradient each iteration through the documented update_* /
*_value hooks below rather than the BC hard-coding a wrong value.
Variants§
FixedValue(T)
Dirichlet: fixed uniform value.
OpenFOAM: fixedValueFvPatchField.
FixedField(Field<T>)
Dirichlet: fixed per-face values.
OpenFOAM: fixedValueFvPatchField (non-uniform list form).
ZeroGradient
Neumann: zero normal gradient — boundary face value = internal adjacent value.
OpenFOAM: zeroGradientFvPatchField.
FixedGradient(T)
Neumann with a prescribed non-zero normal gradient g ([T]·m⁻¹).
The boundary face value is φ_face = φ_cell + g · delta, where delta
[m] is the owner-cell-centre-to-face-centre distance. Reduces to
ZeroGradient when g = 0.
OpenFOAM: fixedGradientFvPatchField
(src/finiteVolume/fields/fvPatchFields/derived/fixedGradient/fixedGradientFvPatchField.H).
Mixed
Robin / mixed boundary condition — a per-face blend of a Dirichlet part
(fixedValue, weight value_fraction) and a Neumann part
(fixedGradient, weight 1 - value_fraction).
With w = value_fraction ∈ [0, 1], delta [m] the cell-to-face
distance, φ_c the owner cell value:
- face value:
φ_face = w·ref_value + (1 - w)·(φ_c + ref_grad·delta) - it reduces to
FixedValue(ref_value)atw = 1and toFixedGradient(ref_grad)atw = 0.
This is the general form underlying every value/gradient-blending BC, including the albedo / Robin condition used in neutron diffusion.
value_fraction— dimensionless weight in[0, 1].ref_value— the Dirichlet reference value ([T]).ref_grad— the Neumann reference normal gradient ([T]·m⁻¹).
OpenFOAM: mixedFvPatchField
(src/finiteVolume/fields/fvPatchFields/basic/mixed/mixedFvPatchField.H).
Fields
ref_value: TDirichlet reference value ([T]).
ref_grad: TNeumann reference normal gradient ([T]·m⁻¹).
MixedField
Robin / mixed boundary condition with per-face coefficients — the
non-uniform counterpart of Mixed.
Same algebra, face by face: with w = value_fraction[i], delta the
owner-cell-to-face distance of face i and φ_c the owner cell value,
φ_face[i] = w·ref_value[i] + (1 − w)·(φ_c + ref_grad[i]·delta)§When the uniform form will not do
A Robin coefficient is rarely constant along a patch, because it is built
from quantities that are not: the cell-to-face distance on a graded mesh,
a heat-transfer coefficient that tracks the local flow, or — the case
this was added for — a neutron albedo, whose weight
w = (γ·delta/D)/(1 + γ·delta/D) carries both the local mesh spacing and
the local diffusion coefficient. Collapsing that to one number per patch
is an approximation, and an unquantified one, which is exactly what a
code-to-code comparison must not contain.
All three fields are sized to the patch. Use Mixed when
the coefficients genuinely are uniform; it is cheaper and reads better.
OpenFOAM: mixedFvPatchField with non-uniform valueFraction.
Fields
InletOutlet
Flux-switched inflow/outflow BC: behaves as
FixedValue(inlet_value) on inflow faces and
ZeroGradient on outflow faces.
The switch is decided per face by the sign of the outward face flux
φ_f = U·S_f [m³·s⁻¹]: φ_f < 0 is inflow (fixed value), φ_f ≥ 0 is
outflow (zero gradient). Equivalent to a Mixed BC whose
value_fraction is set to 1 on inflow and 0 on outflow. The flux is
supplied by the convection operator at assembly time, so this variant is
only flux-switched inside operators that carry phi.
OpenFOAM: inletOutletFvPatchField
(src/finiteVolume/fields/fvPatchFields/derived/inletOutlet/inletOutletFvPatchField.H).
Fields
inlet_value: TValue imposed on inflow faces ([T]).
OutletInlet
Flux-switched outflow/inflow BC — the opposite of
InletOutlet: FixedValue(outlet_value)
on outflow faces (φ_f ≥ 0) and ZeroGradient
on inflow faces (φ_f < 0).
OpenFOAM: outletInletFvPatchField
(src/finiteVolume/fields/fvPatchFields/derived/outletInlet/outletInletFvPatchField.H).
Fields
outlet_value: TValue imposed on outflow faces ([T]).
Symmetry
Symmetry plane — normal component zeroed.
OpenFOAM: symmetryFvPatchField.
Slip
Free-slip wall: the wall-normal component of a vector field is removed
(as for Symmetry) while the tangential component is
zero-gradient. For a scalar field it is exactly zero-gradient.
See BoundaryCondition::<Vector3>::slip_face_value for the exact
vector reconstruction.
OpenFOAM: slipFvPatchField
(src/finiteVolume/fields/fvPatchFields/derived/slip/slipFvPatchField.H).
NoSlip
No-slip wall for velocity: a fixedValue of zero. Semantically it is
FixedValue(T::zero) specialised to walls; the
stored patch values are all zero.
OpenFOAM: noSlipFvPatchField
(src/finiteVolume/fields/fvPatchFields/derived/noSlip/noSlipFvPatchField.H).
Wedge
Axisymmetric wedge patch (wedgeFvPatchField).
First-pass simplification (Layer-1): treated as zero-gradient — the patch face value equals the adjacent internal cell value. A full wedge BC rotates the patch-internal field onto the wedge face about the geometric axis (pairing across the wedge like a cyclic); that rotation is not yet implemented here. The zero-gradient stand-in is exact only for a field that is uniform in the wedge (azimuthal) direction. Do not treat wedge results as validated until the rotation transform lands.
OpenFOAM: wedgeFvPatchField
(src/finiteVolume/fields/fvPatchFields/constraint/wedge/wedgeFvPatchField.H).
Empty
2-D / empty — zero-area faces; value has no physical meaning.
OpenFOAM: emptyFvPatchField.
Calculated(Field<T>)
Value computed by the solver and stored here (read-only from BC side).
OpenFOAM: calculatedFvPatchField.
Freestream
Freestream (far-field) inflow/outflow BC — an InletOutlet
specialised to external / far-field flow: it imposes the uniform
freestream value on inflow faces and is ZeroGradient
on outflow faces, switched per face by the sign of the outward face
flux φ_f = U·S_f [m³·s⁻¹] (φ_f < 0 inflow, φ_f ≥ 0 outflow).
For a velocity field freestream_value is the far-field velocity U_∞
[m·s⁻¹]; for a scalar it is the far-field scalar value ([T]). It is
self-contained: the flux is supplied by the convection operator at
assembly time, exactly like InletOutlet, so no
solver hook is needed. See flux_value_fraction
/ flux_ref_value.
OpenFOAM: freestreamFvPatchField
(src/finiteVolume/fields/fvPatchFields/derived/freestream/freestreamFvPatchField.H),
which derives from inletOutletFvPatchField with inletValue = freestreamValue.
Fields
freestream_value: TFar-field freestream value imposed on inflow faces ([T]; for a
velocity field, m·s⁻¹).
PressureInletOutletVelocity
Velocity BC for a pressure-driven inlet/outlet patch: the patch velocity
is reconstructed from the face flux φ_f [m³·s⁻¹] and the face area.
On outflow (φ_f ≥ 0) it is ZeroGradient; on
inflow (φ_f < 0) it imposes the flux-implied wall-normal velocity
U = (φ_f / |S_f|)·n̂ [m·s⁻¹], where n̂ = S_f/|S_f| is the unit outward
face normal. (OpenFOAM sets valueFraction = 1 − pos0(φ_f), i.e.
fixedValue on inflow and zeroGradient on outflow; the imposed value is
the normal velocity above, the tangential component taken as zero here —
OpenFOAM’s optional tangentialVelocity is not modelled.)
The per-face imposed velocity depends on the flux and face geometry, which
a value-only variant cannot carry, so this variant is solver-driven:
the solver refreshes PatchField::values each iteration via
PatchField::update_pressure_inlet_outlet_velocity, and the convection
operator additionally flux-switches it per face
(flux_value_fraction returns the inflow/
outflow weight). The pure per-face formula is
pressure_inlet_outlet_velocity_value.
OpenFOAM: pressureInletOutletVelocityFvPatchVectorField.
FixedFluxPressure
Pressure BC that fixes the surface-normal pressure gradient snGrad(p)
[Pa·m⁻¹] so the pressure-corrected face flux matches a target flux — the
natural wall / outlet pressure condition in a PISO/PIMPLE pressure solve.
It behaves as a FixedGradient(gradient) whose
gradient the solver sets each pressure solve from the flux mismatch:
snGrad(p) = (φ_HbyA − φ_target) / (D_p · |S_f|)
where φ_HbyA [m³·s⁻¹] is the momentum-predictor (H/A) face flux,
φ_target [m³·s⁻¹] the desired boundary flux, D_p [m³·s·kg⁻¹] the
face-interpolated rAU (interpolated 1/A_p from the momentum-matrix
diagonal, which absorbs any body-force term folded into H/A), and |S_f|
[m²] the face area. The gradient is solver-set because it needs the
predictor flux and the rAU field, which this Layer does not own. See
fixed_flux_pressure_sn_grad
for the pure formula. The stored gradient is uniform over the patch
(matching FixedGradient); the diffusion and
snGrad operators consume it as a prescribed normal gradient.
OpenFOAM: fixedFluxPressureFvPatchScalarField.
Fields
gradient: TCurrently-set surface-normal pressure gradient snGrad(p) [Pa·m⁻¹],
uniform over the patch.
TotalPressure
Total-pressure (stagnation-pressure) inlet/outlet BC: the static boundary
pressure is set from a fixed total pressure p0 and the local dynamic
head. Incompressible form:
p = p0 − 0.5·ρ·|U|²
with p, p0 in Pa, ρ in kg·m⁻³, |U| in m·s⁻¹. At rest (|U| = 0)
it reduces to FixedValue(p0). The compressible
(subsonic) form p = p0 (1 + ((γ−1)/2)·M²)^(−γ/(γ−1)) is deferred.
This needs the velocity magnitude and density at the patch — a
cross-field dependency a per-face BC update cannot supply on its own — so
this variant is solver-driven: the solver refreshes
PatchField::values every iteration via
PatchField::update_total_pressure (which reads p0 from this variant
and applies
total_pressure_value).
At assembly time it acts as a FixedValue holding the
last-computed face pressure.
OpenFOAM: totalPressureFvPatchScalarField.
Fields
p0: TFixed total (stagnation) pressure p0 [Pa].
FlowRateInletVelocity
Uniform inlet-velocity BC scaled to a prescribed volumetric flow rate:
the whole patch is given a uniform velocity directed into the domain
whose magnitude makes the patch-integral volumetric flux equal Q:
U = −(Q / A_patch)·n̂, A_patch = Σ_f |S_f|
with U in m·s⁻¹, Q in m³·s⁻¹, A_patch in m², n̂ = S_f/|S_f| the
unit outward face normal (so −n̂ points into the domain). The patch-area
integral comes from the mesh, so this variant is geometry/solver-driven:
the per-face values are filled from the patch face-area vectors by
PatchField::update_flow_rate_inlet_velocity (the fixed quantity is the
rate Q; the resulting velocity depends on the patch area). At assembly it
acts as a FixedValue inlet. Per-face formula:
flow_rate_inlet_velocity_value.
Only the volumetric form is modelled; the mass-flow form
U = −(ṁ / (ρ·A))·n̂ is obtained by passing Q = ṁ/ρ.
OpenFOAM: flowRateInletVelocityFvPatchVectorField.
Implementations§
Source§impl<T: Clone + Default> BoundaryCondition<T>
impl<T: Clone + Default> BoundaryCondition<T>
Sourcepub fn is_fixed_value(&self) -> bool
pub fn is_fixed_value(&self) -> bool
True if the BC imposes a value (Dirichlet-like) unconditionally.
Flux-switched BCs (InletOutlet /
OutletInlet) are not counted here because
whether they impose a value depends on the per-face flux; use
flux_value_fraction for those.
Source§impl<T: Clone> BoundaryCondition<T>
impl<T: Clone> BoundaryCondition<T>
Sourcepub fn flux_value_fraction(&self, phi_f: f64) -> Option<f64>
pub fn flux_value_fraction(&self, phi_f: f64) -> Option<f64>
Value fraction (1 ⇒ acts as fixedValue, 0 ⇒ acts as
zeroGradient) for a flux-switched BC, given the outward face flux
phi_f = U·S_f [m³·s⁻¹].
Returns None for BCs that are not flux-switched. The sign convention
matches OpenFOAM’s inletOutlet/outletInlet: phi_f < 0 is inflow,
phi_f ≥ 0 is outflow.
use outram_foam_basic_lib::fields::boundary::bc::BoundaryCondition;
let io = BoundaryCondition::InletOutlet { inlet_value: 5.0_f64 };
assert_eq!(io.flux_value_fraction(-1.0), Some(1.0)); // inflow -> fixedValue
assert_eq!(io.flux_value_fraction( 1.0), Some(0.0)); // outflow -> zeroGradient
assert_eq!(BoundaryCondition::ZeroGradient::<f64>.flux_value_fraction(1.0), None);Sourcepub fn flux_ref_value(&self) -> Option<&T>
pub fn flux_ref_value(&self) -> Option<&T>
The reference (Dirichlet) value of a flux-switched BC, if it has one.
Returns the inlet value for InletOutlet, the
outlet value for OutletInlet, and None
otherwise.
Source§impl BoundaryCondition<f64>
impl BoundaryCondition<f64>
Sourcepub fn total_pressure_value(p0: f64, rho: f64, u_mag: f64) -> f64
pub fn total_pressure_value(p0: f64, rho: f64, u_mag: f64) -> f64
Incompressible total-pressure face value: p = p0 − 0.5·ρ·|U|².
Physical quantity: the static pressure [Pa] imposed on a
TotalPressure patch given a fixed total
(stagnation) pressure and the local dynamic head.
p0— fixed total (stagnation) pressure[Pa].rho— density at the patch face[kg·m⁻³](ρ ≥ 0).u_mag— velocity magnitude|U|at the patch face[m·s⁻¹](≥ 0).
Returns the static pressure [Pa]. Reduces to p0 at u_mag = 0. The
compressible (subsonic) form is deferred — see the
TotalPressure docs.
use outram_foam_basic_lib::fields::boundary::bc::BoundaryCondition;
// At rest the static pressure equals the total pressure.
assert!((BoundaryCondition::total_pressure_value(1.0e5, 1.2, 0.0) - 1.0e5).abs() < 1e-6);
// Moving: p = 1e5 − 0.5·1.2·10² = 1e5 − 60.
assert!((BoundaryCondition::total_pressure_value(1.0e5, 1.2, 10.0) - (1.0e5 - 60.0)).abs() < 1e-6);Sourcepub fn fixed_flux_pressure_sn_grad(
phi_hbya: f64,
phi_target: f64,
dp: f64,
mag_sf: f64,
) -> f64
pub fn fixed_flux_pressure_sn_grad( phi_hbya: f64, phi_target: f64, dp: f64, mag_sf: f64, ) -> f64
Surface-normal pressure gradient for a
FixedFluxPressure face:
snGrad(p) = (φ_HbyA − φ_target) / (D_p · |S_f|) [Pa·m⁻¹]
chosen so the pressure-corrected face flux
φ = φ_HbyA − D_p·snGrad(p)·|S_f| equals the target flux φ_target.
phi_hbya— momentum-predictor (H/A) face fluxφ_HbyA[m³·s⁻¹](already includes any body-force term folded intoH/A).phi_target— desired boundary face fluxφ_target[m³·s⁻¹].dp— face-interpolatedrAUcoefficientD_p[m³·s·kg⁻¹].mag_sf— face area|S_f|[m²].
Returns 0.0 for a degenerate D_p·|S_f| ≈ 0.
use outram_foam_basic_lib::fields::boundary::bc::BoundaryCondition;
let (phi_hbya, phi_target, dp, mag_sf) = (0.30_f64, 0.20, 0.5, 2.0);
let g = BoundaryCondition::fixed_flux_pressure_sn_grad(phi_hbya, phi_target, dp, mag_sf);
// Reconstructed corrected flux reproduces the target.
let phi = phi_hbya - dp * g * mag_sf;
assert!((phi - phi_target).abs() < 1e-12);Source§impl BoundaryCondition<Vector3>
impl BoundaryCondition<Vector3>
Sourcepub fn slip_face_value(internal: Vector3, unit_normal: Vector3) -> Vector3
pub fn slip_face_value(internal: Vector3, unit_normal: Vector3) -> Vector3
Free-slip face value for a vector field: the wall-normal component is removed and the tangential component is kept (a zero-gradient projection onto the wall plane).
φ_face = φ_internal − n̂ (φ_internal · n̂), where n̂ is the unit
outward face normal (dimensionless) and φ_internal is the adjacent
cell value. After this projection φ_face · n̂ = 0 to rounding.
use outram_foam_basic_lib::fields::boundary::bc::BoundaryCondition;
use outram_foam_basic_lib::primitives::Vector3;
let internal = Vector3::new(3.0, 4.0, 0.0);
let n = Vector3::new(1.0, 0.0, 0.0); // wall normal along +x
let v = BoundaryCondition::slip_face_value(internal, n);
assert!(v.x.abs() < 1e-15); // normal component removed
assert!((v.y - 4.0).abs() < 1e-15); // tangential component preservedSourcepub fn pressure_inlet_outlet_velocity_value(
phi_f: f64,
area_vector: Vector3,
) -> Vector3
pub fn pressure_inlet_outlet_velocity_value( phi_f: f64, area_vector: Vector3, ) -> Vector3
Flux-implied wall-normal velocity for a
PressureInletOutletVelocity face:
U = (φ_f / |S_f|)·n̂ with n̂ = S_f/|S_f|.
Physical quantity: a velocity [m·s⁻¹] parallel to the face normal whose
signed magnitude is φ_f/|S_f| — pointing into the domain when
φ_f < 0 (inflow), out when φ_f > 0. The tangential component is
zero (OpenFOAM’s optional tangentialVelocity is not modelled).
phi_f— outward face fluxφ_f = U·S_f[m³·s⁻¹].area_vector— the face area vectorS_f = |S_f| n̂[m²].
Returns Vector3::ZERO for a degenerate zero-area face.
use outram_foam_basic_lib::fields::boundary::bc::BoundaryCondition;
use outram_foam_basic_lib::primitives::Vector3;
let sf = Vector3::new(2.0, 0.0, 0.0); // area 2 m², normal +x
let u = BoundaryCondition::pressure_inlet_outlet_velocity_value(3.0, sf);
assert!((u.x - 1.5).abs() < 1e-15); // |U| = φ_f/|S_f| = 3/2
assert!(u.y.abs() < 1e-15 && u.z.abs() < 1e-15); // purely normalSourcepub fn flow_rate_inlet_velocity_value(
q: f64,
area_patch: f64,
area_vector: Vector3,
) -> Vector3
pub fn flow_rate_inlet_velocity_value( q: f64, area_patch: f64, area_vector: Vector3, ) -> Vector3
Uniform inlet velocity for a
FlowRateInletVelocity face given the
prescribed volumetric flow rate and the patch-area integral:
U = −(Q / A_patch)·n̂, n̂ = S_f/|S_f|.
Physical quantity: an inlet velocity [m·s⁻¹] of magnitude Q/A_patch
directed into the domain (opposite the outward normal).
q— prescribed volumetric flow rateQ[m³·s⁻¹](positive = inflow).area_patch— patch-area integralA_patch = Σ_f |S_f|[m²].area_vector— this face’s area vectorS_f[m²].
Returns Vector3::ZERO for a degenerate zero-area face or patch.
use outram_foam_basic_lib::fields::boundary::bc::BoundaryCondition;
use outram_foam_basic_lib::primitives::Vector3;
// Q = 4 m³/s through a patch of area 2 m², face normal +x.
let sf = Vector3::new(1.0, 0.0, 0.0);
let u = BoundaryCondition::flow_rate_inlet_velocity_value(4.0, 2.0, sf);
assert!((u.x + 2.0).abs() < 1e-15); // U = −(4/2) x̂ = −2 x̂ (inward)