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::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<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)]
|
||||
struct Params {
|
||||
feat_size: f32,
|
||||
@@ -42,7 +58,17 @@ struct Params {
|
||||
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 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
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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<S=SimState> {
|
||||
start_time: Instant,
|
||||
last_diag_time: Instant,
|
||||
/// simulation end time
|
||||
sim_end_time: Option<f32>,
|
||||
sim_end_time: Option<Frame>,
|
||||
}
|
||||
|
||||
pub type SpirvDriver = Driver<SpirvSim>;
|
||||
@@ -101,6 +102,9 @@ impl<S: SampleableSim> Driver<S> {
|
||||
pub fn size(&self) -> Index {
|
||||
self.state.size()
|
||||
}
|
||||
pub fn timestep(&self) -> f32 {
|
||||
self.state.timestep()
|
||||
}
|
||||
}
|
||||
|
||||
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 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<S: GenericSim + Clone + Default + Send + Sync + 'static> Driver<S> {
|
||||
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);
|
||||
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
|
||||
|
@@ -646,6 +646,17 @@ impl CsvRenderer {
|
||||
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 {
|
||||
|
@@ -10,6 +10,7 @@ use std::convert::From;
|
||||
use std::iter::Sum;
|
||||
|
||||
pub mod spirv;
|
||||
pub mod units;
|
||||
|
||||
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