2021-03-22 19:54:28 +00:00
|
|
|
use argh::FromArgs;
|
2021-03-22 18:28:01 +00:00
|
|
|
use rayon::prelude::*;
|
2020-04-15 18:18:51 +00:00
|
|
|
|
2021-06-29 15:55:19 +00:00
|
|
|
use euler::eval::Evaluator;
|
2021-01-17 14:37:45 +00:00
|
|
|
use sbp::operators::SbpOperator2d;
|
2020-03-31 22:08:55 +00:00
|
|
|
use sbp::*;
|
|
|
|
|
2020-04-13 11:31:01 +00:00
|
|
|
mod file;
|
2020-09-03 21:49:45 +00:00
|
|
|
mod parsing;
|
2020-04-13 11:31:01 +00:00
|
|
|
use file::*;
|
2021-06-29 15:55:19 +00:00
|
|
|
mod eval;
|
2020-04-13 11:31:01 +00:00
|
|
|
|
2020-04-12 22:00:27 +00:00
|
|
|
struct System {
|
2020-03-31 22:08:55 +00:00
|
|
|
fnow: Vec<euler::Field>,
|
|
|
|
fnext: Vec<euler::Field>,
|
2020-04-12 19:32:20 +00:00
|
|
|
wb: Vec<euler::WorkBuffers>,
|
2021-03-30 16:46:28 +00:00
|
|
|
k: [Vec<euler::Diff>; 4],
|
2020-04-03 22:29:02 +00:00
|
|
|
grids: Vec<grid::Grid>,
|
2020-04-15 17:49:59 +00:00
|
|
|
metrics: Vec<grid::Metrics>,
|
2020-04-02 19:36:56 +00:00
|
|
|
bt: Vec<euler::BoundaryCharacteristics>,
|
2020-04-10 10:30:18 +00:00
|
|
|
eb: Vec<euler::BoundaryStorage>,
|
2020-04-06 20:11:35 +00:00
|
|
|
time: Float,
|
2021-01-17 14:37:45 +00:00
|
|
|
operators: Vec<Box<dyn SbpOperator2d>>,
|
2020-03-31 22:08:55 +00:00
|
|
|
}
|
|
|
|
|
2021-03-25 23:00:42 +00:00
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
pub(crate) static MULTITHREAD: AtomicBool = AtomicBool::new(false);
|
|
|
|
|
2021-03-22 18:28:01 +00:00
|
|
|
impl integrate::Integrable for System {
|
|
|
|
type State = Vec<euler::Field>;
|
2021-03-30 16:46:28 +00:00
|
|
|
type Diff = Vec<euler::Diff>;
|
2021-03-22 18:28:01 +00:00
|
|
|
fn assign(s: &mut Self::State, o: &Self::State) {
|
2021-03-25 23:00:42 +00:00
|
|
|
if MULTITHREAD.load(Ordering::Acquire) {
|
|
|
|
s.par_iter_mut()
|
|
|
|
.zip(o.par_iter())
|
|
|
|
.for_each(|(s, o)| euler::Field::assign(s, o))
|
|
|
|
} else {
|
|
|
|
s.iter_mut()
|
|
|
|
.zip(o.iter())
|
|
|
|
.for_each(|(s, o)| euler::Field::assign(s, o))
|
|
|
|
}
|
2021-03-22 18:28:01 +00:00
|
|
|
}
|
|
|
|
fn scaled_add(s: &mut Self::State, o: &Self::Diff, scale: Float) {
|
2021-03-25 23:00:42 +00:00
|
|
|
if MULTITHREAD.load(Ordering::Acquire) {
|
|
|
|
s.par_iter_mut()
|
|
|
|
.zip(o.par_iter())
|
|
|
|
.for_each(|(s, o)| euler::Field::scaled_add(s, o, scale))
|
|
|
|
} else {
|
|
|
|
s.iter_mut()
|
|
|
|
.zip(o.iter())
|
|
|
|
.for_each(|(s, o)| euler::Field::scaled_add(s, o, scale))
|
|
|
|
}
|
2021-03-22 18:28:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 22:00:27 +00:00
|
|
|
impl System {
|
|
|
|
fn new(
|
|
|
|
grids: Vec<grid::Grid>,
|
|
|
|
bt: Vec<euler::BoundaryCharacteristics>,
|
2021-01-17 14:37:45 +00:00
|
|
|
operators: Vec<Box<dyn SbpOperator2d>>,
|
2020-04-12 22:00:27 +00:00
|
|
|
) -> Self {
|
2020-03-31 22:08:55 +00:00
|
|
|
let fnow = grids
|
|
|
|
.iter()
|
|
|
|
.map(|g| euler::Field::new(g.ny(), g.nx()))
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
let fnext = fnow.clone();
|
|
|
|
let wb = grids
|
|
|
|
.iter()
|
2020-04-12 19:32:20 +00:00
|
|
|
.map(|g| euler::WorkBuffers::new(g.ny(), g.nx()))
|
2020-03-31 22:08:55 +00:00
|
|
|
.collect();
|
2021-03-30 16:46:28 +00:00
|
|
|
let k = grids
|
|
|
|
.iter()
|
|
|
|
.map(|g| euler::Diff::zeros((g.ny(), g.nx())))
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
let k = [k.clone(), k.clone(), k.clone(), k];
|
2020-04-12 22:00:27 +00:00
|
|
|
let metrics = grids
|
|
|
|
.iter()
|
2020-04-15 17:49:59 +00:00
|
|
|
.zip(&operators)
|
2021-01-17 14:37:45 +00:00
|
|
|
.map(|(g, op)| g.metrics(&**op).unwrap())
|
2020-04-12 22:00:27 +00:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2020-04-06 20:11:35 +00:00
|
|
|
let eb = bt
|
|
|
|
.iter()
|
|
|
|
.zip(&grids)
|
2020-04-10 10:30:18 +00:00
|
|
|
.map(|(bt, grid)| euler::BoundaryStorage::new(bt, grid))
|
2020-04-06 20:11:35 +00:00
|
|
|
.collect();
|
2020-03-31 22:08:55 +00:00
|
|
|
|
|
|
|
Self {
|
|
|
|
fnow,
|
|
|
|
fnext,
|
|
|
|
k,
|
|
|
|
wb,
|
|
|
|
grids,
|
2020-04-03 22:29:02 +00:00
|
|
|
metrics,
|
2020-04-02 19:36:56 +00:00
|
|
|
bt,
|
2020-04-06 20:11:35 +00:00
|
|
|
eb,
|
|
|
|
time: 0.0,
|
2020-04-15 17:49:59 +00:00
|
|
|
operators,
|
2020-03-31 22:08:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-22 21:59:06 +00:00
|
|
|
fn vortex(&mut self, t: Float, vortex_params: &euler::VortexParameters) {
|
2020-03-31 22:08:55 +00:00
|
|
|
for (f, g) in self.fnow.iter_mut().zip(&self.grids) {
|
2020-04-22 21:59:06 +00:00
|
|
|
f.vortex(g.x(), g.y(), t, &vortex_params);
|
2020-03-31 22:08:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-22 18:28:01 +00:00
|
|
|
fn advance(&mut self, dt: Float) {
|
2020-04-12 22:00:27 +00:00
|
|
|
let metrics = &self.metrics;
|
2020-04-13 16:39:21 +00:00
|
|
|
let grids = &self.grids;
|
|
|
|
let bt = &self.bt;
|
|
|
|
let wb = &mut self.wb;
|
2020-04-22 20:22:19 +00:00
|
|
|
let eb = &mut self.eb;
|
2020-04-15 17:49:59 +00:00
|
|
|
let operators = &self.operators;
|
2020-04-13 16:39:21 +00:00
|
|
|
|
2021-03-30 16:46:28 +00:00
|
|
|
let rhs = move |fut: &mut Vec<euler::Diff>, prev: &Vec<euler::Field>, time: Float| {
|
2020-04-22 20:22:19 +00:00
|
|
|
let prev_all = &prev;
|
2021-03-25 23:00:42 +00:00
|
|
|
if MULTITHREAD.load(Ordering::Acquire) {
|
|
|
|
rayon::scope(|s| {
|
|
|
|
for (((((((fut, prev), wb), grid), metrics), op), bt), eb) in fut
|
|
|
|
.iter_mut()
|
|
|
|
.zip(prev.iter())
|
|
|
|
.zip(wb.iter_mut())
|
|
|
|
.zip(grids)
|
|
|
|
.zip(metrics.iter())
|
|
|
|
.zip(operators.iter())
|
|
|
|
.zip(bt.iter())
|
|
|
|
.zip(eb.iter_mut())
|
|
|
|
{
|
|
|
|
s.spawn(move |_| {
|
|
|
|
let bc = euler::boundary_extracts(prev_all, bt, prev, grid, eb, time);
|
|
|
|
if op.upwind().is_some() {
|
|
|
|
euler::RHS_upwind(&**op, fut, prev, metrics, &bc, &mut wb.0);
|
|
|
|
} else {
|
|
|
|
euler::RHS_trad(&**op, fut, prev, metrics, &bc, &mut wb.0);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
2020-04-22 20:22:19 +00:00
|
|
|
for (((((((fut, prev), wb), grid), metrics), op), bt), eb) in fut
|
2020-04-12 10:35:16 +00:00
|
|
|
.iter_mut()
|
|
|
|
.zip(prev.iter())
|
|
|
|
.zip(wb.iter_mut())
|
2020-04-22 20:22:19 +00:00
|
|
|
.zip(grids)
|
2020-04-12 10:35:16 +00:00
|
|
|
.zip(metrics.iter())
|
2020-04-15 17:49:59 +00:00
|
|
|
.zip(operators.iter())
|
2020-04-22 20:22:19 +00:00
|
|
|
.zip(bt.iter())
|
|
|
|
.zip(eb.iter_mut())
|
2020-04-02 21:36:20 +00:00
|
|
|
{
|
2021-03-25 23:00:42 +00:00
|
|
|
let bc = euler::boundary_extracts(prev_all, bt, prev, grid, eb, time);
|
|
|
|
if op.upwind().is_some() {
|
|
|
|
euler::RHS_upwind(&**op, fut, prev, metrics, &bc, &mut wb.0);
|
|
|
|
} else {
|
|
|
|
euler::RHS_trad(&**op, fut, prev, metrics, &bc, &mut wb.0);
|
|
|
|
}
|
2020-04-02 21:36:20 +00:00
|
|
|
}
|
2021-03-25 23:00:42 +00:00
|
|
|
}
|
2020-04-12 10:35:16 +00:00
|
|
|
};
|
2020-04-12 22:00:27 +00:00
|
|
|
|
2021-03-22 18:28:01 +00:00
|
|
|
integrate::integrate::<integrate::Rk4, System, _>(
|
2020-04-12 10:35:16 +00:00
|
|
|
rhs,
|
|
|
|
&self.fnow,
|
|
|
|
&mut self.fnext,
|
|
|
|
&mut self.time,
|
|
|
|
dt,
|
2021-03-22 18:28:01 +00:00
|
|
|
&mut self.k,
|
2020-04-12 10:35:16 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
std::mem::swap(&mut self.fnow, &mut self.fnext);
|
2020-04-02 21:36:20 +00:00
|
|
|
}
|
2020-05-03 18:45:27 +00:00
|
|
|
|
|
|
|
/// Suggested maximum dt for this problem
|
|
|
|
fn max_dt(&self) -> Float {
|
2021-01-17 14:37:45 +00:00
|
|
|
let is_h2 = self
|
|
|
|
.operators
|
|
|
|
.iter()
|
|
|
|
.any(|op| op.is_h2xi() || op.is_h2eta());
|
2020-09-04 15:44:06 +00:00
|
|
|
let c_max = if is_h2 { 0.5 } else { 1.0 };
|
2020-05-03 18:45:27 +00:00
|
|
|
let mut max_dt: Float = Float::INFINITY;
|
|
|
|
|
|
|
|
for (field, metrics) in self.fnow.iter().zip(self.metrics.iter()) {
|
|
|
|
let nx = field.nx();
|
|
|
|
let ny = field.ny();
|
|
|
|
|
|
|
|
let rho = field.rho();
|
|
|
|
let rhou = field.rhou();
|
|
|
|
let rhov = field.rhov();
|
|
|
|
|
|
|
|
let mut max_u: Float = 0.0;
|
|
|
|
let mut max_v: Float = 0.0;
|
|
|
|
|
|
|
|
for ((((((rho, rhou), rhov), detj_dxi_dx), detj_dxi_dy), detj_deta_dx), detj_deta_dy) in
|
|
|
|
rho.iter()
|
|
|
|
.zip(rhou.iter())
|
|
|
|
.zip(rhov.iter())
|
|
|
|
.zip(metrics.detj_dxi_dx())
|
|
|
|
.zip(metrics.detj_dxi_dy())
|
|
|
|
.zip(metrics.detj_deta_dx())
|
|
|
|
.zip(metrics.detj_deta_dy())
|
|
|
|
{
|
|
|
|
let u = rhou / rho;
|
|
|
|
let v = rhov / rho;
|
|
|
|
|
|
|
|
let uhat: Float = detj_dxi_dx * u + detj_dxi_dy * v;
|
|
|
|
let vhat: Float = detj_deta_dx * u + detj_deta_dy * v;
|
|
|
|
|
|
|
|
max_u = max_u.max(uhat.abs());
|
|
|
|
max_v = max_v.max(vhat.abs());
|
|
|
|
}
|
|
|
|
|
|
|
|
let dx = 1.0 / nx as Float;
|
|
|
|
let dy = 1.0 / ny as Float;
|
|
|
|
|
|
|
|
let c_dt = Float::max(max_u / dx, max_v / dy);
|
|
|
|
|
|
|
|
max_dt = Float::min(max_dt, c_max / c_dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
max_dt
|
|
|
|
}
|
2020-03-31 22:08:55 +00:00
|
|
|
}
|
2020-04-06 20:32:36 +00:00
|
|
|
|
2021-03-22 19:54:28 +00:00
|
|
|
#[derive(Debug, FromArgs)]
|
|
|
|
/// Options for configuring and running the solver
|
|
|
|
struct CliOptions {
|
|
|
|
#[argh(positional)]
|
2020-04-02 19:36:56 +00:00
|
|
|
json: std::path::PathBuf,
|
2021-03-22 19:54:28 +00:00
|
|
|
/// number of simultaneous threads
|
|
|
|
#[argh(option, short = 'j')]
|
2021-03-22 18:28:01 +00:00
|
|
|
jobs: Option<usize>,
|
2021-03-22 19:54:28 +00:00
|
|
|
/// name of output file
|
|
|
|
#[argh(
|
|
|
|
option,
|
|
|
|
short = 'o',
|
|
|
|
default = "std::path::PathBuf::from(\"output.hdf\")"
|
|
|
|
)]
|
2020-04-04 20:14:15 +00:00
|
|
|
output: std::path::PathBuf,
|
2021-03-22 19:54:28 +00:00
|
|
|
/// number of outputs to save
|
|
|
|
#[argh(option, short = 'n')]
|
2020-04-07 21:25:19 +00:00
|
|
|
number_of_outputs: Option<u64>,
|
2021-03-22 19:54:28 +00:00
|
|
|
/// print the time to complete, taken in the compute loop
|
|
|
|
#[argh(switch)]
|
2020-04-08 18:04:12 +00:00
|
|
|
timings: bool,
|
2021-03-22 19:54:28 +00:00
|
|
|
/// print error at the end of the run
|
|
|
|
#[argh(switch)]
|
2020-04-08 18:19:50 +00:00
|
|
|
error: bool,
|
2021-03-22 19:54:28 +00:00
|
|
|
/// disable the progressbar
|
|
|
|
#[argh(switch)]
|
|
|
|
no_progressbar: bool,
|
|
|
|
/// output information regarding time elapsed and error
|
2021-02-12 17:28:30 +00:00
|
|
|
/// in json format
|
2021-03-22 19:54:28 +00:00
|
|
|
#[argh(switch)]
|
2021-02-12 17:28:30 +00:00
|
|
|
output_json: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default, serde::Serialize)]
|
|
|
|
struct OutputInformation {
|
|
|
|
filename: std::path::PathBuf,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
time_elapsed: Option<std::time::Duration>,
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
error: Option<Float>,
|
2020-03-31 22:08:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2021-03-22 19:54:28 +00:00
|
|
|
let opt: CliOptions = argh::from_env();
|
2020-04-02 19:36:56 +00:00
|
|
|
let filecontents = std::fs::read_to_string(&opt.json).unwrap();
|
2020-03-31 22:08:55 +00:00
|
|
|
|
2021-02-12 17:08:10 +00:00
|
|
|
let config: parsing::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;
|
|
|
|
}
|
|
|
|
};
|
2020-04-03 22:29:02 +00:00
|
|
|
|
2020-09-03 21:49:45 +00:00
|
|
|
let parsing::RuntimeConfiguration {
|
|
|
|
names,
|
|
|
|
grids,
|
2021-06-29 15:55:19 +00:00
|
|
|
grid_connections,
|
2020-09-03 21:49:45 +00:00
|
|
|
op: operators,
|
|
|
|
integration_time,
|
2021-06-29 15:55:19 +00:00
|
|
|
initial_conditions,
|
|
|
|
boundary_conditions: _,
|
2020-09-04 15:44:06 +00:00
|
|
|
} = config.into_runtime();
|
2020-03-31 22:08:55 +00:00
|
|
|
|
2021-06-29 15:55:19 +00:00
|
|
|
let mut sys = System::new(grids, grid_connections, operators);
|
2021-06-29 17:45:20 +00:00
|
|
|
match &initial_conditions {
|
2021-06-29 15:55:19 +00:00
|
|
|
/*
|
|
|
|
parsing::InitialConditions::File(f) => {
|
|
|
|
for grid in &sys.grids {
|
|
|
|
// Copy initial conditions from file, requires name of field
|
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
parsing::InitialConditions::Vortex(vortexparams) => sys.vortex(0.0, &vortexparams),
|
|
|
|
parsing::InitialConditions::Expressions(expr) => {
|
|
|
|
let t = 0.0;
|
|
|
|
for (grid, field) in sys.grids.iter().zip(sys.fnow.iter_mut()) {
|
|
|
|
// Evaluate the expressions on all variables
|
|
|
|
let x = grid.x();
|
|
|
|
let y = grid.y();
|
|
|
|
let (rho, rhou, rhov, e) = field.components_mut();
|
|
|
|
(*expr).evaluate(t, x, y, rho, rhou, rhov, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-02 19:36:56 +00:00
|
|
|
|
2020-05-03 18:45:27 +00:00
|
|
|
let dt = sys.max_dt();
|
2020-04-02 20:32:07 +00:00
|
|
|
|
2020-04-04 20:14:15 +00:00
|
|
|
let ntime = (integration_time / dt).round() as u64;
|
2020-04-02 20:32:07 +00:00
|
|
|
|
2021-03-22 18:28:01 +00:00
|
|
|
{
|
|
|
|
let nthreads = opt.jobs.unwrap_or(1);
|
2021-03-25 23:00:42 +00:00
|
|
|
if nthreads > 1 {
|
|
|
|
MULTITHREAD.store(true, Ordering::Release);
|
|
|
|
rayon::ThreadPoolBuilder::new()
|
|
|
|
.num_threads(nthreads)
|
|
|
|
.build_global()
|
|
|
|
.unwrap();
|
|
|
|
}
|
2021-03-22 18:28:01 +00:00
|
|
|
}
|
2020-04-02 21:36:20 +00:00
|
|
|
|
2020-04-07 21:25:19 +00:00
|
|
|
let should_output = |itime| {
|
|
|
|
opt.number_of_outputs.map_or(false, |num_out| {
|
|
|
|
if num_out == 0 {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
itime % (std::cmp::max(ntime / (num_out - 1), 1)) == 0
|
|
|
|
}
|
|
|
|
})
|
|
|
|
};
|
|
|
|
|
2020-04-22 18:47:26 +00:00
|
|
|
let output = File::create(&opt.output, sys.grids.as_slice(), names).unwrap();
|
2020-04-07 20:54:00 +00:00
|
|
|
let mut output = OutputThread::new(output);
|
2021-06-29 21:12:48 +00:00
|
|
|
output.add_timestep(0, &sys.fnow);
|
2020-04-07 19:23:51 +00:00
|
|
|
|
2020-04-12 18:44:52 +00:00
|
|
|
let progressbar = progressbar(opt.no_progressbar, ntime);
|
2020-04-08 18:04:12 +00:00
|
|
|
|
|
|
|
let timer = if opt.timings {
|
|
|
|
Some(std::time::Instant::now())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2020-04-07 21:25:19 +00:00
|
|
|
for itime in 0..ntime {
|
|
|
|
if should_output(itime) {
|
|
|
|
output.add_timestep(itime, &sys.fnow);
|
|
|
|
}
|
2020-04-12 18:44:52 +00:00
|
|
|
progressbar.inc(1);
|
2021-03-22 18:28:01 +00:00
|
|
|
sys.advance(dt);
|
2020-04-01 20:37:01 +00:00
|
|
|
}
|
2020-04-12 18:44:52 +00:00
|
|
|
progressbar.finish_and_clear();
|
2020-04-01 20:37:01 +00:00
|
|
|
|
2021-02-12 17:28:30 +00:00
|
|
|
let mut outinfo = OutputInformation {
|
|
|
|
filename: opt.output,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
2020-04-08 18:04:12 +00:00
|
|
|
if let Some(timer) = timer {
|
|
|
|
let duration = timer.elapsed();
|
2021-02-12 17:28:30 +00:00
|
|
|
outinfo.time_elapsed = Some(duration);
|
2020-04-08 18:04:12 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 20:54:00 +00:00
|
|
|
output.add_timestep(ntime, &sys.fnow);
|
2021-06-29 17:45:20 +00:00
|
|
|
|
2020-04-08 18:19:50 +00:00
|
|
|
if opt.error {
|
2020-04-11 13:19:34 +00:00
|
|
|
let time = ntime as Float * dt;
|
2020-04-08 18:19:50 +00:00
|
|
|
let mut e = 0.0;
|
2020-04-15 17:49:59 +00:00
|
|
|
for ((fmod, grid), op) in sys.fnow.iter().zip(&sys.grids).zip(&sys.operators) {
|
2020-04-08 18:19:50 +00:00
|
|
|
let mut fvort = fmod.clone();
|
2021-06-29 17:45:20 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2021-01-17 14:37:45 +00:00
|
|
|
e += fmod.h2_err(&fvort, &**op);
|
2020-04-08 18:19:50 +00:00
|
|
|
}
|
2021-02-12 17:28:30 +00:00
|
|
|
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);
|
|
|
|
}
|
2020-04-08 18:19:50 +00:00
|
|
|
}
|
2020-04-01 20:37:01 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 20:42:44 +00:00
|
|
|
fn progressbar(dummy: bool, ntime: u64) -> indicatif::ProgressBar {
|
|
|
|
if dummy {
|
|
|
|
indicatif::ProgressBar::hidden()
|
|
|
|
} else {
|
2020-04-12 18:44:52 +00:00
|
|
|
let progressbar = indicatif::ProgressBar::new(ntime);
|
|
|
|
progressbar.with_style(
|
2020-04-06 20:42:44 +00:00
|
|
|
indicatif::ProgressStyle::default_bar()
|
|
|
|
.template("{wide_bar:.cyan/blue} {pos}/{len} ({eta})"),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|