265 lines
7.9 KiB
Rust
265 lines
7.9 KiB
Rust
use crate::compound::enumerated::{DiscriminantCodable, Enum, EnumRequirements, Visitor};
|
|
use crate::compound::list::{Indexable, List2, List3};
|
|
use crate::compound::peano::{Peano, P0, P1, P2, P3};
|
|
use crate::real::Real;
|
|
use crate::vec::Vec3;
|
|
use crate::mat::{
|
|
AnisomorphicConductor,
|
|
Ferroxcube3R1MH,
|
|
IsomorphicConductor,
|
|
Material,
|
|
MBPgram,
|
|
MHPgram,
|
|
Vacuum,
|
|
};
|
|
|
|
#[cfg(feature = "serde")]
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
/// a material which can take on 1 of N types.
|
|
/// it's assumed that the first type in the material list is capable of storing the discriminant
|
|
/// (i.e. that it implements DiscriminantCodable).
|
|
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
|
#[cfg_attr(feature = "fmt", derive(Debug))]
|
|
#[derive(Copy, Clone, Default, PartialEq)]
|
|
pub struct DiscrMat<Mats>(Enum<(), Mats>);
|
|
pub type DiscrMat2<M0, M1> = DiscrMat<List2<M0, M1>>;
|
|
pub type DiscrMat3<M0, M1, M2> = DiscrMat<List3<M0, M1, M2>>;
|
|
|
|
impl<Mats: Default> DiscrMat<Mats> {
|
|
fn new<P: Peano>(m: Mats::Element) -> Self
|
|
where
|
|
Mats: Indexable<P>,
|
|
Enum<(), Mats>: EnumRequirements,
|
|
{
|
|
let mut me = Self::default();
|
|
me.0.set::<P>(m);
|
|
me
|
|
}
|
|
}
|
|
|
|
/// invokes Material::conductivity on any Material
|
|
struct ConductivityDispatcher;
|
|
impl<P: Peano, R: Real, T: Material<R>> Visitor<P, T, Vec3<R>> for ConductivityDispatcher {
|
|
fn call(self, v: T) -> Vec3<R> {
|
|
v.conductivity()
|
|
}
|
|
}
|
|
|
|
/// invokes Material::move_b_vec on any Material
|
|
struct MoveBVecDispatcher<R> {
|
|
m: Vec3<R>,
|
|
target_b: Vec3<R>,
|
|
}
|
|
impl<R: Real, P: Peano, T: Material<R>> Visitor<P, T, Vec3<R>> for MoveBVecDispatcher<R> {
|
|
fn call(self, v: T) -> Vec3<R> {
|
|
v.move_b_vec(self.m, self.target_b)
|
|
}
|
|
}
|
|
|
|
/// invokes Into<T>::into on any variant
|
|
struct IntoDispatcher;
|
|
impl<P: Peano, T: Into<I>, I> Visitor<P, T, I> for IntoDispatcher {
|
|
fn call(self, v: T) -> I {
|
|
v.into()
|
|
}
|
|
}
|
|
|
|
impl<R, M0, M1> Into<GenericMaterial<R>> for DiscrMat2<M0, M1>
|
|
where
|
|
M0: DiscriminantCodable<P2> + Into<GenericMaterial<R>> + Copy,
|
|
M1: Into<GenericMaterial<R>> + Copy,
|
|
{
|
|
fn into(self) -> GenericMaterial<R> {
|
|
self.0.dispatch(IntoDispatcher)
|
|
}
|
|
}
|
|
|
|
impl<R: Real, M0, M1> Material<R> for DiscrMat2<M0, M1>
|
|
where
|
|
M0: DiscriminantCodable<P2> + Material<R> + Copy,
|
|
M1: Material<R> + Copy,
|
|
{
|
|
fn conductivity(&self) -> Vec3<R> {
|
|
self.0.dispatch(ConductivityDispatcher)
|
|
}
|
|
fn move_b_vec(&self, m: Vec3<R>, target_b: Vec3<R>) -> Vec3<R> {
|
|
self.0.dispatch(MoveBVecDispatcher { m, target_b })
|
|
}
|
|
}
|
|
|
|
impl<R, M0, M1, M2> Into<GenericMaterial<R>> for DiscrMat3<M0, M1, M2>
|
|
where
|
|
M0: DiscriminantCodable<P3> + Into<GenericMaterial<R>> + Copy,
|
|
M1: Into<GenericMaterial<R>> + Copy,
|
|
M2: Into<GenericMaterial<R>> + Copy,
|
|
{
|
|
fn into(self) -> GenericMaterial<R> {
|
|
self.0.dispatch(IntoDispatcher)
|
|
}
|
|
}
|
|
|
|
impl<R: Real, M0, M1, M2> Material<R> for DiscrMat3<M0, M1, M2>
|
|
where
|
|
M0: DiscriminantCodable<P3> + Material<R> + Copy,
|
|
M1: Material<R> + Copy,
|
|
M2: Material<R> + Copy,
|
|
{
|
|
fn conductivity(&self) -> Vec3<R> {
|
|
self.0.dispatch(ConductivityDispatcher)
|
|
}
|
|
fn move_b_vec(&self, m: Vec3<R>, target_b: Vec3<R>) -> Vec3<R> {
|
|
self.0.dispatch(MoveBVecDispatcher { m, target_b })
|
|
}
|
|
}
|
|
|
|
/// represents a Material which is either an isomorphic conductor, or some other Material `M1`
|
|
pub type IsoConductorOr<R, M1> = DiscrMat2<IsomorphicConductor<R>, M1>;
|
|
|
|
// XXX: can't do this for generic M, because that creates duplicate `From` impls for the
|
|
// IsomorphicConductor itself
|
|
impl<R: Real> From<Ferroxcube3R1MH> for IsoConductorOr<R, Ferroxcube3R1MH> {
|
|
fn from(mat: Ferroxcube3R1MH) -> Self {
|
|
IsoConductorOr::new::<P1>(mat)
|
|
}
|
|
}
|
|
impl<R: Real> From<IsomorphicConductor<R>> for IsoConductorOr<R, Ferroxcube3R1MH> {
|
|
fn from(mat: IsomorphicConductor<R>) -> Self {
|
|
IsoConductorOr::new::<P0>(mat)
|
|
}
|
|
}
|
|
|
|
/// muxes operations to either the conductor or the magnetic material
|
|
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
|
#[cfg_attr(feature = "fmt", derive(Debug))]
|
|
#[derive(Copy, Clone, Default, PartialEq)]
|
|
pub struct DualMaterial<C, M> {
|
|
conductor: C,
|
|
magnetic: M,
|
|
}
|
|
|
|
impl<C, M> DualMaterial<C, M> {
|
|
pub fn new(conductor: C, magnetic: M) -> Self {
|
|
Self { conductor, magnetic }
|
|
}
|
|
}
|
|
|
|
impl<R: Real, C: Material<R>, M: Material<R>> Material<R> for DualMaterial<C, M> {
|
|
fn conductivity(&self) -> Vec3<R> {
|
|
self.conductor.conductivity()
|
|
}
|
|
fn move_b_vec(&self, m: Vec3<R>, target_b: Vec3<R>) -> Vec3<R> {
|
|
self.magnetic.move_b_vec(m, target_b)
|
|
}
|
|
}
|
|
|
|
/// Material which can encode any of the well-known magnetic materials (or Vacuum)
|
|
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
|
#[cfg_attr(feature = "fmt", derive(Debug))]
|
|
#[derive(Copy, Clone, PartialEq)]
|
|
pub struct GenericMagnetic<R>(DiscrMat3<MBPgram<R>, MHPgram<R>, Vacuum>);
|
|
|
|
impl<R: Real> Default for GenericMagnetic<R> {
|
|
fn default() -> Self {
|
|
// N.B.: the default is not the first variant.
|
|
// we order the variants specifically so that the first one can store the discriminant, but
|
|
// we NEED Vacuum to be the default.
|
|
Vacuum.into()
|
|
}
|
|
}
|
|
|
|
impl<R: Real> Material<R> for GenericMagnetic<R> {
|
|
fn conductivity(&self) -> Vec3<R> {
|
|
self.0.conductivity()
|
|
}
|
|
fn move_b_vec(&self, m: Vec3<R>, target_b: Vec3<R>) -> Vec3<R> {
|
|
self.0.move_b_vec(m, target_b)
|
|
}
|
|
}
|
|
|
|
impl<R: Real> From<MBPgram<R>> for GenericMagnetic<R> {
|
|
fn from(mat: MBPgram<R>) -> Self {
|
|
GenericMagnetic(DiscrMat3::new::<P0>(mat))
|
|
}
|
|
}
|
|
impl<R: Real> From<MHPgram<R>> for GenericMagnetic<R> {
|
|
fn from(mat: MHPgram<R>) -> Self {
|
|
GenericMagnetic(DiscrMat3::new::<P1>(mat))
|
|
}
|
|
}
|
|
impl<R: Real> From<Vacuum> for GenericMagnetic<R> {
|
|
fn from(mat: Vacuum) -> Self {
|
|
GenericMagnetic(DiscrMat3::new::<P2>(mat))
|
|
}
|
|
}
|
|
|
|
/// "Fully Generic" in that one can set both the conductivity,
|
|
/// and set any of the well-known magnetic materials, simultaneously.
|
|
pub type GenericMaterial<R> = DualMaterial<
|
|
AnisomorphicConductor<R>,
|
|
GenericMagnetic<R>,
|
|
>;
|
|
|
|
impl<R: Real> From<AnisomorphicConductor<R>> for GenericMaterial<R> {
|
|
fn from(mat: AnisomorphicConductor<R>) -> Self {
|
|
Self::new(mat, Default::default())
|
|
}
|
|
}
|
|
impl<R: Real> From<MBPgram<R>> for GenericMaterial<R> {
|
|
fn from(mat: MBPgram<R>) -> Self {
|
|
Self::new(Default::default(), mat.into())
|
|
}
|
|
}
|
|
impl<R: Real> From<MHPgram<R>> for GenericMaterial<R> {
|
|
fn from(mat: MHPgram<R>) -> Self {
|
|
Self::new(Default::default(), mat.into())
|
|
}
|
|
}
|
|
impl<R: Real> From<Vacuum> for GenericMaterial<R> {
|
|
fn from(mat: Vacuum) -> Self {
|
|
Self::new(Default::default(), mat.into())
|
|
}
|
|
}
|
|
impl<R: Real> From<IsomorphicConductor<R>> for GenericMaterial<R> {
|
|
fn from(mat: IsomorphicConductor<R>) -> Self {
|
|
let mat: AnisomorphicConductor<R> = mat.into();
|
|
mat.into()
|
|
}
|
|
}
|
|
impl<R: Real> From<Ferroxcube3R1MH> for GenericMaterial<R> {
|
|
fn from(mat: Ferroxcube3R1MH) -> Self {
|
|
let mat: MHPgram<R> = mat.into();
|
|
mat.into()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
use crate::mat::AnisomorphicConductor;
|
|
use crate::real::R32;
|
|
|
|
#[test]
|
|
fn iso_conductor_or_3r1() {
|
|
let c: IsoConductorOr<f32, Ferroxcube3R1MH> = IsomorphicConductor::new(22.0f32).into();
|
|
assert!(c.conductivity() == Vec3::uniform(22.0f32));
|
|
|
|
let c: IsoConductorOr<f32, Ferroxcube3R1MH> = Ferroxcube3R1MH::new().into();
|
|
assert!(c.conductivity() == Vec3::zero());
|
|
}
|
|
|
|
#[test]
|
|
fn iso_conductor_or_aniso() {
|
|
type I = IsoConductorOr<R32, AnisomorphicConductor<R32>>;
|
|
|
|
let c = I::new::<P0>(IsomorphicConductor::new(22f32.cast()));
|
|
assert!(c.conductivity() == Vec3::uniform(22.0).cast());
|
|
|
|
let c = I::new::<P1>(AnisomorphicConductor::new(
|
|
Vec3::new(2.0, 3.0, 4.0).cast()
|
|
));
|
|
|
|
assert!(c.conductivity() == Vec3::new(2.0, 3.0, 4.0).cast());
|
|
}
|
|
}
|