Abstract coordinates behind a Coord type

This will allow adding another dimension to the coordinate, more easily.
This commit is contained in:
2020-09-22 11:23:58 -07:00
parent b96f9c5dcc
commit 6d77c85179
7 changed files with 95 additions and 59 deletions

View File

@@ -1,4 +1,5 @@
use coremem::{consts, Driver, Flt, mat, meas}; use coremem::{consts, Driver, Flt, mat, meas};
use coremem::coord::Coord;
use coremem::geom::{Circle, Point}; use coremem::geom::{Circle, Point};
fn main() { fn main() {
@@ -33,26 +34,45 @@ fn main() {
driver.add_measurement(meas::Current(Circle::new(Point::new( driver.add_measurement(meas::Current(Circle::new(Point::new(
to_m(half_width), to_m(half_width)), to_m(half_width), to_m(half_width)),
to_m(conductor_outer_rad)))); to_m(conductor_outer_rad))));
driver.add_measurement(meas::Magnetization(half_width + ferro_inner_rad + 2, half_width)); driver.add_measurement(meas::Magnetization(
driver.add_measurement(meas::MagneticFlux(half_width + ferro_inner_rad + 2, half_width)); (half_width + ferro_inner_rad + 2, half_width).into()
driver.add_measurement(meas::MagneticStrength(half_width + ferro_inner_rad + 2, half_width)); ));
driver.add_measurement(meas::Magnetization(half_width + ferro_inner_rad + 1, half_width)); driver.add_measurement(meas::MagneticFlux(
driver.add_measurement(meas::MagneticFlux(half_width + ferro_inner_rad + 1, half_width)); (half_width + ferro_inner_rad + 2, half_width).into()
driver.add_measurement(meas::MagneticStrength(half_width + ferro_inner_rad + 1, half_width)); ));
driver.add_measurement(meas::Magnetization(half_width + (ferro_inner_rad + ferro_outer_rad) / 2, half_width)); driver.add_measurement(meas::MagneticStrength(
driver.add_measurement(meas::MagneticFlux(half_width + (ferro_inner_rad + ferro_outer_rad) / 2, half_width)); (half_width + ferro_inner_rad + 2, half_width).into()
driver.add_measurement(meas::MagneticStrength(half_width + (ferro_inner_rad + ferro_outer_rad) / 2, half_width)); ));
driver.add_measurement(meas::Magnetization(
(half_width + ferro_inner_rad + 1, half_width).into()
));
driver.add_measurement(meas::MagneticFlux(
(half_width + ferro_inner_rad + 1, half_width).into()
));
driver.add_measurement(meas::MagneticStrength(
(half_width + ferro_inner_rad + 1, half_width).into()
));
driver.add_measurement(meas::Magnetization(
(half_width + (ferro_inner_rad + ferro_outer_rad) / 2, half_width).into()
));
driver.add_measurement(meas::MagneticFlux(
(half_width + (ferro_inner_rad + ferro_outer_rad) / 2, half_width).into()
));
driver.add_measurement(meas::MagneticStrength(
(half_width + (ferro_inner_rad + ferro_outer_rad) / 2, half_width).into()
));
let center = Point::new(half_width as _, half_width as _); let center = Point::new(half_width as _, half_width as _);
for y in 0..width { for y in 0..width {
for x in 0..width { for x in 0..width {
let d = Point::new(x as _, y as _) - center; let loc = Coord::new(x, y);
let d = Point::from(loc) - center;
let r = d.mag(); let r = d.mag();
if (conductor_inner_rad as _..conductor_outer_rad as _).contains(&r) { if (conductor_inner_rad as _..conductor_outer_rad as _).contains(&r) {
*driver.state.get_mut(x, y).mat_mut() = mat::Static::conductor(conductivity).into(); *driver.state.get_mut(loc).mat_mut() = mat::Static::conductor(conductivity).into();
} else if (ferro_inner_rad as _..ferro_outer_rad as _).contains(&r) { } else if (ferro_inner_rad as _..ferro_outer_rad as _).contains(&r) {
*driver.state.get_mut(x, y).mat_mut() = mat::db::ferroxcube_3r1(); *driver.state.get_mut(loc).mat_mut() = mat::db::ferroxcube_3r1();
} }
} }
} }
@@ -75,9 +95,10 @@ fn main() {
let e = drive_current/conductivity/area; let e = drive_current/conductivity/area;
for y in half_width-conductor_outer_rad..half_width+conductor_outer_rad { for y in half_width-conductor_outer_rad..half_width+conductor_outer_rad {
for x in half_width-conductor_outer_rad..half_width+conductor_outer_rad { for x in half_width-conductor_outer_rad..half_width+conductor_outer_rad {
let d = Point::new(x as _, y as _) - center; let loc = Coord::new(x, y);
let d = Point::from(loc) - center;
if (conductor_inner_rad as _..conductor_outer_rad as _).contains(&d.mag()) { if (conductor_inner_rad as _..conductor_outer_rad as _).contains(&d.mag()) {
driver.state.impulse_ez(x, y, e); driver.state.impulse_ez(loc, e);
} }
} }
} }

View File

@@ -1,5 +1,6 @@
use crate::{flt::Flt, mat}; use crate::{flt::Flt, mat};
use crate::consts; use crate::consts;
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::SimState;
@@ -22,7 +23,7 @@ pub struct Driver {
impl Driver { impl Driver {
pub fn new(width: u32, height: u32, feature_size: Flt) -> Self { pub fn new(width: u32, height: u32, feature_size: Flt) -> Self {
Driver { Driver {
state: SimState::new(width, height, feature_size), state: SimState::new(Coord::new(width, height), feature_size),
renderer: Default::default(), renderer: Default::default(),
steps_per_frame: 1, steps_per_frame: 1,
time_spent_stepping: Default::default(), time_spent_stepping: Default::default(),
@@ -61,15 +62,15 @@ impl Driver {
let conductivity = base_conductivity * (depth*depth) as Flt; let conductivity = base_conductivity * (depth*depth) as Flt;
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).into()).mat_mut() = mat::Static::conductor(conductivity).into();
// right // right
*self.state.get_mut(x, self.state.height() - 1 - inset).mat_mut() = mat::Static::conductor(conductivity).into(); *self.state.get_mut((x, self.state.height() - 1 - inset).into()).mat_mut() = mat::Static::conductor(conductivity).into();
} }
for y in inset..self.state.height() - inset { for y in inset..self.state.height() - inset {
// top // top
*self.state.get_mut(inset, y).mat_mut() = mat::Static::conductor(conductivity).into(); *self.state.get_mut((inset, y).into()).mat_mut() = mat::Static::conductor(conductivity).into();
// bottom // bottom
*self.state.get_mut(self.state.width() - 1 - inset, y).mat_mut() = mat::Static::conductor(conductivity).into(); *self.state.get_mut((self.state.width() - 1 - inset, y).into()).mat_mut() = mat::Static::conductor(conductivity).into();
} }
} }
} }
@@ -100,7 +101,7 @@ impl Driver {
let cond_x = scale * (depth_x as Flt/thickness as Flt).powf(3.0); let cond_x = scale * (depth_x as Flt/thickness as Flt).powf(3.0);
let cond_y = scale * (depth_y as Flt/thickness as Flt).powf(3.0); let cond_y = scale * (depth_y as Flt/thickness as Flt).powf(3.0);
let conductor = mat::Static::anisotropic_conductor(Vec3::new(cond_x, cond_y, 0.0)); let conductor = mat::Static::anisotropic_conductor(Vec3::new(cond_x, cond_y, 0.0));
*self.state.get_mut(x, y).mat_mut() = conductor.into(); *self.state.get_mut((x, y).into()).mat_mut() = conductor.into();
} }
} }
} }

