parse_monitors/monitors/reports/loader/
y2021_25.rs1use std::time::Instant;
2use std::{fs::File, io::Read, path::Path};
3
4use regex::Regex;
5
6use crate::{Exertion, Monitors, MonitorsError};
7
8use super::MonitorsLoader;
9
10type Result<T> = std::result::Result<T, MonitorsError>;
11
12impl<const Y: u32> MonitorsLoader<Y> {
13 #[cfg(feature = "bzip2")]
14 fn decompress(&self) -> Result<String> {
15 let mut contents = String::new();
16 let data_path = Path::new(&self.path).with_extension("csv.bz2");
17 let csv_file =
18 File::open(&data_path).map_err(|e| MonitorsError::Io(e, data_path.clone()))?;
19
20 log::info!("Loading {:?}...", csv_file);
21 let buf = std::io::BufReader::new(csv_file);
22 let mut bz2 = bzip2::bufread::BzDecoder::new(buf);
23 bz2.read_to_string(&mut contents)
24 .map_err(|e| MonitorsError::Io(e, data_path))?;
25 Ok(contents)
26 }
27 #[cfg(not(feature = "bzip2"))]
28 fn decompress(&self) -> Result<String> {
29 use flate2::read::GzDecoder;
30
31 use crate::MonitorsError;
32
33 let mut contents = String::new();
34 let data_path = Path::new(&self.path).with_extension("csv.z");
35 log::info!("Loading {:?}...", data_path);
36 let csv_file =
37 File::open(&data_path).map_err(|e| MonitorsError::Io(e, data_path.clone()))?;
38 let mut gz = GzDecoder::new(csv_file);
39 gz.read_to_string(&mut contents)
40 .map_err(|e| MonitorsError::Io(e, data_path))?;
41 Ok(contents)
42 }
43 pub fn load(self) -> Result<Monitors> {
44 let now = Instant::now();
45 let contents = self.decompress()?;
46 let mut rdr = csv::Reader::from_reader(contents.as_bytes());
47
48 let headers: Vec<_> = {
49 let headers = rdr.headers()?;
50 headers.into_iter().map(|h| h.to_string()).collect()
52 };
53 if Y == 2025 {
54 headers
55 .iter()
56 .find(|h| h.contains("M1c_"))
57 .ok_or(MonitorsError::YearMismatch(2021, Y))?;
58 }
59
60 let re_htc = Regex::new(
61 r"(\w+) Monitor: Surface Average of Heat Transfer Coefficient \(W/m\^2-K\)",
62 )?;
63 let re_force = Regex::new(r"(.+)_([XYZ]) Monitor(?:: Force)? \(N\)")?;
65 let re_moment = Regex::new(r"(.+)Mom_([XYZ]) Monitor(?:: Moment)? \(N-m\)")?;
66
67 let re_header = Regex::new(&self.header_regex)?;
68 let re_x_header = if let Some(re) = self.header_exclude_regex {
69 Some(Regex::new(&re)?)
70 } else {
71 None
72 };
73
74 let mut monitors = Monitors::default();
75
76 for result in rdr.records() {
77 let record = result?;
78 let time = record.iter().next().unwrap().parse::<f64>()?;
79 if time < self.time_range.0 - 1. / 40. || time > self.time_range.1 + 1. / 40. {
80 continue;
81 };
82 monitors.time.push(time);
83 for (data, header) in record.iter().skip(1).zip(headers.iter().skip(1)).filter(
84 |(_, h)| match &re_x_header {
85 Some(re_x_header) => re_header.is_match(h) && !re_x_header.is_match(h),
86 None => re_header.is_match(h),
87 },
88 ) {
89 if let Some(capts) = re_htc.captures(header) {
91 let key = capts.get(1).unwrap().as_str().to_owned();
92 let value = data.parse::<f64>()?;
93 monitors
94 .heat_transfer_coefficients
95 .entry(key)
96 .or_insert_with(Vec::new)
97 .push(value.abs());
98 }
99 if let Some(capts) = re_force.captures(header) {
101 let key = capts.get(1).unwrap().as_str().to_owned();
102 let value = data.parse::<f64>()?;
103 let exertions = monitors
104 .forces_and_moments
105 .entry(key)
106 .or_insert(vec![Exertion::default()]);
107 let exertion = exertions.last_mut().unwrap();
108 match capts.get(2).unwrap().as_str() {
109 "X" => match exertion.force.x {
110 Some(_) => exertions.push(Exertion::from_force_x(value)),
111 None => {
112 exertion.force.x = Some(value);
113 }
114 },
115 "Y" => match exertion.force.y {
116 Some(_) => exertions.push(Exertion::from_force_y(value)),
117 None => {
118 exertion.force.y = Some(value);
119 }
120 },
121 "Z" => match exertion.force.z {
122 Some(_) => exertions.push(Exertion::from_force_z(value)),
123 None => {
124 exertion.force.z = Some(value);
125 }
126 },
127 &_ => (),
128 };
129 }
130 if let Some(capts) = re_moment.captures(header) {
132 let key = capts
133 .get(1)
134 .unwrap()
135 .as_str()
136 .trim_end_matches('_')
137 .to_owned();
138 let value = data.parse::<f64>()?;
139 let exertions = monitors
140 .forces_and_moments
141 .entry(key)
142 .or_insert(vec![Exertion::default()]);
143 let exertion = exertions.last_mut().unwrap();
144 match capts.get(2).unwrap().as_str() {
145 "X" => match exertion.moment.x {
146 Some(_) => exertions.push(Exertion::from_moment_x(value)),
147 None => {
148 exertion.moment.x = Some(value);
149 }
150 },
151 "Y" => match exertion.moment.y {
152 Some(_) => exertions.push(Exertion::from_moment_y(value)),
153 None => {
154 exertion.moment.y = Some(value);
155 }
156 },
157 "Z" => match exertion.moment.z {
158 Some(_) => exertions.push(Exertion::from_moment_z(value)),
159 None => {
160 exertion.moment.z = Some(value);
161 }
162 },
163 &_ => (),
164 };
165 }
166 }
167 }
168 log::info!("... loaded in {:}s", now.elapsed().as_secs());
169 Ok(monitors)
170 }
171}