parse_monitors/
temperature.rs

1use flate2::read::GzDecoder;
2use serde::Deserialize;
3use std::io::prelude::*;
4use std::{fs::File, path::Path};
5
6#[derive(thiserror::Error, Debug)]
7pub enum TemperatureError {
8    #[error("Failed to open the pressure file")]
9    Io(#[from] std::io::Error),
10    #[error("Failed to deserialize the CSV file")]
11    Csv(#[from] csv::Error),
12}
13type Result<T> = std::result::Result<T, TemperatureError>;
14
15#[derive(Deserialize, Debug)]
16struct Record {
17    #[serde(rename = "Temperature (K)")]
18    temperature: f64,
19    #[serde(rename = "X (m)")]
20    x: f64,
21    #[serde(rename = "Y (m)")]
22    y: f64,
23    #[serde(rename = "Z (m)")]
24    z: f64,
25}
26
27#[derive(Debug)]
28pub struct Temperature {
29    // the temperature [K]
30    temperature: Vec<f64>,
31    // the (x,y,z) coordinate where the temperature is monitored
32    xyz: Vec<[f64; 3]>,
33}
34impl Default for Temperature {
35    fn default() -> Self {
36        Self {
37            temperature: Vec::with_capacity(6546592),
38            xyz: Vec::with_capacity(6546592),
39        }
40    }
41}
42impl Temperature {
43    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self> {
44        let csv_file = File::open(path)?;
45        let mut gz = GzDecoder::new(csv_file);
46        let mut contents = String::new();
47        gz.read_to_string(&mut contents)?;
48        let mut rdr = csv::Reader::from_reader(contents.as_bytes());
49        let mut this = Self::default();
50        for result in rdr.deserialize() {
51            let record: Record = result?;
52            this.temperature.push(record.temperature);
53            this.xyz.push([record.x, record.y, record.z]);
54        }
55        Ok(this)
56    }
57    /// Iterator over the x coordinate
58    fn xyz_iter(&self, axis: usize) -> impl Iterator<Item = f64> + '_ {
59        self.xyz.iter().map(move |v| v[axis])
60    }
61    pub fn x_iter(&self) -> impl Iterator<Item = f64> + '_ {
62        self.xyz_iter(0)
63    }
64    /// Returns the range of the x cooordinate
65    pub fn x_range(&self) -> (f64, f64) {
66        (
67            self.x_iter().fold(std::f64::INFINITY, f64::min),
68            self.x_iter().fold(std::f64::NEG_INFINITY, f64::max),
69        )
70    }
71    /// Iterator over the y coordinate
72    pub fn y_iter(&self) -> impl Iterator<Item = f64> + '_ {
73        self.xyz_iter(1)
74    }
75    /// Iterator over the (x,y) coordinates
76    pub fn xy_iter(&self) -> impl Iterator<Item = (f64, f64)> + '_ {
77        self.x_iter().zip(self.y_iter())
78    }
79    /// Returns the range of the y cooordinate
80    pub fn y_range(&self) -> (f64, f64) {
81        (
82            self.y_iter().fold(std::f64::INFINITY, f64::min),
83            self.y_iter().fold(std::f64::NEG_INFINITY, f64::max),
84        )
85    }
86    /// Iterator over the z coordinate
87    pub fn z_iter(&self) -> impl Iterator<Item = f64> + '_ {
88        self.xyz_iter(2)
89    }
90    /// Returns the range of the z cooordinate
91    pub fn z_range(&self) -> (f64, f64) {
92        (
93            self.z_iter().fold(std::f64::INFINITY, f64::min),
94            self.z_iter().fold(std::f64::NEG_INFINITY, f64::max),
95        )
96    }
97    /// Iterator over the (x,y) coordinates of a given segment
98    pub fn temperature_iter(&self) -> impl Iterator<Item = &f64> + '_ {
99        self.temperature.iter()
100    }
101}