embedded3 item 9b: the device step carries a static cut-cell mask (e3_cut.cu: cut predictor, apertured merged continuity with the fold, owner-read corrections; device CG off-stencil links) — host = device to 2e-10 (CFD1 cylinder nz 4) and 4e-14 (sphere) under tight tolerances
CI / Python Bindings (maturin) (macos-latest) (push) Blocked by required conditions
CI / Python Bindings (maturin) (ubuntu-latest) (push) Blocked by required conditions
CI / WASM Build + Size Check (push) Blocked by required conditions
CI / Distributed Training Tests (push) Blocked by required conditions
CI / CI Success (push) Blocked by required conditions
CI / Test (macos-latest) (push) Blocked by required conditions
CI / Test (ubuntu-latest) (push) Blocked by required conditions
CI / Build (macos-latest) (push) Waiting to run
CI / Clippy Check (push) Failing after 4s
Performance Benchmarks / Run Benchmarks (push) Failing after 5s
CI / Format Check (push) Failing after 4s
CI / Build (ubuntu-latest) (push) Failing after 4s
Documentation / Build User Guide (push) Successful in 5s
CI / Build CPU-Only (Explicit) (push) Failing after 56s
Documentation / Build API Documentation (push) Failing after 58s

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Omar Sobh
2026-09-17 17:22:52 -05:00
co-authored by Claude Fable 5.1
parent 0fa05f2056
commit 3b3d6c84c0
8 changed files with 982 additions and 3 deletions
@@ -176,3 +176,55 @@ fn the_singular_box_honours_the_anchor_and_the_mean() {
println!(" singular box without anchor: mean {mean:.3e} of {scale:.3e}");
assert!(mean.abs() <= 1e-13 * scale, "mean {mean:.3e}");
}
/// Item 9b: off-stencil links (the virtually merged small cells) on the
/// device operator — the channel with 60 symmetric links between active
/// cells two apart; device = host PCG to the solve's accuracy.
#[test]
fn device_cg_carries_the_links() {
let mut problem = channel(96, 40, 8, true, true, 7);
let n = problem.nx * problem.ny * problem.nz;
let mut seed = 12345u64;
let mut links = Vec::new();
while links.len() < 60 {
seed = seed
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
let a = (seed >> 20) as usize % n;
let b = a + 2;
if b < n && problem.active[a] && problem.active[b] && a % problem.nx + 2 < problem.nx {
links.push((a, b, 0.7 * problem.ae[a].max(problem.aw[a])));
}
}
problem.links = links;
problem.validate().expect("linked problem");
let params = MultigridParameters {
smoother: MgSmoother::RedBlack,
..MultigridParameters::default()
};
let tol = 1e-9 * problem.rhs.iter().map(|r| r.abs()).sum::<f64>();
let mut p_host = vec![0.0; n];
let host = solve_pcg(&problem, &mut p_host, &params, tol, None);
let mut p_dev = vec![0.0; n];
let mut cache = DevicePcgCache::default();
let dev = solve_pcg_device_cached(&problem, &mut p_dev, &params, tol, None, &mut cache);
let scale = p_host.iter().fold(0.0_f64, |m, &x| m.max(x.abs()));
let diff = p_host
.iter()
.zip(&p_dev)
.fold(0.0_f64, |m, (&a, &b)| m.max((a - b).abs()));
println!(
" linked channel (60 links): host {} it residual {:.3e}; device {} it residual {:.3e}; max |Δp| {:.3e} on {:.3e}",
host.iterations, host.residual, dev.iterations, dev.residual, diff, scale
);
assert!(host.converged && dev.converged);
assert!(
diff < 1e-8 * scale,
"device with links differs from the host: {diff:.3e} on {scale:.3e}"
);
assert!(
problem.residual_l1(&p_dev) < 2.0 * tol,
"device residual on the linked operator {:.3e}",
problem.residual_l1(&p_dev)
);
}