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:
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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
54
src/sim/units.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user