use argh::FromArgs; use sbp::*; mod eval; mod input; mod parsing; mod system; #[derive(Debug, FromArgs)] /// Options for configuring and running the solver struct CliOptions { #[argh(positional)] json: std::path::PathBuf, /// name of output file #[argh( option, short = 'o', default = "std::path::PathBuf::from(\"output.hdf\")" )] output: std::path::PathBuf, /// number of outputs to save #[argh(option, short = 'n')] number_of_outputs: Option, /// print the time to complete, taken in the compute loop #[argh(switch)] timings: bool, /// print error at the end of the run #[argh(switch)] error: bool, /// disable the progressbar #[argh(switch)] no_progressbar: bool, /// output information regarding time elapsed and error /// in json format #[argh(switch)] output_json: bool, /// distribute the computation on multiple threads #[argh(switch)] distribute: bool, } #[derive(Default, serde::Serialize)] struct OutputInformation { filename: std::path::PathBuf, #[serde(skip_serializing_if = "Option::is_none")] time_elapsed: Option, #[serde(skip_serializing_if = "Option::is_none")] error: Option, } fn main() { let opt: CliOptions = argh::from_env(); let filecontents = std::fs::read_to_string(&opt.json).unwrap(); let config: input::Configuration = match json5::from_str(&filecontents) { Ok(config) => config, Err(e) => { eprintln!("Configuration could not be read: {}", e); if let json5::Error::Message { location: Some(location), .. } = e { eprintln!("\t{:?}", location); } return; } }; let parsing::RuntimeConfiguration { names, grids, boundary_conditions, op: operators, integration_time, initial_conditions, } = config.into_runtime(); let basesystem = system::BaseSystem::new( names, grids, 0.0, operators, boundary_conditions, initial_conditions, opt.output.clone(), ); let mut sys = if opt.distribute { basesystem.create_distributed() } else { basesystem.create() }; let dt = sys.max_dt(); sys.set_dt(dt); let ntime = (integration_time / dt).round() as u64; let steps_between_outputs = if let Some(n) = opt.number_of_outputs { std::cmp::max(n / ntime, 1) } else { ntime }; sys.output(0); if !opt.no_progressbar { sys.add_progressbar(ntime) } let timer = if opt.timings { Some(std::time::Instant::now()) } else { None }; let mut itime = 0; while itime < ntime { sys.advance(steps_between_outputs); itime += steps_between_outputs; sys.output(itime); } if itime != ntime { sys.advance(ntime - itime); sys.output(ntime); } if !opt.no_progressbar { sys.finish_progressbar(); } let mut outinfo = OutputInformation { filename: opt.output, ..Default::default() }; if let Some(timer) = timer { let duration = timer.elapsed(); outinfo.time_elapsed = Some(duration); } //output.add_timestep(ntime, &sys.fnow); /* if opt.error { let time = ntime as Float * dt; let mut e = 0.0; for ((fmod, grid), op) in sys.fnow.iter().zip(&sys.grids).zip(&sys.operators) { let mut fvort = fmod.clone(); match &initial_conditions { parsing::InitialConditions::Vortex(vortexparams) => { fvort.vortex(grid.x(), grid.y(), time, &vortexparams); } parsing::InitialConditions::Expressions(expr) => { let (rho, rhou, rhov, e) = fvort.components_mut(); expr.as_ref() .evaluate(time, grid.x(), grid.y(), rho, rhou, rhov, e) } } e += fmod.h2_err(&fvort, &**op); } outinfo.error = Some(e); } */ if opt.output_json { println!("{}", json5::to_string(&outinfo).unwrap()); } else { if let Some(duration) = outinfo.time_elapsed { println!("Time elapsed: {} seconds", duration.as_secs_f64()); } if let Some(error) = outinfo.error { println!("Total error: {:e}", error); } } } fn progressbar(ntime: u64) -> indicatif::ProgressBar { let progressbar = indicatif::ProgressBar::new(ntime); progressbar.with_style( indicatif::ProgressStyle::default_bar() .template("{wide_bar:.cyan/blue} {pos}/{len} ({eta})"), ) }