use russell_lab::{format_scientific, get_num_threads, set_num_threads, StrError};
use russell_ode::prelude::*;
use russell_sparse::{Genie, LinSolParams, Ordering, Scaling};
use structopt::StructOpt;
#[derive(StructOpt)]
#[structopt(name = "BrusselatorPDE", about = "Solve the Brusselator PDE System")]
struct Options {
#[structopt(long)]
first_book: bool,
#[structopt(long, default_value = "129")]
npoint: usize,
#[structopt(long)]
dopri5: bool,
#[structopt(long)]
dopri8: bool,
#[structopt(long, default_value = "4")]
neg_exp_tol: i32,
#[structopt(long)]
serial: bool,
#[structopt(long, default_value = "4")]
blas_nt: usize,
#[structopt(long)]
write_matrix: bool,
#[structopt(short = "g", long, default_value = "Umfpack")]
genie: String,
#[structopt(short = "o", long, default_value = "Auto")]
ordering: String,
#[structopt(short = "s", long, default_value = "Auto")]
scaling: String,
}
fn main() -> Result<(), StrError> {
let opt = Options::from_args();
if opt.npoint < 2 {
return Err("npoint must be ≥ 2 ");
}
if opt.neg_exp_tol < 1 || opt.neg_exp_tol > 30 {
return Err("neg_exp_tol must satisfy: 1 ≤ net ≤ 30");
}
if opt.blas_nt < 1 || opt.blas_nt > 32 {
return Err("blas_nt must satisfy: 1 ≤ net ≤ 32");
}
set_num_threads(opt.blas_nt);
let alpha = if opt.first_book { 2e-3 } else { 0.1 };
let (system, t0, mut yy0, mut args) = Samples::brusselator_pde(alpha, opt.npoint, !opt.first_book, false);
let t1 = 1.5;
let mut ls_params = LinSolParams::new();
ls_params.ordering = Ordering::from(&opt.ordering);
ls_params.scaling = Scaling::from(&opt.scaling);
let mut params = if opt.dopri8 {
Params::new(Method::DoPri8)
} else if opt.dopri5 {
Params::new(Method::DoPri5)
} else {
Params::new(Method::Radau5)
};
let tol = f64::powi(10.0, -opt.neg_exp_tol);
params.step.h_ini = 1e-4;
params.radau5.concurrent = !opt.serial;
params.set_tolerances(tol, tol, None)?;
params.newton.genie = Genie::from(&opt.genie);
params.newton.lin_sol_params = Some(ls_params);
if opt.write_matrix {
params.newton.write_matrix_after_nstep_and_stop = Some(0);
}
let ndim = system.get_ndim();
let jac_nnz = system.get_jac_nnz();
let mut solver = OdeSolver::new(params, system)?;
solver.solve(&mut yy0, t0, t1, None, &mut args)?;
let stat = solver.stats();
println!("Second-book problem = {}", !opt.first_book);
println!("Number of points along x and y = {}", opt.npoint);
println!("Tolerance (abs_tol = rel_tol) = {}", format_scientific(tol, 8, 2));
println!("Concurrent real and complex sys = {}", !opt.serial);
println!("Problem dimension (ndim) = {}", ndim);
println!("Number of non-zeros (jac_nnz) = {}", jac_nnz);
println!("Number of BLAS threads = {}", get_num_threads());
println!("Linear solver = {:?}", params.newton.genie);
println!("{}", stat);
Ok(())
}