Region: remove `Clone` from the trait, and also parameterize everything

i didn't necessarily *want* to parameterize it all,
but it turned out to be easier to do that than to force all users to
workaround the lack of Clone.
This commit is contained in:
colin 2022-08-12 01:42:19 -07:00
parent d5fbb4e9b2
commit 084c5bc342
7 changed files with 133 additions and 145 deletions

7
Cargo.lock generated
View File

@ -317,7 +317,6 @@ dependencies = [
"crossterm",
"csv",
"dashmap",
"dyn-clone",
"env_logger",
"float_eq",
"font8x8",
@ -554,12 +553,6 @@ dependencies = [
"libc",
]
[[package]]
name = "dyn-clone"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "140206b78fb2bc3edbcfc9b5ccbd0b30699cfe8d348b8b31b330e47df5291a5a"
[[package]]
name = "either"
version = "1.7.0"

View File

@ -3,7 +3,20 @@
//! search for the conditions which maximize energy transfer from the one core to the other.
use coremem::{Driver, mat, meas};
use coremem::geom::{region, Cube, Dilate, Memoize, Meters, Spiral, SwapYZ, Torus, Translate, Wrap};
use coremem::geom::Meters;
use coremem::geom::region::{
self,
Cube,
Dilate,
Intersection,
InvertedRegion,
Memoize,
Spiral,
SwapYZ,
Torus,
Translate,
Wrap
};
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr};
use coremem::real::{R32, Real as _};
use coremem::render::CsvRenderer;
@ -13,9 +26,8 @@ use coremem::stim::{CurlStimulus, Exp1, Gated, Sinusoid1, TimeVarying as _};
use log::{error, info, warn};
use serde::{Deserialize, Serialize};
// XXX: cache was disabled during Region rework.
// mod cache;
// use cache::DiskCache;
mod cache;
use cache::DiskCache;
type Mat = IsoConductorOr<f32, Ferroxcube3R1MH>;
@ -142,14 +154,18 @@ struct Params {
dump_frames: (u64, Option<u64>),
}
#[derive(Clone, Default)]
#[derive(Clone, Default, Serialize, Deserialize)]
struct Geometries {
dim: Meters,
ferro1_region: Torus,
ferro2_region: Torus,
set1_region: Torus,
set2_region: Torus,
coupling_region: region::Union,
coupling_region: region::Union3<
Memoize<Dilate<Wrap<Translate<SwapYZ<Intersection<Spiral, Cube>>>>>>,
Memoize<Dilate<Wrap<Translate<SwapYZ<Intersection<Spiral, InvertedRegion<Cube>>>>>>>,
region::Union3<Cube, Cube, region::Union4<Cube, Cube, Cube, Cube>>
>,
coupling_wire_top: Cube,
coupling_wire_bot: Cube,
wrap1_len: f32,
@ -285,29 +301,29 @@ fn derive_geometries(p: GeomParams) -> Option<Geometries> {
wrap2_bot - feat_sizes*2.0,
wrap2_bot.with_y(coupling_wire_bot.top()) + feat_sizes*2.0,
);
let coupling_stubs = region::Union::new()
.with(coupling_stub_top_left.clone())
.with(coupling_stub_top_right.clone())
.with(coupling_stub_bot_left.clone())
.with(coupling_stub_bot_right.clone())
;
let coupling_stubs = region::Union::new4(
coupling_stub_top_left.clone(),
coupling_stub_top_right.clone(),
coupling_stub_bot_left.clone(),
coupling_stub_bot_right.clone(),
);
let coupling_wires = region::Union::new()
.with(coupling_wire_top.clone())
.with(coupling_wire_bot.clone())
.with(coupling_stubs.clone())
;
let coupling_wires = region::Union::new3(
coupling_wire_top.clone(),
coupling_wire_bot.clone(),
coupling_stubs.clone(),
);
let coupling_region = region::Union::new()
.with(coupling_region1.clone())
.with(coupling_region2.clone())
.with(coupling_wires.clone())
;
let coupling_region = region::Union::new3(
coupling_region1.clone(),
coupling_region2.clone(),
coupling_wires.clone(),
);
let wrap1_with_coupling = region::union(
let wrap1_with_coupling = region::Union::new2(
coupling_region1.clone(), coupling_wires.clone()
);
let wrap2_with_coupling = region::union(
let wrap2_with_coupling = region::Union::new2(
coupling_region2.clone(), coupling_wires.clone()
);
@ -657,14 +673,10 @@ fn main() {
variants.len() / post_times.len(),
);
// let mut geom_cache = DiskCache::new_with_supplier(
// &format!("{}/.geom_cache", ensure_out_dir(i)),
// |geom: &GeomParams| derive_geometries(geom.clone())
// );
// TODO: re-enable geometry cache. had to disable during Region serialization rework
fn geom_cache_get_or_insert_from_supplier(geom: GeomParams) -> Option<Geometries> {
derive_geometries(geom)
}
let mut geom_cache = DiskCache::new_with_supplier(
&format!("{}/.geom_cache", ensure_out_dir(i)),
|geom: &GeomParams| derive_geometries(geom.clone())
);
for (peak_clock_current, clock_duration, post_time, clock_type, ferro_major, wrap1_coverage, wrap2_coverage, wrap1_density, wrap2_density) in variants {
info!("{}A/{}s {}s {}m {}:{}cov {}:{}density", peak_clock_current, clock_duration, post_time, ferro_major, wrap1_coverage, wrap2_coverage, wrap1_density, wrap2_density);
@ -713,7 +725,7 @@ fn main() {
wraps1: (wraps1 * 4) as f32,
..base_params.geom
};
let geoms = geom_cache_get_or_insert_from_supplier(params.clone())?;
let geoms = geom_cache.get_or_insert_from_supplier(params.clone())?;
Some((params, geoms))
})
.collect();
@ -738,7 +750,7 @@ fn main() {
wraps2: (wraps2 * 4) as f32,
..base_params.geom
};
let geoms = geom_cache_get_or_insert_from_supplier(params.clone())?;
let geoms = geom_cache.get_or_insert_from_supplier(params.clone())?;
Some((params, geoms))
})
.collect();
@ -759,7 +771,7 @@ fn main() {
let mut params = base_params;
params.geom.wraps1 = wraps1;
params.geom.wraps2 = wraps2;
match geom_cache_get_or_insert_from_supplier(params.geom.clone()) {
match geom_cache.get_or_insert_from_supplier(params.geom.clone()) {
Some(geoms) => {
run_sim(i, params, geoms);
},

View File

@ -15,7 +15,6 @@ common_macros = "0.1" # MIT or Apache 2.0
crossterm = "0.24" # MIT
csv = "1.1" # MIT or Unlicense
dashmap = "5.3" # MIT
dyn-clone = "1.0" # MIT or Apache 2.0
env_logger = "0.9" # MIT or Apache 2.0
float_eq = "1.0" # MIT or Apache 2.0
font8x8 = "0.3" # MIT

View File

@ -2,7 +2,6 @@ use crate::geom::{Coord, Meters, OrdMeters};
use coremem_cross::vec::Vec3;
use dyn_clone::{self, DynClone};
use rayon::prelude::*;
use serde::{Serialize, Deserialize};
use std::collections::BTreeSet;
@ -12,10 +11,9 @@ mod primitives;
pub use primitives::*;
pub trait Region: Send + Sync + DynClone {
pub trait Region: Send + Sync {
fn contains(&self, p: Meters) -> bool;
}
dyn_clone::clone_trait_object!(Region);
/// some (volume) which has a tangent vector everywhere inside/on it.
/// for example, a cylinder has tangents everywhere except its axis.
@ -24,16 +22,16 @@ pub trait HasCrossSection {
fn cross_section_normal(&self, p: Meters) -> Vec3<f32>;
}
pub fn and<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Intersection {
Intersection::new().and(r1).and(r2)
pub fn and<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Intersection<T1, T2> {
Intersection::new2(r1, r2)
}
pub fn and_not<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Intersection {
pub fn and_not<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Intersection<T1, InvertedRegion<T2>> {
and(r1, InvertedRegion::new(r2))
}
pub fn union<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Union {
Union::new().with(r1).with(r2)
pub fn union<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Union<T1, T2> {
Union::new2(r1, r2)
}
/// returns true if there's a path (via the cardinal directions) from p0 to p1 within this region.
@ -75,7 +73,7 @@ pub fn distance_to<R: Region, C: Coord>(r: &R, p0: C, p1: C, feat_size: f32) ->
}
/// Region describing the entire simulation space
#[derive(Copy, Clone, Serialize, Deserialize)]
#[derive(Copy, Clone, Default, Serialize, Deserialize)]
pub struct WorldRegion;
impl Region for WorldRegion {
@ -84,121 +82,115 @@ impl Region for WorldRegion {
}
}
#[derive(Clone)]
pub struct InvertedRegion(Box<dyn Region>);
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct InvertedRegion<R>(R);
impl InvertedRegion {
pub fn new<R: Region + 'static>(r: R) -> Self {
Self(Box::new(r))
impl<R> InvertedRegion<R> {
pub fn new(r: R) -> Self {
Self(r)
}
}
impl Region for InvertedRegion {
impl<R: Region> Region for InvertedRegion<R> {
fn contains(&self, p: Meters) -> bool {
!self.0.contains(p)
}
}
#[derive(Clone, Default)]
pub struct Union(Vec<Box<dyn Region>>);
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct Union<R1, R2>(R1, R2);
impl Union {
pub fn new() -> Self {
Self(Vec::new())
pub type Union3<R1, R2, R3> = Union<Union<R1, R2>, R3>;
pub type Union4<R1, R2, R3, R4> = Union<Union3<R1, R2, R3>, R4>;
impl<R1, R2> Union<R1, R2> {
pub fn with<R: Region>(self, r: R) -> Union<Self, R> {
Union::new2(self, r)
}
pub fn new_with<R: Region + 'static>(r: R) -> Self {
Self::new().with(r)
pub fn new2(r1: R1, r2: R2) -> Self {
Self(r1, r2)
}
pub fn with<R: Region + 'static>(self, r: R) -> Self {
self.with_box(Box::new(r))
pub fn new3<R3: Region>(r1: R1, r2: R2, r3: R3) -> Union<Self, R3> {
Union::new2(r1, r2).with(r3)
}
pub fn with_box(mut self, r: Box<dyn Region>) -> Self {
self.0.push(r);
self
pub fn new4<R3: Region, R4: Region>(r1: R1, r2: R2, r3: R3, r4: R4) -> Union<Union<Self, R3>, R4> {
Union::new2(r1, r2).with(r3).with(r4)
}
}
impl Region for Union {
impl<R1: Region, R2: Region> Region for Union<R1, R2> {
fn contains(&self, p: Meters) -> bool {
self.0.iter().any(|r| r.contains(p))
self.0.contains(p) || self.1.contains(p)
}
}
#[derive(Clone)]
pub struct Intersection(Vec<Box<dyn Region>>);
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct Intersection<R1, R2>(R1, R2);
impl Intersection {
pub fn new() -> Self {
Self(Vec::new())
impl<R1, R2> Intersection<R1, R2> {
pub fn and<R3: Region>(self, r: R3) -> Intersection<Self, R3> {
Intersection::new2(self, r)
}
pub fn new_with<R: Region + 'static>(r: R) -> Self {
Self::new().and(r)
}
pub fn and<R: Region + 'static>(self, r: R) -> Self {
self.and_box(Box::new(r))
}
pub fn and_box(mut self, r: Box<dyn Region>) -> Self {
self.0.push(r);
self
pub fn new2(r1: R1, r2: R2) -> Self {
Self(r1, r2)
}
}
impl Region for Intersection {
impl<R1: Region, R2: Region> Region for Intersection<R1, R2> {
fn contains(&self, p: Meters) -> bool {
self.0.iter().all(|r| r.contains(p))
self.0.contains(p) && self.1.contains(p)
}
}
#[derive(Clone)]
pub struct Translate {
inner: Box<dyn Region>,
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct Translate<R> {
inner: R,
shift: Meters,
}
impl Translate {
pub fn new<T: Region + 'static>(inner: T, shift: Meters) -> Self {
Self { inner: Box::new(inner), shift }
impl<R> Translate<R> {
pub fn new(inner: R, shift: Meters) -> Self {
Self { inner, shift }
}
}
impl Region for Translate {
impl<R: Region> Region for Translate<R> {
fn contains(&self, p: Meters) -> bool {
self.inner.contains(p - self.shift)
}
}
#[derive(Clone)]
pub struct SwapXZ {
inner: Box<dyn Region>,
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct SwapXZ<R> {
inner: R,
}
impl SwapXZ {
pub fn new<T: Region + 'static>(inner: T) -> Self {
Self { inner: Box::new(inner) }
impl<R> SwapXZ<R> {
pub fn new(inner: R) -> Self {
Self { inner }
}
}
impl Region for SwapXZ {
impl<R: Region> Region for SwapXZ<R> {
fn contains(&self, p: Meters) -> bool {
let p = Meters::new(p.z(), p.y(), p.z());
self.inner.contains(p)
}
}
#[derive(Clone)]
pub struct SwapYZ {
inner: Box<dyn Region>,
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct SwapYZ<R> {
inner: R,
}
impl SwapYZ {
pub fn new<T: Region + 'static>(inner: T) -> Self {
Self { inner: Box::new(inner) }
impl<R> SwapYZ<R> {
pub fn new(inner: R) -> Self {
Self { inner }
}
}
impl Region for SwapYZ {
impl<R: Region> Region for SwapYZ<R> {
fn contains(&self, p: Meters) -> bool {
let mapped = Meters::new(p.x(), p.z(), p.y());
self.inner.contains(mapped)
@ -211,20 +203,20 @@ impl Region for SwapYZ {
/// the resulting region is mapped onto the original region y=[0, y_max]. x is just the radius
/// so that (0, 0) is mapped to (0, 0), and (1, 0) is mapped to (1, 0) and (0, 1) is mapped to
/// (1, 0.5*y_max) and (-5, 0) is mapped to (5, 0.5*y_max).
#[derive(Clone)]
pub struct Wrap {
inner: Box<dyn Region>,
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct Wrap<R> {
inner: R,
y_max: f32,
about: Meters,
}
impl Wrap {
pub fn new<T: Region + 'static>(inner: T, y_max: f32) -> Self {
impl<R> Wrap<R> {
pub fn new(inner: R, y_max: f32) -> Self {
Self::new_about(inner, y_max, Meters::new(0.0, 0.0, 0.0))
}
pub fn new_about<T: Region + 'static>(inner: T, y_max: f32, about: Meters) -> Self {
Self { inner: Box::new(inner), y_max, about }
pub fn new_about(inner: R, y_max: f32, about: Meters) -> Self {
Self { inner, y_max, about }
}
fn map(&self, p: Meters) -> Meters {
@ -236,26 +228,26 @@ impl Wrap {
}
}
impl Region for Wrap {
impl<R: Region> Region for Wrap<R> {
fn contains(&self, p: Meters) -> bool {
self.inner.contains(self.map(p))
}
}
#[derive(Clone)]
pub struct Dilate {
inner: Box<dyn Region>,
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct Dilate<R> {
inner: R,
rad: f32,
res: f32,
}
impl Dilate {
pub fn new<T: Region + 'static>(inner: T, rad: f32, res: f32) -> Self {
Self { inner: Box::new(inner), rad, res }
impl<R> Dilate<R> {
pub fn new(inner: R, rad: f32, res: f32) -> Self {
Self { inner, rad, res }
}
}
impl Region for Dilate {
impl<R: Region> Region for Dilate<R> {
fn contains(&self, p: Meters) -> bool {
let rad_iters = (self.rad / self.res).ceil() as i32;
let rad_range = -rad_iters..=rad_iters;
@ -278,22 +270,23 @@ impl Region for Dilate {
}
}
#[derive(Clone)]
pub struct Memoize {
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct Memoize<R> {
#[serde(skip)]
lut: Arc<dashmap::DashMap<OrdMeters, bool>>,
inner: Box<dyn Region>,
inner: R,
}
impl Memoize {
pub fn new<R: Region + 'static>(inner: R) -> Self {
impl<R> Memoize<R> {
pub fn new(inner: R) -> Self {
Self {
lut: Arc::new(dashmap::DashMap::new()),
inner: Box::new(inner),
inner,
}
}
}
impl Region for Memoize {
impl<R: Region> Region for Memoize<R> {
fn contains(&self, p: Meters) -> bool {
*self.lut.entry(OrdMeters(p)).or_insert_with(|| self.inner.contains(p))
}
@ -304,7 +297,7 @@ mod test {
use super::*;
use float_eq::assert_float_eq;
fn assert_map(w: &Wrap, from: Meters, to: Meters) {
fn assert_map<R>(w: &Wrap<R>, from: Meters, to: Meters) {
let mapped = w.map(from);
assert_float_eq!(mapped.x(), to.x(), abs <= 0.01);
assert_float_eq!(mapped.y(), to.y(), abs <= 0.01);

View File

@ -8,7 +8,7 @@ use std::ops::Range;
use super::{HasCrossSection, Region};
#[derive(Copy, Clone, Serialize, Deserialize)]
#[derive(Copy, Clone, Default, Serialize, Deserialize)]
pub struct CylinderZ {
center: Vec2<f32>,
radius: f32,
@ -111,7 +111,7 @@ impl HasCrossSection for Torus {
}
}
#[derive(Copy, Clone, Serialize, Deserialize)]
#[derive(Copy, Clone, Default, Serialize, Deserialize)]
pub struct Sphere {
center: Meters,
rad: f32,
@ -243,7 +243,7 @@ impl Region for Cube {
}
/// a Spiral traces out a circle on the xy plane as z increases.
#[derive(Copy, Clone, Serialize, Deserialize)]
#[derive(Copy, Clone, Default, Serialize, Deserialize)]
pub struct Spiral {
/// radius of the spiral
major: f32,

View File

@ -212,7 +212,6 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Meta {
}
}
#[derive(Clone)]
pub struct Volume {
name: String,
region: Box<dyn Region>,
@ -241,7 +240,6 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Volume {
}
}
#[derive(Clone)]
pub struct Current {
name: String,
region: Box<dyn Region>,
@ -471,7 +469,6 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagneticLoop {
}
/// mean M over a region
#[derive(Clone)]
pub struct MagneticFlux {
name: String,
region: Box<dyn Region>,
@ -508,7 +505,6 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagneticFlux {
}
/// mean B over a region
#[derive(Clone)]
pub struct Magnetization {
name: String,
region: Box<dyn Region>,
@ -604,7 +600,6 @@ impl<S: AbstractSim> AbstractMeasurement<S> for ElectricField {
}
}
#[derive(Clone)]
pub struct Energy {
name: String,
region: Box<dyn Region>,
@ -648,7 +643,6 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Energy {
}
}
#[derive(Clone)]
pub struct Power {
name: String,
region: Box<dyn Region>
@ -732,7 +726,6 @@ pub mod test {
}
}
#[derive(Clone, Serialize, Deserialize)]
struct MockRegion {
normal: Vec3<f32>,
}

View File

@ -362,7 +362,6 @@ impl<T: TimeVarying3> TimeVarying3 for Shifted<T> {
#[cfg(test)]
mod test {
use super::*;
use serde::{Serialize, Deserialize};
macro_rules! assert_approx_eq {
($x:expr, $e:expr, $h:expr) => {
@ -396,7 +395,6 @@ mod test {
assert_approx_eq!(s.at(0.00075), Vec3::new(-10.0, -1.0, 100.0), Vec3::zero());
}
#[derive(Clone, Serialize, Deserialize)]
struct MockRegion {
normal: Vec3<f32>,
}