rtx-cfd: OversetPisoSolver::momentum_residual — the background predictor's own staggered stencil (u_rhs/v_rhs, factored out of the predictor bit-identically) evaluated on every face of a NaN-masked field; solved faces read rounding, the active–fringe interface reads the composite's pressure level offset δ·h (cancels in the sum), prescribed fringe–fringe / fringe–hole faces read the stamping's momentum injection; hole ghosts (p, u, v) from a band widened three rows into the hole make every ring face evaluable; overset_cfd1 prints the buckets, the ring x-bands and δ at the settled state; pin: residual vanishes on the solved faces
CI / Format Check (push) Canceled after 0s
Performance Benchmarks / Run Benchmarks (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 (macos-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Build CPU-Only (Explicit) (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
Documentation / Build User Guide (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
Performance Benchmarks / Run Benchmarks (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 (macos-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Build CPU-Only (Explicit) (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
Documentation / Build User Guide (push) Canceled after 0s
Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01X2GmJXeQ2njUecEKiJZ1G2
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
cbec40b999
commit
6f9b0d43b2
@@ -118,6 +118,15 @@ pub struct OverlapMap {
|
||||
pub fringe_u: Vec<FringeEntry>,
|
||||
/// Prescribed v faces with donors.
|
||||
pub fringe_v: Vec<FringeEntry>,
|
||||
/// Hole cells within two cells of the fringe that have a patch donor in
|
||||
/// the widened band: ghost pressures for the momentum-residual
|
||||
/// diagnostic (never read by the solver).
|
||||
pub hole_p: Vec<FringeEntry>,
|
||||
/// Hole–hole u faces the solver never stamps, with a widened-band
|
||||
/// donor: ghost velocities for the diagnostic.
|
||||
pub ghost_u: Vec<FringeEntry>,
|
||||
/// See `ghost_u`.
|
||||
pub ghost_v: Vec<FringeEntry>,
|
||||
/// Acceptor cells on the patch's outer row.
|
||||
pub acceptors: Vec<Acceptor>,
|
||||
/// Patch rows searched for fringe donors (`nn − 1 − overlap_rows − 1 ..= nn − 2`).
|
||||
@@ -218,6 +227,29 @@ impl OverlapMap {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Diagnostic ghosts (never read by the solver): hole cells within
|
||||
// two cells of the fringe and the hole–hole faces around them, with
|
||||
// donors from a band widened three rows into the hole, so every
|
||||
// fringe–hole face's momentum stencil reads a patch value.
|
||||
let wide = QuadIndex::dual(patch, k_lo.saturating_sub(3), k_hi);
|
||||
let near_fringe = |j: usize, i: usize| {
|
||||
let lo_j = j.saturating_sub(2);
|
||||
let lo_i = i.saturating_sub(2);
|
||||
(lo_j..=(j + 2).min(ny - 1)).any(|jj| {
|
||||
(lo_i..=(i + 2).min(nx - 1)).any(|ii| class[jj * nx + ii] == CellClass::Fringe)
|
||||
})
|
||||
};
|
||||
let mut hole_p = Vec::new();
|
||||
for j in 0..ny {
|
||||
for i in 0..nx {
|
||||
if class[j * nx + i] == CellClass::Hole && near_fringe(j, i) {
|
||||
let (x, y) = ((i as f64 + 0.5) * dx, (j as f64 + 0.5) * dy);
|
||||
if let Some(donor) = wide.dual_donor(patch, x, y) {
|
||||
hole_p.push(FringeEntry { j, i, donor });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Prescribed faces: interior faces with no active neighbour, that
|
||||
// have a donor in the band (deeper ones are never read).
|
||||
let mut fringe_u = Vec::new();
|
||||
@@ -259,6 +291,40 @@ impl OverlapMap {
|
||||
}
|
||||
}
|
||||
|
||||
let hole = |jj: usize, ii: usize| class[jj * nx + ii] == CellClass::Hole;
|
||||
let stamped_u: std::collections::HashSet<(usize, usize)> =
|
||||
fringe_u.iter().map(|e| (e.j, e.i)).collect();
|
||||
let stamped_v: std::collections::HashSet<(usize, usize)> =
|
||||
fringe_v.iter().map(|e| (e.j, e.i)).collect();
|
||||
let mut ghost_u = Vec::new();
|
||||
for j in 0..ny {
|
||||
for i in 1..nx {
|
||||
if hole(j, i - 1) && hole(j, i) && (near_fringe(j, i - 1) || near_fringe(j, i)) {
|
||||
let (x, y) = (i as f64 * dx, (j as f64 + 0.5) * dy);
|
||||
if stamped_u.contains(&(j, i)) {
|
||||
continue;
|
||||
}
|
||||
if let Some(donor) = wide.dual_donor(patch, x, y) {
|
||||
ghost_u.push(FringeEntry { j, i, donor });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut ghost_v = Vec::new();
|
||||
for j in 1..ny {
|
||||
for i in 0..nx {
|
||||
if hole(j - 1, i) && hole(j, i) && (near_fringe(j - 1, i) || near_fringe(j, i)) {
|
||||
let (x, y) = ((i as f64 + 0.5) * dx, j as f64 * dy);
|
||||
if stamped_v.contains(&(j, i)) {
|
||||
continue;
|
||||
}
|
||||
if let Some(donor) = wide.dual_donor(patch, x, y) {
|
||||
ghost_v.push(FringeEntry { j, i, donor });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Acceptors: patch row nn − 1, lattice donors on the background.
|
||||
let u_fluid = |jj: usize, ii: usize| {
|
||||
// A u face is fluid unless both adjacent cells are non-active.
|
||||
@@ -319,6 +385,9 @@ impl OverlapMap {
|
||||
fringe_cells,
|
||||
fringe_u,
|
||||
fringe_v,
|
||||
hole_p,
|
||||
ghost_u,
|
||||
ghost_v,
|
||||
acceptors,
|
||||
donor_rows: (k_lo, k_hi),
|
||||
hole_cells,
|
||||
@@ -384,6 +453,38 @@ impl OverlapMap {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Interpolate a patch cell field to the hole ghost cells (order of
|
||||
/// `hole_p`).
|
||||
pub fn hole_p_values(&self, patch_vals: &[f64]) -> Vec<f64> {
|
||||
self.hole_p
|
||||
.iter()
|
||||
.map(|e| dual_value(&e.donor, patch_vals))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Stamp `values` (from [`Self::hole_p_values`]) onto a background
|
||||
/// cell field.
|
||||
pub fn stamp_hole_p(&self, target: &mut nalgebra::DMatrix<f64>, values: &[f64]) {
|
||||
for (e, &v) in self.hole_p.iter().zip(values) {
|
||||
target[(e.j, e.i)] = v;
|
||||
}
|
||||
}
|
||||
|
||||
/// Stamp the diagnostic ghost faces (`ghost_u`, `ghost_v`) from the
|
||||
/// patch cell velocities, onto both `u`/`v` and `u_old`/`v_old`.
|
||||
pub fn stamp_ghost_faces(&self, field: &mut FlowField, patch_u: &[f64], patch_v: &[f64]) {
|
||||
for e in &self.ghost_u {
|
||||
let v = dual_value(&e.donor, patch_u);
|
||||
field.u[(e.j, e.i)] = v;
|
||||
field.u_old[(e.j, e.i)] = v;
|
||||
}
|
||||
for e in &self.ghost_v {
|
||||
let v = dual_value(&e.donor, patch_v);
|
||||
field.v[(e.j, e.i)] = v;
|
||||
field.v_old[(e.j, e.i)] = v;
|
||||
}
|
||||
}
|
||||
|
||||
/// Stamp `values` (from [`Self::fringe_cell_values`]) onto a
|
||||
/// background cell field.
|
||||
pub fn stamp_fringe_cells(&self, target: &mut nalgebra::DMatrix<f64>, values: &[f64]) {
|
||||
|
||||
Reference in New Issue
Block a user