diff --git a/examples/toroid25d.rs b/examples/toroid25d.rs index 43bc260..8441558 100644 --- a/examples/toroid25d.rs +++ b/examples/toroid25d.rs @@ -63,31 +63,31 @@ fn main() { // driver.add_term_renderer(); driver.add_measurement(meas::Label(format!("Conductivity: {}, Imax: {:.2e}", conductivity, peak_current))); //driver.add_measurement(meas::Current(conductor_region.clone())); - driver.add_measurement(meas::Magnetization( + driver.add_measurement(meas::MagnetizationAt( Meters((half_width + ferro_inner_rad + 2.0*feat_size, half_width, half_depth).into()) )); - driver.add_measurement(meas::MagneticFlux( + driver.add_measurement(meas::MagneticFluxAt( Meters((half_width + ferro_inner_rad + 2.0*feat_size, half_width, half_depth).into()) )); - driver.add_measurement(meas::MagneticStrength( + driver.add_measurement(meas::MagneticStrengthAt( Meters((half_width + ferro_inner_rad + 2.0*feat_size, half_width, half_depth).into()) )); - driver.add_measurement(meas::Magnetization( + driver.add_measurement(meas::MagnetizationAt( Meters((half_width + ferro_inner_rad + 1.0*feat_size, half_width, half_depth).into()) )); - driver.add_measurement(meas::MagneticFlux( + driver.add_measurement(meas::MagneticFluxAt( Meters((half_width + ferro_inner_rad + 1.0*feat_size, half_width, half_depth).into()) )); - driver.add_measurement(meas::MagneticStrength( + driver.add_measurement(meas::MagneticStrengthAt( Meters((half_width + ferro_inner_rad + 1.0*feat_size, half_width, half_depth).into()) )); - driver.add_measurement(meas::Magnetization( + driver.add_measurement(meas::MagnetizationAt( Meters((half_width + 0.5 * (ferro_inner_rad + ferro_outer_rad), half_width, half_depth).into()) )); - driver.add_measurement(meas::MagneticFlux( + driver.add_measurement(meas::MagneticFluxAt( Meters((half_width + 0.5 * (ferro_inner_rad + ferro_outer_rad), half_width, half_depth).into()) )); - driver.add_measurement(meas::MagneticStrength( + driver.add_measurement(meas::MagneticStrengthAt( Meters((half_width + 0.5 * (ferro_inner_rad + ferro_outer_rad), half_width, half_depth).into()) )); diff --git a/examples/wrapped_torus.rs b/examples/wrapped_torus.rs index 762db88..2fba8ba 100644 --- a/examples/wrapped_torus.rs +++ b/examples/wrapped_torus.rs @@ -1,11 +1,11 @@ use coremem::{Driver, Flt, mat, meas}; use coremem::geom::{Index, Meters, Torus}; -use coremem::stim::{CurlStimulus, Sinusoid1}; +use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying1 as _}; fn main() { coremem::init_logging(); let feat_size = 10e-6; // feature size - let duration = 3e-9; + let duration = 2e-9; let width = 2200e-6; let depth = 1800e-6; let buffer = 200e-6; @@ -13,8 +13,9 @@ fn main() { let ferro_minor = 40e-6; let wire_minor = 20e-6; let wire_major = 100e-6; - let peak_current = 2e2; - let current_duration = 0.6e-9; // half-wavelength of the sine wave + let peak_current = 1e4; + let current_duration = 0.5e-9; // half-wavelength of the sine wave + let current_break = 0.5e-9; // time between 'set' pulse and 'clear' pulse let conductivity = 1.0e9; let from_m = |m| (m/feat_size) as u32; @@ -26,8 +27,8 @@ fn main() { let depth_px = from_m(depth); let size_px = Index((width_px, width_px, depth_px).into()); let mut driver = Driver::new(size_px, feat_size); - driver.set_steps_per_frame(400); - let base = "wrapped_torus-8"; + driver.set_steps_per_frame(2000); + let base = "wrapped_torus-9"; let ferro_region = Torus::new_xy(Meters((half_width, half_width, half_depth).into()), ferro_major, ferro_minor); let drive_region = Torus::new_xz(Meters((half_width - ferro_major, half_width, half_depth).into()), wire_major, wire_minor); let sense_region = Torus::new_xz(Meters((half_width + ferro_major, half_width, half_depth).into()), wire_major, wire_minor); @@ -41,19 +42,33 @@ fn main() { println!("boundary: {}um; {}um", m_to_um(boundary_xy), m_to_um(boundary_z)); driver.add_upml_boundary(Meters((boundary_xy, boundary_xy, boundary_z).into())); + let pos_wave = Sinusoid1::from_wavelength(peak_current, current_duration * 2.0) + .half_cycle(); + let neg_wave = Sinusoid1::from_wavelength(-peak_current, current_duration * 2.0) + .half_cycle() + .shifted(current_duration + current_break); + driver.add_stimulus(CurlStimulus::new( drive_region.clone(), - Sinusoid1::from_wavelength(peak_current, current_duration * 2.0), + pos_wave, drive_region.center(), - drive_region.axis(), + drive_region.axis() + )); + driver.add_stimulus(CurlStimulus::new( + drive_region.clone(), + neg_wave, + drive_region.center(), + drive_region.axis() )); driver.add_measurement(meas::CurrentLoop::new("sense", sense_region.clone())); driver.add_measurement(meas::Current::new("sense", sense_region.clone())); + driver.add_measurement(meas::Magnetization::new("mem", ferro_region.clone())); + driver.add_measurement(meas::MagneticFlux::new("mem", ferro_region.clone())); driver.add_measurement(meas::CurrentLoop::new("drive", drive_region.clone())); driver.add_measurement(meas::Current::new("drive", drive_region.clone())); - let prefix = format!("{}/{}-flt{}-{}-feat{}um-{}mA-{}ps--radii{}um-{}um-{}um-{}um", + let prefix = format!("out/{}/{}-flt{}-{}-feat{}um-{}mA-{}ps--radii{}um-{}um-{}um-{}um", base, base, std::mem::size_of::() * 8, @@ -66,8 +81,7 @@ fn main() { m_to_um(wire_major), m_to_um(wire_minor), ); - let _ = std::fs::create_dir(base); - let _ = std::fs::create_dir(&prefix); + let _ = std::fs::create_dir_all(&prefix); driver.add_serializer_renderer(&*format!("{}/frame-", prefix)); diff --git a/src/bin/decimate.rs b/src/bin/decimate.rs index 261e97c..bcf77e1 100644 --- a/src/bin/decimate.rs +++ b/src/bin/decimate.rs @@ -1,4 +1,4 @@ -use coremem::post::{Loader, Viewer}; +use coremem::post::Loader; use std::fs; use std::path::PathBuf; use structopt::StructOpt; diff --git a/src/meas.rs b/src/meas.rs index 0061555..6385098 100644 --- a/src/meas.rs +++ b/src/meas.rs @@ -76,14 +76,14 @@ impl Current { } #[derive(Default)] -struct CurrentSample(usize, Flt, Vec3); -impl std::iter::Sum for CurrentSample { +struct FieldSample(usize, Flt, Vec3); +impl std::iter::Sum for FieldSample { fn sum(iter: I) -> Self where I: Iterator { - let mut s = CurrentSample::default(); - for CurrentSample(a, b, c) in iter { - s = CurrentSample(s.0 + a, s.1 + b, s.2 + c) + let mut s = FieldSample::default(); + for FieldSample(a, b, c) in iter { + s = FieldSample(s.0 + a, s.1 + b, s.2 + c) } s } @@ -92,13 +92,13 @@ impl std::iter::Sum for CurrentSample { #[typetag::serde] impl AbstractMeasurement for Current { fn eval(&self, state: &dyn GenericSim) -> String { - let CurrentSample(volume, current_mag, current_vec) = sum_over_region(state, &*self.region, |coord, _cell| { + let FieldSample(volume, current_mag, current_vec) = sum_over_region(state, &*self.region, |coord, _cell| { let current = state.current(coord); - CurrentSample(1, current.mag(), current) + FieldSample(1, current.mag(), current) }); let mean_current_mag = current_mag / (volume as Flt); let mean_current_vec = current_vec / (volume as Flt); - format!("I({}): {:.2e}, avg ({:.2e}, {:.2e}, {:.2e})", + format!("I/cell({}): {:.2e} ({:.2e}, {:.2e}, {:.2e})", self.name, mean_current_mag, mean_current_vec.x(), @@ -126,13 +126,13 @@ impl CurrentLoop { #[typetag::serde] impl AbstractMeasurement for CurrentLoop { fn eval(&self, state: &dyn GenericSim) -> String { - let CurrentSample(volume, directed_current, _current_vec) = sum_over_region(state, &self.region, |coord, _cell| { + let FieldSample(volume, directed_current, _current_vec) = sum_over_region(state, &self.region, |coord, _cell| { let normal = self.region.axis(); let to_coord = *coord - *self.region.center(); let tangent = normal.cross(to_coord).norm(); let current = state.current(coord); let directed_current = current.dot(tangent); - CurrentSample(1, directed_current, current) + FieldSample(1, directed_current, current) }); let mean_directed_current = directed_current / (volume as Flt); let cross_section = self.region.cross_section() / (state.feature_size() * state.feature_size()); @@ -141,6 +141,64 @@ impl AbstractMeasurement for CurrentLoop { } } +/// mean M over a region +#[derive(Clone, Serialize, Deserialize)] +pub struct MagneticFlux { + name: String, + region: Box, +} + +impl MagneticFlux { + pub fn new(name: &str, r: R) -> Self { + Self { + name: name.into(), + region: Box::new(r) + } + } +} + +#[typetag::serde] +impl AbstractMeasurement for MagneticFlux { + fn eval(&self, state: &dyn GenericSim) -> String { + let FieldSample(volume, _directed_mag, mag_vec) = sum_over_region(state, &*self.region, |_coord, cell| { + let b = cell.b(); + let mag = b.mag(); + FieldSample(1, mag, b) + }); + let mean_mag = mag_vec / (volume as Flt); + format!("B({}): ({:.2e}, {:.2e}, {:.2e})", self.name, mean_mag.x(), mean_mag.y(), mean_mag.z()) + } +} + +/// mean B over a region +#[derive(Clone, Serialize, Deserialize)] +pub struct Magnetization { + name: String, + region: Box, +} + +impl Magnetization { + pub fn new(name: &str, r: R) -> Self { + Self { + name: name.into(), + region: Box::new(r) + } + } +} + +#[typetag::serde] +impl AbstractMeasurement for Magnetization { + fn eval(&self, state: &dyn GenericSim) -> String { + let FieldSample(volume, _directed_mag, mag_vec) = sum_over_region(state, &*self.region, |_coord, cell| { + let m = cell.mat().m(); + let mag = m.mag(); + FieldSample(1, mag, m) + }); + let mean_mag = mag_vec / (volume as Flt); + format!("M({}): ({:.2e}, {:.2e}, {:.2e})", self.name, mean_mag.x(), mean_mag.y(), mean_mag.z()) + } +} + fn loc(v: Meters) -> String { let (x, y, z): (Flt, Flt, Flt) = (*v * 1e6).into(); format!("({}, {}, {}) um", x as i32, y as i32, z as i32) @@ -148,10 +206,10 @@ fn loc(v: Meters) -> String { /// M #[derive(Clone, Serialize, Deserialize)] -pub struct Magnetization(pub Meters); +pub struct MagnetizationAt(pub Meters); #[typetag::serde] -impl AbstractMeasurement for Magnetization { +impl AbstractMeasurement for MagnetizationAt { fn eval(&self, state: &dyn GenericSim) -> String { let m = state.sample(self.0).mat().m(); format!("M{}: ({:.2e}, {:.2e}, {:.2e})", loc(self.0), m.x(), m.y(), m.z()) @@ -160,10 +218,10 @@ impl AbstractMeasurement for Magnetization { /// B #[derive(Clone, Serialize, Deserialize)] -pub struct MagneticFlux(pub Meters); +pub struct MagneticFluxAt(pub Meters); #[typetag::serde] -impl AbstractMeasurement for MagneticFlux { +impl AbstractMeasurement for MagneticFluxAt { fn eval(&self, state: &dyn GenericSim) -> String { let b = state.sample(self.0).b(); format!("B{}: ({:.2e}, {:.2e}, {:.2e})", loc(self.0), b.x(), b.y(), b.z()) @@ -172,10 +230,10 @@ impl AbstractMeasurement for MagneticFlux { /// H #[derive(Clone, Serialize, Deserialize)] -pub struct MagneticStrength(pub Meters); +pub struct MagneticStrengthAt(pub Meters); #[typetag::serde] -impl AbstractMeasurement for MagneticStrength { +impl AbstractMeasurement for MagneticStrengthAt { fn eval(&self, state: &dyn GenericSim) -> String { let h = state.sample(self.0).h(); format!("H{}: ({:.2e}, {:.2e}, {:.2e})", loc(self.0), h.x(), h.y(), h.z()) diff --git a/src/render.rs b/src/render.rs index 498b606..8e936d5 100644 --- a/src/render.rs +++ b/src/render.rs @@ -93,13 +93,16 @@ impl<'a> RenderSteps<'a> { 5.0 } }); - me.render_scalar_field(100.0, true, 0, |cell| cell.mat().m().mag()); + //me.render_scalar_field(100.0, true, 0, |cell| cell.mat().m().mag()); if false { me.render_b_z_field(); me.render_e_xy_field(); - } else { + } else if false { me.render_e_z_field(); me.render_b_xy_field(); + } else { + me.render_b(); + me.render_current(); } me.render_measurements(); me.im @@ -124,7 +127,7 @@ impl<'a> RenderSteps<'a> { ////////////// Ex/Ey/Bz configuration //////////// fn render_b_z_field(&mut self) { - self.render_scalar_field(1.0e-4, true, 1, |cell| cell.b().z()); + self.render_scalar_field(1.0e-4, true, 1, |cell| cell.b().z()); } fn render_e_xy_field(&mut self) { self.render_vector_field(Rgb([0xff, 0xff, 0xff]), 100.0, |cell| cell.e().xy()); @@ -133,10 +136,19 @@ impl<'a> RenderSteps<'a> { cell.e().elem_mul(cell.mat().conductivity()).xy() }); } + ////////////// Magnitude configuration ///////////// + fn render_b(&mut self) { + self.render_scalar_field(1.0e-3, false, 1, |cell| cell.b().mag()); + } + fn render_current(&mut self) { + self.render_scalar_field(1.0e1, false, 0, |cell| { + cell.e().elem_mul(cell.mat().conductivity()).mag() + }); + } ////////////// Bx/By/Ez configuration //////////// fn render_e_z_field(&mut self) { - self.render_scalar_field(1e4, true, 1, |cell| cell.e().z()); + self.render_scalar_field(1e4, true, 1, |cell| cell.e().z()); } fn render_b_xy_field(&mut self) { self.render_vector_field(Rgb([0xff, 0xff, 0xff]), 1.0e-9, |cell| cell.b().xy());