Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 12 additions & 28 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 21 additions & 3 deletions crates/vcad-kernel-magnetostatic/src/filament.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,15 @@ impl Segment {
let n1 = r1.norm();
let n2 = r2.norm();
let perp = (r1 - tangent * t1).norm();
Some(SegmentGeometry { tangent, r1, n1, n2, t1, t2, perp })
Some(SegmentGeometry {
tangent,
r1,
n1,
n2,
t1,
t2,
perp,
})
}

/// Magnetic flux density at `p`, tesla.
Expand Down Expand Up @@ -180,12 +188,22 @@ pub struct Filament {
impl Filament {
/// A closed loop through `points`.
pub fn closed_loop(points: Vec<Vec3>, current_a: f64, wire_radius_m: f64) -> Self {
Self { points, current_a, wire_radius_m, closed: true }
Self {
points,
current_a,
wire_radius_m,
closed: true,
}
}

/// An open path through `points`.
pub fn open_path(points: Vec<Vec3>, current_a: f64, wire_radius_m: f64) -> Self {
Self { points, current_a, wire_radius_m, closed: false }
Self {
points,
current_a,
wire_radius_m,
closed: false,
}
}

/// Iterate the path's segments.
Expand Down
15 changes: 12 additions & 3 deletions crates/vcad-kernel-magnetostatic/src/iron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,18 @@ pub struct IronStack {
impl IronStack {
/// No iron — the pure free-space case.
pub fn none() -> Self {
Self { planes_z: Vec::new(), max_reflections: 0 }
Self {
planes_z: Vec::new(),
max_reflections: 0,
}
}

/// A single back-iron plane at `z_m`.
pub fn single(z_m: f64) -> Self {
Self { planes_z: vec![z_m], max_reflections: 1 }
Self {
planes_z: vec![z_m],
max_reflections: 1,
}
}

/// Two parallel planes — the usual rotor/stator back-iron sandwich.
Expand All @@ -81,7 +87,10 @@ impl IronStack {
/// confirm the achieved truncation with [`IronStack::tail_fraction`].
pub fn pair(z_a: f64, z_b: f64, max_reflections: usize) -> Self {
assert!(z_a != z_b, "iron planes must be distinct");
Self { planes_z: vec![z_a, z_b], max_reflections: max_reflections.max(1) }
Self {
planes_z: vec![z_a, z_b],
max_reflections: max_reflections.max(1),
}
}

/// Reflection depth that converges a balanced multi-pole rotor to ~1e-4.
Expand Down
7 changes: 5 additions & 2 deletions crates/vcad-kernel-magnetostatic/src/magnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl Polarity {

/// Alternating polarity for pole index `k`.
pub fn alternating(k: usize) -> Self {
if k % 2 == 0 {
if k.is_multiple_of(2) {
Polarity::North
} else {
Polarity::South
Expand Down Expand Up @@ -187,7 +187,10 @@ impl MagnetRing {

/// All bound-current loops for the ring.
pub fn to_filaments(&self, n_axial: usize) -> Vec<Filament> {
self.magnets.iter().flat_map(|m| m.to_filaments(n_axial)).collect()
self.magnets
.iter()
.flat_map(|m| m.to_filaments(n_axial))
.collect()
}

/// The ring rotated about z by `angle` radians — the rotor position sweep.
Expand Down
42 changes: 35 additions & 7 deletions crates/vcad-kernel-magnetostatic/src/vec3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ pub struct Vec3 {

impl Vec3 {
/// The zero vector.
pub const ZERO: Vec3 = Vec3 { x: 0.0, y: 0.0, z: 0.0 };
pub const ZERO: Vec3 = Vec3 {
x: 0.0,
y: 0.0,
z: 0.0,
};

/// Construct from components.
#[inline]
Expand All @@ -34,7 +38,11 @@ impl Vec3 {
/// Cylindrical construction: radius, azimuth (rad), height.
#[inline]
pub fn cylindrical(r: f64, theta: f64, z: f64) -> Self {
Self { x: r * theta.cos(), y: r * theta.sin(), z }
Self {
x: r * theta.cos(),
y: r * theta.sin(),
z,
}
}

/// Euclidean length.
Expand Down Expand Up @@ -82,7 +90,11 @@ impl Vec3 {
#[inline]
pub fn rotated_z(self, angle: f64) -> Vec3 {
let (s, c) = angle.sin_cos();
Vec3 { x: c * self.x - s * self.y, y: s * self.x + c * self.y, z: self.z }
Vec3 {
x: c * self.x - s * self.y,
y: s * self.x + c * self.y,
z: self.z,
}
}

/// Distance from the z axis.
Expand All @@ -96,31 +108,47 @@ impl std::ops::Add for Vec3 {
type Output = Vec3;
#[inline]
fn add(self, o: Vec3) -> Vec3 {
Vec3 { x: self.x + o.x, y: self.y + o.y, z: self.z + o.z }
Vec3 {
x: self.x + o.x,
y: self.y + o.y,
z: self.z + o.z,
}
}
}

impl std::ops::Sub for Vec3 {
type Output = Vec3;
#[inline]
fn sub(self, o: Vec3) -> Vec3 {
Vec3 { x: self.x - o.x, y: self.y - o.y, z: self.z - o.z }
Vec3 {
x: self.x - o.x,
y: self.y - o.y,
z: self.z - o.z,
}
}
}

impl std::ops::Mul<f64> for Vec3 {
type Output = Vec3;
#[inline]
fn mul(self, s: f64) -> Vec3 {
Vec3 { x: self.x * s, y: self.y * s, z: self.z * s }
Vec3 {
x: self.x * s,
y: self.y * s,
z: self.z * s,
}
}
}

impl std::ops::Neg for Vec3 {
type Output = Vec3;
#[inline]
fn neg(self) -> Vec3 {
Vec3 { x: -self.x, y: -self.y, z: -self.z }
Vec3 {
x: -self.x,
y: -self.y,
z: -self.z,
}
}
}

Expand Down
12 changes: 10 additions & 2 deletions crates/vcad-kernel-magnetostatic/tests/filament_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ fn on_axis_loop_matches_the_closed_form() {
b.z,
expected
);
assert!(b.x.abs().max(b.y.abs()) < 1e-9 * expected, "off-axis leakage at z={z}");
assert!(
b.x.abs().max(b.y.abs()) < 1e-9 * expected,
"off-axis leakage at z={z}"
);
}
}

Expand All @@ -72,7 +75,12 @@ fn off_axis_loop_matches_particle_crates_elliptic_integrals() {
// elliptic integrals, written for a different crate and a different purpose.
let r = 0.02;
let i = 5.0;
let coil = RingCoil { radius_m: r, z_m: 0.0, ampere_turns: i, wire_radius_m: 0.0 };
let coil = RingCoil {
radius_m: r,
z_m: 0.0,
ampere_turns: i,
wire_radius_m: 0.0,
};
let loop_ = ring_filament(r, 0.0, i, 4096);

for &(rho, z) in &[
Expand Down
10 changes: 8 additions & 2 deletions crates/vcad-kernel-magnetostatic/tests/iron_images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ fn two_plane_series_converges_for_a_balanced_rotor() {
let probe = Vec3::new(0.0225, 0.0, 0.0045);
let b_at = |depth: usize| -> Vec3 {
let stack = IronStack::pair(0.0, 0.0056, depth);
rotor.iter().flat_map(|s| stack.expand(s)).map(|f| f.b_at(probe)).sum()
rotor
.iter()
.flat_map(|s| stack.expand(s))
.map(|f| f.b_at(probe))
.sum()
};
let shallow = b_at(8);
let deep = b_at(IronStack::DEFAULT_REFLECTIONS);
Expand Down Expand Up @@ -176,7 +180,9 @@ fn two_planes_beat_one_which_beats_none() {

let none = b_with_iron(&IronStack::none(), &src, probe).z.abs();
let one = b_with_iron(&IronStack::single(0.0), &src, probe).z.abs();
let two = b_with_iron(&IronStack::pair(0.0, 0.0056, 12), &src, probe).z.abs();
let two = b_with_iron(&IronStack::pair(0.0, 0.0056, 12), &src, probe)
.z
.abs();

assert!(none < one, "one plane must beat none: {none} vs {one}");
assert!(one < two, "two planes must beat one: {one} vs {two}");
Expand Down
5 changes: 4 additions & 1 deletion crates/vcad-kernel-magnetostatic/tests/magnet_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ fn disc_magnet_matches_the_closed_form_on_axis() {
b.z,
want
);
assert!(b.x.abs().max(b.y.abs()) < 1e-6 * want.abs(), "off-axis leakage");
assert!(
b.x.abs().max(b.y.abs()) < 1e-6 * want.abs(),
"off-axis leakage"
);
}
}

Expand Down
Loading