View File

@@ -1,4 +1,6 @@
use crate::coord::Coord;
use crate::flt::{Flt, Real}; use crate::flt::{Flt, Real};
use std::convert::From;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::ops::{Add, AddAssign, Mul, Neg, Sub}; use std::ops::{Add, AddAssign, Mul, Neg, Sub};
@@ -16,6 +18,12 @@ pub struct Point {
pub y: Real, pub y: Real,
} }
impl From<Coord> for Point {
fn from(c: Coord) -> Self {
Self::new(c.x() as _, c.y() as _)
}
}
impl Add for Point { impl Add for Point {
type Output = Point; type Output = Point;
fn add(self, other: Point) -> Point { fn add(self, other: Point) -> Point {

View File

@@ -7,6 +7,7 @@
use log::info; use log::info;
pub mod coord;
pub mod driver; pub mod driver;
pub mod geom; pub mod geom;
pub mod mat; pub mod mat;

View File

@@ -1,3 +1,4 @@
use crate::coord::Coord;
use crate::geom::{Point, Region}; use crate::geom::{Point, Region};
use crate::mat::Material as _; use crate::mat::Material as _;
use crate::sim::{Cell, SimSnapshot}; use crate::sim::{Cell, SimSnapshot};
@@ -38,9 +39,9 @@ impl AbstractMeasurement for Label {
} }
} }
fn sum_over_region<T: Default + Send + Sum<T>, R: Region + Sync, F: Fn(u32, u32, &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(|x, y, cell| if r.contains(Point::new(x as _, y as _)*state.feature_size()) { state.map_sum_enumerated(|coord, cell| if r.contains(Point::from(coord)*state.feature_size()) {
f(x, y, cell) f(coord, cell)
} else { } else {
Default::default() Default::default()
}) })
@@ -50,47 +51,47 @@ 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, |x, y, _cell| state.current(x, y)); 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())
} }
} }
/// M /// M
pub struct Magnetization(pub u32, pub u32); pub struct Magnetization(pub Coord);
impl AbstractMeasurement for Magnetization { impl AbstractMeasurement for Magnetization {
fn eval(&self, state: &SimSnapshot) -> String { fn eval(&self, state: &SimSnapshot) -> String {
let m = state.get(self.0, self.1).mat().m(); let m = state.get(self.0).mat().m();
format!("M({}, {}): ({:.2e}, {:.2e}, {:.2e})", self.0, self.1, m.x(), m.y(), m.z()) format!("M{}: ({:.2e}, {:.2e}, {:.2e})", self.0, m.x(), m.y(), m.z())
} }
} }
/// B /// B
pub struct MagneticFlux(pub u32, pub u32); pub struct MagneticFlux(pub Coord);
impl AbstractMeasurement for MagneticFlux { impl AbstractMeasurement for MagneticFlux {
fn eval(&self, state: &SimSnapshot) -> String { fn eval(&self, state: &SimSnapshot) -> String {
let b = state.get(self.0, self.1).b(); let b = state.get(self.0).b();
format!("B({}, {}): ({:.2e}, {:.2e}, {:.2e})", self.0, self.1, b.x(), b.y(), b.z()) format!("B{}: ({:.2e}, {:.2e}, {:.2e})", self.0, b.x(), b.y(), b.z())
} }
} }
/// H /// H
pub struct MagneticStrength(pub u32, pub u32); pub struct MagneticStrength(pub Coord);
impl AbstractMeasurement for MagneticStrength { impl AbstractMeasurement for MagneticStrength {
fn eval(&self, state: &SimSnapshot) -> String { fn eval(&self, state: &SimSnapshot) -> String {
let h = state.get(self.0, self.1).h(); let h = state.get(self.0).h();
format!("H({}, {}): ({:.2e}, {:.2e}, {:.2e})", self.0, self.1, h.x(), h.y(), h.z()) format!("H{}: ({:.2e}, {:.2e}, {:.2e})", self.0, h.x(), h.y(), h.z())
} }
} }
pub struct ElectricField(pub u32, pub u32); pub struct ElectricField(pub Coord);
impl AbstractMeasurement for ElectricField { impl AbstractMeasurement for ElectricField {
fn eval(&self, state: &SimSnapshot) -> String { fn eval(&self, state: &SimSnapshot) -> String {
let e = state.get(self.0, self.1).e(); let e = state.get(self.0).e();
format!("E({}, {}): ({:.2e}, {:.2e}, {:.2e})", self.0, self.1, e.x(), e.y(), e.z()) format!("E{}: ({:.2e}, {:.2e}, {:.2e})", self.0, e.x(), e.y(), e.z())
} }
} }

