Skip to main content

cmtool_core/model/
scalar.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3use std::ops::Index;
4
5use cmtool_data::ScalarValueType;
6
7use crate::{
8    CoreError,
9    ensight_gold::{self, types::ElementsType},
10    model::CMGeometry,
11};
12
13pub struct Scalar {
14    pub(crate) value_in_vo: Vec<cmtool_data::ScalarValueType>,
15    pub name: String,
16}
17
18impl Scalar {
19    pub(crate) fn new(
20        eg_scalar: ensight_gold::scalar::ScalarField,
21        geometry: &CMGeometry,
22        eg_geometry: &ensight_gold::Geometry,
23    ) -> Self {
24        let mut value_in_vo: Vec<cmtool_data::ScalarValueType> =
25            vec![0.; geometry.volume_elements.n_element()];
26
27        for (i_part, part) in eg_geometry.parts.iter().enumerate() {
28            for (i_e, element) in part.elements.iter().enumerate() {
29                if let ElementsType::VolumeElementType(vetype) = element.etype {
30                    let element_index = vetype.to_index();
31
32                    for volume_element_id in 0..element.n_elements {
33                        let volume_element_global_id = geometry.volume_elements.get_global_id(
34                            i_part,
35                            element_index,
36                            volume_element_id,
37                        );
38                        value_in_vo[volume_element_global_id] =
39                            eg_scalar.get_value(i_part, i_e, volume_element_id).into();
40                    }
41                }
42            }
43        }
44
45        Self {
46            value_in_vo,
47            name: eg_scalar.get_name().to_string(),
48        }
49    }
50
51    pub fn element_wise(self, a: &Self) -> Result<Self, CoreError> {
52        if a.value_in_vo.len() != self.value_in_vo.len() {
53            return Err(CoreError::Custom(format!(
54                "Bad size for scalar scaling {} vs {} ",
55                self.value_in_vo.len(),
56                a.value_in_vo.len()
57            )));
58        }
59
60        let values: Vec<cmtool_data::ScalarValueType> = a
61            .value_in_vo
62            .iter()
63            .zip(&self.value_in_vo)
64            .map(|(a, b)| a * b)
65            .collect();
66        Ok(Self {
67            value_in_vo: values,
68            name: format!("{} per {} scalar ", self.name, a.name),
69        })
70    }
71
72    pub fn scalar_shift(self, lambda: ScalarValueType) -> Self {
73        let value_in_vo = self.value_in_vo.iter().map(|i| lambda - i).collect();
74
75        Self {
76            value_in_vo,
77            name: format!("{} shifted by {} ", self.name, lambda),
78        }
79    }
80}
81
82impl Index<usize> for Scalar {
83    type Output = cmtool_data::ScalarValueType;
84
85    fn index(&self, index: usize) -> &Self::Output {
86        #[cfg(debug_assertions)]
87        {
88            // Debug mode: safe indexing with bounds check
89            &self.value_in_vo[index]
90        }
91
92        #[cfg(not(debug_assertions))]
93        unsafe {
94            // Release mode: unchecked access (unsafe but fast)
95            self.value_in_vo.get_unchecked(index)
96        }
97    }
98}
99
100// impl IndexMut<usize> for Scalar {
101//     fn index_mut(&mut self, index: usize) -> &mut Self::Output {
102//         let (part, mesh_element_type, mesh_cell) = index;
103//         let flat_index = part * (self.mesh_element_types * self.mesh_cells)
104//             + mesh_element_type * self.mesh_cells
105//             + mesh_cell;
106//         &mut self.data[flat_index]
107//     }
108// }