Allow conductivity to be specified as a vector

This is necessary to implement UPML boundary conditions
This commit is contained in:
2020-09-19 19:33:11 -07:00
parent a7899d9be1
commit ae93101676
6 changed files with 68 additions and 27 deletions

View File

@@ -3,20 +3,29 @@ use coremem::geom::Point;
fn main() { fn main() {
coremem::init_logging(); coremem::init_logging();
let width = 700; let feat_size = 20e-6; // feature size
let buffer = 80; let from_m = |m| (m/feat_size) as u32;
let feat_size = 1e-5; // feature size let to_um = |px| px * (feat_size*1e6) as u32;
let width = from_m(8000e-6);
let conductor_inner_rad = from_m(0e-6);
let conductor_outer_rad = from_m(200e-6);
let ferro_inner_rad = from_m(200e-6);
let ferro_outer_rad = from_m(300e-6);
let buffer = from_m(800e-6);
let peak_current = 2.5e6; let peak_current = 2.5e6;
let conductivity = 1.0e5; let conductivity = 1.0e5;
let ferro_inner_rad = 60;
let ferro_outer_rad = 150;
let conductor_inner_rad = 0;
let conductor_outer_rad = 50;
let half_width = width / 2; let half_width = width / 2;
let mut driver = Driver::new(width, width, feat_size); let mut driver = Driver::new(width, width, feat_size);
driver.set_steps_per_frame(8); //driver.set_steps_per_frame(8);
//driver.set_steps_per_frame(40); //driver.set_steps_per_frame(40);
driver.add_y4m_renderer("toroid25d.y4m"); driver.set_steps_per_frame(200);
driver.add_y4m_renderer(&*format!("-toroid25d-feat{}um-{}A--radii{}um-{}um-{}um.y4m",
(feat_size * 1e6) as u32,
peak_current as u32,
to_um(conductor_outer_rad),
to_um(ferro_inner_rad),
to_um(ferro_outer_rad),
));
// driver.add_term_renderer(); // driver.add_term_renderer();
driver.add_measurement(meas::Label(format!("Conductivity: {}, Imax: {:.2e}", conductivity, peak_current))); driver.add_measurement(meas::Label(format!("Conductivity: {}, Imax: {:.2e}", conductivity, peak_current)));
driver.add_measurement(meas::Current(half_width + (conductor_inner_rad + conductor_outer_rad) / 2, half_width)); driver.add_measurement(meas::Current(half_width + (conductor_inner_rad + conductor_outer_rad) / 2, half_width));

View File

@@ -12,6 +12,7 @@ pub struct Driver {
renderer: MultiRenderer, renderer: MultiRenderer,
steps_per_frame: u64, steps_per_frame: u64,
time_spent_stepping: Duration, time_spent_stepping: Duration,
time_spent_rendering: Duration,
measurements: Vec<Box<dyn AbstractMeasurement>>, measurements: Vec<Box<dyn AbstractMeasurement>>,
start_time: SystemTime, start_time: SystemTime,
} }
@@ -23,6 +24,7 @@ impl Driver {
renderer: Default::default(), renderer: Default::default(),
steps_per_frame: 1, steps_per_frame: 1,
time_spent_stepping: Default::default(), time_spent_stepping: 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)],
start_time: SystemTime::now(), start_time: SystemTime::now(),
} }
@@ -71,22 +73,34 @@ impl Driver {
} }
pub fn step(&mut self) { pub fn step(&mut self) {
let start_time = SystemTime::now();
if self.state.step_no() % self.steps_per_frame == 0 { if self.state.step_no() % self.steps_per_frame == 0 {
trace!("render begin"); trace!("render begin");
let start_time = SystemTime::now();
self.renderer.render(&self.state, &*self.measurements); self.renderer.render(&self.state, &*self.measurements);
self.time_spent_rendering += start_time.elapsed().unwrap();
trace!("render end"); trace!("render end");
} }
trace!("step begin"); trace!("step begin");
let start_time = SystemTime::now();
self.state.step(); self.state.step();
trace!("step end");
self.time_spent_stepping += start_time.elapsed().unwrap(); self.time_spent_stepping += start_time.elapsed().unwrap();
trace!("step end");
let step = self.state.step_no(); let step = self.state.step_no();
if step % (10*self.steps_per_frame) == 0 { if step % (10*self.steps_per_frame) == 0 {
let driver_time = self.time_spent_stepping.as_secs_f64() as Flt; let driver_time = self.time_spent_stepping.as_secs_f64() as Flt;
let render_time = self.time_spent_rendering.as_secs_f64() as Flt;
let overall_time = self.start_time.elapsed().unwrap().as_secs_f64() as Flt; let overall_time = self.start_time.elapsed().unwrap().as_secs_f64() as Flt;
let fps = (self.state.step_no() as Flt) / overall_time; let fps = (self.state.step_no() as Flt) / overall_time;
info!("frame {:6}/fps: {:6.2} (driver: {:.1}s, rest: {:.1}s)", step, fps, driver_time, overall_time - driver_time); let sim_time = self.state.time();
info!(
"t={:.2e} frame {:06} fps: {:6.2} (sim: {:.1}s, render: {:.1}s, other: {:.1}s)",
sim_time,
step,
fps,
driver_time,
render_time,
overall_time - driver_time - render_time
);
} }
} }
} }

