R8-f: the operator-route wall load on the device (RTX_E3_LOADS_DEVICE=1, default off)
e3_loads.cu evaluates every summand of Mask::cut_wall_force (cells' p W, fluid faces' implicit wall shear) and cut_wall_exchange_parts (diffusive and convective exchange with prescribed neighbours) on the device from the predictor set of the device mask, in the host's expression order with FMA off; the summands are appended as records, downloaded once per pass, sorted into the host's loop order and summed sequentially on the host, so the totals are the host route's to the bit. Records replay into the R8-a load sink (exact zeros dropped; sum-invariant) and into R8-c's WallLoad shape. DeviceStep::cut_wall_loads_device / cut_wall_force_device / check_wall_loads (the G1 instrument, RTX_E3_LOADS_CHECK=1 in the flag test). The flag test and the R8-a harness take the device route under the knob; default paths untouched. cut.rs: E3CutPtrs and DeviceCut::ptrs pub(super). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
171da41ed1
commit
2d5ffbabdd
@@ -650,23 +650,80 @@ fn flag_wake_on_the_device() {
|
||||
let (mut drag_sum, mut lift_min, mut lift_max, mut samples) =
|
||||
(0.0, f64::INFINITY, f64::NEG_INFINITY, 0usize);
|
||||
let mut worst_residual = 0.0_f64;
|
||||
// R8-f: `RTX_E3_LOADS_DEVICE=1` takes the operator route on the device
|
||||
// (the per-span and whole-body totals below); `RTX_E3_LOADS_CHECK=1`
|
||||
// checks the device route against the host on EVERY step (both the
|
||||
// slab's planes and the whole body), bit for bit.
|
||||
let loads_device =
|
||||
rtx_cfd::solvers::incompressible::embedded3::step::device::loads_device_enabled();
|
||||
let loads_check = std::env::var("RTX_E3_LOADS_CHECK").is_ok_and(|v| v == "1");
|
||||
let mut loads_bad = 0usize;
|
||||
for step in 0..steps {
|
||||
let r = device.advance(dt);
|
||||
worst_residual = worst_residual.max(r.final_residual);
|
||||
assert!(r.final_residual.is_finite(), "death at step {step}");
|
||||
let t = device.solver.time();
|
||||
if loads_check {
|
||||
for (name, planes) in [("slab", Some(slab)), ("whole", None)] {
|
||||
let ck = device
|
||||
.check_wall_loads(RHO * NU, planes)
|
||||
.expect("R8-f: the device route is unsupported here");
|
||||
let ok =
|
||||
ck.totals_identical && ck.items_identical && ck.r8c_identical.unwrap_or(true);
|
||||
loads_bad += usize::from(!ok);
|
||||
println!(
|
||||
" loads check step {step} t {t:.5} {name}: {} — totals host ({:+.12e}, {:+.12e}, {:+.12e}) device ({:+.12e}, {:+.12e}, {:+.12e}); items host {} ({} non-zero) device {} {}; item sums x {:+.12e}/{:+.12e} y {:+.12e}/{:+.12e}; R8-c {}; device-order rel {:.2e}; host {:.1} ms device {:.1} ms",
|
||||
if ok { "IDENTICAL" } else { "DIFFERS" },
|
||||
ck.host[0],
|
||||
ck.host[1],
|
||||
ck.host[2],
|
||||
ck.device[0],
|
||||
ck.device[1],
|
||||
ck.device[2],
|
||||
ck.host_items,
|
||||
ck.host_nonzero,
|
||||
ck.device_items,
|
||||
if ck.items_identical {
|
||||
"identical"
|
||||
} else {
|
||||
"DIFFER"
|
||||
},
|
||||
ck.host_item_sum[0],
|
||||
ck.device_item_sum[0],
|
||||
ck.host_item_sum[1],
|
||||
ck.device_item_sum[1],
|
||||
match ck.r8c_identical {
|
||||
Some(true) => "identical",
|
||||
Some(false) => "DIFFERS",
|
||||
None => "n/a",
|
||||
},
|
||||
ck.device_order_rel,
|
||||
ck.host_ms,
|
||||
ck.device_ms
|
||||
);
|
||||
}
|
||||
}
|
||||
let sample = (step + 1) % 10 == 0 || step + 1 == steps;
|
||||
let phase_due = vtk_dir.is_some()
|
||||
&& t >= last_period_start + next_phase as f64 * period / phases as f64
|
||||
&& next_phase < total_phases;
|
||||
if sample || phase_due {
|
||||
let dev = loads_device.then(|| {
|
||||
(
|
||||
device.cut_wall_force_device(RHO * NU, Some(slab)),
|
||||
device.cut_wall_force_device(RHO * NU, None),
|
||||
)
|
||||
});
|
||||
device.download(&mut field);
|
||||
let solver = &device.solver;
|
||||
let mask = solver.mask().expect("mask");
|
||||
let body = solver.body().expect("body");
|
||||
let fs = mask
|
||||
.cut_wall_force_per_span(body, &field, RHO * NU, t, slab)
|
||||
.expect("wall");
|
||||
let fs = match dev {
|
||||
Some((Some(v), _)) => v,
|
||||
_ => mask
|
||||
.cut_wall_force_per_span(body, &field, RHO * NU, t, slab)
|
||||
.expect("wall"),
|
||||
};
|
||||
// The reconstructed wall route on the same slab, per span.
|
||||
let fr = mask
|
||||
.cut_wall_force_reconstructed(body, &field, RHO * NU, t, Some(slab))
|
||||
@@ -675,9 +732,12 @@ fn flag_wake_on_the_device() {
|
||||
[v[0] / lz, v[1] / lz, v[2] / lz]
|
||||
})
|
||||
.expect("reconstructed");
|
||||
let ft = mask
|
||||
.cut_wall_force(body, &field, RHO * NU, t)
|
||||
.expect("wall");
|
||||
let ft = match dev {
|
||||
Some((_, Some(v))) => v,
|
||||
_ => mask
|
||||
.cut_wall_force(body, &field, RHO * NU, t)
|
||||
.expect("wall"),
|
||||
};
|
||||
if sample {
|
||||
samples_seen += 1;
|
||||
}
|
||||
@@ -910,4 +970,8 @@ fn flag_wake_on_the_device() {
|
||||
if let Some(t) = device.timers() {
|
||||
println!(" timers: {t:?}");
|
||||
}
|
||||
if loads_check {
|
||||
println!(" R8-f LOADS CHECK: {loads_bad} calls differ");
|
||||
assert_eq!(loads_bad, 0, "R8-f: the device route differs from the host");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user