convert AbstractSim::sample to include a reference to the material -- not just its conductivity

This commit is contained in:
2022-07-29 16:02:16 -07:00
parent 895c87869b
commit 9c1fc65068
7 changed files with 157 additions and 110 deletions

View File

@@ -1,5 +1,5 @@
use crate::geom::{Coord, Cube, Index, InvertedRegion, Meters, Region};
use crate::cross::mat::{FullyGenericMaterial, Vacuum};
use crate::geom::{Coord, Cube, Index, InvertedRegion, Region};
use crate::cross::mat::{FullyGenericMaterial, Material, Vacuum};
use crate::cross::real::Real;
use crate::cross::step::SimMeta;
use crate::cross::vec::{Vec3, Vec3u};
@@ -80,10 +80,70 @@ pub type GenericSim<R> = SpirvSim<R, FullyGenericMaterial<R>, CpuBackend>;
/// \| | |
/// +------------+------------+
///
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct Sample<R=f32> {
state: Fields<R>,
conductivity: Vec3<R>,
pub struct Sample<'a, R, M> {
fields: Fields<R>,
material: &'a M,
}
impl<'a, R: Real, M> Sample<'a, R, M> {
pub fn fields(&self) -> Fields<R> {
self.fields
}
pub fn e(&self) -> Vec3<R> {
self.fields.e()
}
pub fn ex(&self) -> R {
self.e().x()
}
pub fn ey(&self) -> R {
self.e().y()
}
pub fn ez(&self) -> R {
self.e().z()
}
pub fn h(&self) -> Vec3<R> {
self.fields.h()
}
pub fn hx(&self) -> R {
self.h().x()
}
pub fn hy(&self) -> R {
self.h().y()
}
pub fn hz(&self) -> R {
self.h().z()
}
pub fn b(&self) -> Vec3<R> {
self.fields.b()
}
pub fn bx(&self) -> R {
self.b().x()
}
pub fn by(&self) -> R {
self.b().y()
}
pub fn bz(&self) -> R {
self.b().z()
}
pub fn m(&self) -> Vec3<R> {
self.fields.m()
}
}
impl<'a, R: Real, M: Material<R>> Sample<'a, R, M> {
pub fn conductivity(&self) -> Vec3<R> {
self.material.conductivity()
}
pub fn current_density(&self) -> Vec3<R> {
// TODO: does this make sense for Pml?
let conductivity = self.conductivity();
self.e().elem_mul(conductivity)
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
@@ -116,16 +176,23 @@ impl<R: Real> Fields<R> {
pub fn b(&self) -> Vec3<R> {
(self.h() + self.m()) * R::mu0()
}
pub fn with_material<'a, M>(self, material: &'a M) -> Sample<'a, R, M> {
Sample {
fields: self,
material,
}
}
}
// TODO: the Sync bound here could be removed with some refactoring
pub trait AbstractSim: Sync {
type Real: Real;
type Material;
type Material: Material<Self::Real>;
// TODO: should return SimMeta<Self::Real>?
fn meta(&self) -> SimMeta<f32>;
fn step_no(&self) -> u64;
fn sample(&self, pos: Meters) -> Sample;
fn fields_at_index(&self, pos: Index) -> Fields<Self::Real>;
fn get_material_index(&self, at: Index) -> &Self::Material;
fn put_material_index(&mut self, at: Index, m: Self::Material);
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, s: &S);
@@ -144,6 +211,11 @@ pub trait AbstractSim: Sync {
self.put_material_index(pos.to_index(self.feature_size()), mat.into())
}
fn sample<'a, C: Coord>(&'a self, pos: C) -> Sample<'a, Self::Real, Self::Material> {
self.fields_at_index(pos.to_index(self.feature_size()))
.with_material(self.get_material(pos))
}
fn step(&mut self) {
// XXX: try not to exercise this path! NoopStimulus is probably a lot of waste.
self.step_multiple(1, &NoopStimulus);
@@ -180,14 +252,12 @@ pub trait AbstractSim: Sync {
self.timestep() * self.step_no() as f32
}
fn get<C: Coord>(&self, at: C) -> Sample {
self.sample(at.to_meters(self.feature_size()))
}
// TODO: these should all live off-trait as some sort of `SimExt` thing.
/// Apply `F` to each Cell, and sum the results.
fn map_sum<F, Ret>(&self, f: F) -> Ret
where
F: Fn(&Sample) -> Ret + Sync,
F: Fn(&Sample<'_, Self::Real, Self::Material>) -> Ret + Sync,
Ret: Sum<Ret> + Send,
{
self.map_sum_enumerated(|_at: Index, cell| f(cell))
@@ -195,7 +265,7 @@ pub trait AbstractSim: Sync {
fn map_sum_enumerated<C, F, Ret>(&self, f: F) -> Ret
where C: Coord,
F: Fn(C, &Sample) -> Ret + Sync,
F: Fn(C, &Sample<'_, Self::Real, Self::Material>) -> Ret + Sync,
Ret: Sum<Ret> + Send,
{
let (w, h, d) = (self.width(), self.height(), self.depth());
@@ -205,7 +275,7 @@ pub trait AbstractSim: Sync {
|&mut (z, y), x|
{
let at = Index(Vec3u::new(x, y, z));
f(C::from_index(at, self.feature_size()), &self.get(at))
f(C::from_index(at, self.feature_size()), &self.sample(at))
}))).flatten().flatten().sum()
}
@@ -216,7 +286,7 @@ pub trait AbstractSim: Sync {
/// Apply `F` to each Cell, and sum the results.
fn map_sum_over<F, Ret, Reg>(&self, region: &Reg, f: F) -> Ret
where
F: Fn(&Sample) -> Ret + Sync,
F: Fn(&Sample<'_, Self::Real, Self::Material>) -> Ret + Sync,
Ret: Sum<Ret> + Default + Send,
Reg: Region + ?Sized
{
@@ -225,7 +295,7 @@ pub trait AbstractSim: Sync {
fn map_sum_over_enumerated<C, F, Ret, Reg>(&self, region: &Reg, f: F) -> Ret
where C: Coord,
F: Fn(C, &Sample) -> Ret + Sync,
F: Fn(C, &Sample<'_, Self::Real, Self::Material>) -> Ret + Sync,
Ret: Sum<Ret> + Default + Send,
Reg: Region + ?Sized,
{
@@ -238,7 +308,7 @@ pub trait AbstractSim: Sync {
let at = Index(Vec3u::new(x, y, z));
let meters = at.to_meters(self.feature_size());
if region.contains(meters) {
f(C::from_index(at, self.feature_size()), &self.get(at))
f(C::from_index(at, self.feature_size()), &self.sample(at))
} else {
Default::default()
}
@@ -246,7 +316,7 @@ pub trait AbstractSim: Sync {
}
fn current<C: Coord>(&self, c: C) -> Vec3<f32> {
self.get(c).current_density() * self.feature_size() * self.feature_size()
self.sample(c).current_density().cast::<f32>() * self.feature_size() * self.feature_size()
}
fn fill_region_using<C, Reg, F, M>(&mut self, region: &Reg, f: F)