Rendering now mostly uses the GenericSim
This commit is contained in:
@@ -3,7 +3,7 @@ use crate::consts;
|
|||||||
use crate::coord::Coord;
|
use crate::coord::Coord;
|
||||||
use crate::meas::{self, AbstractMeasurement};
|
use crate::meas::{self, AbstractMeasurement};
|
||||||
use crate::render::{self, MultiRenderer, Renderer};
|
use crate::render::{self, MultiRenderer, Renderer};
|
||||||
use crate::sim::SimState;
|
use crate::sim::{GenericSim as _, SimState};
|
||||||
use crate::vec3::Vec3;
|
use crate::vec3::Vec3;
|
||||||
|
|
||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
|
66
src/meas.rs
66
src/meas.rs
@@ -1,18 +1,18 @@
|
|||||||
use crate::coord::Coord;
|
use crate::coord::Coord;
|
||||||
use crate::geom::{Point, Region};
|
use crate::geom::Region;
|
||||||
use crate::mat::Material as _;
|
use crate::mat::Material as _;
|
||||||
use crate::sim::{Cell, SimSnapshot};
|
use crate::sim::GenericSim;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::iter::Sum;
|
//use std::iter::Sum;
|
||||||
|
|
||||||
pub trait AbstractMeasurement {
|
pub trait AbstractMeasurement {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String;
|
fn eval(&self, state: &dyn GenericSim) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Time;
|
pub struct Time;
|
||||||
|
|
||||||
impl AbstractMeasurement for Time {
|
impl AbstractMeasurement for Time {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> String {
|
||||||
format!("{:.3e}s (step {})", state.time(), state.step_no())
|
format!("{:.3e}s (step {})", state.time(), state.step_no())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ impl AbstractMeasurement for Time {
|
|||||||
pub struct Meta;
|
pub struct Meta;
|
||||||
|
|
||||||
impl AbstractMeasurement for Meta {
|
impl AbstractMeasurement for Meta {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> String {
|
||||||
format!("{}x{} feat: {:.1e}m", state.width(), state.height(), state.feature_size())
|
format!("{}x{} feat: {:.1e}m", state.width(), state.height(), state.feature_size())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,25 +34,28 @@ impl Label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractMeasurement for Label {
|
impl AbstractMeasurement for Label {
|
||||||
fn eval(&self, _state: &SimSnapshot) -> String {
|
fn eval(&self, _state: &dyn GenericSim) -> String {
|
||||||
self.0.clone()
|
self.0.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sum_over_region<T: Default + Send + Sum<T>, R: Region + Sync, F: Fn(Coord, &Cell) -> T + Sync>(state: &SimSnapshot, r: &R, f: F) -> T {
|
// fn sum_over_region<T: Default + Send + Sum<T>, R: Region + Sync, F: Fn(Coord, &Cell) -> T + Sync>(state: &SimSnapshot, r: &R, f: F) -> T {
|
||||||
state.map_sum_enumerated(|coord, cell| if r.contains(Point::from(coord)*state.feature_size()) {
|
// state.map_sum_enumerated(|coord, cell| if r.contains(Point::from(coord)*state.feature_size()) {
|
||||||
f(coord, cell)
|
// f(coord, cell)
|
||||||
} else {
|
// } else {
|
||||||
Default::default()
|
// Default::default()
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub struct Current<R>(pub R);
|
pub struct Current<R>(pub R);
|
||||||
|
|
||||||
impl<R: Region + Display + Sync> AbstractMeasurement for Current<R> {
|
impl<R: Region + Display + Sync> AbstractMeasurement for Current<R> {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String {
|
// fn eval(&self, state: &SimSnapshot) -> 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())
|
||||||
|
// }
|
||||||
|
fn eval(&self, _state: &dyn GenericSim) -> String {
|
||||||
|
format!("I: TODO")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +63,7 @@ impl<R: Region + Display + Sync> AbstractMeasurement for Current<R> {
|
|||||||
pub struct Magnetization(pub Coord);
|
pub struct Magnetization(pub Coord);
|
||||||
|
|
||||||
impl AbstractMeasurement for Magnetization {
|
impl AbstractMeasurement for Magnetization {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> String {
|
||||||
let m = state.get(self.0).mat().m();
|
let m = state.get(self.0).mat().m();
|
||||||
format!("M{}: ({:.2e}, {:.2e}, {:.2e})", self.0, m.x(), m.y(), m.z())
|
format!("M{}: ({:.2e}, {:.2e}, {:.2e})", self.0, m.x(), m.y(), m.z())
|
||||||
}
|
}
|
||||||
@@ -70,7 +73,7 @@ impl AbstractMeasurement for Magnetization {
|
|||||||
pub struct MagneticFlux(pub Coord);
|
pub struct MagneticFlux(pub Coord);
|
||||||
|
|
||||||
impl AbstractMeasurement for MagneticFlux {
|
impl AbstractMeasurement for MagneticFlux {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> String {
|
||||||
let b = state.get(self.0).b();
|
let b = state.get(self.0).b();
|
||||||
format!("B{}: ({:.2e}, {:.2e}, {:.2e})", self.0, b.x(), b.y(), b.z())
|
format!("B{}: ({:.2e}, {:.2e}, {:.2e})", self.0, b.x(), b.y(), b.z())
|
||||||
}
|
}
|
||||||
@@ -80,7 +83,7 @@ impl AbstractMeasurement for MagneticFlux {
|
|||||||
pub struct MagneticStrength(pub Coord);
|
pub struct MagneticStrength(pub Coord);
|
||||||
|
|
||||||
impl AbstractMeasurement for MagneticStrength {
|
impl AbstractMeasurement for MagneticStrength {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> String {
|
||||||
let h = state.get(self.0).h();
|
let h = state.get(self.0).h();
|
||||||
format!("H{}: ({:.2e}, {:.2e}, {:.2e})", self.0, h.x(), h.y(), h.z())
|
format!("H{}: ({:.2e}, {:.2e}, {:.2e})", self.0, h.x(), h.y(), h.z())
|
||||||
}
|
}
|
||||||
@@ -89,7 +92,7 @@ impl AbstractMeasurement for MagneticStrength {
|
|||||||
pub struct ElectricField(pub Coord);
|
pub struct ElectricField(pub Coord);
|
||||||
|
|
||||||
impl AbstractMeasurement for ElectricField {
|
impl AbstractMeasurement for ElectricField {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> String {
|
||||||
let e = state.get(self.0).e();
|
let e = state.get(self.0).e();
|
||||||
format!("E{}: ({:.2e}, {:.2e}, {:.2e})", self.0, e.x(), e.y(), e.z())
|
format!("E{}: ({:.2e}, {:.2e}, {:.2e})", self.0, e.x(), e.y(), e.z())
|
||||||
}
|
}
|
||||||
@@ -98,21 +101,22 @@ impl AbstractMeasurement for ElectricField {
|
|||||||
pub struct Energy;
|
pub struct Energy;
|
||||||
|
|
||||||
impl AbstractMeasurement for Energy {
|
impl AbstractMeasurement for Energy {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String {
|
fn eval(&self, _state: &dyn GenericSim) -> String {
|
||||||
// Potential energy stored in a E/M field:
|
// Potential energy stored in a E/M field:
|
||||||
// https://en.wikipedia.org/wiki/Magnetic_energy
|
// https://en.wikipedia.org/wiki/Magnetic_energy
|
||||||
// https://en.wikipedia.org/wiki/Electric_potential_energy#Energy_stored_in_an_electrostatic_field_distribution
|
// https://en.wikipedia.org/wiki/Electric_potential_energy#Energy_stored_in_an_electrostatic_field_distribution
|
||||||
// U(B) = 1/2 \int H . B dV
|
// U(B) = 1/2 \int H . B dV
|
||||||
// U(E) = 1/2 \int E . D dV
|
// U(E) = 1/2 \int E . D dV
|
||||||
let f = state.feature_size();
|
// let f = state.feature_size();
|
||||||
#[allow(non_snake_case)]
|
// #[allow(non_snake_case)]
|
||||||
let dV = f*f*f;
|
// let dV = f*f*f;
|
||||||
let e = state.map_sum(|cell| {
|
//let e = state.map_sum(|cell| {
|
||||||
// E . D is perpetually 0 since we don't model D.
|
// // E . D is perpetually 0 since we don't model D.
|
||||||
// All potential energy is in the magnetic field.
|
// // All potential energy is in the magnetic field.
|
||||||
0.5 * cell.h().dot(cell.b()) * dV
|
// 0.5 * cell.h().dot(cell.b()) * dV
|
||||||
});
|
//});
|
||||||
format!("U: {:.2e}", e)
|
//format!("U: {:.2e}", e)
|
||||||
|
format!("U: TODO")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,7 +2,8 @@ use ansi_term::Color::RGB;
|
|||||||
use crate::geom::Point;
|
use crate::geom::Point;
|
||||||
use crate::{flt::{Flt, Real}, Material as _, SimSnapshot, SimState};
|
use crate::{flt::{Flt, Real}, Material as _, SimSnapshot, SimState};
|
||||||
use crate::mat;
|
use crate::mat;
|
||||||
use crate::sim::Cell;
|
use crate::sim::{Cell, GenericSim};
|
||||||
|
use crate::vec3::Vec3;
|
||||||
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;
|
use log::trace;
|
||||||
@@ -54,12 +55,12 @@ fn scale_vector(x: Point, typical_mag: Flt) -> Point {
|
|||||||
|
|
||||||
struct RenderSteps<'a> {
|
struct RenderSteps<'a> {
|
||||||
im: RgbImage,
|
im: RgbImage,
|
||||||
sim: &'a SimSnapshot,
|
sim: &'a dyn GenericSim,
|
||||||
meas: &'a [Box<dyn AbstractMeasurement>],
|
meas: &'a [Box<dyn AbstractMeasurement>],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RenderSteps<'a> {
|
impl<'a> RenderSteps<'a> {
|
||||||
fn render(state: &'a SimSnapshot, measurements: &'a [Box<dyn AbstractMeasurement>]) -> RgbImage {
|
fn render(state: &'a dyn GenericSim, measurements: &'a [Box<dyn AbstractMeasurement>]) -> RgbImage {
|
||||||
let width = 768;
|
let width = 768;
|
||||||
let height = width * state.height() / state.width();
|
let height = width * state.height() / state.width();
|
||||||
let mut me = Self::new(state, measurements, width, height);
|
let mut me = Self::new(state, measurements, width, height);
|
||||||
@@ -75,7 +76,7 @@ impl<'a> RenderSteps<'a> {
|
|||||||
me.render_measurements();
|
me.render_measurements();
|
||||||
me.im
|
me.im
|
||||||
}
|
}
|
||||||
fn new(sim: &'a SimSnapshot, meas: &'a [Box<dyn AbstractMeasurement>], width: u32, height: u32) -> Self {
|
fn new(sim: &'a dyn GenericSim, meas: &'a [Box<dyn AbstractMeasurement>], width: u32, height: u32) -> Self {
|
||||||
RenderSteps {
|
RenderSteps {
|
||||||
im: RgbImage::new(width, height),
|
im: RgbImage::new(width, height),
|
||||||
sim,
|
sim,
|
||||||
@@ -83,10 +84,12 @@ impl<'a> RenderSteps<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_at_px(&self, x_px: u32, y_px: u32) -> &Cell {
|
fn get_at_px(&self, x_px: u32, y_px: u32) -> Cell {
|
||||||
let x_sim = x_px * self.sim.width() / self.im.width();
|
let x_prop = x_px as Flt / self.im.width() as Flt;
|
||||||
let y_sim = y_px * self.sim.height() / self.im.height();
|
let x_m = x_prop * (self.sim.width() as Flt * self.sim.feature_size());
|
||||||
self.sim.get((x_sim, y_sim).into())
|
let y_prop = y_px as Flt / self.im.height() as Flt;
|
||||||
|
let y_m = y_prop * (self.sim.height() as Flt * self.sim.feature_size());
|
||||||
|
self.sim.sample(Vec3::new(x_m, y_m, 0.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////// Ex/Ey/Bz configuration ////////////
|
////////////// Ex/Ey/Bz configuration ////////////
|
||||||
@@ -132,7 +135,7 @@ impl<'a> RenderSteps<'a> {
|
|||||||
for y in 0..h {
|
for y in 0..h {
|
||||||
for x in 0..w {
|
for x in 0..w {
|
||||||
let cell = self.get_at_px(x, y);
|
let cell = self.get_at_px(x, y);
|
||||||
let value = measure(cell);
|
let value = measure(&cell);
|
||||||
let scaled = if signed {
|
let scaled = if signed {
|
||||||
scale_signed_to_u8(value, typical)
|
scale_signed_to_u8(value, typical)
|
||||||
} else {
|
} else {
|
||||||
@@ -176,7 +179,7 @@ impl<'a> RenderSteps<'a> {
|
|||||||
let yend = (ystart + size).min(h);
|
let yend = (ystart + size).min(h);
|
||||||
for y in ystart..yend {
|
for y in ystart..yend {
|
||||||
for x in xstart..xend {
|
for x in xstart..xend {
|
||||||
field += measure(self.get_at_px(x, y));
|
field += measure(&self.get_at_px(x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let xw = xend - xstart;
|
let xw = xend - xstart;
|
||||||
|
71
src/sim.rs
71
src/sim.rs
@@ -11,6 +11,20 @@ use std::iter::Sum;
|
|||||||
|
|
||||||
pub type SimSnapshot = SimState<mat::Static>;
|
pub type SimSnapshot = SimState<mat::Static>;
|
||||||
|
|
||||||
|
pub trait GenericSim {
|
||||||
|
fn sample(&self, pos_meters: Vec3) -> Cell<mat::Static>;
|
||||||
|
fn get(&self, at: Coord) -> Cell<mat::Static> {
|
||||||
|
// DEPRECATED
|
||||||
|
self.sample(Vec3::new(at.x().into(), at.y().into(), 0.0) * self.feature_size())
|
||||||
|
}
|
||||||
|
fn width(&self) -> u32;
|
||||||
|
fn height(&self) -> u32;
|
||||||
|
fn depth(&self) -> u32;
|
||||||
|
fn feature_size(&self) -> Flt;
|
||||||
|
fn time(&self) -> Flt;
|
||||||
|
fn step_no(&self) -> u64;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SimState<M=GenericMaterial> {
|
pub struct SimState<M=GenericMaterial> {
|
||||||
cells: Array3<Cell<M>>,
|
cells: Array3<Cell<M>>,
|
||||||
@@ -112,6 +126,43 @@ impl<M: Material + Default + Send + Sync> SimState<M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<M: Material> GenericSim for SimState<M> {
|
||||||
|
fn sample(&self, pos_meters: Vec3) -> Cell<mat::Static> {
|
||||||
|
// TODO: smarter sampling than nearest neighbor?
|
||||||
|
let pos_sim = pos_meters / self.feature_size();
|
||||||
|
let idx = [pos_sim.z() as usize, pos_sim.y() as _, pos_sim.x() as _];
|
||||||
|
match self.cells.get(idx) {
|
||||||
|
Some(cell) => Cell {
|
||||||
|
state: cell.state,
|
||||||
|
mat: mat::Static {
|
||||||
|
conductivity: cell.mat.conductivity(),
|
||||||
|
m: cell.mat.m(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> u32 {
|
||||||
|
self.cells.shape()[2] as _
|
||||||
|
}
|
||||||
|
fn height(&self) -> u32 {
|
||||||
|
self.cells.shape()[1] as _
|
||||||
|
}
|
||||||
|
fn depth(&self) -> u32 {
|
||||||
|
self.cells.shape()[0] as _
|
||||||
|
}
|
||||||
|
fn feature_size(&self) -> Flt {
|
||||||
|
self.feature_size.into()
|
||||||
|
}
|
||||||
|
fn time(&self) -> Flt {
|
||||||
|
self.timestep() * self.step_no as Flt
|
||||||
|
}
|
||||||
|
fn step_no(&self) -> u64 {
|
||||||
|
self.step_no
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<M: Material> SimState<M> {
|
impl<M: Material> SimState<M> {
|
||||||
pub fn impulse_bz(&mut self, c: Coord, bz: Flt) {
|
pub fn impulse_bz(&mut self, c: Coord, bz: Flt) {
|
||||||
self.get_mut(c).impulse_bz(bz);
|
self.get_mut(c).impulse_bz(bz);
|
||||||
@@ -122,17 +173,6 @@ impl<M: Material> SimState<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<M> SimState<M> {
|
impl<M> SimState<M> {
|
||||||
pub fn time(&self) -> Flt {
|
|
||||||
self.timestep() * self.step_no as Flt
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn step_no(&self) -> u64 {
|
|
||||||
self.step_no
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn feature_size(&self) -> Flt {
|
|
||||||
self.feature_size.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn impulse_ex(&mut self, c: Coord, ex: Flt) {
|
pub fn impulse_ex(&mut self, c: Coord, ex: Flt) {
|
||||||
self.get_mut(c).state.e += Vec3::new(ex, 0.0, 0.0);
|
self.get_mut(c).state.e += Vec3::new(ex, 0.0, 0.0);
|
||||||
@@ -144,15 +184,6 @@ impl<M> SimState<M> {
|
|||||||
self.get_mut(c).state.e += Vec3::new(0.0, 0.0, ez);
|
self.get_mut(c).state.e += Vec3::new(0.0, 0.0, ez);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width(&self) -> u32 {
|
|
||||||
self.cells.shape()[2] as _
|
|
||||||
}
|
|
||||||
pub fn height(&self) -> u32 {
|
|
||||||
self.cells.shape()[1] as _
|
|
||||||
}
|
|
||||||
pub fn depth(&self) -> u32 {
|
|
||||||
self.cells.shape()[0] as _
|
|
||||||
}
|
|
||||||
pub fn get(&self, c: Coord) -> &Cell<M> {
|
pub fn get(&self, c: Coord) -> &Cell<M> {
|
||||||
&self.cells[c.row_major_idx()]
|
&self.cells[c.row_major_idx()]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user