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 pub bc: BoundaryCondition<T>,
62 /// Current face values for this patch (length == patch.size).
63 pub values: Field<T>,
64}
65
66impl PatchField<f64> {
67 pub fn fixed_value(size: usize, v: f64) -> Self {
68 Self {
69 bc: BoundaryCondition::FixedValue(v),
70 values: Field::uniform(size, v),
71 }
72 }
73
74 pub fn zero_gradient(size: usize) -> Self {
75 Self {
76 bc: BoundaryCondition::ZeroGradient,
77 values: Field::zeros(size),
78 }
79 }
80
81 pub fn empty() -> Self {
82 Self {
83 bc: BoundaryCondition::Empty,
84 values: Field::new(vec![]),
85 }
86 }
87}
88
89impl PatchField<Vector3> {
90 pub fn fixed_value_vec(size: usize, v: Vector3) -> Self {
91 Self {
92 bc: BoundaryCondition::FixedValue(v),
93 values: Field::uniform(size, v),
94 }
95 }
96
97 pub fn zero_gradient_vec(size: usize) -> Self {
98 Self {
99 bc: BoundaryCondition::ZeroGradient,
100 values: Field::zero_vec(size),
101 }
102 }
103
104 pub fn empty_vec() -> Self {
105 Self {
106 bc: BoundaryCondition::Empty,
107 values: Field::new(vec![]),
108 }
109 }
110}
111
112impl PatchField<Tensor> {
113 /// Dirichlet patch holding a uniform `Tensor` value.
114 pub fn fixed_value_tensor(size: usize, v: Tensor) -> Self {
115 Self {
116 bc: BoundaryCondition::FixedValue(v),
117 values: Field::uniform(size, v),
118 }
119 }
120
121 /// Zero-gradient (Neumann) patch for a `Tensor` field; values default to
122 /// `Tensor::ZERO` and are overwritten by the operator that owns them.
123 pub fn zero_gradient_tensor(size: usize) -> Self {
124 Self {
125 bc: BoundaryCondition::ZeroGradient,
126 values: Field::uniform(size, Tensor::ZERO),
127 }
128 }
129}
130
131impl PatchField<SymmTensor> {
132 /// Dirichlet patch holding a uniform `SymmTensor` value.
133 pub fn fixed_value_symm_tensor(size: usize, v: SymmTensor) -> Self {
134 Self {
135 bc: BoundaryCondition::FixedValue(v),
136 values: Field::uniform(size, v),
137 }
138 }
139
140 /// Zero-gradient (Neumann) patch for a `SymmTensor` field; values default to
141 /// `SymmTensor::ZERO` and are overwritten by the operator that owns them.
142 pub fn zero_gradient_symm_tensor(size: usize) -> Self {
143 Self {
144 bc: BoundaryCondition::ZeroGradient,
145 values: Field::uniform(size, SymmTensor::ZERO),
146 }
147 }
148}