use std::fs::File;
use std::io::{BufRead, BufReader};
use std::time::Instant;
use astroimsim_geometry::grid1d::{Location1D, Neighbors, GRID1D};
use astroimsim_geometry::grid2d::GRID2D;
use plotpy::{Curve, Plot};
use crate::datafile::{DataFile, DATAGRID};
#[derive(Clone,Debug)]
pub enum DataSource{
DatFile(DataFile,String), None
}
#[derive(Debug,Clone)]
pub struct DATAGRID1D{
pub grid1d: GRID1D,
pub data: Vec<(usize,Vec<f64>)>, pub data_shape: (usize,usize), pub label: &'static str,
pub source: DataSource,
}
#[derive(Clone, Debug)]
pub struct DATAGRID2D{
pub grid1d: GRID2D,
pub data: Vec<(usize,Vec<f64>)>, pub data_shape: (usize,usize), pub label: &'static str,
pub source: DataSource,
}
impl DATAGRID1D {
pub fn new_empty(grid1d:GRID1D,data_shape:(usize,usize),label:&'static str)->DATAGRID1D{
DATAGRID1D{
grid1d,
data:vec![],
data_shape,
label,
source: DataSource::None
}
}
pub fn get_data(&self, index: usize) -> Vec<f64> {
assert_eq!(self.data[index].0, index);
self.data[index].1.clone()
}
pub fn load_data(mut self, plot: bool) {
let (path,delineator) = match self.source{
DataSource::DatFile(file, delineator) => {
println!("Loading file {:?} from {:?}", file.name, file.path);
(file.path,delineator)}
DataSource::None => {panic!("Can't load data from DataSource::None")}
};
assert_ne!(0, self.data.len(), "Loading data {:?} into would overwrite current data", self.label);
println!("Loading {:?} into {:?}", path, self.label);
let start = Instant::now();
let file = File::open(path).expect("Failed to open file");
let reader = BufReader::new(file);
let data: Vec<Vec<f64>> = reader.lines().map(|line| {
let line = line.expect("Failed to read line");
let mut parsable = true;
let parsed: Vec<f64> = line
.trim()
.split(&delineator)
.map(|a|a.parse::<f64>())
.map(|result|
match result {
Ok(value) => value,
Err(_) => {parsable = false; 0.0},
}).collect();
if parsable { if parsed.len() == self.data_shape.0 * self.data_shape.1 + 1 {
parsed }
else{ vec![] }
} else{vec![]}
}).collect();
println!("Parsed {:?} lines in {:?}", data.len(), start.elapsed().as_millis());
assert_eq!(data.len(), self.grid1d.num(), "Retrieved a different number of records than expected");
let mut same_num_data_points_per_record = true;
for i in 0..data.len() - 1 {
if data[i].len() - data[i + 1].len() != 0 {
same_num_data_points_per_record = false;
}
}
if !same_num_data_points_per_record {
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)
} if plot {
let mut plot = Plot::new();
for i in 1..data[0].len() {
let mut curve = Curve::new();
curve.set_line_width(2.0);
curve.points_begin();
for point in &data.clone() {
curve.points_add(point[0], point[i]);
}
curve.points_end();
plot.add(&curve).grid_and_labels("x", "y");
}
plot.show("ksenf").expect("hHHHHHH");
}
println!("The first record is {:?} and the last is {:?}, snapping to grid: {:?}", data[0], data[data.len() - 1], self.grid1d);
let mut snapped_data = Vec::new();
for datum in data {
let location = datum[0];
let index = self.grid1d.snap(location as f64);
snapped_data.push((index, datum)) }
self.data = snapped_data;
}
pub fn plot(&self) -> Vec<Vec<Vec<f64>>>{
let mut curves = Vec::new();
for i in 1..self.data[0].1.len() {
let mut curve = Vec::new();
for point in self.data.clone() {
println!("adding {:?}",(point.1[0],point.1[i]));
curve.push(vec![point.1[0] as f64, point.1[i] as f64]);
}
curves.push(curve);
}
println!("{:?}",self.data);
curves
}
pub fn re_grid(&mut self, new_grid: GRID1D) -> DATAGRID1D {
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");
self.data.sort_by_key(|x| x.0); let mut new_data = Vec::new();
for point in 0..new_grid.num() {
let new_location = new_grid.location(point);
let value = match self.grid1d.inside_or_outside(new_location) {
Location1D::TooHigh => {
println!("new gridding {:?},location is {:?}, too high", point, new_location);
let mut datum = self.data[self.data.len() - 1].1.clone();
datum[0] = new_location;
datum
}
Location1D::TooLow => {
println!("new gridding {:?},location is {:?}, too low", point, new_location);
let mut datum = self.data[0].1.clone();
datum[0] = new_location;
datum
}
Location1D::JustRight => {
match self.grid1d.find_neighbors(new_location) {
Neighbors::Two(lower_index, upper_index) => {
println!("new gridding {:?},location is {:?}, just right, two neiborhs: {:?}", point, new_location, (lower_index, upper_index));
let lower = self.grid1d.location(lower_index);
let upper = self.grid1d.location(upper_index);
let lower_delta = new_location - lower;
let upper_delta = upper - new_location;
let lower_weight = lower_delta / (lower_delta + upper_delta);
let upper_weight = upper_delta / (lower_delta + upper_delta);
let upper_data = self.get_data(upper_index);
let lower_data = self.get_data(lower_index);
upper_data.iter().zip(lower_data.iter()).map(|(a, b)|
a * upper_weight + b * lower_weight).collect()
}
Neighbors::One(snap) => { self.get_data(snap) }
}
}
};
new_data.push((point, value))
}
let mut new_frequency_file = (*self).clone();
new_frequency_file.data = new_data;
new_frequency_file
}
}