From e0b5983436c2601c445d1c8b3a248c89288d8e1e Mon Sep 17 00:00:00 2001 From: Omar Sobh Date: Tue, 15 Sep 2026 23:34:40 -0500 Subject: [PATCH] PERF-2 P1.2: the overlap map's cell classification skips the point location for background cells outside the patch's node bounding box (no patch cell can contain them and the body lies inside the patch: Active, the class the search returns); PatchMesh::bounding_box Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01YJPeT6WA2e7YvAnS875AHL --- .../specialized/rtx-cfd/src/mesh/patch_mesh.rs | 17 +++++++++++++++++ .../solvers/incompressible/overset/overlap.rs | 9 ++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/specialized/rtx-cfd/src/mesh/patch_mesh.rs b/crates/specialized/rtx-cfd/src/mesh/patch_mesh.rs index 235ae29..80fe1b0 100644 --- a/crates/specialized/rtx-cfd/src/mesh/patch_mesh.rs +++ b/crates/specialized/rtx-cfd/src/mesh/patch_mesh.rs @@ -173,6 +173,23 @@ impl PatchMesh { k * (self.ns + 1) + i } /// Node coordinates. + /// `[x_min, x_max, y_min, y_max]` over the nodes. + pub fn bounding_box(&self) -> [f64; 4] { + let (mut b, mut first) = ([0.0; 4], true); + for (&x, &y) in self.x.iter().zip(&self.y) { + if first { + b = [x, x, y, y]; + first = false; + } else { + b[0] = b[0].min(x); + b[1] = b[1].max(x); + b[2] = b[2].min(y); + b[3] = b[3].max(y); + } + } + b + } + pub fn node_xy(&self, n: usize) -> [f64; 2] { [self.x[n], self.y[n]] } diff --git a/crates/specialized/rtx-cfd/src/solvers/incompressible/overset/overlap.rs b/crates/specialized/rtx-cfd/src/solvers/incompressible/overset/overlap.rs index 2e208c6..a20ca16 100644 --- a/crates/specialized/rtx-cfd/src/solvers/incompressible/overset/overlap.rs +++ b/crates/specialized/rtx-cfd/src/solvers/incompressible/overset/overlap.rs @@ -162,13 +162,20 @@ impl OverlapMap { let primal = QuadIndex::primal(patch); let body = body_polygon(patch); - // 1. Cells. + // 1. Cells. A centre outside the patch's node bounding box lies in + // no patch cell and outside the body (which the patch encloses): + // Active without a point location (PERF-2 P1.2, the same class + // the search would return). + let bbox = patch.bounding_box(); let mut class = vec![CellClass::Active; nx * ny]; let mut hole_cells = 0; for j in 0..ny { for i in 0..nx { let x = (i as f64 + 0.5) * dx; let y = (j as f64 + 0.5) * dy; + if x < bbox[0] || x > bbox[1] || y < bbox[2] || y > bbox[3] { + continue; + } let in_hole = match primal.locate(patch, x, y) { Some(c) => patch.cell_ki(c).0 <= hole_row_max, None => body