Cleanup
AKA I made these changes a month ago but forgot to commit them and don't really want to figure out what they did.
This commit is contained in:
@@ -9,6 +9,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ansi_term = "0.12"
|
ansi_term = "0.12"
|
||||||
decorum = "0.3"
|
decorum = "0.3"
|
||||||
|
dyn-clone = "1.0"
|
||||||
enum_dispatch = "0.3"
|
enum_dispatch = "0.3"
|
||||||
env_logger = "0.7"
|
env_logger = "0.7"
|
||||||
font8x8 = "0.2"
|
font8x8 = "0.2"
|
||||||
@@ -18,7 +19,8 @@ lazy_static = "1.4"
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
ndarray = { version = "0.13", features = ["rayon"] }
|
ndarray = { version = "0.13", features = ["rayon"] }
|
||||||
piecewise-linear = "0.1"
|
piecewise-linear = "0.1"
|
||||||
plotly = { version = "0.6", features = ["kaleido", "plotly_ndarray"] }
|
plotly = { version = "0.6", features = ["kaleido", "plotly_ndarray"], path = "../plotly/plotly" }
|
||||||
|
threadpool = "1.8"
|
||||||
y4m = "0.7"
|
y4m = "0.7"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@@ -32,22 +32,30 @@ fn main() {
|
|||||||
let size_px = Index((width_px, width_px, depth_px).into());
|
let size_px = Index((width_px, width_px, depth_px).into());
|
||||||
let mut driver = Driver::new(size_px, feat_size);
|
let mut driver = Driver::new(size_px, feat_size);
|
||||||
//driver.set_steps_per_frame(8);
|
//driver.set_steps_per_frame(8);
|
||||||
|
//driver.set_steps_per_frame(20);
|
||||||
//driver.set_steps_per_frame(40);
|
//driver.set_steps_per_frame(40);
|
||||||
//driver.set_steps_per_frame(80);
|
//driver.set_steps_per_frame(80);
|
||||||
driver.set_steps_per_frame(120);
|
//driver.set_steps_per_frame(120);
|
||||||
|
driver.set_steps_per_frame(160);
|
||||||
//driver.set_steps_per_frame(200);
|
//driver.set_steps_per_frame(200);
|
||||||
// driver.add_y4m_renderer(&*format!("toroid25d.5-flt{}-{}-feat{}um-{:.1e}A-{:.1e}s--radii{}um-{}um-{}um-{}um.y4m",
|
let base = "toroid25d-7";
|
||||||
// std::mem::size_of::<Flt>() * 8,
|
let _ = std::fs::create_dir(base);
|
||||||
// *size_px,
|
let prefix = format!("{}/{}-flt{}-{}-feat{}um-{}mA-{}ps--radii{}um-{}um-{}um-{}um",
|
||||||
// m_to_um(feat_size),
|
base,
|
||||||
// peak_current,
|
base,
|
||||||
// current_duration,
|
std::mem::size_of::<Flt>() * 8,
|
||||||
// m_to_um(conductor_outer_rad),
|
*size_px,
|
||||||
// m_to_um(ferro_inner_rad),
|
m_to_um(feat_size),
|
||||||
// m_to_um(ferro_outer_rad),
|
(peak_current * 1e3) as i64,
|
||||||
// m_to_um(ferro_depth),
|
(current_duration * 1e12) as i64,
|
||||||
// ));
|
m_to_um(conductor_outer_rad),
|
||||||
driver.add_plotly_renderer();
|
m_to_um(ferro_inner_rad),
|
||||||
|
m_to_um(ferro_outer_rad),
|
||||||
|
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));
|
||||||
let conductor_region = CylinderZ::new(
|
let conductor_region = CylinderZ::new(
|
||||||
Vec2::new(half_width, half_width),
|
Vec2::new(half_width, half_width),
|
||||||
conductor_outer_rad);
|
conductor_outer_rad);
|
||||||
|
@@ -8,32 +8,43 @@ use crate::stim::AbstractStimulus;
|
|||||||
|
|
||||||
use log::{info, debug, trace};
|
use log::{info, debug, trace};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
use threadpool::ThreadPool;
|
||||||
|
|
||||||
pub struct Driver {
|
pub struct Driver {
|
||||||
pub state: SimState,
|
pub state: SimState,
|
||||||
renderer: MultiRenderer,
|
renderer: Arc<MultiRenderer>,
|
||||||
|
render_pool: ThreadPool,
|
||||||
|
render_channel: (SyncSender<()>, Receiver<()>),
|
||||||
steps_per_frame: u64,
|
steps_per_frame: u64,
|
||||||
time_spent_stepping: Duration,
|
time_spent_stepping: Duration,
|
||||||
time_spent_on_stimuli: Duration,
|
time_spent_on_stimuli: Duration,
|
||||||
time_spent_rendering: Duration,
|
time_spent_blocked_on_render: Duration,
|
||||||
|
time_spent_rendering: Arc<Mutex<Duration>>,
|
||||||
measurements: Vec<Box<dyn AbstractMeasurement>>,
|
measurements: Vec<Box<dyn AbstractMeasurement>>,
|
||||||
stimuli: Vec<Box<dyn AbstractStimulus>>,
|
stimuli: Vec<Box<dyn AbstractStimulus>>,
|
||||||
start_time: SystemTime,
|
start_time: Instant,
|
||||||
|
last_diag_time: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Driver {
|
impl Driver {
|
||||||
pub fn new<C: Coord>(size: C, feature_size: Flt) -> Self {
|
pub fn new<C: Coord>(size: C, feature_size: Flt) -> Self {
|
||||||
Driver {
|
Driver {
|
||||||
state: SimState::new(size.to_index(feature_size), feature_size),
|
state: SimState::new(size.to_index(feature_size), feature_size),
|
||||||
renderer: Default::default(),
|
renderer: Arc::new(MultiRenderer::new()),
|
||||||
|
render_pool: ThreadPool::new(3),
|
||||||
|
render_channel: sync_channel(0),
|
||||||
steps_per_frame: 1,
|
steps_per_frame: 1,
|
||||||
time_spent_stepping: Default::default(),
|
time_spent_stepping: Default::default(),
|
||||||
time_spent_on_stimuli: Default::default(),
|
time_spent_on_stimuli: Default::default(),
|
||||||
|
time_spent_blocked_on_render: Default::default(),
|
||||||
time_spent_rendering: Default::default(),
|
time_spent_rendering: Default::default(),
|
||||||
measurements: vec![Box::new(meas::Time), Box::new(meas::Meta), Box::new(meas::Energy)],
|
measurements: vec![Box::new(meas::Time), Box::new(meas::Meta), Box::new(meas::Energy)],
|
||||||
stimuli: vec![],
|
stimuli: vec![],
|
||||||
start_time: SystemTime::now(),
|
start_time: Instant::now(),
|
||||||
|
last_diag_time: Instant::now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +75,8 @@ impl Driver {
|
|||||||
self.add_renderer(render::Y4MRenderer::new(output), &*name);
|
self.add_renderer(render::Y4MRenderer::new(output), &*name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_plotly_renderer(&mut self) {
|
pub fn add_plotly_renderer(&mut self, out_base: &str) {
|
||||||
self.add_renderer(render::PlotlyRenderer, "plotly");
|
self.add_renderer(render::PlotlyRenderer::new(out_base), out_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_term_renderer(&mut self) {
|
pub fn add_term_renderer(&mut self) {
|
||||||
@@ -150,44 +161,62 @@ impl Driver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render(&mut self) {
|
||||||
|
let their_state = self.state.clone();
|
||||||
|
let their_measurements = self.measurements.clone();
|
||||||
|
let renderer = self.renderer.clone();
|
||||||
|
let time_spent_rendering = self.time_spent_rendering.clone();
|
||||||
|
let sender = self.render_channel.0.clone();
|
||||||
|
self.render_pool.execute(move || {
|
||||||
|
sender.send(()).unwrap();
|
||||||
|
trace!("render begin");
|
||||||
|
let start_time = Instant::now();
|
||||||
|
renderer.render(&their_state, &*their_measurements);
|
||||||
|
*time_spent_rendering.lock().unwrap() += start_time.elapsed();
|
||||||
|
trace!("render end");
|
||||||
|
});
|
||||||
|
let block_start = Instant::now();
|
||||||
|
self.render_channel.1.recv().unwrap();
|
||||||
|
self.time_spent_blocked_on_render += block_start.elapsed();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn step(&mut self) {
|
pub fn step(&mut self) {
|
||||||
if self.state.step_no() % self.steps_per_frame == 0 {
|
if self.state.step_no() % self.steps_per_frame == 0 {
|
||||||
trace!("render begin");
|
self.render();
|
||||||
let start_time = SystemTime::now();
|
|
||||||
self.renderer.render(&self.state, &*self.measurements);
|
|
||||||
self.time_spent_rendering += start_time.elapsed().unwrap();
|
|
||||||
trace!("render end");
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
trace!("stimuli begin");
|
trace!("stimuli begin");
|
||||||
let start_time = SystemTime::now();
|
let start_time = Instant::now();
|
||||||
for stim in &mut *self.stimuli {
|
for stim in &mut *self.stimuli {
|
||||||
stim.apply(&mut self.state);
|
stim.apply(&mut self.state);
|
||||||
}
|
}
|
||||||
self.time_spent_on_stimuli += start_time.elapsed().unwrap();
|
self.time_spent_on_stimuli += start_time.elapsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("step begin");
|
trace!("step begin");
|
||||||
let start_time = SystemTime::now();
|
let start_time = Instant::now();
|
||||||
self.state.step();
|
self.state.step();
|
||||||
self.time_spent_stepping += start_time.elapsed().unwrap();
|
self.time_spent_stepping += start_time.elapsed();
|
||||||
trace!("step end");
|
trace!("step end");
|
||||||
|
if self.last_diag_time.elapsed().as_secs_f64() >= 5.0 {
|
||||||
|
self.last_diag_time = Instant::now();
|
||||||
let step = self.state.step_no();
|
let step = self.state.step_no();
|
||||||
if step % (10*self.steps_per_frame) == 0 {
|
|
||||||
let step_time = self.time_spent_stepping.as_secs_f64();
|
let step_time = self.time_spent_stepping.as_secs_f64();
|
||||||
let stim_time = self.time_spent_on_stimuli.as_secs_f64();
|
let stim_time = self.time_spent_on_stimuli.as_secs_f64();
|
||||||
let render_time = self.time_spent_rendering.as_secs_f64();
|
let render_time = self.time_spent_rendering.lock().unwrap().as_secs_f64();
|
||||||
let overall_time = self.start_time.elapsed().unwrap().as_secs_f64();
|
let block_time = self.time_spent_blocked_on_render.as_secs_f64();
|
||||||
|
let overall_time = self.start_time.elapsed().as_secs_f64();
|
||||||
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;
|
||||||
info!(
|
info!(
|
||||||
"t={:.2e} frame {:06} fps: {:6.2} (sim: {:.1}s, stim: {:.1}s, render: {:.1}s, other: {:.1}s)",
|
"t={:.2e} frame {:06} fps: {:6.2} (sim: {:.1}s, stim: {:.1}s, render: {:.1}s, blocked: {:.1}s, other: {:.1}s)",
|
||||||
sim_time,
|
sim_time,
|
||||||
step,
|
step,
|
||||||
fps,
|
fps,
|
||||||
step_time,
|
step_time,
|
||||||
stim_time,
|
stim_time,
|
||||||
render_time,
|
render_time,
|
||||||
|
block_time,
|
||||||
overall_time - step_time - stim_time - render_time
|
overall_time - step_time - stim_time - render_time
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
15
src/meas.rs
15
src/meas.rs
@@ -2,13 +2,16 @@ use crate::flt::Flt;
|
|||||||
use crate::geom::{Meters, Region};
|
use crate::geom::{Meters, Region};
|
||||||
use crate::mat::Material as _;
|
use crate::mat::Material as _;
|
||||||
use crate::sim::{Cell, GenericSim};
|
use crate::sim::{Cell, GenericSim};
|
||||||
|
use dyn_clone::{self, DynClone};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
|
|
||||||
pub trait AbstractMeasurement {
|
pub trait AbstractMeasurement: Send + DynClone {
|
||||||
fn eval(&self, state: &dyn GenericSim) -> String;
|
fn eval(&self, state: &dyn GenericSim) -> String;
|
||||||
}
|
}
|
||||||
|
dyn_clone::clone_trait_object!(AbstractMeasurement);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Time;
|
pub struct Time;
|
||||||
|
|
||||||
impl AbstractMeasurement for Time {
|
impl AbstractMeasurement for Time {
|
||||||
@@ -17,6 +20,7 @@ impl AbstractMeasurement for Time {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Meta;
|
pub struct Meta;
|
||||||
|
|
||||||
impl AbstractMeasurement for Meta {
|
impl AbstractMeasurement for Meta {
|
||||||
@@ -25,6 +29,7 @@ impl AbstractMeasurement for Meta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Label(pub String);
|
pub struct Label(pub String);
|
||||||
|
|
||||||
impl Label {
|
impl Label {
|
||||||
@@ -50,9 +55,10 @@ fn sum_over_region<T: Default + Sum<T>, R: Region, F: Fn(Meters, &Cell) -> T>(st
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Current<R>(pub R);
|
pub struct Current<R>(pub R);
|
||||||
|
|
||||||
impl<R: Region + Display + Sync> AbstractMeasurement for Current<R> {
|
impl<R: Region + Clone + Display + Send + Sync> AbstractMeasurement for Current<R> {
|
||||||
fn eval(&self, state: &dyn GenericSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> String {
|
||||||
let current = sum_over_region(state, &self.0, |coord, _cell| state.current(coord));
|
let current = sum_over_region(state, &self.0, |coord, _cell| state.current(coord));
|
||||||
format!("I({}): ({:.2e}, {:.2e}, {:.2e})", self.0, current.x(), current.y(), current.z())
|
format!("I({}): ({:.2e}, {:.2e}, {:.2e})", self.0, current.x(), current.y(), current.z())
|
||||||
@@ -65,6 +71,7 @@ fn loc(v: Meters) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// M
|
/// M
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Magnetization(pub Meters);
|
pub struct Magnetization(pub Meters);
|
||||||
|
|
||||||
impl AbstractMeasurement for Magnetization {
|
impl AbstractMeasurement for Magnetization {
|
||||||
@@ -75,6 +82,7 @@ impl AbstractMeasurement for Magnetization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// B
|
/// B
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct MagneticFlux(pub Meters);
|
pub struct MagneticFlux(pub Meters);
|
||||||
|
|
||||||
impl AbstractMeasurement for MagneticFlux {
|
impl AbstractMeasurement for MagneticFlux {
|
||||||
@@ -85,6 +93,7 @@ impl AbstractMeasurement for MagneticFlux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// H
|
/// H
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct MagneticStrength(pub Meters);
|
pub struct MagneticStrength(pub Meters);
|
||||||
|
|
||||||
impl AbstractMeasurement for MagneticStrength {
|
impl AbstractMeasurement for MagneticStrength {
|
||||||
@@ -94,6 +103,7 @@ impl AbstractMeasurement for MagneticStrength {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ElectricField(pub Meters);
|
pub struct ElectricField(pub Meters);
|
||||||
|
|
||||||
impl AbstractMeasurement for ElectricField {
|
impl AbstractMeasurement for ElectricField {
|
||||||
@@ -103,6 +113,7 @@ impl AbstractMeasurement for ElectricField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Energy;
|
pub struct Energy;
|
||||||
|
|
||||||
impl AbstractMeasurement for Energy {
|
impl AbstractMeasurement for Energy {
|
||||||
|
148
src/render.rs
148
src/render.rs
@@ -6,12 +6,12 @@ use crate::sim::{Cell, GenericSim};
|
|||||||
use crate::meas::AbstractMeasurement;
|
use crate::meas::AbstractMeasurement;
|
||||||
use font8x8::{BASIC_FONTS, GREEK_FONTS, UnicodeFonts as _};
|
use font8x8::{BASIC_FONTS, GREEK_FONTS, UnicodeFonts as _};
|
||||||
use log::{trace, info};
|
use log::{trace, info};
|
||||||
use plotly::{Plot, ImageFormat};
|
use plotly;
|
||||||
use plotly::heat_map::HeatMap;
|
|
||||||
use image::{RgbImage, Rgb};
|
use image::{RgbImage, Rgb};
|
||||||
use imageproc::{pixelops, drawing};
|
use imageproc::{pixelops, drawing};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::{Mutex, RwLock};
|
||||||
use y4m;
|
use y4m;
|
||||||
|
|
||||||
/// Accept a value from (-\inf, \inf) and return a value in (-1, 1).
|
/// Accept a value from (-\inf, \inf) and return a value in (-1, 1).
|
||||||
@@ -54,6 +54,17 @@ fn scale_vector(x: Vec2, typical_mag: Flt) -> Vec2 {
|
|||||||
x.with_mag(new_mag)
|
x.with_mag(new_mag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn im_size(state: &dyn GenericSim, max_w: u32, max_h: u32) -> (u32, u32) {
|
||||||
|
let mut width = max_w;
|
||||||
|
let mut height = width * state.height() / state.width();
|
||||||
|
if height > max_h {
|
||||||
|
let stretch = max_h as f32 / height as f32;
|
||||||
|
width = (width as f32 * stretch) as _;
|
||||||
|
height = max_h;
|
||||||
|
}
|
||||||
|
(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
struct RenderSteps<'a> {
|
struct RenderSteps<'a> {
|
||||||
im: RgbImage,
|
im: RgbImage,
|
||||||
sim: &'a dyn GenericSim,
|
sim: &'a dyn GenericSim,
|
||||||
@@ -64,14 +75,7 @@ struct RenderSteps<'a> {
|
|||||||
|
|
||||||
impl<'a> RenderSteps<'a> {
|
impl<'a> RenderSteps<'a> {
|
||||||
fn render(state: &'a dyn GenericSim, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32) -> RgbImage {
|
fn render(state: &'a dyn GenericSim, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32) -> RgbImage {
|
||||||
let mut width = 640;
|
let (width, height) = im_size(state, 640, 480);
|
||||||
let max_height = 480;
|
|
||||||
let mut height = width * state.height() / state.width();
|
|
||||||
if height > max_height {
|
|
||||||
let stretch = max_height as f32 / height as f32;
|
|
||||||
width = (width as f32 * stretch) as _;
|
|
||||||
height = max_height;
|
|
||||||
}
|
|
||||||
trace!("rendering at {}x{} with z={}", width, height, z);
|
trace!("rendering at {}x{} with z={}", width, height, z);
|
||||||
let mut me = Self::new(state, measurements, width, height, z);
|
let mut me = Self::new(state, measurements, width, height, z);
|
||||||
me.render_scalar_field(10.0, false, 2, |cell| {
|
me.render_scalar_field(10.0, false, 2, |cell| {
|
||||||
@@ -230,11 +234,13 @@ impl ImageRenderExt for RgbImage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Renderer {
|
pub trait Renderer: Send + Sync {
|
||||||
fn render(&mut self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2));
|
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2));
|
||||||
}
|
}
|
||||||
fn render_with_image(&mut self, state: &dyn GenericSim, _im: &RgbImage) {
|
/// Not intended to be called directly by users; implement this if you want the image to be
|
||||||
|
/// computed using default settings and you just manage where to display/save it.
|
||||||
|
fn render_with_image(&self, state: &dyn GenericSim, _im: &RgbImage) {
|
||||||
self.render(state, &[]);
|
self.render(state, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,7 +268,7 @@ pub trait Renderer {
|
|||||||
pub struct ColorTermRenderer;
|
pub struct ColorTermRenderer;
|
||||||
|
|
||||||
impl Renderer for ColorTermRenderer {
|
impl Renderer for ColorTermRenderer {
|
||||||
fn render_with_image(&mut self, _state: &dyn GenericSim, im: &RgbImage) {
|
fn render_with_image(&self, _state: &dyn GenericSim, im: &RgbImage) {
|
||||||
let square = "█";
|
let square = "█";
|
||||||
let buf: String = im
|
let buf: String = im
|
||||||
.enumerate_rows()
|
.enumerate_rows()
|
||||||
@@ -279,28 +285,31 @@ impl Renderer for ColorTermRenderer {
|
|||||||
|
|
||||||
pub struct Y4MRenderer {
|
pub struct Y4MRenderer {
|
||||||
out_path: PathBuf,
|
out_path: PathBuf,
|
||||||
encoder: Option<y4m::Encoder<File>>,
|
encoder: Mutex<Option<y4m::Encoder<File>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Y4MRenderer {
|
impl Y4MRenderer {
|
||||||
pub fn new<S: Into<PathBuf>>(output: S) -> Self {
|
pub fn new<S: Into<PathBuf>>(output: S) -> Self {
|
||||||
Self {
|
Self {
|
||||||
out_path: output.into(),
|
out_path: output.into(),
|
||||||
encoder: None,
|
encoder: Mutex::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for Y4MRenderer {
|
impl Renderer for Y4MRenderer {
|
||||||
fn render_with_image(&mut self, _state: &dyn GenericSim, im: &RgbImage) {
|
fn render_with_image(&self, _state: &dyn GenericSim, im: &RgbImage) {
|
||||||
if self.encoder.is_none() {
|
{
|
||||||
|
let mut enc = self.encoder.lock().unwrap();
|
||||||
|
if enc.is_none() {
|
||||||
let writer = File::create(&self.out_path).unwrap();
|
let writer = File::create(&self.out_path).unwrap();
|
||||||
self.encoder = Some(y4m::encode(im.width() as usize, im.height() as usize, y4m::Ratio::new(30, 1))
|
*enc = Some(y4m::encode(im.width() as usize, im.height() as usize, y4m::Ratio::new(30, 1))
|
||||||
.with_colorspace(y4m::Colorspace::C444)
|
.with_colorspace(y4m::Colorspace::C444)
|
||||||
.write_header(writer)
|
.write_header(writer)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut pix_y = Vec::new();
|
let mut pix_y = Vec::new();
|
||||||
let mut pix_u = Vec::new();
|
let mut pix_u = Vec::new();
|
||||||
@@ -318,7 +327,8 @@ impl Renderer for Y4MRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let frame = y4m::Frame::new([&*pix_y, &*pix_u, &*pix_v], None);
|
let frame = y4m::Frame::new([&*pix_y, &*pix_u, &*pix_v], None);
|
||||||
let enc = self.encoder.as_mut().unwrap();
|
let mut lock = self.encoder.lock().unwrap();
|
||||||
|
let enc = lock.as_mut().unwrap();
|
||||||
trace!("write_frame begin");
|
trace!("write_frame begin");
|
||||||
let ret = enc.write_frame(&frame).unwrap();
|
let ret = enc.write_frame(&frame).unwrap();
|
||||||
trace!("write_frame end");
|
trace!("write_frame end");
|
||||||
@@ -326,44 +336,112 @@ impl Renderer for Y4MRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PlotlyRenderer;
|
pub struct PlotlyRenderer {
|
||||||
|
out_base: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_scatter(plot: &mut plotly::Plot, xv: &mut Vec<u32>, yv: &mut Vec<u32>, zv: &mut Vec<u32>, colors: &mut Vec<plotly::Rgba>) {
|
||||||
|
let xv = std::mem::replace(xv, Vec::new());
|
||||||
|
let yv = std::mem::replace(yv, Vec::new());
|
||||||
|
let zv = std::mem::replace(zv, Vec::new());
|
||||||
|
let colors = std::mem::replace(colors, Vec::new());
|
||||||
|
let scatter = plotly::Scatter::new3(xv, yv, zv)
|
||||||
|
.mode(plotly::common::Mode::Markers)
|
||||||
|
.marker(plotly::common::Marker::new()
|
||||||
|
.opacity(0.01)
|
||||||
|
//.size_array(sizes)
|
||||||
|
//.opacity_array(opacities)
|
||||||
|
.color_array(colors)
|
||||||
|
);
|
||||||
|
plot.add_trace(scatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlotlyRenderer {
|
||||||
|
pub fn new(out_base: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
out_base: out_base.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Renderer for PlotlyRenderer {
|
impl Renderer for PlotlyRenderer {
|
||||||
fn render(&mut self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
|
use plotly::{ImageFormat, Plot, Rgba, Scatter};
|
||||||
|
use plotly::common::Marker;
|
||||||
|
use plotly::layout::{AspectMode, Axis, Layout, LayoutScene};
|
||||||
let mut plot = Plot::new();
|
let mut plot = Plot::new();
|
||||||
|
let scene = LayoutScene::new()
|
||||||
|
.x_axis(Axis::new().range(vec![0, state.width() as i32]))
|
||||||
|
.y_axis(Axis::new().range(vec![0, state.height() as i32]))
|
||||||
|
.z_axis(Axis::new().range(vec![0, state.depth() as i32]))
|
||||||
|
.aspect_mode(AspectMode::Cube);
|
||||||
|
let layout = Layout::new()
|
||||||
|
.scene(scene);
|
||||||
|
plot.set_layout(layout);
|
||||||
|
|
||||||
let mut xv = Vec::new();
|
let mut xv = Vec::new();
|
||||||
let mut yv = Vec::new();
|
let mut yv = Vec::new();
|
||||||
let mut zv = Vec::new();
|
let mut zv = Vec::new();
|
||||||
|
// let mut opacities = Vec::new();
|
||||||
|
let mut colors = Vec::new();
|
||||||
for z in 0..state.depth() {
|
for z in 0..state.depth() {
|
||||||
|
if xv.len() >= 120000 {
|
||||||
|
add_scatter(&mut plot, &mut xv, &mut yv, &mut zv, &mut colors);
|
||||||
|
}
|
||||||
for y in 0..state.height() {
|
for y in 0..state.height() {
|
||||||
for x in 0..state.width() {
|
for x in 0..state.width() {
|
||||||
|
// if x%5 == 0 || y%5 == 0 || z%5 == 0 {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
let cell = state.get(Index(Vec3u::new(x, y, z)));
|
let cell = state.get(Index(Vec3u::new(x, y, z)));
|
||||||
if cell.e().mag() > 10.0 {
|
|
||||||
xv.push(x);
|
xv.push(x);
|
||||||
yv.push(y);
|
yv.push(y);
|
||||||
zv.push(z);
|
zv.push(z);
|
||||||
|
// opacities.push((cell.e().mag() * 0.1).min(1.0) as f64)
|
||||||
|
let mat = cell.mat().conductivity().mag() + if cell.mat().is_vacuum() {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
5.0
|
||||||
|
};
|
||||||
|
//let g = scale_unsigned_to_u8(mat, 10.0);
|
||||||
|
//let r = scale_unsigned_to_u8(cell.mat().m().mag(), 100.0);
|
||||||
|
//let b = scale_unsigned_to_u8(cell.e().mag(), 1e2);
|
||||||
|
let r = scale_unsigned_to_u8(cell.mat().m().mag(), 100.0);
|
||||||
|
let g = scale_unsigned_to_u8(cell.e().mag(), 1e2);
|
||||||
|
let b = scale_unsigned_to_u8(mat, 10.0);
|
||||||
|
let alpha = 1.0;
|
||||||
|
colors.push(Rgba::new(r, g, b, alpha));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// let scatter = plotly::Scatter::new3(xv, yv, zv)
|
||||||
|
// .mode(plotly::common::Mode::Markers)
|
||||||
|
// .marker(plotly::common::Marker::new()
|
||||||
|
// //.opacity(0.2)
|
||||||
|
// //.size_array(sizes)
|
||||||
|
// //.opacity_array(opacities)
|
||||||
|
// .color_array(colors)
|
||||||
|
// );
|
||||||
|
// plot.add_trace(scatter);
|
||||||
}
|
}
|
||||||
}
|
add_scatter(&mut plot, &mut xv, &mut yv, &mut zv, &mut colors);
|
||||||
let heat_map = HeatMap::new(xv, yv, zv);
|
|
||||||
plot.add_trace(heat_map);
|
let name = format!("{}{}", self.out_base, state.step_no());
|
||||||
let name = format!("frame{}", state.step_no());
|
let (im_w, im_h) = im_size(state, 2048, 2048);
|
||||||
plot.save(&*name, ImageFormat::PNG, state.width() as _, state.height() as _, 1.0);
|
plot.save(&*name, ImageFormat::PNG, im_w as _, im_h as _, 1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct MultiRenderer {
|
pub struct MultiRenderer {
|
||||||
renderers: Vec<Box<dyn Renderer>>,
|
renderers: RwLock<Vec<Box<dyn Renderer>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MultiRenderer {
|
impl MultiRenderer {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
pub fn push<R: Renderer + 'static>(&mut self, r: R) {
|
pub fn push<R: Renderer + 'static>(&self, r: R) {
|
||||||
self.renderers.push(Box::new(r));
|
self.renderers.write().unwrap().push(Box::new(r));
|
||||||
}
|
}
|
||||||
pub fn with<R: Renderer + 'static>(mut self, r: R) -> Self {
|
pub fn with<R: Renderer + 'static>(mut self, r: R) -> Self {
|
||||||
self.push(r);
|
self.push(r);
|
||||||
@@ -372,14 +450,14 @@ impl MultiRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for MultiRenderer {
|
impl Renderer for MultiRenderer {
|
||||||
fn render(&mut self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
if self.renderers.len() != 0 {
|
if self.renderers.read().unwrap().len() != 0 {
|
||||||
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2));
|
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_with_image(&mut self, state: &dyn GenericSim, im: &RgbImage) {
|
fn render_with_image(&self, state: &dyn GenericSim, im: &RgbImage) {
|
||||||
for r in &mut self.renderers {
|
for r in &*self.renderers.read().unwrap() {
|
||||||
r.render_with_image(state, im);
|
r.render_with_image(state, im);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
22
src/sim.rs
22
src/sim.rs
@@ -1,6 +1,7 @@
|
|||||||
use crate::{flt::{Flt, Real}, consts};
|
use crate::{flt::{Flt, Real}, consts};
|
||||||
use crate::geom::{Coord, Index, Meters, Vec3, Vec3u};
|
use crate::geom::{Coord, Index, Meters, Vec3, Vec3u};
|
||||||
use crate::mat::{self, GenericMaterial, Material};
|
use crate::mat::{self, GenericMaterial, Material};
|
||||||
|
use dyn_clone::{self, DynClone};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
use ndarray::{Array3, Zip};
|
use ndarray::{Array3, Zip};
|
||||||
@@ -8,7 +9,7 @@ use ndarray::parallel::prelude::*;
|
|||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
|
|
||||||
pub trait GenericSim {
|
pub trait GenericSim: Send + Sync + DynClone {
|
||||||
fn sample(&self, pos: Meters) -> Cell<mat::Static>;
|
fn sample(&self, pos: Meters) -> Cell<mat::Static>;
|
||||||
fn impulse_e_meters(&mut self, pos: Meters, amount: Vec3);
|
fn impulse_e_meters(&mut self, pos: Meters, amount: Vec3);
|
||||||
fn impulse_h_meters(&mut self, pos: Meters, amount: Vec3);
|
fn impulse_h_meters(&mut self, pos: Meters, amount: Vec3);
|
||||||
@@ -29,7 +30,20 @@ pub trait GenericSim {
|
|||||||
fn time(&self) -> Flt {
|
fn time(&self) -> Flt {
|
||||||
self.timestep() * self.step_no() as Flt
|
self.timestep() * self.step_no() as Flt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Take a "snapshot" of the simulation, dropping all material-specific information.
|
||||||
|
fn to_static(&self) -> SimState<mat::Static> {
|
||||||
|
let mut state = SimState::new(self.size(), self.feature_size());
|
||||||
|
Zip::from(ndarray::indices_of(&state.cells)).par_apply_assign_into(
|
||||||
|
&mut state.cells,
|
||||||
|
|(z, y, x)| {
|
||||||
|
let idx = Index((x as u32, y as u32, z as u32).into());
|
||||||
|
self.sample(idx.to_meters(self.feature_size()))
|
||||||
|
});
|
||||||
|
state
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
dyn_clone::clone_trait_object!(GenericSim);
|
||||||
|
|
||||||
impl<'a> dyn GenericSim + 'a {
|
impl<'a> dyn GenericSim + 'a {
|
||||||
pub fn get<C: Coord>(&self, at: C) -> Cell<mat::Static> {
|
pub fn get<C: Coord>(&self, at: C) -> Cell<mat::Static> {
|
||||||
@@ -82,7 +96,7 @@ impl<'a> dyn GenericSim + 'a {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, Clone)]
|
||||||
pub struct SimState<M=GenericMaterial> {
|
pub struct SimState<M=GenericMaterial> {
|
||||||
cells: Array3<Cell<M>>,
|
cells: Array3<Cell<M>>,
|
||||||
scratch: Array3<Cell<M>>,
|
scratch: Array3<Cell<M>>,
|
||||||
@@ -101,7 +115,7 @@ impl<M: Material + Default> SimState<M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Material + Clone + Default + Send + Sync> SimState<M> {
|
impl<M: Material + Clone + Default + Send + Sync + 'static> SimState<M> {
|
||||||
pub fn step(&mut self) {
|
pub fn step(&mut self) {
|
||||||
use consts::real::*;
|
use consts::real::*;
|
||||||
let time_step = Real::from_inner(self.timestep());
|
let time_step = Real::from_inner(self.timestep());
|
||||||
@@ -134,7 +148,7 @@ impl<M: Material + Clone + Default + Send + Sync> SimState<M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Material> GenericSim for SimState<M> {
|
impl<M: Material + Clone + Send + Sync + 'static> GenericSim for SimState<M> {
|
||||||
fn sample(&self, pos: Meters) -> Cell<mat::Static> {
|
fn sample(&self, pos: Meters) -> Cell<mat::Static> {
|
||||||
// TODO: smarter sampling than nearest neighbor?
|
// TODO: smarter sampling than nearest neighbor?
|
||||||
let pos_sim = pos.to_index(self.feature_size());
|
let pos_sim = pos.to_index(self.feature_size());
|
||||||
|
Reference in New Issue
Block a user