Skip to main content

outram_foam_basic_lib/fields/boundary/
bc.rs

1// SPDX-License-Identifier: GPL-3.0-only
2// Copyright (C) 2026 OUTRAM PARK contributors
3// Derived from OpenFOAM (www.openfoam.com)
4// Copyright (C) 2004-2023 OpenFOAM Foundation
5// Copyright (C) 2016-2023 OpenCFD Ltd.
6//
7// This file is part of OUTRAM PARK.
8//
9// OUTRAM PARK is free software: you can redistribute it and/or modify it
10// under the terms of the GNU General Public License as published by the
11// Free Software Foundation, either version 3 of the License, or (at your
12// option) any later version.
13//
14// OUTRAM PARK is distributed in the hope that it will be useful, but
15// WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17// General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License along
20// with OUTRAM PARK.  If not, see <https://www.gnu.org/licenses/>.
21
22use crate::fields::field::Field;
23use crate::primitives::{SymmTensor, Tensor, Vector3};
24
25/// Boundary condition variant for a single patch.
26///
27/// Covers the BC types required by the target solvers.  More exotic types
28/// (inlet-outlet, total pressure, etc.) will be added when Layer 3 is
29/// implemented.
30#[derive(Debug, Clone)]
31pub enum BoundaryCondition<T: Clone> {
32    /// Dirichlet: fixed uniform value.
33    FixedValue(T),
34    /// Dirichlet: fixed per-face values.
35    FixedField(Field<T>),
36    /// Neumann: zero normal gradient — boundary face value = internal adjacent value.
37    ZeroGradient,
38    /// Symmetry plane — normal component zeroed.
39    Symmetry,
40    /// 2-D / wedge — zero-area faces; value has no physical meaning.
41    Empty,
42    /// Value computed by the solver and stored here (read-only from BC side).
43    Calculated(Field<T>),
44}
45
46impl<T: Clone + Default> BoundaryCondition<T> {
47    /// True if the BC imposes a value (Dirichlet-like).
48    pub fn is_fixed_value(&self) -> bool {
49        matches!(self, Self::FixedValue(_) | Self::FixedField(_))
50    }
51}
52
53/// Boundary field for one patch: the BC type plus the current face values.
54///
55/// The `values` field always holds the latest face values (updated by
56/// `update_coeffs` in Layer 3 operators).  For `FixedValue`/`FixedField` the
57/// values are set at construction and never change.  For `ZeroGradient` and
58/// `Calculated` they are written by the operator code.
59#[derive(Debug, Clone)]
60pub struct PatchField<T: Clone> {
61    /// The boundary condition applied on this patch.
62    pub bc: BoundaryCondition<T>,
63    /// Current face values for this patch (length == patch.size).
64    pub values: Field<T>,
65}
66
67impl PatchField<f64> {
68    /// Dirichlet patch holding a uniform scalar `v` on all `size` faces.
69    pub fn fixed_value(size: usize, v: f64) -> Self {
70        Self {
71            bc: BoundaryCondition::FixedValue(v),
72            values: Field::uniform(size, v),
73        }
74    }
75
76    /// Zero-gradient (Neumann) scalar patch of `size` faces; values default to
77    /// `0.0` and are overwritten by the operator that owns them.
78    pub fn zero_gradient(size: usize) -> Self {
79        Self {
80            bc: BoundaryCondition::ZeroGradient,
81            values: Field::zeros(size),
82        }
83    }
84
85    /// Empty (zero-area) scalar patch — no faces, no physical value.
86    pub fn empty() -> Self {
87        Self {
88            bc: BoundaryCondition::Empty,
89            values: Field::new(vec![]),
90        }
91    }
92}
93
94impl PatchField<Vector3> {
95    /// Dirichlet patch holding a uniform `Vector3` value `v` on all `size` faces.
96    pub fn fixed_value_vec(size: usize, v: Vector3) -> Self {
97        Self {
98            bc: BoundaryCondition::FixedValue(v),
99            values: Field::uniform(size, v),
100        }
101    }
102
103    /// Zero-gradient (Neumann) vector patch of `size` faces; values default to
104    /// `Vector3::ZERO` and are overwritten by the operator that owns them.
105    pub fn zero_gradient_vec(size: usize) -> Self {
106        Self {
107            bc: BoundaryCondition::ZeroGradient,
108            values: Field::zero_vec(size),
109        }
110    }
111
112    /// Empty (zero-area) vector patch — no faces, no physical value.
113    pub fn empty_vec() -> Self {
114        Self {
115            bc: BoundaryCondition::Empty,
116            values: Field::new(vec![]),
117        }
118    }
119}
120
121impl PatchField<Tensor> {
122    /// Dirichlet patch holding a uniform `Tensor` value.
123    pub fn fixed_value_tensor(size: usize, v: Tensor) -> Self {
124        Self {
125            bc: BoundaryCondition::FixedValue(v),
126            values: Field::uniform(size, v),
127        }
128    }
129
130    /// Zero-gradient (Neumann) patch for a `Tensor` field; values default to
131    /// `Tensor::ZERO` and are overwritten by the operator that owns them.
132    pub fn zero_gradient_tensor(size: usize) -> Self {
133        Self {
134            bc: BoundaryCondition::ZeroGradient,
135            values: Field::uniform(size, Tensor::ZERO),
136        }
137    }
138}
139
140impl PatchField<SymmTensor> {
141    /// Dirichlet patch holding a uniform `SymmTensor` value.
142    pub fn fixed_value_symm_tensor(size: usize, v: SymmTensor) -> Self {
143        Self {
144            bc: BoundaryCondition::FixedValue(v),
145            values: Field::uniform(size, v),
146        }
147    }
148
149    /// Zero-gradient (Neumann) patch for a `SymmTensor` field; values default to
150    /// `SymmTensor::ZERO` and are overwritten by the operator that owns them.
151    pub fn zero_gradient_symm_tensor(size: usize) -> Self {
152        Self {
153            bc: BoundaryCondition::ZeroGradient,
154            values: Field::uniform(size, SymmTensor::ZERO),
155        }
156    }
157}