outram_foam_basic_lib/fields/
surface_field.rs1use std::ops::{Add, Div, Mul, Neg, Sub};
23use std::sync::Arc;
24
25use super::boundary::bc::PatchField;
26use super::field::Field;
27use crate::mesh::fv_mesh::FvMesh;
28use crate::primitives::Vector3;
29
30#[derive(Debug, Clone)]
42pub struct SurfaceField<T: Clone> {
43 pub name: String,
45 pub mesh: Arc<FvMesh>,
47 pub internal: Field<T>,
49 pub boundary: Vec<PatchField<T>>,
52}
53
54pub type SurfaceScalarField = SurfaceField<f64>;
58pub type SurfaceVectorField = SurfaceField<Vector3>;
60
61impl<T: Clone> SurfaceField<T> {
64 pub fn new(
68 name: impl Into<String>,
69 mesh: Arc<FvMesh>,
70 internal: Field<T>,
71 boundary: Vec<PatchField<T>>,
72 ) -> Self {
73 debug_assert_eq!(
74 internal.len(),
75 mesh.n_internal_faces,
76 "SurfaceField internal field length must equal n_internal_faces"
77 );
78 debug_assert_eq!(
79 boundary.len(),
80 mesh.patches.len(),
81 "SurfaceField boundary length must equal number of patches"
82 );
83 Self {
84 name: name.into(),
85 mesh,
86 internal,
87 boundary,
88 }
89 }
90}
91
92impl SurfaceScalarField {
93 pub fn zeros(name: impl Into<String>, mesh: Arc<FvMesh>) -> Self {
96 let n_int = mesh.n_internal_faces;
97 let boundary = mesh
98 .patches
99 .iter()
100 .map(|p| PatchField::zero_gradient(p.size))
101 .collect();
102 Self::new(name, mesh, Field::zeros(n_int), boundary)
103 }
104
105 pub fn uniform(name: impl Into<String>, mesh: Arc<FvMesh>, value: f64) -> Self {
108 let n_int = mesh.n_internal_faces;
109 let boundary = mesh
110 .patches
111 .iter()
112 .map(|p| PatchField::zero_gradient(p.size))
113 .collect();
114 Self::new(name, mesh, Field::uniform(n_int, value), boundary)
115 }
116}
117
118impl SurfaceVectorField {
119 pub fn zero(name: impl Into<String>, mesh: Arc<FvMesh>) -> Self {
122 let n_int = mesh.n_internal_faces;
123 let boundary = mesh
124 .patches
125 .iter()
126 .map(|p| PatchField::zero_gradient_vec(p.size))
127 .collect();
128 Self::new(name, mesh, Field::zero_vec(n_int), boundary)
129 }
130}
131
132impl<T: Clone + Default> SurfaceField<T> {
135 pub fn face_value(&self, f: usize) -> T {
138 if self.mesh.is_internal_face(f) {
139 self.internal[f].clone()
140 } else {
141 let (pi, fi) = self
142 .mesh
143 .patch_for_face(f)
144 .expect("face index out of range for boundary");
145 self.boundary[pi].values[fi].clone()
146 }
147 }
148}
149
150impl<T> Add for SurfaceField<T>
153where
154 T: Add<Output = T> + Clone + Default,
155{
156 type Output = Self;
157 fn add(mut self, rhs: Self) -> Self {
158 self.internal = self.internal + rhs.internal;
163 for (l, r) in self.boundary.iter_mut().zip(rhs.boundary) {
164 l.values = l.values.clone() + r.values;
165 }
166 self
167 }
168}
169
170impl<T> Sub for SurfaceField<T>
171where
172 T: Sub<Output = T> + Clone + Default,
173{
174 type Output = Self;
175 fn sub(mut self, rhs: Self) -> Self {
176 self.internal = self.internal - rhs.internal;
178 for (l, r) in self.boundary.iter_mut().zip(rhs.boundary) {
179 l.values = l.values.clone() - r.values;
180 }
181 self
182 }
183}
184
185impl<T> Neg for SurfaceField<T>
186where
187 T: Neg<Output = T> + Clone,
188{
189 type Output = Self;
190 fn neg(mut self) -> Self {
191 self.internal = -self.internal;
193 for p in self.boundary.iter_mut() {
194 p.values = -p.values.clone();
195 }
196 self
197 }
198}
199
200impl<T> Mul<f64> for SurfaceField<T>
201where
202 T: Mul<f64, Output = T> + Clone,
203{
204 type Output = Self;
205 fn mul(mut self, s: f64) -> Self {
206 self.internal = self.internal * s;
207 for p in self.boundary.iter_mut() {
208 p.values = p.values.clone() * s;
209 }
210 self
211 }
212}
213
214impl<T> Div<f64> for SurfaceField<T>
215where
216 T: Mul<f64, Output = T> + Clone,
217{
218 type Output = Self;
219 fn div(self, s: f64) -> Self {
220 self * (1.0 / s)
221 }
222}
223
224impl Mul for SurfaceScalarField {
226 type Output = Self;
227 fn mul(mut self, rhs: Self) -> Self {
228 self.internal = self.internal * rhs.internal;
229 for (l, r) in self.boundary.iter_mut().zip(rhs.boundary) {
230 l.values = l.values.clone() * r.values;
231 }
232 self
233 }
234}
235
236impl<T: Mul<f64, Output = T> + Clone> Mul<SurfaceField<T>> for f64 {
238 type Output = SurfaceField<T>;
239 fn mul(self, mut rhs: SurfaceField<T>) -> SurfaceField<T> {
240 rhs.internal = rhs.internal * self;
241 for p in rhs.boundary.iter_mut() {
242 p.values = p.values.clone() * self;
243 }
244 rhs
245 }
246}
247
248#[cfg(test)]
251mod tests {
252 use super::*;
253 use crate::mesh::fv_mesh::{BoundaryPatch, FvMeshBuilder, PatchKind};
254
255 fn unit_mesh() -> Arc<FvMesh> {
256 Arc::new(
257 FvMeshBuilder::new()
258 .n_cells(2)
259 .n_internal_faces(1)
260 .owner(vec![0, 1, 0])
261 .neighbour(vec![1])
262 .patches(vec![
263 BoundaryPatch::new("right", 1, 1, PatchKind::Wall),
264 BoundaryPatch::new("left", 2, 1, PatchKind::Wall),
265 ])
266 .cell_volumes(vec![1.0, 1.0])
267 .cell_centres(vec![
268 Vector3::new(0.25, 0.0, 0.0),
269 Vector3::new(0.75, 0.0, 0.0),
270 ])
271 .face_area_vectors(vec![
272 Vector3::new(1.0, 0.0, 0.0),
273 Vector3::new(1.0, 0.0, 0.0),
274 Vector3::new(-1.0, 0.0, 0.0),
275 ])
276 .face_centres(vec![
277 Vector3::new(0.5, 0.0, 0.0),
278 Vector3::new(1.0, 0.0, 0.0),
279 Vector3::new(0.0, 0.0, 0.0),
280 ])
281 .build()
282 .unwrap(),
283 )
284 }
285
286 #[test]
287 fn zeros_surface_scalar_field() {
288 let m = unit_mesh();
289 let phi = SurfaceScalarField::zeros("phi", m.clone());
290 assert_eq!(phi.internal.len(), 1);
292 assert_eq!(phi.boundary.len(), 2);
293 assert_eq!(phi.boundary[0].values.len(), 1);
294 }
295
296 #[test]
297 fn face_value_internal() {
298 let m = unit_mesh();
299 let phi = SurfaceScalarField::uniform("phi", m.clone(), 5.0);
300 assert!((phi.face_value(0) - 5.0).abs() < 1e-15); }
302
303 #[test]
304 fn add_surface_fields() {
305 let m = unit_mesh();
306 let a = SurfaceScalarField::uniform("a", m.clone(), 2.0);
307 let b = SurfaceScalarField::uniform("b", m, 3.0);
308 let c = a + b;
309 assert!((c.internal[0] - 5.0).abs() < 1e-15);
310 }
311
312 #[test]
313 fn mul_surface_field_by_scalar() {
314 let m = unit_mesh();
315 let a = SurfaceScalarField::uniform("a", m, 4.0);
316 let b = a * 0.5;
317 assert!((b.internal[0] - 2.0).abs() < 1e-15);
318 }
319}