Use ndarray's parallelism features
It's easier to read, and it also gets 10-30% perf improvement for Driver::step
This commit is contained in:
@@ -14,7 +14,7 @@ font8x8 = "0.2"
|
|||||||
image = "0.23"
|
image = "0.23"
|
||||||
imageproc = "0.21"
|
imageproc = "0.21"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
ndarray = "0.13"
|
ndarray = { version = "0.13", features = ["rayon"] }
|
||||||
piecewise-linear = "0.1"
|
piecewise-linear = "0.1"
|
||||||
rayon = "1.4"
|
rayon = "1.4"
|
||||||
y4m = "0.7"
|
y4m = "0.7"
|
||||||
|
@@ -291,10 +291,15 @@ impl MultiRenderer {
|
|||||||
|
|
||||||
pub fn render(&mut self, state: &SimState, measurements: &[Box<dyn AbstractMeasurement>]) {
|
pub fn render(&mut self, state: &SimState, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
let max_width = 1980; //< TODO: make configurable
|
let max_width = 1980; //< TODO: make configurable
|
||||||
// let max_width = 200;
|
//let max_width = 100;
|
||||||
|
if state.width() > max_width {
|
||||||
let dec = (state.width() + max_width - 1) / max_width;
|
let dec = (state.width() + max_width - 1) / max_width;
|
||||||
let snap = state.snapshot(dec);
|
let snap = state.snapshot(dec);
|
||||||
Renderer::render(self, &snap, measurements);
|
// XXX: measurements are messed up by rescaling
|
||||||
|
Renderer::render(self, &snap, &[]);
|
||||||
|
} else {
|
||||||
|
Renderer::render(self, &state.snapshot(1), measurements);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
src/sim.rs
58
src/sim.rs
@@ -3,7 +3,7 @@ use crate::geom::Point;
|
|||||||
use crate::mat::{self, GenericMaterial, Material};
|
use crate::mat::{self, GenericMaterial, Material};
|
||||||
|
|
||||||
use decorum::R64;
|
use decorum::R64;
|
||||||
use ndarray::Array2;
|
use ndarray::{Array2, s, Zip};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
pub type SimSnapshot = SimState<mat::Static>;
|
pub type SimSnapshot = SimState<mat::Static>;
|
||||||
@@ -11,6 +11,7 @@ pub type SimSnapshot = SimState<mat::Static>;
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SimState<M=GenericMaterial> {
|
pub struct SimState<M=GenericMaterial> {
|
||||||
cells: Array2<Cell<M>>,
|
cells: Array2<Cell<M>>,
|
||||||
|
scratch: Array2<Cell<M>>,
|
||||||
feature_size: R64,
|
feature_size: R64,
|
||||||
step_no: u64,
|
step_no: u64,
|
||||||
}
|
}
|
||||||
@@ -19,6 +20,7 @@ impl<M: Material + Default> SimState<M> {
|
|||||||
pub fn new(width: u32, height: u32, feature_size: f64) -> Self {
|
pub fn new(width: u32, height: u32, feature_size: f64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cells: Array2::default((height as _, width as _)),
|
cells: Array2::default((height as _, width as _)),
|
||||||
|
scratch: Array2::default((height as _, width as _)),
|
||||||
feature_size: feature_size.into(),
|
feature_size: feature_size.into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
@@ -29,46 +31,29 @@ impl<M: Material + Clone + Default + Send + Sync> SimState<M> {
|
|||||||
pub fn step(&mut self) {
|
pub fn step(&mut self) {
|
||||||
use consts::real::*;
|
use consts::real::*;
|
||||||
let half_time_step = HALF() * self.timestep();
|
let half_time_step = HALF() * self.timestep();
|
||||||
|
let w = self.width() as usize;
|
||||||
|
let h = self.height() as usize;
|
||||||
|
let feature_size = self.feature_size;
|
||||||
|
|
||||||
|
let mut scratch_cells = std::mem::replace(&mut self.scratch, Default::default());
|
||||||
|
|
||||||
// first advance all the magnetic fields
|
// first advance all the magnetic fields
|
||||||
let immute_self = &self;
|
Zip::from(self.cells.slice(s![0..h-1, 0..w-1]))
|
||||||
let new_cells: Vec<Vec<_>> = (0..self.height()).into_par_iter()
|
.and(self.cells.slice(s![0..h-1, 1..w]))
|
||||||
.map(|y| {
|
.and(self.cells.slice(s![1..h, 0..w-1]))
|
||||||
(0..self.width()).into_iter().map(move |x| {
|
.par_apply_assign_into(scratch_cells.slice_mut(s![0..h-1, 0..w-1]), |cell, right_cell, down_cell| {
|
||||||
if x+1 == immute_self.width() || y+1 == immute_self.height() {
|
|
||||||
// XXX This is not an intuitive boundary condition
|
|
||||||
Cell::default()
|
|
||||||
} else {
|
|
||||||
let cell = immute_self.get(x, y);
|
|
||||||
let right_cell = immute_self.get(x+1, y);
|
|
||||||
let down_cell = immute_self.get(x, y+1);
|
|
||||||
cell.clone().step_h(right_cell, down_cell, half_time_step.into())
|
cell.clone().step_h(right_cell, down_cell, half_time_step.into())
|
||||||
}
|
});
|
||||||
}).collect()
|
|
||||||
}).collect();
|
|
||||||
for (row, mut new_row) in new_cells.into_iter().enumerate() {
|
|
||||||
self.cells.row_mut(row).as_slice_mut().unwrap().swap_with_slice(&mut new_row[..]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now advance electic fields
|
// now advance electic fields
|
||||||
let immute_self = &self;
|
Zip::from(scratch_cells.slice(s![1..h, 1..w]))
|
||||||
let new_cells: Vec<Vec<_>> = (0..self.height()).into_par_iter()
|
.and(scratch_cells.slice(s![1..h, 0..w-1]))
|
||||||
.map(|y| {
|
.and(scratch_cells.slice(s![0..h-1, 1..w]))
|
||||||
(0..self.width()).into_iter().map(move |x| {
|
.par_apply_assign_into(self.cells.slice_mut(s![1..h, 1..w]), |cell, left_cell, up_cell| {
|
||||||
if x == 0 || y == 0 {
|
cell.clone().step_e(left_cell, up_cell, half_time_step.into(), feature_size.into())
|
||||||
// XXX This is not an intuitive boundary condition
|
});
|
||||||
Cell::default()
|
|
||||||
} else {
|
self.scratch = scratch_cells;
|
||||||
let cell = immute_self.get(x, y);
|
|
||||||
let left_cell = immute_self.get(x-1, y);
|
|
||||||
let up_cell = immute_self.get(x, y-1);
|
|
||||||
cell.clone().step_e(left_cell, up_cell, half_time_step.into(), immute_self.feature_size.into())
|
|
||||||
}
|
|
||||||
}).collect()
|
|
||||||
}).collect();
|
|
||||||
for (row, mut new_row) in new_cells.into_iter().enumerate() {
|
|
||||||
self.cells.row_mut(row).as_slice_mut().unwrap().swap_with_slice(&mut new_row[..]);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.step_no += 1;
|
self.step_no += 1;
|
||||||
}
|
}
|
||||||
@@ -111,6 +96,7 @@ impl<M: Material + Clone + Default + Send + Sync> SimState<M> {
|
|||||||
|
|
||||||
SimState {
|
SimState {
|
||||||
cells: new_cells,
|
cells: new_cells,
|
||||||
|
scratch: Array2::default((rows as _, cols as _)),
|
||||||
feature_size: self.feature_size,
|
feature_size: self.feature_size,
|
||||||
step_no: self.step_no,
|
step_no: self.step_no,
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user