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
36impl<T: Clone> Field<T> {
39 pub fn new(data: Vec<T>) -> Self {
40 Self { data }
41 }
42
43 pub fn uniform(n: usize, value: T) -> Self {
44 Self {
45 data: vec![value; n],
46 }
47 }
48
49 pub fn from_fn(n: usize, f: impl Fn(usize) -> T) -> Self {
50 Self {
51 data: (0..n).map(f).collect(),
52 }
53 }
54
55 pub fn len(&self) -> usize {
56 self.data.len()
57 }
58
59 pub fn is_empty(&self) -> bool {
60 self.data.is_empty()
61 }
62
63 pub fn as_slice(&self) -> &[T] {
64 &self.data
65 }
66
67 pub fn as_mut_slice(&mut self) -> &mut [T] {
68 &mut self.data
69 }
70
71 pub fn into_vec(self) -> Vec<T> {
72 self.data
73 }
74
75 pub fn iter(&self) -> std::slice::Iter<'_, T> {
76 self.data.iter()
77 }
78
79 pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
80 self.data.iter_mut()
81 }
82
83 pub fn map<U: Clone>(&self, f: impl Fn(&T) -> U) -> Field<U> {
84 Field {
85 data: self.data.iter().map(f).collect(),
86 }
87 }
88}
89
90impl Field<f64> {
91 pub fn zeros(n: usize) -> Self {
92 Self::uniform(n, 0.0)
93 }
94
95 pub fn ones(n: usize) -> Self {
96 Self::uniform(n, 1.0)
97 }
98
99 pub fn sum(&self) -> f64 {
100 self.data.iter().copied().sum()
101 }
102
103 pub fn mean(&self) -> f64 {
104 if self.data.is_empty() {
105 0.0
106 } else {
107 self.sum() / self.data.len() as f64
108 }
109 }
110
111 pub fn min(&self) -> f64 {
112 self.data.iter().cloned().fold(f64::INFINITY, f64::min)
113 }
114
115 pub fn max(&self) -> f64 {
116 self.data.iter().cloned().fold(f64::NEG_INFINITY, f64::max)
117 }
118
119 pub fn l2_norm(&self) -> f64 {
120 self.data.iter().map(|x| x * x).sum::<f64>().sqrt()
121 }
122
123 pub fn abs(&self) -> Self {
125 self.map(|x| x.abs())
126 }
127
128 pub fn clamp(&self, lo: f64, hi: f64) -> Self {
130 self.map(|x| x.clamp(lo, hi))
131 }
132
133 pub fn pointwise_mul(&self, rhs: &Self) -> Self {
135 assert_eq!(
136 self.len(),
137 rhs.len(),
138 "Field length mismatch in pointwise_mul"
139 );
140 Field::from_fn(self.len(), |i| self.data[i] * rhs.data[i])
141 }
142
143 pub fn pointwise_div(&self, rhs: &Self) -> Self {
145 assert_eq!(
146 self.len(),
147 rhs.len(),
148 "Field length mismatch in pointwise_div"
149 );
150 Field::from_fn(self.len(), |i| self.data[i] / rhs.data[i])
151 }
152
153 pub fn weighted_sum(&self, weights: &Field<f64>) -> f64 {
155 assert_eq!(self.len(), weights.len());
156 self.data
157 .iter()
158 .zip(weights.data.iter())
159 .map(|(x, w)| x * w)
160 .sum()
161 }
162}
163
164impl Field<Vector3> {
165 pub fn zero_vec(n: usize) -> Self {
166 Self::uniform(n, Vector3::ZERO)
167 }
168
169 pub fn dot_field(&self, rhs: &Field<Vector3>) -> Field<f64> {
171 assert_eq!(self.len(), rhs.len());
172 Field::from_fn(self.len(), |i| self.data[i].dot(rhs.data[i]))
173 }
174
175 pub fn scale(&self, s: &Field<f64>) -> Self {
177 assert_eq!(self.len(), s.len());
178 Field::from_fn(self.len(), |i| self.data[i] * s[i])
179 }
180}
181
182impl<T> std::ops::Index<usize> for Field<T> {
185 type Output = T;
186 fn index(&self, i: usize) -> &T {
187 &self.data[i]
188 }
189}
190
191impl<T> std::ops::IndexMut<usize> for Field<T> {
192 fn index_mut(&mut self, i: usize) -> &mut T {
193 &mut self.data[i]
194 }
195}
196
197impl<T> AsRef<[T]> for Field<T> {
198 fn as_ref(&self) -> &[T] {
199 &self.data
200 }
201}
202
203impl<T> IntoIterator for Field<T> {
204 type Item = T;
205 type IntoIter = std::vec::IntoIter<T>;
206 fn into_iter(self) -> Self::IntoIter {
207 self.data.into_iter()
208 }
209}
210
211impl<'a, T> IntoIterator for &'a Field<T> {
212 type Item = &'a T;
213 type IntoIter = std::slice::Iter<'a, T>;
214 fn into_iter(self) -> Self::IntoIter {
215 self.data.iter()
216 }
217}
218
219impl<T: Clone> From<Vec<T>> for Field<T> {
220 fn from(v: Vec<T>) -> Self {
221 Self::new(v)
222 }
223}
224
225impl<T: Add<Output = T> + Clone> Add for Field<T> {
228 type Output = Self;
229 fn add(self, rhs: Self) -> Self {
230 assert_eq!(self.len(), rhs.len(), "Field length mismatch in add");
231 Field::from_fn(self.len(), |i| self.data[i].clone() + rhs.data[i].clone())
232 }
233}
234
235impl<T: Sub<Output = T> + Clone> Sub for Field<T> {
236 type Output = Self;
237 fn sub(self, rhs: Self) -> Self {
238 assert_eq!(self.len(), rhs.len(), "Field length mismatch in sub");
239 Field::from_fn(self.len(), |i| self.data[i].clone() - rhs.data[i].clone())
240 }
241}
242
243impl<T: Neg<Output = T> + Clone> Neg for Field<T> {
244 type Output = Self;
245 fn neg(self) -> Self {
246 self.map(|x| -x.clone())
247 }
248}
249
250impl<T: Add<Output = T> + Clone> AddAssign for Field<T> {
251 fn add_assign(&mut self, rhs: Self) {
252 assert_eq!(self.len(), rhs.len());
253 for (a, b) in self.data.iter_mut().zip(rhs.data) {
254 *a = a.clone() + b;
255 }
256 }
257}
258
259impl<T: Sub<Output = T> + Clone> SubAssign for Field<T> {
260 fn sub_assign(&mut self, rhs: Self) {
261 assert_eq!(self.len(), rhs.len());
262 for (a, b) in self.data.iter_mut().zip(rhs.data) {
263 *a = a.clone() - b;
264 }
265 }
266}
267
268impl<T: Mul<f64, Output = T> + Clone> Mul<f64> for Field<T> {
271 type Output = Self;
272 fn mul(self, rhs: f64) -> Self {
273 self.map(|x| x.clone() * rhs)
274 }
275}
276
277impl Mul<Field<f64>> for f64 {
279 type Output = Field<f64>;
280 fn mul(self, rhs: Field<f64>) -> Field<f64> {
281 rhs.map(|x| self * x)
282 }
283}
284
285impl Mul<Field<Vector3>> for f64 {
286 type Output = Field<Vector3>;
287 fn mul(self, rhs: Field<Vector3>) -> Field<Vector3> {
288 rhs.map(|v| v.clone() * self)
289 }
290}
291
292impl<T: Mul<f64, Output = T> + Clone> Div<f64> for Field<T> {
293 type Output = Self;
294 fn div(self, rhs: f64) -> Self {
295 let inv = 1.0 / rhs;
296 self.map(|x| x.clone() * inv)
297 }
298}
299
300impl Mul for Field<f64> {
303 type Output = Self;
304 fn mul(self, rhs: Self) -> Self {
305 self.pointwise_mul(&rhs)
306 }
307}
308
309impl Div for Field<f64> {
310 type Output = Self;
311 fn div(self, rhs: Self) -> Self {
312 self.pointwise_div(&rhs)
313 }
314}
315
316impl Mul<Field<f64>> for Field<Vector3> {
318 type Output = Field<Vector3>;
319 fn mul(self, rhs: Field<f64>) -> Field<Vector3> {
320 self.scale(&rhs)
321 }
322}
323
324impl Mul<Field<Vector3>> for Field<f64> {
325 type Output = Field<Vector3>;
326 fn mul(self, rhs: Field<Vector3>) -> Field<Vector3> {
327 rhs.scale(&self)
328 }
329}
330
331impl Default for Field<f64> {
334 fn default() -> Self {
335 Self::new(vec![])
336 }
337}
338
339impl Default for Field<Vector3> {
340 fn default() -> Self {
341 Self::new(vec![])
342 }
343}
344
345impl Default for Field<Tensor> {
346 fn default() -> Self {
347 Self::new(vec![])
348 }
349}
350
351impl Default for Field<SymmTensor> {
352 fn default() -> Self {
353 Self::new(vec![])
354 }
355}
356
357impl Default for Field<SphericalTensor> {
358 fn default() -> Self {
359 Self::new(vec![])
360 }
361}
362
363#[cfg(test)]
366mod tests {
367 use super::*;
368
369 #[test]
370 fn add_f64_fields() {
371 let a = Field::new(vec![1.0, 2.0, 3.0]);
372 let b = Field::new(vec![4.0, 5.0, 6.0]);
373 let c = a + b;
374 assert_eq!(c.as_slice(), &[5.0, 7.0, 9.0]);
375 }
376
377 #[test]
378 fn mul_scalar() {
379 let a = Field::new(vec![1.0, 2.0, 3.0]);
380 let b = a * 2.0;
381 assert_eq!(b.as_slice(), &[2.0, 4.0, 6.0]);
382 }
383
384 #[test]
385 fn div_scalar() {
386 let a = Field::new(vec![2.0, 4.0, 6.0]);
387 let b = a / 2.0;
388 assert_eq!(b.as_slice(), &[1.0, 2.0, 3.0]);
389 }
390
391 #[test]
392 fn neg_field() {
393 let a = Field::new(vec![1.0, -2.0, 3.0]);
394 let b = -a;
395 assert_eq!(b.as_slice(), &[-1.0, 2.0, -3.0]);
396 }
397
398 #[test]
399 fn sum_mean() {
400 let a = Field::new(vec![1.0, 2.0, 3.0, 4.0]);
401 assert_eq!(a.sum(), 10.0);
402 assert_eq!(a.mean(), 2.5);
403 }
404
405 #[test]
406 fn pointwise_mul_fields() {
407 let a = Field::new(vec![2.0, 3.0]);
408 let b = Field::new(vec![4.0, 5.0]);
409 let c = a.pointwise_mul(&b);
410 assert_eq!(c.as_slice(), &[8.0, 15.0]);
411 }
412
413 #[test]
414 fn vector3_add_fields() {
415 let a = Field::new(vec![
416 Vector3::new(1.0, 0.0, 0.0),
417 Vector3::new(0.0, 1.0, 0.0),
418 ]);
419 let b = Field::new(vec![
420 Vector3::new(0.0, 0.0, 1.0),
421 Vector3::new(1.0, 0.0, 0.0),
422 ]);
423 let c = a + b;
424 assert_eq!(c[0], Vector3::new(1.0, 0.0, 1.0));
425 assert_eq!(c[1], Vector3::new(1.0, 1.0, 0.0));
426 }
427
428 #[test]
429 fn vector3_scale_by_scalar_field() {
430 let v = Field::new(vec![
431 Vector3::new(1.0, 2.0, 3.0),
432 Vector3::new(4.0, 5.0, 6.0),
433 ]);
434 let s = Field::new(vec![2.0, 0.5]);
435 let result = v.scale(&s);
436 assert_eq!(result[0], Vector3::new(2.0, 4.0, 6.0));
437 assert_eq!(result[1], Vector3::new(2.0, 2.5, 3.0));
438 }
439
440 #[test]
441 fn uniform_and_len() {
442 let f: Field<f64> = Field::uniform(5, 3.14);
443 assert_eq!(f.len(), 5);
444 assert!((f[0] - 3.14).abs() < 1e-15);
445 }
446}