SummationByParts/multigrid/src/main.rs

306 lines
9.4 KiB
Rust
Raw Normal View History

2020-04-11 13:19:34 +00:00
#![feature(str_strip)]
2020-04-15 17:49:59 +00:00
use either::*;
use sbp::operators::{SbpOperator2d, UpwindOperator2d};
2020-04-02 19:36:56 +00:00
use sbp::utils::json_to_grids;
2020-03-31 22:08:55 +00:00
use sbp::*;
2020-04-02 19:36:56 +00:00
use structopt::StructOpt;
2020-03-31 22:08:55 +00:00
2020-04-13 11:31:01 +00:00
mod file;
use file::*;
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>,
2020-03-31 22:08:55 +00:00
k: [Vec<euler::Field>; 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,
2020-04-15 17:49:59 +00:00
operators: Vec<Either<Box<dyn SbpOperator2d>, Box<dyn UpwindOperator2d>>>,
interpolation_operators: Vec<euler::InterpolationOperators>,
2020-03-31 22:08:55 +00:00
}
2020-04-12 22:00:27 +00:00
impl System {
fn new(
grids: Vec<grid::Grid>,
bt: Vec<euler::BoundaryCharacteristics>,
interpolation_operators: Vec<euler::InterpolationOperators>,
2020-04-15 17:49:59 +00:00
operators: Vec<Either<Box<dyn SbpOperator2d>, Box<dyn UpwindOperator2d>>>,
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();
let k = [fnow.clone(), fnow.clone(), fnow.clone(), fnow.clone()];
2020-04-12 22:00:27 +00:00
let metrics = grids
.iter()
2020-04-15 17:49:59 +00:00
.zip(&operators)
.map(|(g, op)| {
let sbpop: &dyn SbpOperator2d = op.as_ref().either(|op| &**op, |uo| uo.as_sbp());
g.metrics(sbpop).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,
interpolation_operators,
2020-04-15 17:49:59 +00:00
operators,
2020-03-31 22:08:55 +00:00
}
}
fn vortex(&mut self, t: Float, vortex_params: euler::VortexParameters) {
for (f, g) in self.fnow.iter_mut().zip(&self.grids) {
f.vortex(g.x(), g.y(), t, vortex_params);
}
}
2020-04-12 10:35:16 +00:00
fn advance(&mut self, dt: Float, pool: &rayon::ThreadPool) {
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;
let mut eb = &mut self.eb;
let intops = &self.interpolation_operators;
2020-04-15 17:49:59 +00:00
let operators = &self.operators;
2020-04-13 16:39:21 +00:00
2020-04-12 10:35:16 +00:00
let rhs = move |fut: &mut [euler::Field],
prev: &[euler::Field],
time: Float,
2020-04-13 16:39:21 +00:00
_c: (),
_mt: &mut ()| {
let bc = euler::extract_boundaries(prev, &bt, &mut eb, &grids, time, Some(intops));
2020-04-12 10:35:16 +00:00
pool.scope(|s| {
2020-04-15 17:49:59 +00:00
for (((((fut, prev), bc), wb), metrics), op) in fut
2020-04-12 10:35:16 +00:00
.iter_mut()
.zip(prev.iter())
.zip(bc)
.zip(wb.iter_mut())
.zip(metrics.iter())
2020-04-15 17:49:59 +00:00
.zip(operators.iter())
2020-04-02 21:36:20 +00:00
{
2020-04-15 17:49:59 +00:00
s.spawn(move |_| match op.as_ref() {
Left(sbp) => {
euler::RHS_trad(&**sbp, fut, prev, metrics, &bc, &mut wb.0);
2020-04-12 22:00:27 +00:00
}
2020-04-15 17:49:59 +00:00
Right(uo) => {
euler::RHS_upwind(&**uo, fut, prev, metrics, &bc, &mut wb.0);
2020-04-12 22:00:27 +00:00
}
2020-04-15 17:49:59 +00:00
})
2020-04-02 21:36:20 +00:00
}
});
2020-04-12 10:35:16 +00:00
};
2020-04-12 22:00:27 +00:00
2020-04-12 10:35:16 +00:00
let mut k = self
.k
.iter_mut()
.map(|k| k.as_mut_slice())
.collect::<Vec<_>>();
sbp::integrate::integrate_multigrid::<sbp::integrate::Rk4, _, _, _, _>(
rhs,
&self.fnow,
&mut self.fnext,
&mut self.time,
dt,
&mut k,
2020-04-13 16:39:21 +00:00
(),
&mut (),
2020-04-12 10:35:16 +00:00
pool,
);
std::mem::swap(&mut self.fnow, &mut self.fnext);
2020-04-02 21:36:20 +00:00
}
2020-03-31 22:08:55 +00:00
}
2020-04-06 20:32:36 +00:00
2020-04-02 19:36:56 +00:00
#[derive(Debug, StructOpt)]
struct Options {
json: std::path::PathBuf,
2020-04-03 20:30:30 +00:00
/// Disable the progressbar
#[structopt(long)]
2020-04-02 20:32:07 +00:00
no_progressbar: bool,
2020-04-03 20:30:30 +00:00
/// Number of simultaneous threads
#[structopt(short, long)]
jobs: Option<Option<usize>>,
2020-04-04 20:14:15 +00:00
/// Name of output file
2020-04-10 09:53:37 +00:00
#[structopt(default_value = "output.hdf", long, short)]
2020-04-04 20:14:15 +00:00
output: std::path::PathBuf,
2020-04-07 21:25:19 +00:00
/// Number of outputs to save
#[structopt(long, short)]
number_of_outputs: Option<u64>,
2020-04-08 18:04:12 +00:00
/// Print the time to complete, taken in the compute loop
#[structopt(long)]
timings: bool,
/// Print error at the end of the run
#[structopt(long)]
error: bool,
2020-03-31 22:08:55 +00:00
}
fn main() {
2020-04-02 19:36:56 +00:00
let opt = Options::from_args();
let filecontents = std::fs::read_to_string(&opt.json).unwrap();
2020-03-31 22:08:55 +00:00
2020-04-02 19:36:56 +00:00
let json = json::parse(&filecontents).unwrap();
let jgrids = json_to_grids(json["grids"].clone()).unwrap();
2020-04-06 20:11:35 +00:00
let vortexparams = utils::json_to_vortex(json["vortex"].clone());
2020-03-31 22:08:55 +00:00
2020-04-02 19:36:56 +00:00
let mut bt = Vec::with_capacity(jgrids.len());
2020-04-11 13:19:34 +00:00
let determine_bc = |dir: Option<&String>| match dir {
2020-04-06 20:11:35 +00:00
Some(dir) => {
if dir == "vortex" {
euler::BoundaryCharacteristic::Vortex(vortexparams)
2020-04-11 13:19:34 +00:00
} else if let Some(grid) = dir.strip_prefix("interpolate:") {
euler::BoundaryCharacteristic::Interpolate(
jgrids
.iter()
.position(|other| other.name.as_ref().map_or(false, |name| name == grid))
.unwrap(),
)
2020-04-06 20:11:35 +00:00
} else {
euler::BoundaryCharacteristic::Grid(
jgrids
.iter()
.position(|other| other.name.as_ref().map_or(false, |name| name == dir))
.unwrap(),
)
}
}
2020-04-02 19:36:56 +00:00
None => euler::BoundaryCharacteristic::This,
};
for grid in &jgrids {
bt.push(euler::BoundaryCharacteristics {
north: determine_bc(grid.dirn.as_ref()),
south: determine_bc(grid.dirs.as_ref()),
east: determine_bc(grid.dire.as_ref()),
west: determine_bc(grid.dirw.as_ref()),
});
}
let interpolation_operators = jgrids
.iter()
.map(|_g| euler::InterpolationOperators {
north: Some(Box::new(operators::Interpolation4)),
south: Some(Box::new(operators::Interpolation4)),
east: Some(Box::new(operators::Interpolation4)),
west: Some(Box::new(operators::Interpolation4)),
})
.collect::<Vec<_>>();
2020-04-15 17:49:59 +00:00
let grids = jgrids
.into_iter()
.map(|egrid| egrid.grid)
.collect::<Vec<grid::Grid>>();
2020-04-03 22:29:02 +00:00
2020-04-04 20:33:33 +00:00
let integration_time: Float = json["integration_time"].as_number().unwrap().into();
2020-03-31 22:08:55 +00:00
2020-04-15 17:49:59 +00:00
let operators = grids
.iter()
.map(|_| Right(Box::new(operators::Upwind4) as Box<dyn UpwindOperator2d>))
.collect::<Vec<_>>();
2020-04-12 22:00:27 +00:00
2020-04-15 17:49:59 +00:00
let mut sys = System::new(grids, bt, interpolation_operators, operators);
2020-04-02 20:49:27 +00:00
sys.vortex(0.0, vortexparams);
2020-04-02 19:36:56 +00:00
let max_n = {
let max_nx = sys.grids.iter().map(|g| g.nx()).max().unwrap();
let max_ny = sys.grids.iter().map(|g| g.ny()).max().unwrap();
std::cmp::max(max_nx, max_ny)
};
let dt = 0.2 / (max_n as Float);
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
let pool = {
2020-04-03 20:30:30 +00:00
let builder = rayon::ThreadPoolBuilder::new();
if let Some(j) = opt.jobs {
if let Some(j) = j {
builder.num_threads(j)
} else {
builder
}
2020-04-03 20:30:30 +00:00
} else {
builder.num_threads(1)
}
.build()
.unwrap()
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-07 18:35:00 +00:00
let output = File::create(&opt.output, sys.grids.as_slice()).unwrap();
2020-04-07 20:54:00 +00:00
let mut output = OutputThread::new(output);
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);
sys.advance(dt, &pool);
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
2020-04-08 18:04:12 +00:00
if let Some(timer) = timer {
let duration = timer.elapsed();
println!("Time elapsed: {} seconds", duration.as_secs_f64());
}
2020-04-07 20:54:00 +00:00
output.add_timestep(ntime, &sys.fnow);
if opt.error {
2020-04-11 13:19:34 +00:00
let time = ntime as Float * dt;
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) {
let mut fvort = fmod.clone();
fvort.vortex(grid.x(), grid.y(), time, vortexparams);
2020-04-15 17:49:59 +00:00
let sbpop: &dyn SbpOperator2d = op.as_ref().either(|op| &**op, |uo| uo.as_sbp());
e += fmod.h2_err(&fvort, sbpop);
}
println!("Total error: {:e}", e);
}
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})"),
)
}
}