mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-04 11:05:56 +00:00
geom: the patches about a centre are solved the same to the last bit on every run
The block solve kept its sparse entries in hashed maps and summed the coupling of each patch's interior onto the shared unknowns in the map's order, which a hashed map draws afresh each time: the same loop filled to surfaces differing in their last bits, so a design read back rebuilt another cap (engine patch_continuity_and_points_cap_a_tube, "the same surface read back"). The entries are now in ordered maps; a fill twice of the tube's ring and of a hexagon about a centre are bit for bit the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2054,11 +2054,13 @@ impl Normal {
|
||||
/// form a banded block, eliminated exactly onto the shared unknowns (the spokes', the centre's,
|
||||
/// and any a row couples across patches) by their Schur complement, which is solved dense; the
|
||||
/// interiors then follow by back substitution. Entries are kept sparse until the blocks are
|
||||
/// known (callers add both halves of the symmetric matrix).
|
||||
/// known (callers add both halves of the symmetric matrix), in ordered maps: the eliminations
|
||||
/// sum them in their order, so a hashed map's order (another each run) would make the fill
|
||||
/// differ in its last bits from one run to the next, and a design read back another surface.
|
||||
struct BlockNormal {
|
||||
/// Each coordinate's patch when only one patch holds its point, else `None`.
|
||||
owner: Vec<Option<usize>>,
|
||||
entries: std::collections::HashMap<(usize, usize), f64>,
|
||||
entries: std::collections::BTreeMap<(usize, usize), f64>,
|
||||
}
|
||||
|
||||
impl BlockNormal {
|
||||
@@ -2077,7 +2079,7 @@ impl BlockNormal {
|
||||
let o = if let [p] = h.as_slice() { Some(*p) } else { None };
|
||||
[o; 3]
|
||||
});
|
||||
BlockNormal { owner: owner.collect(), entries: std::collections::HashMap::new() }
|
||||
BlockNormal { owner: owner.collect(), entries: std::collections::BTreeMap::new() }
|
||||
}
|
||||
|
||||
fn add(&mut self, r: usize, s: usize, v: f64) {
|
||||
@@ -2128,8 +2130,8 @@ impl BlockNormal {
|
||||
let m = shared.len();
|
||||
// The shared block, and per patch its block, its coupling to the shared unknowns.
|
||||
let mut s_mat = vec![0.0; m * m];
|
||||
let mut blocks: Vec<std::collections::HashMap<(usize, usize), f64>> = vec![std::collections::HashMap::new(); patches];
|
||||
let mut couple: Vec<std::collections::HashMap<(usize, usize), f64>> = vec![std::collections::HashMap::new(); patches];
|
||||
let mut blocks: Vec<std::collections::BTreeMap<(usize, usize), f64>> = vec![std::collections::BTreeMap::new(); patches];
|
||||
let mut couple: Vec<std::collections::BTreeMap<(usize, usize), f64>> = vec![std::collections::BTreeMap::new(); patches];
|
||||
for ((r, c), v) in std::mem::take(&mut self.entries) {
|
||||
let (or, oc) = (self.owner.get(r).copied().flatten(), self.owner.get(c).copied().flatten());
|
||||
let (pr, pc) = (place.get(r).copied().unwrap_or(0), place.get(c).copied().unwrap_or(0));
|
||||
|
||||
@@ -404,3 +404,27 @@ fn a_crown_fills_out_to_the_side_the_neighbours_face() {
|
||||
eprintln!("the window's middle {plain:.4} from the centre, crowned {out:.4}, crowned to inward neighbours {sunk:.4}");
|
||||
assert!(out > plain + 0.1 && sunk < plain - 0.1, "{plain} {out} {sunk}");
|
||||
}
|
||||
|
||||
/// The same loop fills to the same bits every time, about a centre and in a ring (a design is
|
||||
/// rebuilt on reading it back, and must come back the same surface).
|
||||
#[test]
|
||||
fn a_fill_is_the_same_to_the_last_bit_every_time() {
|
||||
let tube = circle_quarters(30.0, 10.0);
|
||||
let radial = |p: Vec3| (Vec3::new(p.x, p.y, 0.0).normalized().unwrap(), Vec3::Z);
|
||||
let s = IsoSpec { tol: 2e-5, ..spec() };
|
||||
let ring = |_: usize| iso_fill(&tube, &mut beside_by(&tube, radial), &s).unwrap();
|
||||
let corners: Vec<Vec3> =
|
||||
(0..6).map(|k| Vec3::new((k as f64 * 1.047).cos(), (k as f64 * 1.047).sin(), 0.0) * 20.0 + Vec3::Z * (k % 2) as f64).collect();
|
||||
let hexagon: Vec<IsoEdge> = (0..6)
|
||||
.map(|k| {
|
||||
let (a, b) = (corners[k], corners[(k + 1) % 6]);
|
||||
IsoEdge { degree: 2, knots: vec![0.0, 0.0, 0.0, 1.0, 1.0, 1.0], points: vec![a, (a + b) * 0.5 + Vec3::Z * 2.0, b], weights: None }
|
||||
})
|
||||
.collect();
|
||||
let mut g0 = |_k: usize, ts: &[f64]| -> Result<Vec<Option<Across>>, String> { Ok(vec![None; ts.len()]) };
|
||||
let centre = |g0: &mut dyn FnMut(usize, &[f64]) -> Result<Vec<Option<Across>>, String>| iso_fill(&hexagon, g0, &s).unwrap();
|
||||
let (a, b) = (ring(0), ring(1));
|
||||
assert_eq!(a.patches, b.patches, "the ring");
|
||||
let (a, b) = (centre(&mut g0), centre(&mut g0));
|
||||
assert_eq!(a.patches, b.patches, "about a centre");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user