use std::{fs, ops::Range}; use rayon::prelude::*; use plotters::{ prelude::{BitMapBackend, ChartBuilder, Circle, IntoDrawingArea}, series::PointSeries, style::{BLUE, WHITE}, }; use clap::Parser; struct Point { t: f32, posx: f32, velx: f32, dens: f32, ener: f32, pres: f32, } use anyhow::{Context, Result}; fn plot_file(i: usize, xrange: Range) -> Result<()> { let outfilename = format!("out/{i:08}.png"); let inputfilename = format!("results/sim_{i:08}.csv"); let file = fs::read_to_string(&inputfilename) .with_context(|| format!("Failed to read file {}", inputfilename))?; let iter: Vec<_> = file .lines() .map(|l| { let mut s = l.split(';').map(|s| s.trim().parse::().unwrap()); Point { t: s.next().unwrap(), posx: s.next().unwrap(), velx: s.nth(2).unwrap(), dens: s.nth(2).unwrap(), ener: s.next().unwrap(), pres: s.next().unwrap(), } }) .collect(); let root = BitMapBackend::new(&outfilename, (1080, 720)).into_drawing_area(); root.fill(&WHITE)?; let root = root.margin(10, 10, 10, 10); let root = root.titled(&format!("t: {:.5}", iter[0].t), ("sans-serif", 30))?; let charts = root.split_evenly((2, 2)); let pointsize = 2; { let mut chart = ChartBuilder::on(&charts[0]) .set_left_and_bottom_label_area_size(45) .caption("velocity", ("sans-serif", 20)) .build_cartesian_2d(xrange.clone(), 0f32..3f32)?; chart.configure_mesh().draw()?; chart.draw_series(PointSeries::of_element( iter.iter(), pointsize, &BLUE, &|c, s, st| Circle::new((c.posx, c.velx), s, st.filled()), ))?; } { let mut chart = ChartBuilder::on(&charts[1]) .set_left_and_bottom_label_area_size(45) .caption("density", ("sans-serif", 20)) .build_cartesian_2d(xrange.clone(), 0f32..12000f32)?; chart.configure_mesh().draw()?; chart.draw_series(PointSeries::of_element( iter.iter(), pointsize, &BLUE, &|c, s, st| Circle::new((c.posx, c.dens), s, st.filled()), ))?; } { let mut chart = ChartBuilder::on(&charts[2]) .set_left_and_bottom_label_area_size(45) .caption("energy", ("sans-serif", 20)) .build_cartesian_2d(xrange.clone(), 0f32..5f32)?; chart.configure_mesh().draw()?; chart.draw_series(PointSeries::of_element( iter.iter(), pointsize, &BLUE, &|c, s, st| Circle::new((c.posx, c.ener), s, st.filled()), ))?; } { let mut chart = ChartBuilder::on(&charts[3]) .set_left_and_bottom_label_area_size(45) .caption("pressure", ("sans-serif", 20)) .build_cartesian_2d(xrange, 0f32..12000f32)?; chart.configure_mesh().draw()?; chart.draw_series(PointSeries::of_element( iter.iter(), pointsize, &BLUE, &|c, s, st| Circle::new((c.posx, c.pres), s, st.filled()), ))?; } root.present()?; Ok(()) } #[derive(Parser)] struct Args { x_range_min: f32, x_range_max: f32, max_index: usize, #[arg(default_value_t = 1)] step: usize, } fn main() -> Result<()> { let args = Args::parse(); (0..(args.max_index / args.step)) .into_par_iter() .for_each(|i| { if let Err(e) = plot_file(i * args.step, args.x_range_min..args.x_range_max) { println!("Error: {e:?}") } }); Ok(()) }