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() {
coremem::init_logging();
let width = 700;
let buffer = 80;
let feat_size = 1e-5; // feature size
let feat_size = 20e-6; // feature size
let from_m = |m| (m/feat_size) as u32;
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 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 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.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_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));

View File

@@ -12,6 +12,7 @@ pub struct Driver {
renderer: MultiRenderer,
steps_per_frame: u64,
time_spent_stepping: Duration,
time_spent_rendering: Duration,
measurements: Vec<Box<dyn AbstractMeasurement>>,
start_time: SystemTime,
}
@@ -23,6 +24,7 @@ impl Driver {
renderer: Default::default(),
steps_per_frame: 1,
time_spent_stepping: Default::default(),
time_spent_rendering: Default::default(),
measurements: vec![Box::new(meas::Time), Box::new(meas::Meta), Box::new(meas::Energy)],
start_time: SystemTime::now(),
}
@@ -71,22 +73,34 @@ impl Driver {
}
pub fn step(&mut self) {
let start_time = SystemTime::now();
if self.state.step_no() % self.steps_per_frame == 0 {
trace!("render begin");
let start_time = SystemTime::now();
self.renderer.render(&self.state, &*self.measurements);
self.time_spent_rendering += start_time.elapsed().unwrap();
trace!("render end");
}
trace!("step begin");
let start_time = SystemTime::now();
self.state.step();
trace!("step end");
self.time_spent_stepping += start_time.elapsed().unwrap();
trace!("step end");
let step = self.state.step_no();
if step % (10*self.steps_per_frame) == 0 {
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 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 {
/// Return \sigma, the electrical conductivity.
/// For a vacuum, this is zero. For a perfect conductor, \inf.
fn conductivity(&self) -> Flt {
0.0
fn conductivity(&self) -> Vec3 {
Default::default()
}
/// Return the magnetization.
fn m(&self) -> Vec3 {
@@ -26,21 +26,21 @@ pub trait Material {
#[derive(Clone, Default)]
pub struct Static {
pub conductivity: Flt,
pub conductivity: Vec3,
pub m: Vec3,
}
impl Static {
pub fn conductor(conductivity: Flt) -> Self {
Self {
conductivity,
conductivity: Vec3::unit() * conductivity,
..Default::default()
}
}
}
impl Material for Static {
fn conductivity(&self) -> Flt {
fn conductivity(&self) -> Vec3 {
self.conductivity
}
fn m(&self) -> Vec3 {
@@ -140,7 +140,7 @@ impl MHCurve {
pub struct PiecewiseLinearFerromagnet {
/// Instantaneous magnetization in the z direction.
pub m: Vec3,
pub conductivity: Flt,
pub conductivity: Vec3,
mh_curve_x: MHCurve,
mh_curve_y: MHCurve,
mh_curve_z: MHCurve,
@@ -157,7 +157,7 @@ impl PiecewiseLinearFerromagnet {
Self {
m: Vec3::default(),
conductivity: 0.0,
conductivity: Default::default(),
mh_curve_x: MHCurve::new(&*mh_points),
mh_curve_y: MHCurve::new(&*mh_points),
mh_curve_z: MHCurve::new(&*mh_points),
@@ -169,7 +169,7 @@ impl Material for PiecewiseLinearFerromagnet {
fn m(&self) -> Vec3 {
self.m
}
fn conductivity(&self) -> Flt {
fn conductivity(&self) -> Vec3 {
self.conductivity
}
fn step_h(&mut self, context: &CellState, delta_b: Vec3) -> Vec3 {
@@ -223,7 +223,7 @@ pub mod db {
( 50.0, 0.340),
( 0.0, 0.325),
]);
m.conductivity = 1e3;
m.conductivity = Vec3::unit() * 1e3; // XXX colin: should be 1e-3!!?
m
}
}

View File

@@ -61,7 +61,7 @@ struct RenderSteps<'a> {
impl<'a> RenderSteps<'a> {
fn render(state: &'a SimSnapshot, measurements: &'a [Box<dyn AbstractMeasurement>]) -> RgbImage {
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());
if false {
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());
// current
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 {
let conductivity = self.mat.conductivity();
self.e()*conductivity
self.e().elem_mul(conductivity)
}
fn impulse_bz(&mut self, delta_bz: Flt) {
@@ -288,7 +288,7 @@ impl<M: Material> Cell<M> {
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 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 delta_t_eps = delta_t/EPS0();
let rhs = self.state.e() * (ONE() - sigma*delta_t_eps) + nabla_h * (TWO()*delta_t_eps);
let e_next = rhs / (ONE() + sigma*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.elem_div(Vec3::unit() + sigma*delta_t_eps);
Cell {

View File

@@ -40,6 +40,24 @@ impl Vec3 {
let Vec3 { x, y, z } = *self;
(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 {