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}