CI / Test (macos-latest) (push) Canceled after 0s
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
CI / Clippy Check (push) Canceled after 0s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Build (ubuntu-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Build CPU-Only (Explicit) (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s
CI / Python Bindings (maturin) (macos-latest) (push) Canceled after 0s
CI / Python Bindings (maturin) (ubuntu-latest) (push) Canceled after 0s
CI / WASM Build + Size Check (push) Canceled after 0s
CI / Distributed Training Tests (push) Canceled after 0s
CI / CI Success (push) Canceled after 0s
Documentation / Build API Documentation (push) Canceled after 0s
Background = the embedded solver with a mask from the overlap classification
(embedded/{mod,projection}.rs: module split, projection's solve/apply halves,
set_overlap, fringe p' Dirichlet by elimination into extra_diag/rhs, anchor
dropped, set_inner_stop_factor, phase API begin_step/solve_correction/
apply_correction/end_step; advance rebuilt on the phases — every suite digit-
identical, FSI2 default line-for-line). Patch = the curvilinear solver with an
acceptor ring (set_side_velocity; set_acceptor_ring/stamp_acceptors/
set_acceptor_correction; acceptor Dirichlet by elimination into
PressureSystem.links so the BiCGSTAB stop stays in flux units — identity rows
measured unconverged at 2431 iterations; same phase API). overset/overlap.rs:
OverlapMap — hole/fringe/active from the patch's own indices (hole = body or
k <= nn-1-overlap_rows, DEFAULT_OVERLAP_ROWS = 4 from the 2.9 h depth budget),
dual-quad inverse-bilinear donors patch→fringe, lattice donors →acceptors,
both invariants asserted, mass-defect measures. overset/mod.rs:
OversetPisoSolver — advance (exchange rebuilt BEFORE the predictors from the
previous corrected field), alternating Schwarz on the acceptor p' vector with
Anderson(3) (plain Schwarz measured 0.82/round: floating patch, Neumann wall)
and the previous step's vector as warm start (1 round/corrector at steady
state), stop relative to the STEP's p' scale (the MG absolute stop is
1e-9/dt² in pressure — the whole second correction), set_patch_mesh,
snapshot/restore carrying the warm-start vector.
Gates: overlap linear-exact 1e-13, quadratic orders 1.96/1.99 (acceptors),
1.40/1.91 (fringe); half-couplings: patch with exact acceptors Stokes 2.07/1.98
+ 2.08/1.98, upwind 0.84/0.84, background with exact fringe 7.86e-3/2.90e-3/
1.09e-3 (1.44/1.41); two-mesh MMS n=32/64: background 8.717e-3/4.207e-3 (1.03x/
0.97x the embedded circle), patch 1.322e-2/6.904e-3 (1.5-1.6x), orders 1.05/
0.94, patch div <= 5e-13, overlap mass defect 3.6e-3 -> 8.2e-4 of the overlap
flux (under the registered 1e-3 from n=64; disclosed at 32); motion: stationary
patch through set_patch_mesh bit-identical, snapshot/restore with a pending mesh
bit-identical, translating phantom circle 1.22x/1.19x the static level over
4.5 cells. Inherited, disclosed: poisson_equivalence's no-body multigrid pin
fails by 3.9e-9 at d46fb0b (M1's commit; verified in a clean worktree).
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01X2GmJXeQ2njUecEKiJZ1G2
89 lines
3.3 KiB
Rust
89 lines
3.3 KiB
Rust
//! A-P2, step S4 (`docs/overset_metal_campaign.md` §5.9): the two-mesh
|
||
//! manufactured solution on the static overset.
|
||
//!
|
||
//! Unit square (closed box, exact Dirichlet velocity on every side, the
|
||
//! `mms_piso.rs` field and source, upwind) with the phantom circle at
|
||
//! (0.6, 0.45) r = 0.2 as the patch's inner wall (the exact velocity as its
|
||
//! Dirichlet), the skewed stretched annulus to r = 0.354 as the patch
|
||
//! (outer spacing = h), background n = 32 / 64 / 128. Gates: the
|
||
//! background's L2 on its fluid faces within 1.5× the embedded-circle
|
||
//! ladder (8.489e-3 / 4.341e-3 at n = 32 / 64) and first order to 128; the
|
||
//! patch's L2 on its interior cells ≤ 2× the background's at equal h and
|
||
//! first order; both divergence-free on their equation-carrying cells;
|
||
//! Schwarz rounds per corrector recorded; the overlap mass defect per step,
|
||
//! both sides, relative to the overlap flux scale — measured first.
|
||
|
||
mod overset_common;
|
||
|
||
use overset_common::{march, orders};
|
||
use rtx_cfd::CfdResult;
|
||
|
||
#[tokio::test]
|
||
async fn two_mesh_mms_recovers_the_single_mesh_levels_on_both_meshes() -> CfdResult<()> {
|
||
let reference = [8.489e-3, 4.341e-3];
|
||
let only: Option<usize> = std::env::var("RTX_OVERSET_N")
|
||
.ok()
|
||
.and_then(|v| v.parse().ok());
|
||
let tol: f64 = std::env::var("RTX_OVERSET_SCHWARZ")
|
||
.ok()
|
||
.and_then(|v| v.parse().ok())
|
||
.unwrap_or(1e-3);
|
||
let mut bg = Vec::new();
|
||
let mut patch = Vec::new();
|
||
for (idx, n) in [32usize, 64, 128].into_iter().enumerate() {
|
||
if only.is_some_and(|o| o != n) {
|
||
continue;
|
||
}
|
||
let m = march(n, tol).await?;
|
||
println!(
|
||
" overset n={n}: L2 background {:.6e} patch {:.6e} ({} steps); Schwarz rounds mean {:.2} max {} (failures {}); \
|
||
worst bg residual {:.2e}, patch div {:.2e}; overlap mass defect (of the overlap flux) at steady state bg {:.3e} patch {:.3e}, worst over the transient bg {:.3e} patch {:.3e}",
|
||
m.l2_background,
|
||
m.l2_patch,
|
||
m.steps,
|
||
m.mean_rounds,
|
||
m.max_rounds,
|
||
m.schwarz_failures,
|
||
m.worst_bg_residual,
|
||
m.worst_patch_div_rel,
|
||
m.final_defect_bg_rel,
|
||
m.final_defect_patch_rel,
|
||
m.worst_defect_bg_rel,
|
||
m.worst_defect_patch_rel
|
||
);
|
||
if let Some(r) = reference.get(idx) {
|
||
assert!(
|
||
m.l2_background < 1.5 * r,
|
||
"n = {n}: background L2 {:.3e} > 1.5x embedded circle {r:.3e}",
|
||
m.l2_background
|
||
);
|
||
}
|
||
assert!(
|
||
m.l2_patch < 2.0 * m.l2_background,
|
||
"n = {n}: patch L2 {:.3e} > 2x background {:.3e}",
|
||
m.l2_patch,
|
||
m.l2_background
|
||
);
|
||
assert!(
|
||
m.worst_patch_div_rel < 1e-9,
|
||
"patch divergence {:.3e}",
|
||
m.worst_patch_div_rel
|
||
);
|
||
bg.push(m.l2_background);
|
||
patch.push(m.l2_patch);
|
||
}
|
||
if only.is_none() {
|
||
let (ob, op) = (orders(&bg), orders(&patch));
|
||
println!(" overset orders: background {ob:?}, patch {op:?}");
|
||
assert!(
|
||
ob.iter().all(|&x| (0.75..1.3).contains(&x)),
|
||
"background orders {ob:?}"
|
||
);
|
||
assert!(
|
||
op.iter().all(|&x| (0.7..1.6).contains(&x)),
|
||
"patch orders {op:?}"
|
||
);
|
||
}
|
||
Ok(())
|
||
}
|