View File

@@ -125,7 +125,7 @@ impl<'a> RenderSteps<'a> {
let h = self.sim.height(); let h = self.sim.height();
for y in 0..h { for y in 0..h {
for x in 0..w { for x in 0..w {
let cell = self.sim.get(x, y); let cell = self.sim.get((x, y).into());
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)
@@ -170,7 +170,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.sim.get(x, y)); field += measure(self.sim.get((x, y).into()));
} }
} }
let xw = xend - xstart; let xw = xend - xstart;
@@ -217,12 +217,12 @@ impl Renderer for NumericTermRenderer {
fn render(&mut self, state: &SimSnapshot, _measurements: &[Box<dyn AbstractMeasurement>]) { fn render(&mut self, state: &SimSnapshot, _measurements: &[Box<dyn AbstractMeasurement>]) {
for y in 0..state.height() { for y in 0..state.height() {
for x in 0..state.width() { for x in 0..state.width() {
let cell = state.get(x, y); let cell = state.get((x, y).into());
print!(" {:>10.1e}", cell.ex()); print!(" {:>10.1e}", cell.ex());
} }
print!("\n"); print!("\n");
for x in 0..state.width() { for x in 0..state.width() {
let cell = state.get(x, y); let cell = state.get((x, y).into());
print!("{:>10.1e} {:>10.1e}", cell.ey(), cell.bz()); print!("{:>10.1e} {:>10.1e}", cell.ey(), cell.bz());
} }
print!("\n"); print!("\n");

View File

@@ -1,10 +1,12 @@
use crate::{flt::{Flt, Real}, consts}; use crate::{flt::{Flt, Real}, consts};
use crate::coord::Coord;
use crate::mat::{self, GenericMaterial, Material}; use crate::mat::{self, GenericMaterial, Material};
use crate::vec3::Vec3; use crate::vec3::Vec3;
use log::trace; use log::trace;
use ndarray::{Array2, Zip}; use ndarray::{Array2, Zip};
use ndarray::parallel::prelude::*; use ndarray::parallel::prelude::*;
use std::convert::From;
use std::iter::Sum; use std::iter::Sum;
pub type SimSnapshot = SimState<mat::Static>; pub type SimSnapshot = SimState<mat::Static>;
@@ -18,10 +20,10 @@ pub struct SimState<M=GenericMaterial> {
} }
impl<M: Material + Default> SimState<M> { impl<M: Material + Default> SimState<M> {
pub fn new(width: u32, height: u32, feature_size: Flt) -> Self { pub fn new(size: Coord, feature_size: Flt) -> Self {
Self { Self {
cells: Array2::default((height as _, width as _)), cells: Array2::default((size.y() as _, size.x() as _)),
scratch: Array2::default((height as _, width as _)), scratch: Array2::default((size.y() as _, size.x() as _)),
feature_size: feature_size.into(), feature_size: feature_size.into(),
..Default::default() ..Default::default()
} }
@@ -103,17 +105,19 @@ impl<M: Material + Default + Send + Sync> SimState<M> {
self.cells.view().into_par_iter().map(f).sum() self.cells.view().into_par_iter().map(f).sum()
} }
pub fn map_sum_enumerated<F: Fn(u32, u32, &Cell<M>) -> R + Sync + Send, R: Sum<R> + Send>(&self, f: F) -> R { pub fn map_sum_enumerated<F: Fn(Coord, &Cell<M>) -> R + Sync + Send, R: Sum<R> + Send>(&self, f: F) -> R {
Zip::from(ndarray::indices_of(&self.cells)).and(&self.cells).into_par_iter().map(|((x, y), c)| f(x as _, y as _, c)).sum() Zip::from(ndarray::indices_of(&self.cells)).and(&self.cells).into_par_iter().map(|((y, x), c)| {
f(Coord::new(x as _, y as _), c)
}).sum()
} }
} }
impl<M: Material> SimState<M> { impl<M: Material> SimState<M> {
pub fn impulse_bz(&mut self, x: u32, y: u32, bz: Flt) { pub fn impulse_bz(&mut self, c: Coord, bz: Flt) {
self.get_mut(x, y).impulse_bz(bz); self.get_mut(c).impulse_bz(bz);
} }
pub fn current(&self, x: u32, y: u32) -> Vec3 { pub fn current(&self, c: Coord) -> Vec3 {
self.get(x, y).current_density() * (self.feature_size * self.feature_size) self.get(c).current_density() * (self.feature_size * self.feature_size)
} }
} }
@@ -130,14 +134,14 @@ impl<M> SimState<M> {
self.feature_size.into() self.feature_size.into()
} }
pub fn impulse_ex(&mut self, x: u32, y: u32, ex: Flt) { pub fn impulse_ex(&mut self, c: Coord, ex: Flt) {
self.get_mut(x, y).state.e += Vec3::new(ex, 0.0, 0.0); self.get_mut(c).state.e += Vec3::new(ex, 0.0, 0.0);
} }
pub fn impulse_ey(&mut self, x: u32, y: u32, ey: Flt) { pub fn impulse_ey(&mut self, c: Coord, ey: Flt) {
self.get_mut(x, y).state.e += Vec3::new(0.0, ey, 0.0); self.get_mut(c).state.e += Vec3::new(0.0, ey, 0.0);
} }
pub fn impulse_ez(&mut self, x: u32, y: u32, ez: Flt) { pub fn impulse_ez(&mut self, c: Coord, ez: Flt) {
self.get_mut(x, y).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 { pub fn width(&self) -> u32 {
@@ -146,11 +150,11 @@ impl<M> SimState<M> {
pub fn height(&self) -> u32 { pub fn height(&self) -> u32 {
self.cells.shape()[0] as _ self.cells.shape()[0] as _
} }
pub fn get(&self, x: u32, y: u32) -> &Cell<M> { pub fn get(&self, c: Coord) -> &Cell<M> {
&self.cells[[y as _, x as _]] &self.cells[c.row_major_idx()]
} }
pub fn get_mut(&mut self, x: u32, y: u32) -> &mut Cell<M> { pub fn get_mut(&mut self, c: Coord) -> &mut Cell<M> {
&mut self.cells[[y as _, x as _]] &mut self.cells[c.row_major_idx()]
} }
pub fn timestep(&self) -> Flt { pub fn timestep(&self) -> Flt {