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    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}