Steps per frame is configurable per-renderer

This commit is contained in:
2021-06-14 20:09:52 -07:00
parent 8aab8f41f9
commit e02a062dda
6 changed files with 77 additions and 74 deletions

View File

@@ -7,7 +7,7 @@ fn main() {
let height = 401;
let size = Index((width, height, 1).into());
let mut driver: Driver = Driver::new(size, 1e-6 /* feature size */);
driver.add_y4m_renderer("em_reflection.y4m");
driver.add_y4m_renderer("em_reflection.y4m", 1);
// driver.add_term_renderer();
// driver.add_pml_boundary(Index((20, 40, 0).into()));

View File

@@ -18,6 +18,7 @@ fn main() {
let current_duration = 1.0e-11; // half-wavelength of the sine wave
let current_break = 0.5e-11; // time between 'set' pulse and 'clear' pulse
let conductivity = 1.0e9f32;
let steps_per_frame = 400;
let from_m = |m: f32| (m/feat_size).round() as u32;
let m_to_um = |m: f32| (m * 1e6).round() as u32;
@@ -28,7 +29,6 @@ fn main() {
let depth_px = from_m(depth);
let size_px = Index((width_px, width_px, depth_px).into());
let mut driver: Driver<Real> = Driver::new(size_px, feat_size);
driver.set_steps_per_frame(400);
driver.set_steps_per_stim(1);
let base = "minimal_torus-6";
let ferro_region = Torus::new_xy(Meters::new(half_width, half_width, half_depth), ferro_major, ferro_minor);
@@ -117,7 +117,7 @@ fn main() {
);
let _ = std::fs::create_dir_all(&prefix);
driver.add_serializer_renderer(&*format!("{}/frame-", prefix));
driver.add_serializer_renderer(&*format!("{}/frame-", prefix), steps_per_frame);
driver.step_until(duration);
}

View File

@@ -25,6 +25,7 @@ fn main() {
let conductivity = 1.0e5;
let half_width = width * 0.5;
let half_depth = depth * 0.5;
let steps_per_frame = 160;
let duration = 1e-9;
@@ -32,13 +33,6 @@ fn main() {
let depth_px = from_m(depth);
let size_px = Index((width_px, width_px, depth_px).into());
let mut driver: Driver<Real> = Driver::new(size_px, feat_size);
//driver.set_steps_per_frame(8);
//driver.set_steps_per_frame(20);
//driver.set_steps_per_frame(40);
//driver.set_steps_per_frame(80);
//driver.set_steps_per_frame(120);
driver.set_steps_per_frame(160);
//driver.set_steps_per_frame(200);
let base = "toroid25d-9";
let _ = std::fs::create_dir(base);
let prefix = format!("{}/{}-flt{}-{}-feat{}um-{}mA-{}ps--radii{}um-{}um-{}um-{}um",
@@ -55,13 +49,13 @@ fn main() {
m_to_um(ferro_depth),
);
let _ = std::fs::create_dir(&prefix);
//driver.add_y4m_renderer(&*format!("{}.y4m", prefix));
//driver.add_plotly_renderer(&*format!("{}/frame-", prefix));
driver.add_serializer_renderer(&*format!("{}/frame-", prefix));
//driver.add_y4m_renderer(&*format!("{}.y4m", prefix), steps_per_frame);
//driver.add_plotly_renderer(&*format!("{}/frame-", prefix), steps_per_frame);
driver.add_serializer_renderer(&*format!("{}/frame-", prefix), steps_per_frame);
let conductor_region = CylinderZ::new(
Vec2::new(half_width, half_width),
conductor_outer_rad);
// driver.add_term_renderer();
// driver.add_term_renderer(steps_per_frame);
driver.add_measurement(meas::Label(format!("Conductivity: {}, Imax: {:.2e}", conductivity, peak_current)));
//driver.add_measurement(meas::Current(conductor_region.clone()));
driver.add_measurement(meas::MagnetizationAt(

View File

@@ -6,27 +6,27 @@ use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying1 as _};
fn main() {
coremem::init_logging();
let feat_size = 10e-6f32; // feature size
let duration = 3.0e-9;
let width = 4800e-6;
let height = 2200e-6;
let depth = 1800e-6;
let duration = 60.0e-9;
let width = 3400e-6;
let height = 1800e-6;
let depth = 1400e-6;
let buffer = 200e-6;
let ferro_spacing = 600e-6;
let ferro_major = 320e-6;
let ferro_minor = 60e-6;
let wire_minor = 40e-6;
let wire_major = 160e-6;
let peak_current1 = 7.5e6;
let peak_current2 = 5e5;
let current_duration = 0.4e-9; // half-wavelength of the sine wave
//let peak_current2 = 5e5;
let peak_current2 = 7.5e6;
let current_duration = 1.0e-9; // half-wavelength of the sine wave
let current_break = 0.2e-9; // time between 'set' pulse and 'clear' pulse
let drive_conductivity = 5e6f32;
let sense_conductivity = 5e3f32;
let from_m = |m: f32| (m/feat_size).round() as u32;
let m_to_um = |m: f32| (m * 1e6).round() as u32;
// let half_width = width * 0.5;
let q1_width = width * 0.25;
let q3_width = width * 0.75;
let half_width = width * 0.5;
let half_height = height * 0.5;
let half_depth = depth * 0.5;
@@ -35,40 +35,33 @@ fn main() {
let depth_px = from_m(depth);
let size_px = Index((width_px, height_px, depth_px).into());
let mut driver: Driver<Real> = Driver::new(size_px, feat_size);
driver.set_steps_per_frame(500);
// driver.set_steps_per_stim(10);
let base = "wrapped_torus-29-mbferromagnet-0.3899B-310_000M-longer-current";
driver.set_steps_per_stim(10);
let base = "wrapped_torus-30-current-decay";
let ferro1_region = Torus::new_xy(Meters::new(q1_width, half_height, half_depth), ferro_major, ferro_minor);
let drive1_region = Torus::new_xz(Meters::new(q1_width - ferro_major, half_height, half_depth), wire_major, wire_minor);
let sense1_region = Torus::new_xz(Meters::new(q1_width + ferro_major, half_height, half_depth), wire_major, wire_minor);
let ferro1_center = half_width - ferro_major - 0.5*ferro_spacing;
let ferro1_region = Torus::new_xy(Meters::new(ferro1_center, half_height, half_depth), ferro_major, ferro_minor);
let drive1_region = Torus::new_xz(Meters::new(ferro1_center - ferro_major, half_height, half_depth), wire_major, wire_minor);
let sense1_region = Torus::new_xz(Meters::new(ferro1_center + ferro_major, half_height, half_depth), wire_major, wire_minor);
//driver.fill_region(&ferro1_region, mat::db::linear_iron().into());
driver.fill_region(&ferro1_region, mat::MBFerromagnet::new(-0.3899, 0.3900, 310_000.0).into());
driver.fill_region(&ferro1_region, mat::db::linear_iron().into());
//driver.fill_region(&ferro1_region, mat::MBFerromagnet::new(-0.3899, 0.3900, 310_000.0).into());
driver.fill_region(&drive1_region, mat::db::conductor(drive_conductivity).into());
driver.fill_region(&sense1_region, mat::db::conductor(sense_conductivity).into());
let ferro2_region = Torus::new_xy(Meters::new(q3_width, half_height, half_depth), ferro_major, ferro_minor);
let drive2_region = Torus::new_xz(Meters::new(q3_width - ferro_major, half_height, half_depth), wire_major, wire_minor);
let sense2_region = Torus::new_xz(Meters::new(q3_width + ferro_major, half_height, half_depth), wire_major, wire_minor);
let ferro2_center = half_width + ferro_major + 0.5*ferro_spacing;
let ferro2_region = Torus::new_xy(Meters::new(ferro2_center, half_height, half_depth), ferro_major, ferro_minor);
let drive2_region = Torus::new_xz(Meters::new(ferro2_center - ferro_major, half_height, half_depth), wire_major, wire_minor);
let sense2_region = Torus::new_xz(Meters::new(ferro2_center + ferro_major, half_height, half_depth), wire_major, wire_minor);
driver.fill_region(&ferro2_region, mat::MBFerromagnet::new(-0.3899, 0.3900, 310_000.0).into());
driver.fill_region(&drive2_region, mat::db::conductor(drive_conductivity).into());
driver.fill_region(&sense2_region, mat::db::conductor(sense_conductivity).into());
let boundary_xy = q1_width - ferro_major - ferro_minor - buffer;
let boundary_xy = ferro1_center - ferro_major - ferro_minor - buffer;
let boundary_z = half_depth - wire_major - wire_minor - buffer;
println!("boundary: {}um; {}um", m_to_um(boundary_xy), m_to_um(boundary_z));
driver.add_pml_boundary(Meters::new(boundary_xy, boundary_xy, boundary_z));
// J=\sigma E
// dJ/dt = \sigma dE/dT
// dE/dt = dJ/dt / \sigma
// dE/dt = dI/dt / (A*\sigma)
// if I = k*sin(w t) then dE/dt = k*w sin(w t) / (A*\sigma)
// i.e. dE/dt is proportional to I/(A*\sigma), multiplied by w (or, divided by wavelength)
let peak_stim1 = peak_current1/current_duration / (drive1_region.cross_section() * drive_conductivity);
let mut add_drive_pulse = |region: &Torus, start, duration, amp| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0)
.half_cycle()
@@ -81,16 +74,24 @@ fn main() {
));
};
// J=\sigma E
// dJ/dt = \sigma dE/dT
// dE/dt = dJ/dt / \sigma
// dE/dt = dI/dt / (A*\sigma)
// if I = k*sin(w t) then dE/dt = k*w sin(w t) / (A*\sigma)
// i.e. dE/dt is proportional to I/(A*\sigma), multiplied by w (or, divided by wavelength)
let peak_stim1 = peak_current1/current_duration / (drive1_region.cross_section() * drive_conductivity);
add_drive_pulse(&drive1_region, 0.0, current_duration, peak_stim1);
add_drive_pulse(&drive1_region, current_duration + current_break, current_duration, -4.0*peak_stim1);
add_drive_pulse(&drive1_region, 2.0*(current_duration + current_break), current_duration, -4.0*peak_stim1);
add_drive_pulse(&drive1_region, 3.0*(current_duration + current_break), current_duration, peak_stim1);
// add_drive_pulse(&drive1_region, current_duration + current_break, current_duration, -4.0*peak_stim1);
// add_drive_pulse(&drive1_region, 2.0*(current_duration + current_break), current_duration, -4.0*peak_stim1);
// add_drive_pulse(&drive1_region, 3.0*(current_duration + current_break), current_duration, peak_stim1);
let peak_stim2 = peak_current2/current_duration / (drive2_region.cross_section() * drive_conductivity);
add_drive_pulse(&drive2_region, 0.0, current_duration, peak_stim2);
add_drive_pulse(&drive2_region, current_duration + current_break, current_duration, -4.0*peak_stim2);
add_drive_pulse(&drive2_region, 2.0*(current_duration + current_break), current_duration, -4.0*peak_stim2);
add_drive_pulse(&drive2_region, 3.0*(current_duration + current_break), current_duration, peak_stim2);
// add_drive_pulse(&drive2_region, current_duration + current_break, current_duration, -4.0*peak_stim2);
// add_drive_pulse(&drive2_region, 2.0*(current_duration + current_break), current_duration, -4.0*peak_stim2);
// add_drive_pulse(&drive2_region, 3.0*(current_duration + current_break), current_duration, peak_stim2);
driver.add_measurement(meas::CurrentLoop::new("sense1", sense1_region.clone()));
driver.add_measurement(meas::Current::new("sense1", sense1_region.clone()));
@@ -125,7 +126,7 @@ fn main() {
);
let _ = std::fs::create_dir_all(&prefix);
driver.add_serializer_renderer(&*format!("{}/frame-", prefix));
driver.add_serializer_renderer(&*format!("{}/frame-", prefix), 5000);
driver.step_until(duration);
}

View File

@@ -20,7 +20,6 @@ pub struct Driver<R=R32, M=GenericMaterial<R>> {
// TODO: use Rayon's thread pool?
render_pool: ThreadPool,
render_channel: (SyncSender<()>, Receiver<()>),
steps_per_frame: u64,
time_spent_stepping: Duration,
time_spent_on_stimuli: Duration,
time_spent_prepping_render: Duration,
@@ -39,7 +38,6 @@ impl<R: Real, M: Default> Driver<R, M> {
renderer: Arc::new(MultiRenderer::new()),
render_pool: ThreadPool::new(3),
render_channel: sync_channel(0),
steps_per_frame: 1,
time_spent_stepping: Default::default(),
time_spent_on_stimuli: Default::default(),
time_spent_prepping_render: Default::default(),
@@ -67,10 +65,6 @@ impl<R: Real, M: Material<R>> Driver<R, M> {
self.measurements.push(Box::new(m));
}
pub fn set_steps_per_frame(&mut self, steps_per_frame: u64) {
self.steps_per_frame = steps_per_frame;
}
pub fn set_steps_per_stim(&mut self, steps_per_stim: u64) {
self.stimuli.frame_interval = steps_per_stim;
}
@@ -88,30 +82,30 @@ impl<R: Real, M: Material<R> + Clone + Send + Sync + 'static> Driver<R, M> {
}
fn add_renderer<Rend: Renderer<SimState<R, M>> + 'static>(
&mut self, renderer: Rend, name: &str
&mut self, renderer: Rend, name: &str, step_frequency: u64
) {
info!("render to {}", name);
self.renderer.push(renderer);
info!("render to {} at f={}", name, step_frequency);
self.renderer.push(renderer, step_frequency);
}
pub fn add_y4m_renderer<S: Into<PathBuf>>(&mut self, output: S) {
pub fn add_y4m_renderer<S: Into<PathBuf>>(&mut self, output: S, step_frequency: u64) {
let output = output.into();
let name = output.to_string_lossy().into_owned();
self.add_renderer(render::Y4MRenderer::new(output), &*name);
self.add_renderer(render::Y4MRenderer::new(output), &*name, step_frequency);
}
pub fn add_plotly_renderer(&mut self, out_base: &str) {
self.add_renderer(render::PlotlyRenderer::new(out_base), out_base);
pub fn add_plotly_renderer(&mut self, out_base: &str, step_frequency: u64) {
self.add_renderer(render::PlotlyRenderer::new(out_base), out_base, step_frequency);
}
pub fn add_term_renderer(&mut self) {
self.add_renderer(render::ColorTermRenderer, "terminal");
pub fn add_term_renderer(&mut self, step_frequency: u64) {
self.add_renderer(render::ColorTermRenderer, "terminal", step_frequency);
}
}
impl<R: Real + Send + Sync + Serialize, M: Material<R> + Serialize + Clone + Send + Sync + 'static> Driver<R, M> {
pub fn add_serializer_renderer(&mut self, out_base: &str) {
self.add_renderer(render::SerializerRenderer::new(out_base), out_base);
pub fn add_serializer_renderer(&mut self, out_base: &str, step_frequency: u64) {
self.add_renderer(render::SerializerRenderer::new(out_base), out_base, step_frequency);
}
}
@@ -146,7 +140,7 @@ impl<R: Real + Send + Sync + 'static, M: Material<R> + Clone + Default + Send +
trace!("stimuli end");
}
if self.state.step_no() % self.steps_per_frame == 0 {
if self.renderer.any_work_for_frame(self.state.step_no()) {
self.render();
}

View File

@@ -592,8 +592,14 @@ impl<S: GenericSim> Renderer<S> for PlotlyRenderer {
}
}
struct MultiRendererElement<S> {
step_frequency: u64,
renderer: Box<dyn Renderer<S>>,
}
pub struct MultiRenderer<S> {
renderers: RwLock<Vec<Box<dyn Renderer<S>>>>,
renderers: RwLock<Vec<MultiRendererElement<S>>>,
}
impl<S> Default for MultiRenderer<S> {
@@ -608,13 +614,19 @@ impl<S> MultiRenderer<S> {
pub fn new() -> Self {
Default::default()
}
pub fn push<R: Renderer<S> + 'static>(&self, r: R) {
self.renderers.write().unwrap().push(Box::new(r));
pub fn push<R: Renderer<S> + 'static>(&self, renderer: R, step_frequency: u64) {
self.renderers.write().unwrap().push(MultiRendererElement {
step_frequency,
renderer: Box::new(renderer),
});
}
pub fn with<R: Renderer<S> + 'static>(self, r: R) -> Self {
self.push(r);
pub fn with<R: Renderer<S> + 'static>(self, renderer: R, step_frequency: u64) -> Self {
self.push(renderer, step_frequency);
self
}
pub fn any_work_for_frame(&self, frame: u64) -> bool {
self.renderers.read().unwrap().iter().any(|m| frame % m.step_frequency == 0)
}
}
impl<S: GenericSim> Renderer<S> for MultiRenderer<S> {
@@ -629,7 +641,9 @@ impl<S: GenericSim> Renderer<S> for MultiRenderer<S> {
fn render_with_image(&self, state: &S, im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
for r in &*self.renderers.read().unwrap() {
r.render_with_image(state, im, measurements, config);
if state.step_no() % r.step_frequency == 0 {
r.renderer.render_with_image(state, im, measurements, config);
}
}
}
}