Make the float depth compile-time configurable
This commit is contained in:
@@ -5,17 +5,9 @@ fn main() {
|
|||||||
let width = 201;
|
let width = 201;
|
||||||
let mut driver = Driver::new(width, 101, 1e-3 /* feature size */);
|
let mut driver = Driver::new(width, 101, 1e-3 /* feature size */);
|
||||||
driver.add_y4m_renderer("em_reflection.y4m");
|
driver.add_y4m_renderer("em_reflection.y4m");
|
||||||
driver.add_term_renderer();
|
// driver.add_term_renderer();
|
||||||
|
|
||||||
for inset in 0..20 {
|
driver.add_boundary(20, 0.1);
|
||||||
for x in 0..width {
|
|
||||||
*driver.state.get_mut(x, inset).mat_mut() = mat::Static::conductor(0.1*(20.0 - inset as f64)).into();
|
|
||||||
}
|
|
||||||
for y in 0..100 {
|
|
||||||
*driver.state.get_mut(inset, y).mat_mut() = mat::Static::conductor(0.1*(20.0 - inset as f64)).into();
|
|
||||||
*driver.state.get_mut(width-1 - inset, y).mat_mut() = mat::Static::conductor(0.1*(20.0 - inset as f64)).into();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for y in 75..100 {
|
for y in 75..100 {
|
||||||
for x in 0..width {
|
for x in 0..width {
|
||||||
// from https://www.thoughtco.com/table-of-electrical-resistivity-conductivity-608499
|
// from https://www.thoughtco.com/table-of-electrical-resistivity-conductivity-608499
|
||||||
|
@@ -16,6 +16,7 @@ fn main() {
|
|||||||
//driver.set_steps_per_frame(40);
|
//driver.set_steps_per_frame(40);
|
||||||
driver.add_y4m_renderer("toroid2.y4m");
|
driver.add_y4m_renderer("toroid2.y4m");
|
||||||
// driver.add_term_renderer();
|
// driver.add_term_renderer();
|
||||||
|
driver.add_measurement(meas::Label(format!("Conductivity: {}, Imax: {:.2e}", conductivity, peak_current)));
|
||||||
driver.add_measurement(meas::Current(width / 2 + (conductor_inner_rad + conductor_outer_rad) / 2, width / 2));
|
driver.add_measurement(meas::Current(width / 2 + (conductor_inner_rad + conductor_outer_rad) / 2, width / 2));
|
||||||
driver.add_measurement(meas::Current(width / 2 + conductor_inner_rad + 2, width / 2));
|
driver.add_measurement(meas::Current(width / 2 + conductor_inner_rad + 2, width / 2));
|
||||||
driver.add_measurement(meas::Magnetization(width / 2 + ferro_inner_rad + 2, width / 2));
|
driver.add_measurement(meas::Magnetization(width / 2 + ferro_inner_rad + 2, width / 2));
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
use crate::mat;
|
use crate::{flt, mat};
|
||||||
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::SimState;
|
||||||
@@ -17,11 +17,11 @@ pub struct Driver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Driver {
|
impl Driver {
|
||||||
pub fn new(width: u32, height: u32, feature_size: f64) -> Self {
|
pub fn new(width: u32, height: u32, feature_size: flt::Pub) -> Self {
|
||||||
Driver {
|
Driver {
|
||||||
state: SimState::new(width, height, feature_size),
|
state: SimState::new(width, height, feature_size),
|
||||||
steps_per_frame: 1,
|
steps_per_frame: 1,
|
||||||
measurements: vec![Box::new(meas::Time), Box::new(meas::Energy)],
|
measurements: vec![Box::new(meas::Time), Box::new(meas::Meta), Box::new(meas::Energy)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,10 +49,10 @@ impl Driver {
|
|||||||
self.add_renderer(render::ColorTermRenderer, "terminal");
|
self.add_renderer(render::ColorTermRenderer, "terminal");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_boundary(&mut self, thickness: u32, base_conductivity: f64) {
|
pub fn add_boundary(&mut self, thickness: u32, base_conductivity: flt::Pub) {
|
||||||
for inset in 0..thickness {
|
for inset in 0..thickness {
|
||||||
let depth = thickness - inset;
|
let depth = thickness - inset;
|
||||||
let conductivity = base_conductivity * (depth*depth) as f64;
|
let conductivity = base_conductivity * (depth*depth) as flt::Pub;
|
||||||
for x in inset..self.state.width() - inset {
|
for x in inset..self.state.width() - inset {
|
||||||
// left
|
// left
|
||||||
*self.state.get_mut(x, inset).mat_mut() = mat::Static::conductor(conductivity).into();
|
*self.state.get_mut(x, inset).mat_mut() = mat::Static::conductor(conductivity).into();
|
||||||
@@ -76,7 +76,7 @@ impl Driver {
|
|||||||
self.state.step();
|
self.state.step();
|
||||||
self.time_spent_stepping += start_time.elapsed().unwrap();
|
self.time_spent_stepping += start_time.elapsed().unwrap();
|
||||||
if self.state.step_no() % (10*self.steps_per_frame) == 0 {
|
if self.state.step_no() % (10*self.steps_per_frame) == 0 {
|
||||||
info!("fps: {:6.2}", (self.state.step_no() as f64) / self.time_spent_stepping.as_secs_f64());
|
info!("fps: {:6.2}", (self.state.step_no() as flt::Pub) / (self.time_spent_stepping.as_secs_f64() as flt::Pub));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
72
src/geom.rs
72
src/geom.rs
@@ -1,18 +1,18 @@
|
|||||||
use crate::F64;
|
use crate::flt;
|
||||||
use std::ops::{Add, AddAssign, Mul, Neg, Sub};
|
use std::ops::{Add, AddAssign, Mul, Neg, Sub};
|
||||||
|
|
||||||
|
|
||||||
fn real(f: f64) -> F64 {
|
fn real(f: flt::Pub) -> flt::Priv {
|
||||||
F64::from_inner(f)
|
flt::Priv::from_inner(f)
|
||||||
}
|
}
|
||||||
fn round(f: F64) -> F64 {
|
fn round(f: flt::Priv) -> flt::Priv {
|
||||||
F64::from_inner(f.into_inner().round())
|
flt::Priv::from_inner(f.into_inner().round())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub struct Point {
|
pub struct Point {
|
||||||
pub x: F64,
|
pub x: flt::Priv,
|
||||||
pub y: F64,
|
pub y: flt::Priv,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add for Point {
|
impl Add for Point {
|
||||||
@@ -48,9 +48,9 @@ impl Sub for Point {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mul<f64> for Point {
|
impl Mul<flt::Pub> for Point {
|
||||||
type Output = Point;
|
type Output = Point;
|
||||||
fn mul(self, s: f64) -> Point {
|
fn mul(self, s: flt::Pub) -> Point {
|
||||||
Point {
|
Point {
|
||||||
x: self.x * s,
|
x: self.x * s,
|
||||||
y: self.y * s,
|
y: self.y * s,
|
||||||
@@ -58,25 +58,25 @@ impl Mul<f64> for Point {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<(f64, f64)> for Point {
|
impl Into<(flt::Pub, flt::Pub)> for Point {
|
||||||
fn into(self) -> (f64, f64) {
|
fn into(self) -> (flt::Pub, flt::Pub) {
|
||||||
(self.x(), self.y())
|
(self.x(), self.y())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Point {
|
impl Point {
|
||||||
pub fn new(x: f64, y: f64) -> Self {
|
pub fn new(x: flt::Pub, y: flt::Pub) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: x.into(),
|
x: x.into(),
|
||||||
y: y.into(),
|
y: y.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn x(&self) -> f64 {
|
pub fn x(&self) -> flt::Pub {
|
||||||
self.x.into()
|
self.x.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn y(&self) -> f64 {
|
pub fn y(&self) -> flt::Pub {
|
||||||
self.y.into()
|
self.y.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,20 +87,20 @@ impl Point {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mag_sq(&self) -> f64 {
|
pub fn mag_sq(&self) -> flt::Pub {
|
||||||
(self.x*self.x + self.y*self.y).into()
|
(self.x*self.x + self.y*self.y).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mag(&self) -> f64 {
|
pub fn mag(&self) -> flt::Pub {
|
||||||
self.mag_sq().sqrt()
|
self.mag_sq().sqrt()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_mag(&self, new_mag: f64) -> Point {
|
pub fn with_mag(&self, new_mag: flt::Pub) -> Point {
|
||||||
if new_mag == 0.0 {
|
if new_mag == 0.0 {
|
||||||
// avoid div-by-zero if self.mag() == 0 and new_mag == 0
|
// avoid div-by-zero if self.mag() == 0 and new_mag == 0
|
||||||
Point::new(0.0, 0.0)
|
Point::new(0.0, 0.0)
|
||||||
} else {
|
} else {
|
||||||
let scale = F64::from_inner(new_mag) / self.mag();
|
let scale = flt::Priv::from_inner(new_mag) / self.mag();
|
||||||
self.clone() * scale.into_inner()
|
self.clone() * scale.into_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,17 +130,17 @@ impl Line {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn x(&self, y: f64) -> f64 {
|
pub fn x(&self, y: flt::Pub) -> flt::Pub {
|
||||||
self.shifted(Point::new(0.0, -y)).x_intercept()
|
self.shifted(Point::new(0.0, -y)).x_intercept()
|
||||||
}
|
}
|
||||||
pub fn y(&self, x: f64) -> f64 {
|
pub fn y(&self, x: flt::Pub) -> flt::Pub {
|
||||||
(self.from.y + (real(x) - self.from.x) * self.slope()).into()
|
(self.from.y + (real(x) - self.from.x) * self.slope()).into()
|
||||||
}
|
}
|
||||||
pub fn at_x(&self, x: f64) -> Point {
|
pub fn at_x(&self, x: flt::Pub) -> Point {
|
||||||
Point::new(x, self.y(x))
|
Point::new(x, self.y(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn x_intercept(&self) -> f64 {
|
pub fn x_intercept(&self) -> flt::Pub {
|
||||||
let t = (-self.from.y) / (self.to.y - self.from.y);
|
let t = (-self.from.y) / (self.to.y - self.from.y);
|
||||||
(self.from.x + t * (self.to.x - self.from.x)).into()
|
(self.from.x + t * (self.to.x - self.from.x)).into()
|
||||||
}
|
}
|
||||||
@@ -149,12 +149,12 @@ impl Line {
|
|||||||
self.to + (-self.from)
|
self.to + (-self.from)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn length_sq(&self) -> f64 {
|
pub fn length_sq(&self) -> flt::Pub {
|
||||||
let Point { x, y } = self.as_vector();
|
let Point { x, y } = self.as_vector();
|
||||||
(x*x + y*y).into()
|
(x*x + y*y).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn distance_sq(&self, pt: Point) -> f64 {
|
pub fn distance_sq(&self, pt: Point) -> flt::Pub {
|
||||||
// source: https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points
|
// source: https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points
|
||||||
let d = self.as_vector();
|
let d = self.as_vector();
|
||||||
let twice_area = d.y*pt.x - d.x*pt.y + self.to.x*self.from.y - self.to.y*self.from.x;
|
let twice_area = d.y*pt.x - d.x*pt.y + self.to.x*self.from.y - self.to.y*self.from.x;
|
||||||
@@ -170,7 +170,7 @@ impl Line {
|
|||||||
self.to.x > self.from.x
|
self.to.x > self.from.x
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_x(&self, x: f64) -> bool {
|
pub fn contains_x(&self, x: flt::Pub) -> bool {
|
||||||
let x = real(x);
|
let x = real(x);
|
||||||
if self.is_ascending_x() {
|
if self.is_ascending_x() {
|
||||||
x >= self.from.x && x < self.to.x
|
x >= self.from.x && x < self.to.x
|
||||||
@@ -179,7 +179,7 @@ impl Line {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_y(&self, y: f64) -> bool {
|
pub fn contains_y(&self, y: flt::Pub) -> bool {
|
||||||
let y = real(y);
|
let y = real(y);
|
||||||
if self.is_ascending_x() {
|
if self.is_ascending_x() {
|
||||||
y >= self.from.y && y < self.to.y
|
y >= self.from.y && y < self.to.y
|
||||||
@@ -188,15 +188,15 @@ impl Line {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn min_x(&self) -> f64 {
|
pub fn min_x(&self) -> flt::Pub {
|
||||||
self.from.x.min(self.to.x).into()
|
self.from.x.min(self.to.x).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_x(&self) -> f64 {
|
pub fn max_x(&self) -> flt::Pub {
|
||||||
self.from.x.max(self.to.x).into()
|
self.from.x.max(self.to.x).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clamp_x(&self, x: f64) -> f64 {
|
pub fn clamp_x(&self, x: flt::Pub) -> flt::Pub {
|
||||||
match x {
|
match x {
|
||||||
v if v < self.min_x() => self.min_x(),
|
v if v < self.min_x() => self.min_x(),
|
||||||
v if v > self.max_x() => self.max_x(),
|
v if v > self.max_x() => self.max_x(),
|
||||||
@@ -204,18 +204,18 @@ impl Line {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clamp_by_x(&self, x: f64) -> Point {
|
pub fn clamp_by_x(&self, x: flt::Pub) -> Point {
|
||||||
self.at_x(self.clamp_x(x))
|
self.at_x(self.clamp_x(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slope(&self) -> f64 {
|
pub fn slope(&self) -> flt::Pub {
|
||||||
let s = (self.to.y - self.from.y) / (self.to.x - self.from.x);
|
let s = (self.to.y - self.from.y) / (self.to.x - self.from.x);
|
||||||
s.into()
|
s.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move the coordinate along the line toward some desired `y(x)` value.
|
/// Move the coordinate along the line toward some desired `y(x)` value.
|
||||||
/// The returned value could be OOB: check `self.contains_x` to find out.
|
/// The returned value could be OOB: check `self.contains_x` to find out.
|
||||||
pub fn move_toward_y_unclamped(&self, start_x: f64, target_y: f64) -> f64 {
|
pub fn move_toward_y_unclamped(&self, start_x: flt::Pub, target_y: flt::Pub) -> flt::Pub {
|
||||||
let start_y = self.y(start_x);
|
let start_y = self.y(start_x);
|
||||||
let delta_x = real(target_y - start_y) / self.slope();
|
let delta_x = real(target_y - start_y) / self.slope();
|
||||||
(real(start_x) + delta_x).into()
|
(real(start_x) + delta_x).into()
|
||||||
@@ -249,19 +249,19 @@ impl Polygon {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn min_x(&self) -> f64 {
|
pub fn min_x(&self) -> flt::Pub {
|
||||||
self.points.iter().map(|p| p.x).min().unwrap().into()
|
self.points.iter().map(|p| p.x).min().unwrap().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_x(&self) -> f64 {
|
pub fn max_x(&self) -> flt::Pub {
|
||||||
self.points.iter().map(|p| p.x).max().unwrap().into()
|
self.points.iter().map(|p| p.x).max().unwrap().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn min_y(&self) -> f64 {
|
pub fn min_y(&self) -> flt::Pub {
|
||||||
self.points.iter().map(|p| p.y).min().unwrap().into()
|
self.points.iter().map(|p| p.y).min().unwrap().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_y(&self) -> f64 {
|
pub fn max_y(&self) -> flt::Pub {
|
||||||
self.points.iter().map(|p| p.y).max().unwrap().into()
|
self.points.iter().map(|p| p.y).max().unwrap().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
src/lib.rs
50
src/lib.rs
@@ -25,42 +25,60 @@ pub use sim::*;
|
|||||||
// mu_0 = vacuum permeability = 1.25663706212(19)×10−6 H/m
|
// mu_0 = vacuum permeability = 1.25663706212(19)×10−6 H/m
|
||||||
// c_0 = speed of light in vacuum = 299792458
|
// c_0 = speed of light in vacuum = 299792458
|
||||||
|
|
||||||
#[cfg(debug)]
|
#[allow(unused)]
|
||||||
pub(crate) type F64 = decorum::Real<f64>;
|
pub(crate) mod flt {
|
||||||
#[cfg(not(debug))]
|
use decorum::{R32, R64};
|
||||||
pub(crate) type F64 = decorum::Total<f64>;
|
pub(crate) type T64 = decorum::Total<f64>;
|
||||||
|
pub(crate) type T32 = decorum::Total<f32>;
|
||||||
|
|
||||||
|
// Use checked floats for debug and fast floats for release
|
||||||
|
#[cfg(debug)]
|
||||||
|
pub(crate) mod defaults {
|
||||||
|
use super::*;
|
||||||
|
pub(crate) type Priv = R64;
|
||||||
|
pub type Pub = f64;
|
||||||
|
}
|
||||||
|
#[cfg(not(debug))]
|
||||||
|
pub(crate) mod defaults {
|
||||||
|
use super::*;
|
||||||
|
pub(crate) type Priv = T32;
|
||||||
|
pub type Pub = f32;
|
||||||
|
}
|
||||||
|
pub use defaults::*;
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub mod consts {
|
pub mod consts {
|
||||||
|
use super::*;
|
||||||
/// Speed of light in a vacuum; m/s.
|
/// Speed of light in a vacuum; m/s.
|
||||||
/// Also equal to 1/sqrt(epsilon_0 mu_0)
|
/// Also equal to 1/sqrt(epsilon_0 mu_0)
|
||||||
pub const C: f64 = 299792458.0;
|
pub const C: flt::Pub = 299792458.0;
|
||||||
// pub const Z0: f64 = 376.73031366857f32;
|
// pub const Z0: flt::Pub = 376.73031366857f32;
|
||||||
/// Vacuum Permeability
|
/// Vacuum Permeability
|
||||||
pub const MU0: f64 = 1.2566370621219e-6; // H/m
|
pub const MU0: flt::Pub = 1.2566370621219e-6; // H/m
|
||||||
// Vacuum Permittivity
|
// Vacuum Permittivity
|
||||||
pub const EPS0: f64 = 8.854187812813e-12; // F⋅m−1
|
pub const EPS0: flt::Pub = 8.854187812813e-12; // F⋅m−1
|
||||||
pub mod real {
|
pub mod real {
|
||||||
use crate::F64;
|
use super::*;
|
||||||
pub fn C() -> F64 {
|
pub(crate) fn C() -> flt::Priv {
|
||||||
super::C.into()
|
super::C.into()
|
||||||
}
|
}
|
||||||
pub fn C2() -> F64 {
|
pub(crate) fn C2() -> flt::Priv {
|
||||||
C() * C()
|
C() * C()
|
||||||
}
|
}
|
||||||
pub fn EPS0() -> F64 {
|
pub(crate) fn EPS0() -> flt::Priv {
|
||||||
super::EPS0.into()
|
super::EPS0.into()
|
||||||
}
|
}
|
||||||
pub fn MU0() -> F64 {
|
pub(crate) fn MU0() -> flt::Priv {
|
||||||
super::MU0.into()
|
super::MU0.into()
|
||||||
}
|
}
|
||||||
pub fn ONE() -> F64 {
|
pub(crate) fn ONE() -> flt::Priv {
|
||||||
1.0.into()
|
1.0.into()
|
||||||
}
|
}
|
||||||
pub fn TWO() -> F64 {
|
pub(crate) fn TWO() -> flt::Priv {
|
||||||
2.0.into()
|
2.0.into()
|
||||||
}
|
}
|
||||||
pub fn HALF() -> F64 {
|
pub(crate) fn HALF() -> flt::Priv {
|
||||||
0.5.into()
|
0.5.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
55
src/mat.rs
55
src/mat.rs
@@ -1,4 +1,4 @@
|
|||||||
use crate::{CellState, consts};
|
use crate::{CellState, consts, flt};
|
||||||
use crate::geom::{Line, Point, Polygon};
|
use crate::geom::{Line, Point, Polygon};
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@@ -7,15 +7,15 @@ use std::cmp::Ordering;
|
|||||||
pub trait Material {
|
pub trait Material {
|
||||||
/// Return \sigma, the electrical conductivity.
|
/// Return \sigma, the electrical conductivity.
|
||||||
/// For a vacuum, this is zero. For a perfect conductor, \inf.
|
/// For a vacuum, this is zero. For a perfect conductor, \inf.
|
||||||
fn conductivity(&self) -> f64 {
|
fn conductivity(&self) -> flt::Pub {
|
||||||
0.0
|
0.0
|
||||||
}
|
}
|
||||||
/// Return the magnetization in the z direction (M_z).
|
/// Return the magnetization in the z direction (M_z).
|
||||||
fn mz(&self) -> f64 {
|
fn mz(&self) -> flt::Pub {
|
||||||
0.0
|
0.0
|
||||||
}
|
}
|
||||||
/// Return the new h_z, and optionally change any internal state (e.g. magnetization).
|
/// Return the new h_z, and optionally change any internal state (e.g. magnetization).
|
||||||
fn step_h(&mut self, context: &CellState, delta_bz: f64) -> f64 {
|
fn step_h(&mut self, context: &CellState, delta_bz: flt::Pub) -> flt::Pub {
|
||||||
// B = mu0*(H+M), and in a default material M=0.
|
// B = mu0*(H+M), and in a default material M=0.
|
||||||
context.hz() + delta_bz / consts::MU0
|
context.hz() + delta_bz / consts::MU0
|
||||||
}
|
}
|
||||||
@@ -23,12 +23,12 @@ pub trait Material {
|
|||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Static {
|
pub struct Static {
|
||||||
pub conductivity: f64,
|
pub conductivity: flt::Pub,
|
||||||
pub mz: f64,
|
pub mz: flt::Pub,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Static {
|
impl Static {
|
||||||
pub fn conductor(conductivity: f64) -> Self {
|
pub fn conductor(conductivity: flt::Pub) -> Self {
|
||||||
Self {
|
Self {
|
||||||
conductivity,
|
conductivity,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -37,10 +37,10 @@ impl Static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Material for Static {
|
impl Material for Static {
|
||||||
fn conductivity(&self) -> f64 {
|
fn conductivity(&self) -> flt::Pub {
|
||||||
self.conductivity
|
self.conductivity
|
||||||
}
|
}
|
||||||
fn mz(&self) -> f64 {
|
fn mz(&self) -> flt::Pub {
|
||||||
self.mz
|
self.mz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,19 +48,19 @@ impl Material for Static {
|
|||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct ComsolFerromagnet {
|
pub struct ComsolFerromagnet {
|
||||||
/// Instantaneous magnetization in the z direction.
|
/// Instantaneous magnetization in the z direction.
|
||||||
pub mz: f64,
|
pub mz: flt::Pub,
|
||||||
// Ferromagnetic parameters:
|
// Ferromagnetic parameters:
|
||||||
/// Magnetic saturation (symmetric, so saturates to either +Ms or -Ms).
|
/// Magnetic saturation (symmetric, so saturates to either +Ms or -Ms).
|
||||||
pub ms: f64,
|
pub ms: flt::Pub,
|
||||||
/// Rate at which M changes w.r.t. H.
|
/// Rate at which M changes w.r.t. H.
|
||||||
pub xi: f64,
|
pub xi: flt::Pub,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Material for ComsolFerromagnet {
|
impl Material for ComsolFerromagnet {
|
||||||
fn mz(&self) -> f64 {
|
fn mz(&self) -> flt::Pub {
|
||||||
self.mz
|
self.mz
|
||||||
}
|
}
|
||||||
fn step_h(&mut self, context: &CellState, delta_bz: f64) -> f64 {
|
fn step_h(&mut self, context: &CellState, delta_bz: flt::Pub) -> flt::Pub {
|
||||||
// COMSOL ferromagnetic model: https://www.comsol.com/blogs/accessing-external-material-models-for-magnetic-simulations/
|
// COMSOL ferromagnetic model: https://www.comsol.com/blogs/accessing-external-material-models-for-magnetic-simulations/
|
||||||
// delta(M) = xi * delta*(H) # delta(M) = M(t+1) - M(t)
|
// delta(M) = xi * delta*(H) # delta(M) = M(t+1) - M(t)
|
||||||
// new_M = clamp(M+delta(M), -Ms, Ms)) # i.e. clamp to saturation
|
// new_M = clamp(M+delta(M), -Ms, Ms)) # i.e. clamp to saturation
|
||||||
@@ -113,7 +113,7 @@ impl MHCurve {
|
|||||||
/// Moves (h, m) towards some location in the MH curve where H + M = target_hm.
|
/// Moves (h, m) towards some location in the MH curve where H + M = target_hm.
|
||||||
/// Returns `Ok((h, m))` if complete; `Err((h, m))` if there's more work to be done (call it
|
/// Returns `Ok((h, m))` if complete; `Err((h, m))` if there's more work to be done (call it
|
||||||
/// again).
|
/// again).
|
||||||
fn step_toward(&self, h: f64, m: f64, target_hm: f64) -> Result<(f64, f64), (f64, f64)> {
|
fn step_toward(&self, h: flt::Pub, m: flt::Pub, target_hm: flt::Pub) -> Result<(flt::Pub, flt::Pub), (flt::Pub, flt::Pub)> {
|
||||||
let is_ascending = match target_hm.partial_cmp(&(h + m)).unwrap() {
|
let is_ascending = match target_hm.partial_cmp(&(h + m)).unwrap() {
|
||||||
Ordering::Greater => true,
|
Ordering::Greater => true,
|
||||||
Ordering::Less => false,
|
Ordering::Less => false,
|
||||||
@@ -153,7 +153,7 @@ impl MHCurve {
|
|||||||
Err(active_segment.clamp_by_x(new_h).into())
|
Err(active_segment.clamp_by_x(new_h).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn move_to(&self, mut h: f64, mut m: f64, target_hm: f64) -> (f64, f64) {
|
fn move_to(&self, mut h: flt::Pub, mut m: flt::Pub, target_hm: flt::Pub) -> (flt::Pub, flt::Pub) {
|
||||||
loop {
|
loop {
|
||||||
match self.step_toward(h, m, target_hm) {
|
match self.step_toward(h, m, target_hm) {
|
||||||
Ok((x, y)) => break (x, y),
|
Ok((x, y)) => break (x, y),
|
||||||
@@ -169,7 +169,8 @@ impl MHCurve {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PiecewiseLinearFerromagnet {
|
pub struct PiecewiseLinearFerromagnet {
|
||||||
/// Instantaneous magnetization in the z direction.
|
/// Instantaneous magnetization in the z direction.
|
||||||
pub mz: f64,
|
pub mz: flt::Pub,
|
||||||
|
pub conductivity: flt::Pub,
|
||||||
mh_curve: MHCurve,
|
mh_curve: MHCurve,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,23 +178,27 @@ impl PiecewiseLinearFerromagnet {
|
|||||||
/// Construct a B(H) curve from a sweep from H = 0 to Hs and back down to H = 0.
|
/// Construct a B(H) curve from a sweep from H = 0 to Hs and back down to H = 0.
|
||||||
/// The curve below B = 0 is derived by symmetry.
|
/// The curve below B = 0 is derived by symmetry.
|
||||||
/// Points are (H, B).
|
/// Points are (H, B).
|
||||||
pub fn from_bh(points: &[(f64, f64)]) -> Self {
|
pub fn from_bh(points: &[(flt::Pub, flt::Pub)]) -> Self {
|
||||||
let mh_points: Vec<Point> = points.iter().cloned().map(|(h, b)| {
|
let mh_points: Vec<Point> = points.iter().cloned().map(|(h, b)| {
|
||||||
Point::new(h, b / consts::MU0 - h)
|
Point::new(h, b / consts::MU0 - h)
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
mz: 0.0,
|
mz: 0.0,
|
||||||
|
conductivity: 0.0,
|
||||||
mh_curve: MHCurve::new(&*mh_points),
|
mh_curve: MHCurve::new(&*mh_points),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Material for PiecewiseLinearFerromagnet {
|
impl Material for PiecewiseLinearFerromagnet {
|
||||||
fn mz(&self) -> f64 {
|
fn mz(&self) -> flt::Pub {
|
||||||
self.mz
|
self.mz
|
||||||
}
|
}
|
||||||
fn step_h(&mut self, context: &CellState, delta_bz: f64) -> f64 {
|
fn conductivity(&self) -> flt::Pub {
|
||||||
|
self.conductivity
|
||||||
|
}
|
||||||
|
fn step_h(&mut self, context: &CellState, delta_bz: flt::Pub) -> flt::Pub {
|
||||||
let (h, m) = (context.hz(), self.mz);
|
let (h, m) = (context.hz(), self.mz);
|
||||||
let target_hm = h + m + delta_bz/consts::MU0;
|
let target_hm = h + m + delta_bz/consts::MU0;
|
||||||
|
|
||||||
@@ -223,7 +228,7 @@ pub mod db {
|
|||||||
use super::*;
|
use super::*;
|
||||||
/// https://www.ferroxcube.com/upload/media/product/file/MDS/3r1.pdf
|
/// https://www.ferroxcube.com/upload/media/product/file/MDS/3r1.pdf
|
||||||
pub fn ferroxcube_3r1() -> GenericMaterial {
|
pub fn ferroxcube_3r1() -> GenericMaterial {
|
||||||
PiecewiseLinearFerromagnet::from_bh(&[
|
let mut m = PiecewiseLinearFerromagnet::from_bh(&[
|
||||||
( 35.0, 0.0),
|
( 35.0, 0.0),
|
||||||
( 50.0, 0.250),
|
( 50.0, 0.250),
|
||||||
( 100.0, 0.325),
|
( 100.0, 0.325),
|
||||||
@@ -234,7 +239,9 @@ pub mod db {
|
|||||||
( 100.0, 0.345),
|
( 100.0, 0.345),
|
||||||
( 50.0, 0.340),
|
( 50.0, 0.340),
|
||||||
( 0.0, 0.325),
|
( 0.0, 0.325),
|
||||||
]).into()
|
]);
|
||||||
|
m.conductivity = 1e3;
|
||||||
|
m.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +265,7 @@ mod test {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_step_toward_symmetric(h: f64, m: f64, target_mh: f64, target: Result<(f64, f64), (f64, f64)>) {
|
fn assert_step_toward_symmetric(h: flt::Pub, m: flt::Pub, target_mh: flt::Pub, target: Result<(flt::Pub, flt::Pub), (flt::Pub, flt::Pub)>) {
|
||||||
let curve = mh_curve_for_test();
|
let curve = mh_curve_for_test();
|
||||||
let neg_target = match target {
|
let neg_target = match target {
|
||||||
Ok((a, b)) => Ok((-a, -b)),
|
Ok((a, b)) => Ok((-a, -b)),
|
||||||
@@ -268,7 +275,7 @@ mod test {
|
|||||||
assert_eq!(curve.step_toward(-h, -m, -target_mh), neg_target);
|
assert_eq!(curve.step_toward(-h, -m, -target_mh), neg_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_move_to_symmetric(h: f64, m: f64, target_mh: f64, target: (f64, f64)) {
|
fn assert_move_to_symmetric(h: flt::Pub, m: flt::Pub, target_mh: flt::Pub, target: (flt::Pub, flt::Pub)) {
|
||||||
let curve = mh_curve_for_test();
|
let curve = mh_curve_for_test();
|
||||||
assert_eq!(curve.move_to(h, m, target_mh), target);
|
assert_eq!(curve.move_to(h, m, target_mh), target);
|
||||||
assert_eq!(curve.move_to(-h, -m, -target_mh), (-target.0, -target.1));
|
assert_eq!(curve.move_to(-h, -m, -target_mh), (-target.0, -target.1));
|
||||||
|
24
src/meas.rs
24
src/meas.rs
@@ -9,7 +9,29 @@ pub struct Time;
|
|||||||
|
|
||||||
impl AbstractMeasurement for Time {
|
impl AbstractMeasurement for Time {
|
||||||
fn eval(&self, state: &SimSnapshot) -> String {
|
fn eval(&self, state: &SimSnapshot) -> String {
|
||||||
format!("time: {:.3e} (step {})", state.time(), state.step_no())
|
format!("{:.3e}s (step {})", state.time(), state.step_no())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Meta;
|
||||||
|
|
||||||
|
impl AbstractMeasurement for Meta {
|
||||||
|
fn eval(&self, state: &SimSnapshot) -> String {
|
||||||
|
format!("{}x{} feat: {:.1e}m", state.width(), state.height(), state.feature_size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Label(pub String);
|
||||||
|
|
||||||
|
impl Label {
|
||||||
|
pub fn new<S: Into<String>>(s: S) -> Self {
|
||||||
|
Self(s.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractMeasurement for Label {
|
||||||
|
fn eval(&self, _state: &SimSnapshot) -> String {
|
||||||
|
self.0.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
use ansi_term::Color::RGB;
|
use ansi_term::Color::RGB;
|
||||||
use crate::geom::Point;
|
use crate::geom::Point;
|
||||||
use crate::{F64, Material as _, SimSnapshot, SimState};
|
use crate::{flt, Material as _, SimSnapshot, SimState};
|
||||||
use crate::mat;
|
use crate::mat;
|
||||||
use crate::sim::Cell;
|
use crate::sim::Cell;
|
||||||
use crate::meas::AbstractMeasurement;
|
use crate::meas::AbstractMeasurement;
|
||||||
use font8x8::{BASIC_FONTS, UnicodeFonts as _};
|
use font8x8::{BASIC_FONTS, GREEK_FONTS, UnicodeFonts as _};
|
||||||
use image::{RgbImage, Rgb};
|
use image::{RgbImage, Rgb};
|
||||||
use imageproc::{pixelops, drawing};
|
use imageproc::{pixelops, drawing};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -14,7 +14,7 @@ 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).
|
||||||
/// If the input is equal to `typical`, it will be mapped to 0.5.
|
/// If the input is equal to `typical`, it will be mapped to 0.5.
|
||||||
/// If the input is equal to -`typical`, it will be mapped to -0.5.
|
/// If the input is equal to -`typical`, it will be mapped to -0.5.
|
||||||
fn scale_signed(x: f64, typical: f64) -> f64 {
|
fn scale_signed(x: flt::Pub, typical: flt::Pub) -> flt::Pub {
|
||||||
if x >= 0.0 {
|
if x >= 0.0 {
|
||||||
scale_unsigned(x, typical)
|
scale_unsigned(x, typical)
|
||||||
} else {
|
} else {
|
||||||
@@ -24,29 +24,29 @@ fn scale_signed(x: f64, typical: f64) -> f64 {
|
|||||||
|
|
||||||
/// Accept a value from [0, \inf) and return a value in [0, 1).
|
/// Accept a value from [0, \inf) and return a value in [0, 1).
|
||||||
/// If the input is equal to `typical`, it will be mapped to 0.5.
|
/// If the input is equal to `typical`, it will be mapped to 0.5.
|
||||||
fn scale_unsigned(x: f64, typical: f64) -> f64 {
|
fn scale_unsigned(x: flt::Pub, typical: flt::Pub) -> flt::Pub {
|
||||||
// f(0) => 0
|
// f(0) => 0
|
||||||
// f(1) => 0.5
|
// f(1) => 0.5
|
||||||
// f(\inf) => 1
|
// f(\inf) => 1
|
||||||
// f(x) = 1 - 1/(x+1)
|
// f(x) = 1 - 1/(x+1)
|
||||||
let x = F64::from_inner(x);
|
let x = flt::Priv::from_inner(x);
|
||||||
let typ = F64::from_inner(typical);
|
let typ = flt::Priv::from_inner(typical);
|
||||||
let y = F64::from_inner(1.0) - F64::from_inner(1.0)/(x/typ + 1.0);
|
let y = flt::Priv::from_inner(1.0) - flt::Priv::from_inner(1.0)/(x/typ + 1.0);
|
||||||
y.into()
|
y.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale_signed_to_u8(x: f64, typ: f64) -> u8 {
|
fn scale_signed_to_u8(x: flt::Pub, typ: flt::Pub) -> u8 {
|
||||||
let norm = 128.0 + 128.0*scale_signed(x, typ);
|
let norm = 128.0 + 128.0*scale_signed(x, typ);
|
||||||
norm as _
|
norm as _
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale_unsigned_to_u8(x: f64, typ: f64) -> u8 {
|
fn scale_unsigned_to_u8(x: flt::Pub, typ: flt::Pub) -> u8 {
|
||||||
let norm = 256.0*scale_unsigned(x, typ);
|
let norm = 256.0*scale_unsigned(x, typ);
|
||||||
norm as _
|
norm as _
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scale a vector to have magnitude between [0, 1).
|
/// Scale a vector to have magnitude between [0, 1).
|
||||||
fn scale_vector(x: Point, typical_mag: f64) -> Point {
|
fn scale_vector(x: Point, typical_mag: flt::Pub) -> Point {
|
||||||
let new_mag = scale_unsigned(x.mag(), typical_mag);
|
let new_mag = scale_unsigned(x.mag(), typical_mag);
|
||||||
x.with_mag(new_mag)
|
x.with_mag(new_mag)
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ impl<'a> RenderSteps<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn render_vector_field<F: Fn(&Cell<mat::Static>) -> Point>(&mut self, color: Rgb<u8>, typical: f64, measure: F) {
|
fn render_vector_field<F: Fn(&Cell<mat::Static>) -> Point>(&mut self, color: Rgb<u8>, typical: flt::Pub, measure: F) {
|
||||||
let w = self.sim.width();
|
let w = self.sim.width();
|
||||||
let h = self.sim.height();
|
let h = self.sim.height();
|
||||||
let vec_spacing = 10;
|
let vec_spacing = 10;
|
||||||
@@ -98,7 +98,7 @@ impl<'a> RenderSteps<'a> {
|
|||||||
let vec = self.field_vector(x, y, vec_spacing, &measure);
|
let vec = self.field_vector(x, y, vec_spacing, &measure);
|
||||||
let norm_vec = scale_vector(vec, typical);
|
let norm_vec = scale_vector(vec, typical);
|
||||||
let alpha = 0.7*scale_unsigned(vec.mag_sq(), typical * 5.0);
|
let alpha = 0.7*scale_unsigned(vec.mag_sq(), typical * 5.0);
|
||||||
let vec = norm_vec * (vec_spacing as f64);
|
let vec = norm_vec * (vec_spacing as flt::Pub);
|
||||||
let center = Point::new(x as _, y as _) + Point::new(vec_spacing as _, vec_spacing as _)*0.5;
|
let center = Point::new(x as _, y as _) + Point::new(vec_spacing as _, vec_spacing as _)*0.5;
|
||||||
self.im.draw_field_arrow(center, vec, color, alpha as f32);
|
self.im.draw_field_arrow(center, vec, color, alpha as f32);
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,9 @@ impl<'a> RenderSteps<'a> {
|
|||||||
for (meas_no, m) in self.meas.iter().enumerate() {
|
for (meas_no, m) in self.meas.iter().enumerate() {
|
||||||
let meas_string = m.eval(self.sim);
|
let meas_string = m.eval(self.sim);
|
||||||
for (i, c) in meas_string.chars().enumerate() {
|
for (i, c) in meas_string.chars().enumerate() {
|
||||||
let glyph = BASIC_FONTS.get(c).unwrap();
|
let glyph = BASIC_FONTS.get(c)
|
||||||
|
.or_else(|| GREEK_FONTS.get(c))
|
||||||
|
.unwrap_or_else(|| BASIC_FONTS.get('?').unwrap());
|
||||||
for (y, bmp) in glyph.iter().enumerate() {
|
for (y, bmp) in glyph.iter().enumerate() {
|
||||||
for x in 0..8 {
|
for x in 0..8 {
|
||||||
if (bmp & 1 << x) != 0 {
|
if (bmp & 1 << x) != 0 {
|
||||||
@@ -155,7 +157,7 @@ impl<'a> RenderSteps<'a> {
|
|||||||
// avoid division by zero
|
// avoid division by zero
|
||||||
Point::new(0.0, 0.0)
|
Point::new(0.0, 0.0)
|
||||||
} else {
|
} else {
|
||||||
field * (1.0 / ((xw*yw) as f64))
|
field * (1.0 / ((xw*yw) as flt::Pub))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
52
src/sim.rs
52
src/sim.rs
@@ -1,4 +1,4 @@
|
|||||||
use crate::{F64, consts};
|
use crate::{flt, consts};
|
||||||
use crate::geom::Point;
|
use crate::geom::Point;
|
||||||
use crate::mat::{self, GenericMaterial, Material};
|
use crate::mat::{self, GenericMaterial, Material};
|
||||||
|
|
||||||
@@ -12,12 +12,12 @@ pub type SimSnapshot = SimState<mat::Static>;
|
|||||||
pub struct SimState<M=GenericMaterial> {
|
pub struct SimState<M=GenericMaterial> {
|
||||||
cells: Array2<Cell<M>>,
|
cells: Array2<Cell<M>>,
|
||||||
scratch: Array2<Cell<M>>,
|
scratch: Array2<Cell<M>>,
|
||||||
feature_size: F64,
|
feature_size: flt::Priv,
|
||||||
step_no: u64,
|
step_no: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Material + Default> SimState<M> {
|
impl<M: Material + Default> SimState<M> {
|
||||||
pub fn new(width: u32, height: u32, feature_size: f64) -> Self {
|
pub fn new(width: u32, height: u32, feature_size: flt::Pub) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cells: Array2::default((height as _, width as _)),
|
cells: Array2::default((height as _, width as _)),
|
||||||
scratch: Array2::default((height as _, width as _)),
|
scratch: Array2::default((height as _, width as _)),
|
||||||
@@ -64,7 +64,7 @@ impl<M: Material + Default + Send + Sync> SimState<M> {
|
|||||||
pub fn snapshot(&self, dec: u32) -> SimSnapshot {
|
pub fn snapshot(&self, dec: u32) -> SimSnapshot {
|
||||||
let rows = self.height() / dec;
|
let rows = self.height() / dec;
|
||||||
let cols = self.width() / dec;
|
let cols = self.width() / dec;
|
||||||
let sample_area = (dec * dec) as f64;
|
let sample_area = (dec * dec) as flt::Pub;
|
||||||
|
|
||||||
// XXX Zip::par_apply_collect requires the Cell type to be Copy,
|
// XXX Zip::par_apply_collect requires the Cell type to be Copy,
|
||||||
// so we assign into a pre-allocated type instead.
|
// so we assign into a pre-allocated type instead.
|
||||||
@@ -102,28 +102,28 @@ impl<M: Material + Default + Send + Sync> SimState<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Material> SimState<M> {
|
impl<M: Material> SimState<M> {
|
||||||
pub fn impulse_bz(&mut self, x: u32, y: u32, bz: f64) {
|
pub fn impulse_bz(&mut self, x: u32, y: u32, bz: flt::Pub) {
|
||||||
self.get_mut(x, y).impulse_bz(bz);
|
self.get_mut(x, y).impulse_bz(bz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> SimState<M> {
|
impl<M> SimState<M> {
|
||||||
pub fn time(&self) -> f64 {
|
pub fn time(&self) -> flt::Pub {
|
||||||
(self.timestep() * self.step_no as f64).into()
|
(self.timestep() * self.step_no as flt::Pub).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_no(&self) -> u64 {
|
pub fn step_no(&self) -> u64 {
|
||||||
self.step_no
|
self.step_no
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn feature_size(&self) -> f64 {
|
pub fn feature_size(&self) -> flt::Pub {
|
||||||
self.feature_size.into()
|
self.feature_size.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn impulse_ex(&mut self, x: u32, y: u32, ex: f64) {
|
pub fn impulse_ex(&mut self, x: u32, y: u32, ex: flt::Pub) {
|
||||||
self.get_mut(x, y).state.ex += ex;
|
self.get_mut(x, y).state.ex += ex;
|
||||||
}
|
}
|
||||||
pub fn impulse_ey(&mut self, x: u32, y: u32, ey: f64) {
|
pub fn impulse_ey(&mut self, x: u32, y: u32, ey: flt::Pub) {
|
||||||
self.get_mut(x, y).state.ey += ey;
|
self.get_mut(x, y).state.ey += ey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ impl<M> SimState<M> {
|
|||||||
&mut self.cells[[y as _, x as _]]
|
&mut self.cells[[y as _, x as _]]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timestep(&self) -> F64 {
|
fn timestep(&self) -> flt::Priv {
|
||||||
self.feature_size / consts::real::C()
|
self.feature_size / consts::real::C()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,16 +170,16 @@ pub struct Cell<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<M> Cell<M> {
|
impl<M> Cell<M> {
|
||||||
pub fn ex(&self) -> f64 {
|
pub fn ex(&self) -> flt::Pub {
|
||||||
self.state.ex()
|
self.state.ex()
|
||||||
}
|
}
|
||||||
pub fn ey(&self) -> f64 {
|
pub fn ey(&self) -> flt::Pub {
|
||||||
self.state.ey()
|
self.state.ey()
|
||||||
}
|
}
|
||||||
pub fn e(&self) -> Point {
|
pub fn e(&self) -> Point {
|
||||||
Point::new(self.ex(), self.ey())
|
Point::new(self.ex(), self.ey())
|
||||||
}
|
}
|
||||||
pub fn hz(&self) -> f64 {
|
pub fn hz(&self) -> flt::Pub {
|
||||||
self.state.hz()
|
self.state.hz()
|
||||||
}
|
}
|
||||||
pub fn mat(&self) -> &M {
|
pub fn mat(&self) -> &M {
|
||||||
@@ -191,7 +191,7 @@ impl<M> Cell<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Material> Cell<M> {
|
impl<M: Material> Cell<M> {
|
||||||
pub fn bz(&self) -> f64 {
|
pub fn bz(&self) -> flt::Pub {
|
||||||
consts::MU0 * (self.hz() + self.mat.mz())
|
consts::MU0 * (self.hz() + self.mat.mz())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,16 +200,16 @@ impl<M: Material> Cell<M> {
|
|||||||
Point::new(self.ex()*conductivity, self.ey()*conductivity)
|
Point::new(self.ex()*conductivity, self.ey()*conductivity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bz_to_hz(&self, bz: f64) -> f64 {
|
fn bz_to_hz(&self, bz: flt::Pub) -> flt::Pub {
|
||||||
// B = mu0*(H + M) => H = B/mu0 - M
|
// B = mu0*(H + M) => H = B/mu0 - M
|
||||||
bz/consts::MU0 - self.mat.mz()
|
bz/consts::MU0 - self.mat.mz()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impulse_bz(&mut self, delta_bz: f64) {
|
fn impulse_bz(&mut self, delta_bz: flt::Pub) {
|
||||||
self.state.hz = self.mat.step_h(&self.state, delta_bz).into();
|
self.state.hz = self.mat.step_h(&self.state, delta_bz).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step_h(mut self, right: &Self, down: &Self, _delta_t: F64) -> Self {
|
fn step_h(mut self, right: &Self, down: &Self, _delta_t: flt::Priv) -> Self {
|
||||||
// ```tex
|
// ```tex
|
||||||
// Maxwell-Faraday equation: $\nabla x E = -dB/dt$
|
// Maxwell-Faraday equation: $\nabla x E = -dB/dt$
|
||||||
// Expand: $dE_y/dx - dE_x/dy = -dB_z/dt$
|
// Expand: $dE_y/dx - dE_x/dy = -dB_z/dt$
|
||||||
@@ -235,7 +235,7 @@ impl<M: Material> Cell<M> {
|
|||||||
|
|
||||||
/// delta_t = timestep covered by this function. i.e. it should be half the timestep of the simulation
|
/// delta_t = timestep covered by this function. i.e. it should be half the timestep of the simulation
|
||||||
/// feature_size = how many units apart is the center of each adjacent cell on the grid.
|
/// feature_size = how many units apart is the center of each adjacent cell on the grid.
|
||||||
fn step_e(self, left: &Self, up: &Self, delta_t: F64, feature_size: F64) -> Self {
|
fn step_e(self, left: &Self, up: &Self, delta_t: flt::Priv, feature_size: flt::Priv) -> Self {
|
||||||
// ```tex
|
// ```tex
|
||||||
// Ampere's circuital law with Maxwell's addition, in SI units ("macroscopic version"):
|
// Ampere's circuital law with Maxwell's addition, in SI units ("macroscopic version"):
|
||||||
// $\nabla x H = J_f + dD/dt$ where $J_f$ = current density = $\sigma E$, $\sigma$ being a material parameter ("conductivity")
|
// $\nabla x H = J_f + dD/dt$ where $J_f$ = current density = $\sigma E$, $\sigma$ being a material parameter ("conductivity")
|
||||||
@@ -262,7 +262,7 @@ impl<M: Material> Cell<M> {
|
|||||||
|
|
||||||
use consts::real::{EPS0, ONE, TWO};
|
use consts::real::{EPS0, ONE, TWO};
|
||||||
|
|
||||||
let sigma: F64 = self.mat.conductivity().into();
|
let sigma: flt::Priv = self.mat.conductivity().into();
|
||||||
|
|
||||||
// XXX not obvious that bz_to_hz is sensible
|
// XXX not obvious that bz_to_hz is sensible
|
||||||
// let delta_hz_y = self.hz() - self.bz_to_hz(up.bz());
|
// let delta_hz_y = self.hz() - self.bz_to_hz(up.bz());
|
||||||
@@ -288,19 +288,19 @@ impl<M: Material> Cell<M> {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
#[derive(Copy, Clone, Default)]
|
||||||
pub struct CellState {
|
pub struct CellState {
|
||||||
ex: F64,
|
ex: flt::Priv,
|
||||||
ey: F64,
|
ey: flt::Priv,
|
||||||
hz: F64,
|
hz: flt::Priv,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellState {
|
impl CellState {
|
||||||
pub fn ex(&self) -> f64 {
|
pub fn ex(&self) -> flt::Pub {
|
||||||
self.ex.into()
|
self.ex.into()
|
||||||
}
|
}
|
||||||
pub fn ey(&self) -> f64 {
|
pub fn ey(&self) -> flt::Pub {
|
||||||
self.ey.into()
|
self.ey.into()
|
||||||
}
|
}
|
||||||
pub fn hz(&self) -> f64 {
|
pub fn hz(&self) -> flt::Pub {
|
||||||
self.hz.into()
|
self.hz.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user