R8-c: drop zero summands from cut_wall_loads; extrapolation diagnostics beyond FAR_OUTSIDE with the worst point

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Omar Sobh
2026-09-25 20:45:04 -05:00
co-authored by Claude Opus 5.5
parent 9c2ae32061
commit 05bf4c74a0
3 changed files with 33 additions and 18 deletions
@@ -79,18 +79,17 @@ impl Mask {
if self.grad_weights.is_some() {
return None;
}
// The loops visit every fluid cell and face; only the non-zero
// summands are loads (the zero ones change no sum).
let mut raw: Vec<(LoadKind, [f64; 3], [f64; 3])> = Vec::new();
let (p, s) = self
.cut_wall_force_parts_sink(body, f, mu, t, None, &mut |k, x, v| raw.push((k, x, v)))?;
let (d, c) = self.cut_wall_exchange_parts_sink(
body,
f,
mu,
self.density,
t,
None,
&mut |k, x, v| raw.push((k, x, v)),
)?;
let mut keep = |k: LoadKind, x: [f64; 3], v: [f64; 3]| {
if v != [0.0; 3] {
raw.push((k, x, v));
}
};
let (p, s) = self.cut_wall_force_parts_sink(body, f, mu, t, None, &mut keep)?;
let (d, c) =
self.cut_wall_exchange_parts_sink(body, f, mu, self.density, t, None, &mut keep)?;
let xch = [d[0] + c[0], d[1] + c[1], d[2] + c[2]];
let total = [
p[0] + s[0] + xch[0],
@@ -209,6 +208,10 @@ pub struct Location {
pub outside: f64,
}
/// The natural-coordinate distance outside an element from which a load
/// counts as extrapolated in [`PlateTransfer`] (0.02 of the half-element).
pub const FAR_OUTSIDE: f64 = 0.02;
/// The result of one load transfer (see [`HexPlate::transfer`]).
#[derive(Debug, Clone)]
pub struct PlateTransfer {
@@ -223,9 +226,13 @@ pub struct PlateTransfer {
/// The largest Newton residual (m) and the largest outside-ness.
pub max_residual: f64,
pub max_outside: f64,
/// Loads located outside every element (extrapolated), and their Σ|F|.
/// Loads located outside every element by more than [`FAR_OUTSIDE`]
/// in natural coordinates (a foot off the plate by more than a few %
/// of an element — the surfaces' round-off-level mismatch is excluded),
/// their Σ|F|, and the worst one's point.
pub extrapolated: usize,
pub extrapolated_load: f64,
pub worst_point: [f64; 3],
/// The share of Σ|f_a| on nodes off the wetted surface (the interior
/// layers and the clamped root face).
pub interior_share: f64,
@@ -481,6 +488,7 @@ impl HexPlate {
let (mut force_in, mut moment_in) = ([0.0f64; 3], [0.0f64; 3]);
let (mut max_residual, mut max_outside) = (0.0f64, f64::NEG_INFINITY);
let (mut extrapolated, mut extrapolated_load) = (0usize, 0.0f64);
let mut worst_point = [0.0f64; 3];
for (&(p, f), loc) in loads.iter().zip(&located) {
for (&n, &w) in loc.nodes.iter().zip(&loc.weights) {
for c in 0..3 {
@@ -493,8 +501,11 @@ impl HexPlate {
moment_in[c] += m[c];
}
max_residual = max_residual.max(loc.residual);
max_outside = max_outside.max(loc.outside);
if loc.outside > 1e-9 {
if loc.outside > max_outside {
max_outside = loc.outside;
worst_point = p;
}
if loc.outside > FAR_OUTSIDE {
extrapolated += 1;
extrapolated_load += norm(f);
}
@@ -524,6 +535,7 @@ impl HexPlate {
max_outside,
extrapolated,
extrapolated_load,
worst_point,
interior_share: if total_abs > 0.0 {
interior_abs / total_abs
} else {
@@ -29,7 +29,7 @@ pub use cut::CutGeometry;
pub use export_vtk::write_vtk;
pub use field::Field;
pub use grid::Grid;
pub use interface::{HexPlate, LoadKind, PlateTransfer, WallLoad};
pub use interface::{FAR_OUTSIDE, HexPlate, LoadKind, PlateTransfer, WallLoad};
pub use loads::SurfaceForce;
pub use plate::PlateSurface;
pub use step::{Boundaries, Fluid, Parameters, Side, Solver, StepResult};