View File

@@ -10,8 +10,8 @@ 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) -> Flt { fn conductivity(&self) -> Vec3 {
0.0 Default::default()
} }
/// Return the magnetization. /// Return the magnetization.
fn m(&self) -> Vec3 { fn m(&self) -> Vec3 {
@@ -26,21 +26,21 @@ pub trait Material {
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct Static { pub struct Static {
pub conductivity: Flt, pub conductivity: Vec3,
pub m: Vec3, pub m: Vec3,
} }
impl Static { impl Static {
pub fn conductor(conductivity: Flt) -> Self { pub fn conductor(conductivity: Flt) -> Self {
Self { Self {
conductivity, conductivity: Vec3::unit() * conductivity,
..Default::default() ..Default::default()
} }
} }
} }
impl Material for Static { impl Material for Static {
fn conductivity(&self) -> Flt { fn conductivity(&self) -> Vec3 {
self.conductivity self.conductivity
} }
fn m(&self) -> Vec3 { fn m(&self) -> Vec3 {
@@ -140,7 +140,7 @@ impl MHCurve {
pub struct PiecewiseLinearFerromagnet { pub struct PiecewiseLinearFerromagnet {
/// Instantaneous magnetization in the z direction. /// Instantaneous magnetization in the z direction.
pub m: Vec3, pub m: Vec3,
pub conductivity: Flt, pub conductivity: Vec3,
mh_curve_x: MHCurve, mh_curve_x: MHCurve,
mh_curve_y: MHCurve, mh_curve_y: MHCurve,
mh_curve_z: MHCurve, mh_curve_z: MHCurve,
@@ -157,7 +157,7 @@ impl PiecewiseLinearFerromagnet {
Self { Self {
m: Vec3::default(), m: Vec3::default(),
conductivity: 0.0, conductivity: Default::default(),
mh_curve_x: MHCurve::new(&*mh_points), mh_curve_x: MHCurve::new(&*mh_points),
mh_curve_y: MHCurve::new(&*mh_points), mh_curve_y: MHCurve::new(&*mh_points),
mh_curve_z: MHCurve::new(&*mh_points), mh_curve_z: MHCurve::new(&*mh_points),
@@ -169,7 +169,7 @@ impl Material for PiecewiseLinearFerromagnet {
fn m(&self) -> Vec3 { fn m(&self) -> Vec3 {
self.m self.m
} }
fn conductivity(&self) -> Flt { fn conductivity(&self) -> Vec3 {
self.conductivity self.conductivity
} }
fn step_h(&mut self, context: &CellState, delta_b: Vec3) -> Vec3 { fn step_h(&mut self, context: &CellState, delta_b: Vec3) -> Vec3 {
@@ -223,7 +223,7 @@ pub mod db {
( 50.0, 0.340), ( 50.0, 0.340),
( 0.0, 0.325), ( 0.0, 0.325),
]); ]);
m.conductivity = 1e3; m.conductivity = Vec3::unit() * 1e3; // XXX colin: should be 1e-3!!?
m m
} }
} }

View File

@@ -61,7 +61,7 @@ struct RenderSteps<'a> {
impl<'a> RenderSteps<'a> { impl<'a> RenderSteps<'a> {
fn render(state: &'a SimSnapshot, measurements: &'a [Box<dyn AbstractMeasurement>]) -> RgbImage { fn render(state: &'a SimSnapshot, measurements: &'a [Box<dyn AbstractMeasurement>]) -> RgbImage {
let mut me = Self::new(state, measurements); let mut me = Self::new(state, measurements);
me.render_scalar_field(10.0, false, 2, |cell| cell.mat().conductivity()); me.render_scalar_field(10.0, false, 2, |cell| cell.mat().conductivity().mag());
me.render_scalar_field(100.0, true, 0, |cell| cell.mat().m().mag()); me.render_scalar_field(100.0, true, 0, |cell| cell.mat().m().mag());
if false { if false {
me.render_b_z_field(); me.render_b_z_field();
@@ -91,7 +91,7 @@ impl<'a> RenderSteps<'a> {
self.render_vector_field(Rgb([0xff, 0xff, 0xff]), 100.0, |cell| cell.e().xy()); self.render_vector_field(Rgb([0xff, 0xff, 0xff]), 100.0, |cell| cell.e().xy());
// current // current
self.render_vector_field(Rgb([0x00, 0xa0, 0x30]), 1.0e-12, |cell| { self.render_vector_field(Rgb([0x00, 0xa0, 0x30]), 1.0e-12, |cell| {
cell.e().xy()*cell.mat().conductivity() cell.e().elem_mul(cell.mat().conductivity()).xy()
}); });
} }

View File

@@ -219,7 +219,7 @@ impl<M: Material> Cell<M> {
pub fn current(&self) -> Vec3 { pub fn current(&self) -> Vec3 {
let conductivity = self.mat.conductivity(); let conductivity = self.mat.conductivity();
self.e()*conductivity self.e().elem_mul(conductivity)
} }
fn impulse_bz(&mut self, delta_bz: Flt) { fn impulse_bz(&mut self, delta_bz: Flt) {
@@ -288,7 +288,7 @@ impl<M: Material> Cell<M> {
use consts::real::{EPS0, ONE, TWO}; use consts::real::{EPS0, ONE, TWO};
let sigma: Real = self.mat.conductivity().into(); let sigma: Vec3 = self.mat.conductivity();
let inv_feature_size = Real::from_inner(1.0) / feature_size; let inv_feature_size = Real::from_inner(1.0) / feature_size;
let delta_hz_y = inv_feature_size * (self.hz() - up.hz()); let delta_hz_y = inv_feature_size * (self.hz() - up.hz());
@@ -300,8 +300,8 @@ impl<M: Material> Cell<M> {
let nabla_h = Vec3::from((delta_hz_y - delta_hy_z, delta_hx_z - delta_hz_x, delta_hy_x - delta_hx_y)); let nabla_h = Vec3::from((delta_hz_y - delta_hy_z, delta_hx_z - delta_hz_x, delta_hy_x - delta_hx_y));
let delta_t_eps = delta_t/EPS0(); let delta_t_eps = delta_t/EPS0();
let rhs = self.state.e() * (ONE() - sigma*delta_t_eps) + nabla_h * (TWO()*delta_t_eps); let rhs = self.state.e().elem_mul(Vec3::unit() - sigma*delta_t_eps) + nabla_h * (TWO()*delta_t_eps);
let e_next = rhs / (ONE() + sigma*delta_t_eps); let e_next = rhs.elem_div(Vec3::unit() + sigma*delta_t_eps);
Cell { Cell {

View File

@@ -40,6 +40,24 @@ impl Vec3 {
let Vec3 { x, y, z } = *self; let Vec3 { x, y, z } = *self;
(x*x + y*y + z*z).into_inner().sqrt() (x*x + y*y + z*z).into_inner().sqrt()
} }
/// Perform element-wise multiplication with `other`.
pub fn elem_mul(&self, other: Self) -> Self {
Self {
x: self.x * other.x,
y: self.y * other.y,
z: self.z * other.z,
}
}
/// Perform element-wise division with `other`.
pub fn elem_div(&self, other: Self) -> Self {
Self {
x: self.x / other.x,
y: self.y / other.y,
z: self.z / other.z,
}
}
} }
impl From<(Real, Real, Real)> for Vec3 { impl From<(Real, Real, Real)> for Vec3 {