125 lines
5.5 KiB
Rust
125 lines
5.5 KiB
Rust
use coremem::{Driver, mat, meas, SimState};
|
|
use coremem::geom::{Cube, Index, InvertedRegion, Meters, Torus, Union};
|
|
use coremem::real::R64 as Real;
|
|
use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
|
|
use coremem::units::Seconds;
|
|
|
|
fn main() {
|
|
coremem::init_logging();
|
|
let feat_size = 10e-6f32; // feature size
|
|
let duration = 6e-9;
|
|
let width = 2200e-6;
|
|
let depth = 1800e-6;
|
|
let buffer = 200e-6;
|
|
let ferro_major = 320e-6;
|
|
let ferro_minor = 60e-6;
|
|
let wire_minor = 40e-6;
|
|
let wire_major = 160e-6;
|
|
let peak_current = 5e11;
|
|
let current_duration = 1.0e-11; // half-wavelength of the sine wave
|
|
let current_break = 0.5e-11; // time between 'set' pulse and 'clear' pulse
|
|
let conductivity = 1.0e9f32;
|
|
let steps_per_frame = 400;
|
|
|
|
let from_m = |m: f32| (m/feat_size).round() as u32;
|
|
let m_to_um = |m: f32| (m * 1e6).round() as u32;
|
|
let half_width = width * 0.5;
|
|
let half_depth = depth * 0.5;
|
|
|
|
let width_px = from_m(width);
|
|
let depth_px = from_m(depth);
|
|
let size_px = Index((width_px, width_px, depth_px).into());
|
|
let mut driver: Driver<SimState<Real>> = Driver::new(size_px, feat_size);
|
|
driver.set_steps_per_stim(1);
|
|
let base = "minimal_torus-6";
|
|
let ferro_region = Torus::new_xy(Meters::new(half_width, half_width, half_depth), ferro_major, ferro_minor);
|
|
let drive_region = Torus::new_xz(Meters::new(half_width - ferro_major, half_width, half_depth), wire_major, wire_minor);
|
|
let sense_region = Torus::new_xz(Meters::new(half_width + ferro_major, half_width, half_depth), wire_major, wire_minor);
|
|
|
|
let boundary_xy = half_width - ferro_major - ferro_minor - buffer;
|
|
let boundary_z = half_depth - wire_major - wire_minor - buffer;
|
|
let boundary_lower = Meters::new(boundary_xy, boundary_xy, boundary_z);
|
|
let boundary_upper = Meters::new(width - boundary_xy, width - boundary_xy, depth - boundary_z);
|
|
println!("boundary: {}um; {}um", m_to_um(boundary_xy), m_to_um(boundary_z));
|
|
let boundary_region = InvertedRegion::new(Cube::new(boundary_lower, boundary_upper));
|
|
|
|
let vacuum_region = InvertedRegion::new(Union::new()
|
|
.with(ferro_region.clone())
|
|
.with(drive_region.clone())
|
|
.with(sense_region.clone())
|
|
.with(boundary_region.clone())
|
|
);
|
|
|
|
driver.fill_region(&ferro_region, mat::db::minimal_square_ferrite());
|
|
driver.fill_region(&drive_region, mat::IsomorphicConductor::new(conductivity));
|
|
driver.fill_region(&sense_region, mat::IsomorphicConductor::new(conductivity));
|
|
// driver.add_pml_boundary(Meters((boundary_xy, boundary_xy, boundary_z).into()));
|
|
driver.add_classical_boundary_explicit::<Real, _>(Meters::new(boundary_xy, boundary_xy, boundary_z));
|
|
|
|
// J=\sigma E
|
|
// dJ/dt = \sigma dE/dT
|
|
// dE/dt = dJ/dt / \sigma
|
|
// dE/dt = dI/dt / (A*\sigma)
|
|
// if I = k*sin(w t) then dE/dt = k*w sin(w t) / (A*\sigma)
|
|
// i.e. dE/dt is proportional to I/(A*\sigma), multiplied by w (or, divided by wavelength)
|
|
let peak_stim = peak_current/current_duration / (drive_region.cross_section() * conductivity);
|
|
let pos_wave = Sinusoid::from_wavelength(peak_stim as _, current_duration * 2.0)
|
|
.half_cycle();
|
|
|
|
let neg_wave = Sinusoid::from_wavelength(-peak_stim as _, current_duration * 2.0)
|
|
.half_cycle()
|
|
.shifted(current_duration + current_break);
|
|
|
|
driver.add_stimulus(CurlStimulus::new(
|
|
drive_region.clone(),
|
|
pos_wave,
|
|
drive_region.center(),
|
|
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::Energy::new("sense", sense_region.clone()));
|
|
driver.add_measurement(meas::Energy::new("sense", sense_region.clone()));
|
|
|
|
driver.add_measurement(meas::CurrentLoop::new("drive", drive_region.clone()));
|
|
driver.add_measurement(meas::Current::new("drive", drive_region.clone()));
|
|
driver.add_measurement(meas::Energy::new("drive", drive_region.clone()));
|
|
driver.add_measurement(meas::Power::new("drive", drive_region.clone()));
|
|
|
|
driver.add_measurement(meas::MagneticLoop::new("mem", ferro_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::Energy::new("mem", ferro_region.clone()));
|
|
driver.add_measurement(meas::Power::new("mem", ferro_region.clone()));
|
|
driver.add_measurement(meas::Energy::new("boundary", boundary_region.clone()));
|
|
driver.add_measurement(meas::Power::new("boundary", boundary_region.clone()));
|
|
driver.add_measurement(meas::Energy::new("vacuum", vacuum_region.clone()));
|
|
driver.add_measurement(meas::Power::new("vacuum", vacuum_region.clone()));
|
|
|
|
let prefix = format!("out/{}/{}-flt{}-{}-feat{}um-{}mA-{}ps--radii{}um-{}um-{}um-{}um",
|
|
base,
|
|
base,
|
|
std::mem::size_of::<Real>() * 8,
|
|
*size_px,
|
|
m_to_um(feat_size),
|
|
(peak_current * 1e3).round() as i64,
|
|
(current_duration * 1e12).round() as i64,
|
|
m_to_um(ferro_major),
|
|
m_to_um(ferro_minor),
|
|
m_to_um(wire_major),
|
|
m_to_um(wire_minor),
|
|
);
|
|
let _ = std::fs::create_dir_all(&prefix);
|
|
|
|
driver.add_serializer_renderer(&*format!("{}/frame-", prefix), steps_per_frame, None);
|
|
|
|
driver.step_until(Seconds(duration));
|
|
}
|