embedded3: the cut mask's surface velocity uses the interpolant's distance and normal (one body call per face instead of eight); the device shares the surface-velocity tables between a step's phases; sphere gate re-read 0.965/0.961
CI / Build (macos-latest) (push) Waiting to run
CI / Test (macos-latest) (push) Blocked by required conditions
CI / Test (ubuntu-latest) (push) Blocked by required conditions
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
Performance Benchmarks / Run Benchmarks (push) Failing after 3s
CI / Clippy Check (push) Failing after 3s
CI / Build (ubuntu-latest) (push) Failing after 3s
CI / Format Check (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 8s
CI / Build CPU-Only (Explicit) (push) Failing after 55s
Documentation / Build API Documentation (push) Failing after 57s

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Omar Sobh
2026-09-17 19:48:15 -05:00
co-authored by Claude Fable 5.1
parent 11d856b3d4
commit 58a5501cef
2 changed files with 89 additions and 11 deletions
@@ -62,6 +62,8 @@ unsafe impl ValidAsZeroBits for E3CutPtrs {}
/// The static cut-cell mask on the device.
pub(super) struct DeviceCut {
/// The surface-velocity tables (kept to share between the phases).
ub_host: [Vec<f64>; 3],
a: [CudaSlice<f64>; 3],
d: [CudaSlice<f64>; 3],
ub: [CudaSlice<f64>; 3],
@@ -88,6 +90,18 @@ impl DeviceCut {
/// The tables of the solver's cut mask (`None` without one) for
/// `phase`, the surface velocities at the mask's time `t`.
pub(super) fn build(solver: &Solver, g: Grid, phase: Phase, t: f64) -> Option<Self> {
Self::build_with(solver, g, phase, t, None)
}
/// As [`Self::build`], reusing the surface-velocity tables of `shared`
/// (built at the same mask and time) instead of evaluating them.
pub(super) fn build_with(
solver: &Solver,
g: Grid,
phase: Phase,
t: f64,
shared: Option<&[Vec<f64>; 3]>,
) -> Option<Self> {
let mask = solver.mask()?;
let cut = mask.cut()?;
let body = solver.body()?;
@@ -130,10 +144,12 @@ impl DeviceCut {
(j as f64 + if c == 1 { 0.0 } else { 0.5 }) * h[1],
(k as f64 + if c == 2 { 0.0 } else { 0.5 }) * h[2],
];
ubc[idx] = if dists[c][idx].abs() <= band {
mask.surface_velocity_at(body, x, c, t)
} else {
0.0
ubc[idx] = match shared {
Some(sh) => sh[c][idx],
None if dists[c][idx].abs() <= band => {
mask.surface_velocity_at(body, x, c, t)
}
None => 0.0,
};
opc[idx] = i32::from(if projection {
match c {
@@ -198,10 +214,13 @@ impl DeviceCut {
fold_idx.extend_from_slice(list);
fold_ptr.push(fold_idx.len() as u32);
}
let ub_host = ub;
let ub_dev = [up_f(&ub_host[0]), up_f(&ub_host[1]), up_f(&ub_host[2])];
Some(Self {
ub_host,
a: [up_f(ap_u), up_f(ap_v), up_f(ap_w)],
d: [up_f(&cut.d_u), up_f(&cut.d_v), up_f(&cut.d_w)],
ub: [up_f(&ub[0]), up_f(&ub[1]), up_f(&ub[2])],
ub: ub_dev,
wall_flux: up_f(&wall_flux),
open: [up_i(&open[0]), up_i(&open[1]), up_i(&open[2])],
active: up_i(&active),
@@ -441,7 +460,9 @@ impl DeviceStep {
// The prescribed faces take the surface velocity (the host's
// end-of-step impose), and the next predictor's tables.
if self.solver.is_moving() {
self.cut = DeviceCut::build(&self.solver, g, Phase::Predictor, t_new);
let shared = self.cut.take().map(|c| c.ub_host);
self.cut =
DeviceCut::build_with(&self.solver, g, Phase::Predictor, t_new, shared.as_ref());
let cptrs = self.cut.as_ref().expect("cut").ptrs();
for c in 0..3i32 {
unsafe {