embedded3 item 11: moving bodies (end-of-step mask, fresh-cell refill, space-time cut cell: step-averaged apertures, GCL wall flux, Reynolds-transport momentum), the 3D fresh-cell falsifier (plate / circle / stadium, wall + control-volume routes) and the Lipschitz sweep; ghost wall reproduces the 2D falsifier to the digit; cut wall 5–14× smoother on the circle, gates not met (fresh cell's first step); wall.rs split (impose.rs)
CI / Clippy Check (push) Failing after 3s
CI / Build (ubuntu-latest) (push) Failing after 4s
CI / Format Check (push) Failing after 4s
Performance Benchmarks / Run Benchmarks (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 6s
CI / Build CPU-Only (Explicit) (push) Failing after 1m6s
Documentation / Build API Documentation (push) Failing after 1m9s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Test (macos-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (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
CI / Clippy Check (push) Failing after 3s
CI / Build (ubuntu-latest) (push) Failing after 4s
CI / Format Check (push) Failing after 4s
Performance Benchmarks / Run Benchmarks (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 6s
CI / Build CPU-Only (Explicit) (push) Failing after 1m6s
Documentation / Build API Documentation (push) Failing after 1m9s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Test (macos-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (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
Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
0e4c97ed24
commit
5b1621e6ad
@@ -47,7 +47,7 @@ pub(crate) struct StencilNode {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(super) struct Ghost {
|
||||
idx: usize,
|
||||
pub(super) idx: usize,
|
||||
x: f64,
|
||||
y: f64,
|
||||
z: f64,
|
||||
@@ -58,7 +58,7 @@ pub(super) struct Ghost {
|
||||
nodes: Vec<StencilNode>,
|
||||
/// Outward-from-fluid sign for the compatibility correction (0 when no
|
||||
/// fluid cell is adjacent).
|
||||
flux_sign: f64,
|
||||
pub(super) flux_sign: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -77,6 +77,17 @@ pub struct Mask {
|
||||
/// The cut geometry of the apertured wall (`WallScheme::CutCell`,
|
||||
/// `cutwall.rs`); `None` on the binary ghost wall.
|
||||
pub(super) cut: Option<CutGeometry>,
|
||||
/// The step-averaged apertures `½(αⁿ + αⁿ⁺¹)` of a moving cut wall
|
||||
/// (the space-time continuity: a cell's volume change over the step
|
||||
/// equals the flux through the apertures it had during it); `None` =
|
||||
/// the instantaneous ones.
|
||||
pub(super) step_apertures: Option<(Vec<f64>, Vec<f64>, Vec<f64>)>,
|
||||
/// The projection's space-time classification on a moving cut wall:
|
||||
/// a face is an unknown where its step-averaged aperture is positive,
|
||||
/// a cell has an equation where it holds fluid at either end of the
|
||||
/// step (a dying cell empties through the apertures it had); `None` =
|
||||
/// the instantaneous kinds.
|
||||
pub(super) step_open: Option<(Vec<bool>, Vec<bool>, Vec<bool>, Vec<bool>)>,
|
||||
}
|
||||
|
||||
/// The z lattice position of a query: the lower plane index, the upper
|
||||
@@ -250,7 +261,7 @@ pub(crate) fn linear_fit(pts_w: &[(f64, f64, f64, f64, f64)], at: (f64, f64, f64
|
||||
}
|
||||
|
||||
impl Ghost {
|
||||
fn reconstruct(&self, values: &[f64]) -> f64 {
|
||||
pub(super) fn reconstruct(&self, values: &[f64]) -> f64 {
|
||||
let mut pts: Vec<(f64, f64, f64, f64, f64)> = self
|
||||
.nodes
|
||||
.iter()
|
||||
@@ -484,9 +495,65 @@ impl Mask {
|
||||
anchor,
|
||||
fluid_cells,
|
||||
cut: None,
|
||||
step_apertures: None,
|
||||
step_open: None,
|
||||
})
|
||||
}
|
||||
|
||||
// The projection's unknowns (the instantaneous kinds at rest).
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn u_open(&self, idx: usize) -> bool {
|
||||
self.step_open
|
||||
.as_ref()
|
||||
.map_or(self.u_kind[idx] == FaceKind::Fluid, |o| o.0[idx])
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn v_open(&self, idx: usize) -> bool {
|
||||
self.step_open
|
||||
.as_ref()
|
||||
.map_or(self.v_kind[idx] == FaceKind::Fluid, |o| o.1[idx])
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn w_open(&self, idx: usize) -> bool {
|
||||
self.step_open
|
||||
.as_ref()
|
||||
.map_or(self.w_kind[idx] == FaceKind::Fluid, |o| o.2[idx])
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn cell_active(&self, idx: usize) -> bool {
|
||||
self.step_open
|
||||
.as_ref()
|
||||
.map_or(self.cell_fluid[idx], |o| o.3[idx])
|
||||
}
|
||||
|
||||
/// The step-averaged aperture of a u / v / w face (the instantaneous
|
||||
/// one for a wall at rest).
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn au_step(&self, idx: usize) -> f64 {
|
||||
self.step_apertures
|
||||
.as_ref()
|
||||
.map_or_else(|| self.a_u(idx), |a| a.0[idx])
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn av_step(&self, idx: usize) -> f64 {
|
||||
self.step_apertures
|
||||
.as_ref()
|
||||
.map_or_else(|| self.a_v(idx), |a| a.1[idx])
|
||||
}
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn aw_step(&self, idx: usize) -> f64 {
|
||||
self.step_apertures
|
||||
.as_ref()
|
||||
.map_or_else(|| self.a_w(idx), |a| a.2[idx])
|
||||
}
|
||||
|
||||
/// The cut geometry (apertured wall only).
|
||||
#[must_use]
|
||||
pub fn cut(&self) -> Option<&CutGeometry> {
|
||||
@@ -555,134 +622,4 @@ impl Mask {
|
||||
pub fn periodic_z(&self) -> bool {
|
||||
self.periodic_z
|
||||
}
|
||||
|
||||
/// Impose the wall on `(u, v, w)` from the same field.
|
||||
pub fn impose(&self, body: &Body, u: &mut [f64], v: &mut [f64], w: &mut [f64], t: f64) -> f64 {
|
||||
let (us, vs, ws) = (u.to_vec(), v.to_vec(), w.to_vec());
|
||||
self.impose_from(body, &us, &vs, &ws, u, v, w, t)
|
||||
}
|
||||
|
||||
/// Solid faces: the surface velocity; ghost faces: the reconstruction
|
||||
/// from the SOURCE field, minus the shared flux compatibility
|
||||
/// correction over the flux-carrying ghosts. Returns the correction.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn impose_from(
|
||||
&self,
|
||||
body: &Body,
|
||||
u_src: &[f64],
|
||||
v_src: &[f64],
|
||||
w_src: &[f64],
|
||||
u: &mut [f64],
|
||||
v: &mut [f64],
|
||||
w: &mut [f64],
|
||||
t: f64,
|
||||
) -> f64 {
|
||||
let g = self.grid;
|
||||
let (nx, ny, nz, dx, dy, dz) = (g.nx, g.ny, g.nz, g.dx, g.dy, g.dz);
|
||||
for k in 0..nz {
|
||||
for j in 0..ny {
|
||||
for i in 1..nx {
|
||||
let idx = g.uface(k, j, i);
|
||||
if self.u_kind[idx] == FaceKind::Solid {
|
||||
u[idx] = body
|
||||
.surface_velocity(
|
||||
i as f64 * dx,
|
||||
(j as f64 + 0.5) * dy,
|
||||
(k as f64 + 0.5) * dz,
|
||||
t,
|
||||
)
|
||||
.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for j in 1..ny {
|
||||
for i in 0..nx {
|
||||
let idx = g.vface(k, j, i);
|
||||
if self.v_kind[idx] == FaceKind::Solid {
|
||||
v[idx] = body
|
||||
.surface_velocity(
|
||||
(i as f64 + 0.5) * dx,
|
||||
j as f64 * dy,
|
||||
(k as f64 + 0.5) * dz,
|
||||
t,
|
||||
)
|
||||
.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for k in 0..=nz {
|
||||
for j in 0..ny {
|
||||
for i in 0..nx {
|
||||
let idx = g.wface(k, j, i);
|
||||
if self.w_kind[idx] == FaceKind::Solid {
|
||||
w[idx] = body
|
||||
.surface_velocity(
|
||||
(i as f64 + 0.5) * dx,
|
||||
(j as f64 + 0.5) * dy,
|
||||
k as f64 * dz,
|
||||
t,
|
||||
)
|
||||
.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let u_vals: Vec<f64> = self
|
||||
.u_ghosts
|
||||
.iter()
|
||||
.map(|gh| gh.reconstruct(u_src))
|
||||
.collect();
|
||||
let v_vals: Vec<f64> = self
|
||||
.v_ghosts
|
||||
.iter()
|
||||
.map(|gh| gh.reconstruct(v_src))
|
||||
.collect();
|
||||
let w_vals: Vec<f64> = self
|
||||
.w_ghosts
|
||||
.iter()
|
||||
.map(|gh| gh.reconstruct(w_src))
|
||||
.collect();
|
||||
let (au, av, aw) = (dy * dz, dx * dz, dx * dy);
|
||||
let mut net = 0.0;
|
||||
let mut area = 0.0;
|
||||
for (gh, &val) in self.u_ghosts.iter().zip(&u_vals) {
|
||||
if gh.flux_sign != 0.0 {
|
||||
net += gh.flux_sign * val * au;
|
||||
area += au;
|
||||
}
|
||||
}
|
||||
for (gh, &val) in self.v_ghosts.iter().zip(&v_vals) {
|
||||
if gh.flux_sign != 0.0 {
|
||||
net += gh.flux_sign * val * av;
|
||||
area += av;
|
||||
}
|
||||
}
|
||||
for (gh, &val) in self.w_ghosts.iter().zip(&w_vals) {
|
||||
if gh.flux_sign != 0.0 {
|
||||
net += gh.flux_sign * val * aw;
|
||||
area += aw;
|
||||
}
|
||||
}
|
||||
let correction = if area > 0.0 { net / area } else { 0.0 };
|
||||
for (gh, &val) in self.u_ghosts.iter().zip(&u_vals) {
|
||||
u[gh.idx] = val - gh.flux_sign * correction;
|
||||
}
|
||||
for (gh, &val) in self.v_ghosts.iter().zip(&v_vals) {
|
||||
v[gh.idx] = val - gh.flux_sign * correction;
|
||||
}
|
||||
for (gh, &val) in self.w_ghosts.iter().zip(&w_vals) {
|
||||
w[gh.idx] = val - gh.flux_sign * correction;
|
||||
}
|
||||
// The periodic seam: the w face at k = nz is the face at k = 0.
|
||||
for j in 0..ny {
|
||||
for i in 0..nx {
|
||||
let (f0, fn_) = (g.wface(0, j, i), g.wface(nz, j, i));
|
||||
if self.w_kind[f0] != FaceKind::Fluid && self.w_kind[fn_] == self.w_kind[f0] {
|
||||
w[fn_] = w[f0];
|
||||
}
|
||||
}
|
||||
}
|
||||
correction
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user