buffer-proto5: auto-measure the extrema for M/H

also, introduce a `Time` abstraction and allow for more precisely
simulating just a specific time range.

the Sim-related traits still need updating to better integrate this.
This commit is contained in:
2022-01-11 18:23:07 -08:00
parent 8bda52d973
commit ce39c1f50b
5 changed files with 123 additions and 11 deletions

View File

@@ -4,12 +4,28 @@
use coremem::{Driver, mat, meas, SpirvDriver}; use coremem::{Driver, mat, meas, SpirvDriver};
use coremem::geom::{region, Cube, Dilate, Memoize, Meters, Region, Spiral, SwapYZ, Torus, Translate, Wrap}; use coremem::geom::{region, Cube, Dilate, Memoize, Meters, Region, Spiral, SwapYZ, Torus, Translate, Wrap};
use coremem::render::CsvRenderer;
use coremem::stim::{CurlStimulus, Gated, Sinusoid1, TimeVarying1 as _}; use coremem::stim::{CurlStimulus, Gated, Sinusoid1, TimeVarying1 as _};
use coremem::sim::units::{Seconds, Frame, Time as _};
use log::info; use log::info;
#[allow(unused)] #[allow(unused)]
use coremem::geom::{Coord as _, Region as _}; use coremem::geom::{Coord as _, Region as _};
/// Return just the extrema of some collection
fn extrema(mut meas: Vec<f32>) -> Vec<f32> {
let mut i = 0;
while i + 2 < meas.len() {
let (prev, cur, next) = (meas[i], meas[i+1], meas[i+2]);
if (prev <= cur && cur <= next) || (prev >= cur && cur >= next) {
meas.remove(i+1);
} else {
i += 1;
}
}
meas
}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
struct Params { struct Params {
feat_size: f32, feat_size: f32,
@@ -42,7 +58,17 @@ struct Params {
dump_frames: Option<u64>, dump_frames: Option<u64>,
} }
fn run_sim(id: u32, p: Params) { #[derive(Clone, Debug)]
struct Results {
m1: Vec<f32>,
m2: Vec<f32>,
h1: Vec<f32>,
h2: Vec<f32>,
iset1: Vec<f32>,
icoupling: Vec<f32>,
}
fn run_sim(id: u32, p: Params) -> Results {
let m_to_um = |m: f32| (m * 1e6).round() as u32; let m_to_um = |m: f32| (m * 1e6).round() as u32;
let feat_vol = p.feat_size * p.feat_size * p.feat_size; let feat_vol = p.feat_size * p.feat_size * p.feat_size;
@@ -260,7 +286,7 @@ fn run_sim(id: u32, p: Params) {
add_drive_square_pulse(&mut driver, &set1_region, p.set_duration + p.pre_time, p.clock_duration, peak_clock); add_drive_square_pulse(&mut driver, &set1_region, p.set_duration + p.pre_time, p.clock_duration, peak_clock);
// add_drive_step(&mut driver, &set1_region, set_duration + pre_time, peak_clock); // add_drive_step(&mut driver, &set1_region, set_duration + pre_time, peak_clock);
let duration = p.set_duration + p.pre_time + p.clock_duration + p.post_time; let duration = Seconds(p.set_duration + p.pre_time + p.clock_duration + p.post_time).to_frame(driver.timestep()).round_up(32000);
driver.add_measurement(meas::Volume::new("mem1", ferro1_region.clone())); driver.add_measurement(meas::Volume::new("mem1", ferro1_region.clone()));
driver.add_measurement(meas::MagneticLoop::new("mem1", ferro1_region.clone())); driver.add_measurement(meas::MagneticLoop::new("mem1", ferro1_region.clone()));
@@ -277,9 +303,7 @@ fn run_sim(id: u32, p: Params) {
driver.add_measurement(meas::Current::new("couplingtop", coupling_wire_top.clone())); driver.add_measurement(meas::Current::new("couplingtop", coupling_wire_top.clone()));
driver.add_measurement(meas::Current::new("couplingbot", coupling_wire_bot.clone())); driver.add_measurement(meas::Current::new("couplingbot", coupling_wire_bot.clone()));
return; let prefix = format!("out/{}/{}-{}-{}setmA-{}setps-{}clkmA-{}clkps-{}um-{}ferromaj-{}:{}wraps",
let prefix = format!("out/{}/{}-{}-{}setmA-{}setps-{}clkmA-{}clkps-{}um-{}:{}wraps",
base, base,
base, base,
*driver.size(), *driver.size(),
@@ -288,6 +312,7 @@ fn run_sim(id: u32, p: Params) {
(p.peak_clock_current * 1e3).round() as i64, (p.peak_clock_current * 1e3).round() as i64,
(p.clock_duration * 1e12).round() as i64, (p.clock_duration * 1e12).round() as i64,
(p.feat_size * 1e6).round() as i64, (p.feat_size * 1e6).round() as i64,
p.ferro_major,
p.wraps1, p.wraps1,
p.wraps2, p.wraps2,
); );
@@ -295,10 +320,26 @@ fn run_sim(id: u32, p: Params) {
driver.add_state_file(&*format!("{}/state.bc", prefix), 16000); driver.add_state_file(&*format!("{}/state.bc", prefix), 16000);
driver.add_serializer_renderer(&*format!("{}/frame-", prefix), 32000, p.dump_frames); driver.add_serializer_renderer(&*format!("{}/frame-", prefix), 32000, p.dump_frames);
driver.add_csv_renderer(&*format!("{}/meas.csv", prefix), 200, None); let meas_csv = format!("{}/meas.csv", prefix);
driver.add_csv_renderer(&*format!("{}/meas-sparse.csv", prefix), 8000, None); let meas_sparse_csv = format!("{}/meas-sparse.csv", prefix);
driver.add_csv_renderer(&*meas_csv, 200, None);
driver.add_csv_renderer(&*meas_sparse_csv, 8000, None);
driver.step_until(duration); driver.step_until(duration);
let res = Results {
m1: extrema(CsvRenderer::new(&*meas_sparse_csv).read_column_as_f32("M(mem1)")),
m2: extrema(CsvRenderer::new(&*meas_sparse_csv).read_column_as_f32("M(mem2)")),
h1: extrema(CsvRenderer::new(&*meas_sparse_csv).read_column_as_f32("H(mem1)")),
h2: extrema(CsvRenderer::new(&*meas_sparse_csv).read_column_as_f32("H(mem2)")),
iset1: extrema(CsvRenderer::new(&*meas_sparse_csv).read_column_as_f32("I(set1)")),
icoupling: extrema(CsvRenderer::new(&*meas_sparse_csv).read_column_as_f32("Imag/cell(couplingtop)")),
};
std::fs::write(
format!("{}/results.txt", prefix),
format!("{:?}", res),
).unwrap();
res
} }

View File

@@ -4,6 +4,7 @@ use crate::meas::{self, AbstractMeasurement};
use crate::real::Real; use crate::real::Real;
use crate::render::{self, MultiRenderer, Renderer}; use crate::render::{self, MultiRenderer, Renderer};
use crate::sim::{GenericSim, MaterialSim, SampleableSim, SimState}; use crate::sim::{GenericSim, MaterialSim, SampleableSim, SimState};
use crate::sim::units::{Frame, Time};
use crate::sim::spirv::SpirvSim; use crate::sim::spirv::SpirvSim;
use crate::stim::AbstractStimulus; use crate::stim::AbstractStimulus;
@@ -31,7 +32,7 @@ pub struct Driver<S=SimState> {
start_time: Instant, start_time: Instant,
last_diag_time: Instant, last_diag_time: Instant,
/// simulation end time /// simulation end time
sim_end_time: Option<f32>, sim_end_time: Option<Frame>,
} }
pub type SpirvDriver = Driver<SpirvSim>; pub type SpirvDriver = Driver<SpirvSim>;
@@ -101,6 +102,9 @@ impl<S: SampleableSim> Driver<S> {
pub fn size(&self) -> Index { pub fn size(&self) -> Index {
self.state.size() self.state.size()
} }
pub fn timestep(&self) -> f32 {
self.state.timestep()
}
} }
impl<S: SampleableSim + Send + Sync + 'static> Driver<S> { impl<S: SampleableSim + Send + Sync + 'static> Driver<S> {
@@ -204,7 +208,7 @@ impl<S: GenericSim + Clone + Default + Send + Sync + 'static> Driver<S> {
let fps = (self.state.step_no() as f64) / overall_time; let fps = (self.state.step_no() as f64) / overall_time;
let sim_time = self.state.time() as f64; let sim_time = self.state.time() as f64;
let percent_complete = match self.sim_end_time { let percent_complete = match self.sim_end_time {
Some(t) => format!("[{:.1}%] ", 100.0 * self.state.time() / t), Some(t) => format!("[{:.1}%] ", 100.0 * self.state.time() / *t.to_seconds(self.timestep())),
None => "".to_owned(), None => "".to_owned(),
}; };
info!( info!(
@@ -233,9 +237,10 @@ impl<S: GenericSim + Clone + Default + Send + Sync + 'static> Driver<S> {
self.step_multiple(1); self.step_multiple(1);
} }
pub fn step_until(&mut self, sim_end_time: f32) { pub fn step_until<T: Time>(&mut self, sim_end_time: T) {
let sim_end_time = sim_end_time.to_frame(self.state.timestep());
self.sim_end_time = Some(sim_end_time); self.sim_end_time = Some(sim_end_time);
while self.dyn_state().time() < sim_end_time { while self.dyn_state().step_no() < *sim_end_time {
self.step_multiple(100); self.step_multiple(100);
} }
// render the final frame // render the final frame

View File

@@ -646,6 +646,17 @@ impl CsvRenderer {
state: Mutex::new(Some(CsvState::Reading(reader))), state: Mutex::new(Some(CsvState::Reading(reader))),
} }
} }
pub fn read_column(self, header: &str) -> Vec<String> {
let mut rd = match self.state.into_inner().unwrap() {
Some(CsvState::Reading(rd)) => rd,
_ => panic!("not reading!"),
};
let colno = rd.headers().unwrap().iter().position(|it| it == header).unwrap();
rd.into_records().map(|items| items.unwrap().get(colno).unwrap().to_owned()).collect()
}
pub fn read_column_as_f32(self, header: &str) -> Vec<f32> {
self.read_column(header).into_iter().map(|s| s.parse().unwrap()).collect()
}
} }
impl<S: SampleableSim> Renderer<S> for CsvRenderer { impl<S: SampleableSim> Renderer<S> for CsvRenderer {

View File

@@ -10,6 +10,7 @@ use std::convert::From;
use std::iter::Sum; use std::iter::Sum;
pub mod spirv; pub mod spirv;
pub mod units;
pub type StaticSim = SimState<R32, mat::Static<R32>>; pub type StaticSim = SimState<R32, mat::Static<R32>>;

54
src/sim/units.rs Normal file
View File

@@ -0,0 +1,54 @@
use std::ops::Deref;
pub trait Time {
fn to_frame(&self, time_step: f32) -> Frame;
fn to_seconds(&self, time_step: f32) -> Seconds;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Frame(pub u64);
impl Time for Frame {
fn to_frame(&self, _: f32) -> Frame {
*self
}
fn to_seconds(&self, time_step: f32) -> Seconds {
Seconds((**self as f32) * time_step)
}
}
impl Deref for Frame {
type Target = u64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Frame {
pub fn round_up(&self, div: u64) -> Frame {
let rem = self.0 % div;
match self.0 % div {
0 => *self,
rem => Frame(self.0 + div - rem),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Seconds(pub f32);
impl Time for Seconds {
fn to_frame(&self, time_step: f32) -> Frame {
Frame((**self / time_step).round() as u64)
}
fn to_seconds(&self, _: f32) -> Seconds {
*self
}
}
impl Deref for Seconds {
type Target = f32;
fn deref(&self) -> &Self::Target {
&self.0
}
}