Skip to main content

astroimsim_data/
datagrids.rs

1use 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), //data file, delineator
12    None
13}
14
15#[derive(Debug,Clone)]
16pub struct DATAGRID1D{
17    pub grid1d: GRID1D,
18    pub data: Vec<(usize,Vec<f64>)>, //a vector of values (point number on grid, data values at that point)
19    pub data_shape: (usize,usize), //shape of data at each grid point
20    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>)>, //a vector of values (point number on grid, data values at that point)
27    pub data_shape: (usize,usize), //shape of data at each point
28    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 { //check there were no errors in parsing
69                if parsed.len() == self.data_shape.0 * self.data_shape.1 + 1 {
70                    parsed //add to list if there is the expected number of data points
71                }
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        } //TODO run this function witha  "verbose" to list out the differences
88        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)) //TODO this must change to plot multiple
108        }
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            /*
133            curve.set_line_style(line)
134
135            .set_marker_line_width(2.5)
136            .set_marker_size(4.0)
137                .set_marker_color(color)
138                .set_line_color(color)
139            .set_marker_style(".");
140
141             */
142
143            // curve.points_begin();
144            for point in self.data.clone() {
145                // println!("{:?}", point);
146                println!("adding {:?}",(point.1[0],point.1[i]));
147                curve.push(vec![point.1[0] as f64, point.1[i] as f64]);
148            }
149            //curve.points_end();
150            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); //TODO move this into a validation function
160        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}