diff --git a/examples/buffer_proto5.rs b/examples/buffer_proto5.rs index c9ab08c..bb59fe3 100644 --- a/examples/buffer_proto5.rs +++ b/examples/buffer_proto5.rs @@ -4,12 +4,28 @@ use coremem::{Driver, mat, meas, SpirvDriver}; 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::sim::units::{Seconds, Frame, Time as _}; use log::info; #[allow(unused)] use coremem::geom::{Coord as _, Region as _}; +/// Return just the extrema of some collection +fn extrema(mut meas: Vec) -> Vec { + 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)] struct Params { feat_size: f32, @@ -42,7 +58,17 @@ struct Params { dump_frames: Option, } -fn run_sim(id: u32, p: Params) { +#[derive(Clone, Debug)] +struct Results { + m1: Vec, + m2: Vec, + h1: Vec, + h2: Vec, + iset1: Vec, + icoupling: Vec, +} + +fn run_sim(id: u32, p: Params) -> Results { let m_to_um = |m: f32| (m * 1e6).round() as u32; 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_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::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("couplingbot", coupling_wire_bot.clone())); - return; - - let prefix = format!("out/{}/{}-{}-{}setmA-{}setps-{}clkmA-{}clkps-{}um-{}:{}wraps", + let prefix = format!("out/{}/{}-{}-{}setmA-{}setps-{}clkmA-{}clkps-{}um-{}ferromaj-{}:{}wraps", base, base, *driver.size(), @@ -288,6 +312,7 @@ fn run_sim(id: u32, p: Params) { (p.peak_clock_current * 1e3).round() as i64, (p.clock_duration * 1e12).round() as i64, (p.feat_size * 1e6).round() as i64, + p.ferro_major, p.wraps1, p.wraps2, ); @@ -295,10 +320,26 @@ fn run_sim(id: u32, p: Params) { driver.add_state_file(&*format!("{}/state.bc", prefix), 16000); driver.add_serializer_renderer(&*format!("{}/frame-", prefix), 32000, p.dump_frames); - driver.add_csv_renderer(&*format!("{}/meas.csv", prefix), 200, None); - driver.add_csv_renderer(&*format!("{}/meas-sparse.csv", prefix), 8000, None); + let meas_csv = format!("{}/meas.csv", prefix); + 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); + + 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 } diff --git a/src/driver.rs b/src/driver.rs index 71a22a1..8c4c077 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -4,6 +4,7 @@ use crate::meas::{self, AbstractMeasurement}; use crate::real::Real; use crate::render::{self, MultiRenderer, Renderer}; use crate::sim::{GenericSim, MaterialSim, SampleableSim, SimState}; +use crate::sim::units::{Frame, Time}; use crate::sim::spirv::SpirvSim; use crate::stim::AbstractStimulus; @@ -31,7 +32,7 @@ pub struct Driver { start_time: Instant, last_diag_time: Instant, /// simulation end time - sim_end_time: Option, + sim_end_time: Option, } pub type SpirvDriver = Driver; @@ -101,6 +102,9 @@ impl Driver { pub fn size(&self) -> Index { self.state.size() } + pub fn timestep(&self) -> f32 { + self.state.timestep() + } } impl Driver { @@ -204,7 +208,7 @@ impl Driver { let fps = (self.state.step_no() as f64) / overall_time; let sim_time = self.state.time() as f64; 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(), }; info!( @@ -233,9 +237,10 @@ impl Driver { self.step_multiple(1); } - pub fn step_until(&mut self, sim_end_time: f32) { + pub fn step_until(&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); - while self.dyn_state().time() < sim_end_time { + while self.dyn_state().step_no() < *sim_end_time { self.step_multiple(100); } // render the final frame diff --git a/src/render.rs b/src/render.rs index dc3c167..2ed780a 100644 --- a/src/render.rs +++ b/src/render.rs @@ -646,6 +646,17 @@ impl CsvRenderer { state: Mutex::new(Some(CsvState::Reading(reader))), } } + pub fn read_column(self, header: &str) -> Vec { + 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 { + self.read_column(header).into_iter().map(|s| s.parse().unwrap()).collect() + } } impl Renderer for CsvRenderer { diff --git a/src/sim/mod.rs b/src/sim/mod.rs index c4485b0..2b3ed6a 100644 --- a/src/sim/mod.rs +++ b/src/sim/mod.rs @@ -10,6 +10,7 @@ use std::convert::From; use std::iter::Sum; pub mod spirv; +pub mod units; pub type StaticSim = SimState>; diff --git a/src/sim/units.rs b/src/sim/units.rs new file mode 100644 index 0000000..5363f0e --- /dev/null +++ b/src/sim/units.rs @@ -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 + } +}