outram_foam_basic_lib/fields/
field.rs1use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
23
24use crate::primitives::{SphericalTensor, SymmTensor, Tensor, Vector3};
25
26#[derive(Debug, Clone, PartialEq)]
32pub struct Field<T> {
33 data: Vec<T>,
34}
35
36pub type ScalarField = Field<f64>;
44
45pub type VectorField = Field<Vector3>;
47
48pub type TensorField = Field<Tensor>;
50
51pub type SymmTensorField = Field<SymmTensor>;
54
55impl<T: Clone> Field<T> {
58 pub fn new(data: Vec<T>) -> Self {
60 Self { data }
61 }
62
63 pub fn uniform(n: usize, value: T) -> Self {
65 Self {
66 data: vec![value; n],
67 }
68 }
69
70 pub fn from_fn(n: usize, f: impl Fn(usize) -> T) -> Self {
72 Self {
73 data: (0..n).map(f).collect(),
74 }
75 }
76
77 pub fn len(&self) -> usize {
79 self.data.len()
80 }
81
82 pub fn is_empty(&self) -> bool {
84 self.data.is_empty()
85 }
86
87 pub fn as_slice(&self) -> &[T] {
89 &self.data
90 }
91
92 pub fn as_mut_slice(&mut self) -> &mut [T] {
94 &mut self.data
95 }
96
97 pub fn into_vec(self) -> Vec<T> {
99 self.data
100 }
101
102 pub fn iter(&self) -> std::slice::Iter<'_, T> {
104 self.data.iter()
105 }
106
107 pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
109 self.data.iter_mut()
110 }
111
112 pub fn map<U: Clone>(&self, f: impl Fn(&T) -> U) -> Field<U> {
114 Field {
115 data: self.data.iter().map(f).collect(),
116 }
117 }
118}
119
120impl Field<f64> {
121 pub fn zeros(n: usize) -> Self {
123 Self::uniform(n, 0.0)
124 }
125
126 pub fn ones(n: usize) -> Self {
128 Self::uniform(n, 1.0)
129 }
130
131 pub fn sum(&self) -> f64 {
133 self.data.iter().copied().sum()
134 }
135
136 pub fn mean(&self) -> f64 {
138 if self.data.is_empty() {
139 0.0
140 } else {
141 self.sum() / self.data.len() as f64
142 }
143 }
144
145 pub fn min(&self) -> f64 {
147 self.data.iter().cloned().fold(f64::INFINITY, f64::min)
148 }
149
150 pub fn max(&self) -> f64 {
152 self.data.iter().cloned().fold(f64::NEG_INFINITY, f64::max)
153 }
154
155 pub fn l2_norm(&self) -> f64 {
157 self.data.iter().map(|x| x * x).sum::<f64>().sqrt()
158 }
159
160 pub fn abs(&self) -> Self {
162 self.map(|x| x.abs())
163 }
164
165 pub fn clamp(&self, lo: f64, hi: f64) -> Self {
167 self.map(|x| x.clamp(lo, hi))
168 }
169
170 pub fn pointwise_mul(&self, rhs: &Self) -> Self {
172 assert_eq!(
173 self.len(),
174 rhs.len(),
175 "Field length mismatch in pointwise_mul"
176 );
177 Field::from_fn(self.len(), |i| self.data[i] * rhs.data[i])
178 }
179
180 pub fn pointwise_div(&self, rhs: &Self) -> Self {
182 assert_eq!(
183 self.len(),
184 rhs.len(),
185 "Field length mismatch in pointwise_div"
186 );
187 Field::from_fn(self.len(), |i| self.data[i] / rhs.data[i])
188 }
189
190 pub fn weighted_sum(&self, weights: &Field<f64>) -> f64 {
192 assert_eq!(self.len(), weights.len());
193 self.data
194 .iter()
195 .zip(weights.data.iter())
196 .map(|(x, w)| x * w)
197 .sum()
198 }
199}
200
201impl Field<Vector3> {
202 pub fn zero_vec(n: usize) -> Self {
204 Self::uniform(n, Vector3::ZERO)
205 }
206
207 pub fn dot_field(&self, rhs: &Field<Vector3>) -> Field<f64> {
209 assert_eq!(self.len(), rhs.len());
210 Field::from_fn(self.len(), |i| self.data[i].dot(rhs.data[i]))
211 }
212
213 pub fn scale(&self, s: &Field<f64>) -> Self {
215 assert_eq!(self.len(), s.len());
216 Field::from_fn(self.len(), |i| self.data[i] * s[i])
217 }
218}
219
220impl<T> std::ops::Index<usize> for Field<T> {
223 type Output = T;
224 fn index(&self, i: usize) -> &T {
225 &self.data[i]
226 }
227}
228
229impl<T> std::ops::IndexMut<usize> for Field<T> {
230 fn index_mut(&mut self, i: usize) -> &mut T {
231 &mut self.data[i]
232 }
233}
234
235impl<T> AsRef<[T]> for Field<T> {
236 fn as_ref(&self) -> &[T] {
237 &self.data
238 }
239}
240
241impl<T> IntoIterator for Field<T> {
242 type Item = T;
243 type IntoIter = std::vec::IntoIter<T>;
244 fn into_iter(self) -> Self::IntoIter {
245 self.data.into_iter()
246 }
247}
248
249impl<'a, T> IntoIterator for &'a Field<T> {
250 type Item = &'a T;
251 type IntoIter = std::slice::Iter<'a, T>;
252 fn into_iter(self) -> Self::IntoIter {
253 self.data.iter()
254 }
255}
256
257impl<T: Clone> From<Vec<T>> for Field<T> {
258 fn from(v: Vec<T>) -> Self {
259 Self::new(v)
260 }
261}
262
263impl<T: Add<Output = T> + Clone> Add for Field<T> {
266 type Output = Self;
267 fn add(self, rhs: Self) -> Self {
268 assert_eq!(self.len(), rhs.len(), "Field length mismatch in add");
269 Field::from_fn(self.len(), |i| self.data[i].clone() + rhs.data[i].clone())
270 }
271}
272
273impl<T: Sub<Output = T> + Clone> Sub for Field<T> {
274 type Output = Self;
275 fn sub(self, rhs: Self) -> Self {
276 assert_eq!(self.len(), rhs.len(), "Field length mismatch in sub");
277 Field::from_fn(self.len(), |i| self.data[i].clone() - rhs.data[i].clone())
278 }
279}
280
281impl<T: Neg<Output = T> + Clone> Neg for Field<T> {
282 type Output = Self;
283 fn neg(self) -> Self {
284 self.map(|x| -x.clone())
285 }
286}
287
288impl<T: Add<Output = T> + Clone> AddAssign for Field<T> {
289 fn add_assign(&mut self, rhs: Self) {
290 assert_eq!(self.len(), rhs.len());
291 for (a, b) in self.data.iter_mut().zip(rhs.data) {
292 *a = a.clone() + b;
293 }
294 }
295}
296
297impl<T: Sub<Output = T> + Clone> SubAssign for Field<T> {
298 fn sub_assign(&mut self, rhs: Self) {
299 assert_eq!(self.len(), rhs.len());
300 for (a, b) in self.data.iter_mut().zip(rhs.data) {
301 *a = a.clone() - b;
302 }
303 }
304}
305
306impl<T: Mul<f64, Output = T> + Clone> Mul<f64> for Field<T> {
309 type Output = Self;
310 fn mul(self, rhs: f64) -> Self {
311 self.map(|x| x.clone() * rhs)
312 }
313}
314
315impl Mul<Field<f64>> for f64 {
317 type Output = Field<f64>;
318 fn mul(self, rhs: Field<f64>) -> Field<f64> {
319 rhs.map(|x| self * x)
320 }
321}
322
323impl Mul<Field<Vector3>> for f64 {
324 type Output = Field<Vector3>;
325 fn mul(self, rhs: Field<Vector3>) -> Field<Vector3> {
326 rhs.map(|v| v.clone() * self)
327 }
328}
329
330impl<T: Mul<f64, Output = T> + Clone> Div<f64> for Field<T> {
331 type Output = Self;
332 fn div(self, rhs: f64) -> Self {
333 let inv = 1.0 / rhs;
334 self.map(|x| x.clone() * inv)
335 }
336}
337
338impl Mul for Field<f64> {
341 type Output = Self;
342 fn mul(self, rhs: Self) -> Self {
343 self.pointwise_mul(&rhs)
344 }
345}
346
347impl Div for Field<f64> {
348 type Output = Self;
349 fn div(self, rhs: Self) -> Self {
350 self.pointwise_div(&rhs)
351 }
352}
353
354impl Mul<Field<f64>> for Field<Vector3> {
356 type Output = Field<Vector3>;
357 fn mul(self, rhs: Field<f64>) -> Field<Vector3> {
358 self.scale(&rhs)
359 }
360}
361
362impl Mul<Field<Vector3>> for Field<f64> {
363 type Output = Field<Vector3>;
364 fn mul(self, rhs: Field<Vector3>) -> Field<Vector3> {
365 rhs.scale(&self)
366 }
367}
368
369impl Default for Field<f64> {
372 fn default() -> Self {
373 Self::new(vec![])
374 }
375}
376
377impl Default for Field<Vector3> {
378 fn default() -> Self {
379 Self::new(vec![])
380 }
381}
382
383impl Default for Field<Tensor> {
384 fn default() -> Self {
385 Self::new(vec![])
386 }
387}
388
389impl Default for Field<SymmTensor> {
390 fn default() -> Self {
391 Self::new(vec![])
392 }
393}
394
395impl Default for Field<SphericalTensor> {
396 fn default() -> Self {
397 Self::new(vec![])
398 }
399}
400
401#[cfg(test)]
404mod tests {
405 use super::*;
406
407 #[test]
408 fn add_f64_fields() {
409 let a = Field::new(vec![1.0, 2.0, 3.0]);
410 let b = Field::new(vec![4.0, 5.0, 6.0]);
411 let c = a + b;
412 assert_eq!(c.as_slice(), &[5.0, 7.0, 9.0]);
413 }
414
415 #[test]
416 fn mul_scalar() {
417 let a = Field::new(vec![1.0, 2.0, 3.0]);
418 let b = a * 2.0;
419 assert_eq!(b.as_slice(), &[2.0, 4.0, 6.0]);
420 }
421
422 #[test]
423 fn div_scalar() {
424 let a = Field::new(vec![2.0, 4.0, 6.0]);
425 let b = a / 2.0;
426 assert_eq!(b.as_slice(), &[1.0, 2.0, 3.0]);
427 }
428
429 #[test]
430 fn neg_field() {
431 let a = Field::new(vec![1.0, -2.0, 3.0]);
432 let b = -a;
433 assert_eq!(b.as_slice(), &[-1.0, 2.0, -3.0]);
434 }
435
436 #[test]
437 fn sum_mean() {
438 let a = Field::new(vec![1.0, 2.0, 3.0, 4.0]);
439 assert_eq!(a.sum(), 10.0);
440 assert_eq!(a.mean(), 2.5);
441 }
442
443 #[test]
444 fn pointwise_mul_fields() {
445 let a = Field::new(vec![2.0, 3.0]);
446 let b = Field::new(vec![4.0, 5.0]);
447 let c = a.pointwise_mul(&b);
448 assert_eq!(c.as_slice(), &[8.0, 15.0]);
449 }
450
451 #[test]
452 fn vector3_add_fields() {
453 let a = Field::new(vec![
454 Vector3::new(1.0, 0.0, 0.0),
455 Vector3::new(0.0, 1.0, 0.0),
456 ]);
457 let b = Field::new(vec![
458 Vector3::new(0.0, 0.0, 1.0),
459 Vector3::new(1.0, 0.0, 0.0),
460 ]);
461 let c = a + b;
462 assert_eq!(c[0], Vector3::new(1.0, 0.0, 1.0));
463 assert_eq!(c[1], Vector3::new(1.0, 1.0, 0.0));
464 }
465
466 #[test]
467 fn vector3_scale_by_scalar_field() {
468 let v = Field::new(vec![
469 Vector3::new(1.0, 2.0, 3.0),
470 Vector3::new(4.0, 5.0, 6.0),
471 ]);
472 let s = Field::new(vec![2.0, 0.5]);
473 let result = v.scale(&s);
474 assert_eq!(result[0], Vector3::new(2.0, 4.0, 6.0));
475 assert_eq!(result[1], Vector3::new(2.0, 2.5, 3.0));
476 }
477
478 #[test]
479 fn uniform_and_len() {
480 let f: Field<f64> = Field::uniform(5, 3.14);
481 assert_eq!(f.len(), 5);
482 assert!((f[0] - 3.14).abs() < 1e-15);
483 }
484}