astroimsim_data/
datagrids.rs1use std::fs::File;
2use std::io::{BufRead, BufReader};
3use std::time::Instant;
4use astroimsim_geometry::grid1d::{Location1D, Neighbors, GRID1D};
5use astroimsim_geometry::grid2d::GRID2D;
6use plotpy::{Curve, Plot};
7use crate::datafile::{DataFile, FILETYPE};
8
9#[derive(Clone,Debug)]
10pub enum DataSource{
11 File(DataFile), None
13}
14
15#[derive(Debug,Clone)]
16pub struct DATAGRID1D{
17 pub grid1d: GRID1D,
18 pub data: Vec<(usize,Vec<f64>)>, pub data_shape: (usize,usize), pub label: &'static str,
21 pub source: DataSource,
22}
23#[derive(Clone, Debug)]
24pub struct DATAGRID2D{
25 pub grid1d: GRID2D,
26 pub data: Vec<(usize,Vec<f64>)>, pub data_shape: (usize,usize), pub label: &'static str,
29 pub source: DataSource,
30}
31
32
33
34impl DATAGRID1D {
35
36 pub fn new_empty(grid1d:GRID1D,data_shape:(usize,usize),label:&'static str)->DATAGRID1D{
37 DATAGRID1D{
38 grid1d,
39 data:vec![],
40 data_shape,
41 label,
42 source: DataSource::None
43 }
44 }
45 pub fn get_data(&self, index: usize) -> Vec<f64> {
46 assert_eq!(self.data[index].0, index);
47 self.data[index].1.clone()
48 }
49
50 fn load_dat(&mut self, path:&'static str, delineator:String, plot: bool) {
51 assert_ne!(0, self.data.len(), "Loading data {:?} into would overwrite current data", self.label);
52 println!("Loading {:?} into {:?}", path, self.label);
53 let start = Instant::now();
54 let file = File::open(path).expect("Failed to open file");
55 let reader = BufReader::new(file);
56 let data: Vec<Vec<f64>> = reader.lines().map(|line| {
57 let line = line.expect("Failed to read line");
58 let mut parsable = true;
59 let parsed: Vec<f64> = line
60 .trim()
61 .split(&delineator)
62 .map(|a|a.parse::<f64>())
63 .map(|result|
64 match result {
65 Ok(value) => value,
66 Err(_) => {parsable = false; 0.0},
67 }).collect();
68 if parsable { if parsed.len() == self.data_shape.0 * self.data_shape.1 + 1 {
70 parsed }
72 else{ vec![] }
73 } else{vec![]}
74 }).collect();
75 println!("Parsed {:?} lines in {:?}", data.len(), start.elapsed().as_millis());
76 assert_eq!(data.len(), self.grid1d.num(), "Retrieved a different number of records than expected");
77
78
79 let mut same_num_data_points_per_record = true;
80 for i in 0..data.len() - 1 {
81 if data[i].len() - data[i + 1].len() != 0 {
82 same_num_data_points_per_record = false;
83 }
84 }
85 if !same_num_data_points_per_record {
86 println!("Warning! There are different numbers of records for each line. This may mess up plotting or indicate a loading error. Will be plotting with {:?}", data[0].len() - 1)
87 } if plot {
89 let mut plot = Plot::new();
90 for i in 1..data[0].len() {
91 let mut curve = Curve::new();
92 curve.set_line_width(2.0);
93 curve.points_begin();
94 for point in &data.clone() {
95 curve.points_add(point[0], point[i]);
96 }
97 curve.points_end();
98 plot.add(&curve).grid_and_labels("x", "y");
99 }
100 plot.show("ksenf").expect("hHHHHHH");
101 }
102 println!("The first record is {:?} and the last is {:?}, snapping to grid: {:?}", data[0], data[data.len() - 1], self.grid1d);
103 let mut snapped_data = Vec::new();
104 for datum in data {
105 let location = datum[0];
106 let index = self.grid1d.snap(location as f64);
107 snapped_data.push((index, datum)) }
109 self.data = snapped_data;
110 }
111
112 fn load_data(&mut self){
113 match &self.source{
114 DataSource::File(file) => {
115 match &file.file_type{
116 FILETYPE::DAT(delinator) => {
117 println!("Loading .dat file");
118 self.load_dat(file.path,delinator.clone(),false)
119 }
120 FILETYPE::FITS => {panic!("unimplemented fits loading for 1D")}
121 }
122 }
123 DataSource::None => {panic!("Can't load data from Datasource::None")}
124 }
125 }
126
127 pub fn plot(&self) -> Vec<Vec<Vec<f64>>>{
128 let mut curves = Vec::new();
129 for i in 1..self.data[0].1.len() {
130 let mut curve = Vec::new();
131
132 for point in self.data.clone() {
145 println!("adding {:?}",(point.1[0],point.1[i]));
147 curve.push(vec![point.1[0] as f64, point.1[i] as f64]);
148 }
149 curves.push(curve);
151 }
152 println!("{:?}",self.data);
153 curves
154 }
155
156
157 pub fn re_grid(&mut self, new_grid: GRID1D) -> DATAGRID1D {
158 assert!(new_grid.snap_precision <= self.grid1d.snap_precision, "Snap precision of new grid must be less than or equal to that of the original grid");
159 self.data.sort_by_key(|x| x.0); let mut new_data = Vec::new();
161 for point in 0..new_grid.num() {
162 let new_location = new_grid.location(point);
163 let value = match self.grid1d.inside_or_outside(new_location) {
164 Location1D::TooHigh => {
165 println!("new gridding {:?},location is {:?}, too high", point, new_location);
166 let mut datum = self.data[self.data.len() - 1].1.clone();
167 datum[0] = new_location;
168 datum
169 }
170 Location1D::TooLow => {
171 println!("new gridding {:?},location is {:?}, too low", point, new_location);
172 let mut datum = self.data[0].1.clone();
173 datum[0] = new_location;
174 datum
175 }
176 Location1D::JustRight => {
177 match self.grid1d.find_neighbors(new_location) {
178 Neighbors::Two(lower_index, upper_index) => {
179 println!("new gridding {:?},location is {:?}, just right, two neiborhs: {:?}", point, new_location, (lower_index, upper_index));
180 let lower = self.grid1d.location(lower_index);
181 let upper = self.grid1d.location(upper_index);
182 let lower_delta = new_location - lower;
183 let upper_delta = upper - new_location;
184 let lower_weight = lower_delta / (lower_delta + upper_delta);
185 let upper_weight = upper_delta / (lower_delta + upper_delta);
186 let upper_data = self.get_data(upper_index);
187 let lower_data = self.get_data(lower_index);
188 upper_data.iter().zip(lower_data.iter()).map(|(a, b)|
189 a * upper_weight + b * lower_weight).collect()
190 }
191 Neighbors::One(snap) => { self.get_data(snap) }
192 }
193 }
194 };
195 new_data.push((point, value))
196 }
197 let mut new_frequency_file = (*self).clone();
198 new_frequency_file.data = new_data;
199 new_frequency_file
200 }
201}