1use ndarray::ArrayD;
9
10use crate::types::NcVariable;
11
12#[derive(Debug, Clone, Copy)]
14pub struct UnpackParams {
15 pub scale_factor: f64,
16 pub add_offset: f64,
17}
18
19impl UnpackParams {
20 pub fn from_variable(var: &NcVariable) -> Option<Self> {
25 let scale = var.attribute("scale_factor").and_then(|a| a.value.as_f64());
26 let offset = var.attribute("add_offset").and_then(|a| a.value.as_f64());
27
28 if scale.is_none() && offset.is_none() {
29 return None;
30 }
31
32 Some(UnpackParams {
33 scale_factor: scale.unwrap_or(1.0),
34 add_offset: offset.unwrap_or(0.0),
35 })
36 }
37
38 pub fn apply(&self, data: &mut ArrayD<f64>) {
40 if self.scale_factor == 1.0 && self.add_offset == 0.0 {
41 return;
42 }
43 data.mapv_inplace(|v| v * self.scale_factor + self.add_offset);
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50 use crate::types::{NcAttrValue, NcAttribute, NcType, NcVariable};
51 use ndarray::arr1;
52
53 fn make_var(attrs: Vec<NcAttribute>) -> NcVariable {
54 NcVariable {
55 name: "test".into(),
56 dimensions: vec![],
57 dtype: NcType::Int,
58 attributes: attrs,
59 data_offset: 0,
60 _data_size: 0,
61 is_record_var: false,
62 record_size: 0,
63 }
64 }
65
66 #[test]
67 fn test_no_unpack_attrs() {
68 let var = make_var(vec![]);
69 assert!(UnpackParams::from_variable(&var).is_none());
70 }
71
72 #[test]
73 fn test_scale_only() {
74 let var = make_var(vec![NcAttribute {
75 name: "scale_factor".into(),
76 value: NcAttrValue::Doubles(vec![0.01]),
77 }]);
78 let params = UnpackParams::from_variable(&var).unwrap();
79 assert_eq!(params.scale_factor, 0.01);
80 assert_eq!(params.add_offset, 0.0);
81 }
82
83 #[test]
84 fn test_offset_only() {
85 let var = make_var(vec![NcAttribute {
86 name: "add_offset".into(),
87 value: NcAttrValue::Doubles(vec![273.15]),
88 }]);
89 let params = UnpackParams::from_variable(&var).unwrap();
90 assert_eq!(params.scale_factor, 1.0);
91 assert_eq!(params.add_offset, 273.15);
92 }
93
94 #[test]
95 fn test_both() {
96 let var = make_var(vec![
97 NcAttribute {
98 name: "scale_factor".into(),
99 value: NcAttrValue::Doubles(vec![0.1]),
100 },
101 NcAttribute {
102 name: "add_offset".into(),
103 value: NcAttrValue::Doubles(vec![10.0]),
104 },
105 ]);
106 let params = UnpackParams::from_variable(&var).unwrap();
107 let mut data = arr1(&[100.0, 200.0, 300.0]).into_dyn();
108 params.apply(&mut data);
109 assert_eq!(data[[0]], 20.0); assert_eq!(data[[1]], 30.0); assert_eq!(data[[2]], 40.0); }
113}