Skip to content

Commit 2d8d94f

Browse files
sifakisclaude
andcommitted
WenoStencil: self-contained Taps tuple, no more Weno5Stencil policy dep
Consolidates the 19-tap WENO5 tuple into WenoStencil<W> itself, drops the external dependency on StencilAccessor.h, and removes references to the Weno5Stencil policy struct / Hull (neither needed now that the hybrid SIMD StencilAccessor is on the way out per the cleanup plan). Before: WenoStencil.h -> #include <StencilAccessor.h> using Taps = Weno5Stencil::Taps; tapIndex() -> detail::findIndex<Taps, ...>(); After: WenoStencil.h -> self-contained; no accessor include nested TapPoint<DI,DJ,DK> as the tap-offset type nested using Taps = std::tuple<TapPoint<...>, ...>; private static findTap<DI,DJ,DK>() helper (compile-time inverse map, same pattern as the ex-detail::findIndex) Tap ordering unchanged — canonical WenoPt<i,j,k>::idx convention (center, x-axis -3..+3, y-axis -3..+3, z-axis -3..+3). Hull intentionally absent (was only consumed by the hybrid StencilAccessor prefetch path, which is no longer exercised). StencilAccessor.h is left alone this pass: it still defines its own StencilPoint + detail::findIndex + Weno5Stencil policy (with both Taps and Hull) for the benchmark passes that still instantiate StencilAccessor<..., Weno5Stencil>. Those will fall away when the hybrid path is removed in a subsequent cleanup step; the decoupling here is preparation for that. LegacyStencilAccessor.h also unchanged — it still includes StencilAccessor.h for StencilPoint/findIndex, and its callers use Weno5Stencil as the policy type. WenoStencil<W>::Taps could replace that role later, but since W=1 vs W=16 stencils would pin the policy to a specific lane width, the more natural move is to introduce a standalone tap-tuple header when StencilAccessor.h retires. Verification on taperLER.vdb (31.8M active voxels, 24 threads): - ex_weno_nanovdb_cpu, ex_narrowband_stencil_cpu, ex_stencil_gather_cpu all rebuild and link clean. - ex_weno_nanovdb_cpu output identical (slot-by-slot) to pre-refactor: 73.75% bit-exact, 3.53% in [1e-8,1e-7), 22.72% in [1e-7,1e-6), 0 voxels above 1e-6; max |Delta|=9.5e-7 at the same slot as before. - Timings within noise (94.8 ms fast / 121.1 ms reference). WenoStencil.md: - §3.3 text refreshed: kPairs indices now cross-reference WenoStencil<W>::Taps rather than Weno5Stencil::Taps. - §5.3 tapIndex forwarding reference: detail::findIndex -> private static findTap. - §7.2 (the old "Consolidate the Weno5Stencil policy" to-do) removed; the consolidation it proposed is this commit. §7.3 renumbered to §7.2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
1 parent 3ffe1e7 commit 2d8d94f

2 files changed

Lines changed: 58 additions & 35 deletions

File tree

nanovdb/nanovdb/util/WenoStencil.h

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
#pragma once
4141

4242
#include <nanovdb/util/Simd.h>
43-
#include <nanovdb/util/StencilAccessor.h> // StencilPoint, Weno5Stencil, detail::findIndex
4443
#include <nanovdb/math/Math.h> // Pow2
4544

4645
#include <cstdint>
@@ -132,12 +131,35 @@ template<int W = 1>
132131
class WenoStencil
133132
{
134133
public:
135-
static constexpr int SIZE = 19;
136-
137-
using Taps = Weno5Stencil::Taps;
138134
using FloatV = util::Simd <float, W>;
139135
using MaskV = util::SimdMask<float, W>;
140136

137+
// --- Tap-offset types (compile-time only) -----------------------------
138+
// TapPoint<DI,DJ,DK> carries the tap offset as a type. Taps is the
139+
// 19-tap tuple in the canonical WenoPt<i,j,k>::idx ordering from
140+
// nanovdb/math/Stencils.h:
141+
// idx 0 : center < 0, 0, 0>
142+
// idx 1.. 6 : x-axis <-3,0,0> <-2,0,0> <-1,0,0> <+1,0,0> <+2,0,0> <+3,0,0>
143+
// idx 7..12 : y-axis <0,-3,0> <0,-2,0> <0,-1,0> <0,+1,0> <0,+2,0> <0,+3,0>
144+
// idx 13..18 : z-axis <0,0,-3> <0,0,-2> <0,0,-1> <0,0,+1> <0,0,+2> <0,0,+3>
145+
template<int DI, int DJ, int DK>
146+
struct TapPoint {
147+
static constexpr int di = DI, dj = DJ, dk = DK;
148+
};
149+
150+
using Taps = std::tuple<
151+
TapPoint< 0, 0, 0>,
152+
TapPoint<-3, 0, 0>, TapPoint<-2, 0, 0>, TapPoint<-1, 0, 0>,
153+
TapPoint<+1, 0, 0>, TapPoint<+2, 0, 0>, TapPoint<+3, 0, 0>,
154+
TapPoint< 0,-3, 0>, TapPoint< 0,-2, 0>, TapPoint< 0,-1, 0>,
155+
TapPoint< 0,+1, 0>, TapPoint< 0,+2, 0>, TapPoint< 0,+3, 0>,
156+
TapPoint< 0, 0,-3>, TapPoint< 0, 0,-2>, TapPoint< 0, 0,-1>,
157+
TapPoint< 0, 0,+1>, TapPoint< 0, 0,+2>, TapPoint< 0, 0,+3>
158+
>;
159+
160+
static constexpr int SIZE = int(std::tuple_size_v<Taps>);
161+
static constexpr int size() { return SIZE; }
162+
141163
// Compute-side storage — first-class Simd values. At W=1 these collapse
142164
// to plain scalar float / bool under the array backend.
143165
FloatV values [SIZE];
@@ -154,17 +176,13 @@ class WenoStencil
154176
NANOVDB_SIMD_HOSTDEV explicit WenoStencil(float dx)
155177
: mDx2(dx * dx), mInvDx2(1.f / (dx * dx)) {}
156178

157-
static constexpr int size() { return SIZE; }
158-
159179
// Compile-time named-tap access: returns the index of tap (DI,DJ,DK) in
160180
// the Taps tuple. Ordering matches WenoPt<i,j,k>::idx in
161-
// nanovdb/math/Stencils.h, so this is interoperable with canonical WENO
162-
// index conventions.
181+
// nanovdb/math/Stencils.h.
163182
template<int DI, int DJ, int DK>
164183
static constexpr int tapIndex()
165184
{
166-
constexpr int I = detail::findIndex<Taps, DI, DJ, DK>(
167-
std::make_index_sequence<SIZE>{});
185+
constexpr int I = findTap<DI, DJ, DK>(std::make_index_sequence<SIZE>{});
168186
static_assert(I >= 0, "WenoStencil::tapIndex: tap not in stencil");
169187
return I;
170188
}
@@ -200,8 +218,22 @@ class WenoStencil
200218
[[gnu::always_inline]] NANOVDB_SIMD_HOSTDEV inline FloatV normSqGrad(float iso = 0.f) const;
201219

202220
private:
203-
// Hardcoded (tap, innerTap) pairs for Weno5Stencil::Taps, ordered by
204-
// ascending |Δ|. Indices match the tuple definition in StencilAccessor.h.
221+
// Compile-time inverse map: (DI,DJ,DK) → slot index in Taps. Returns -1
222+
// if no matching tap exists; tapIndex() turns that into a static_assert.
223+
template<int DI, int DJ, int DK, size_t... Is>
224+
static constexpr int findTap(std::index_sequence<Is...>)
225+
{
226+
int result = -1;
227+
((std::tuple_element_t<Is, Taps>::di == DI &&
228+
std::tuple_element_t<Is, Taps>::dj == DJ &&
229+
std::tuple_element_t<Is, Taps>::dk == DK &&
230+
result < 0 ? (result = int(Is)) : 0), ...);
231+
return result;
232+
}
233+
234+
// Hardcoded (tap, innerTap) pairs for the 19-tap Taps tuple, ordered by
235+
// ascending |Δ| so the inner tap is always already resolved when the
236+
// outer tap is processed. Indices match the Taps tuple above.
205237
//
206238
// idx 0 : center ( 0, 0, 0)
207239
// idx 1.. 6 : x-axis (-3..+3 in the order -3,-2,-1,+1,+2,+3)

nanovdb/nanovdb/util/WenoStencil.md

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ outer tap is processed. Sign propagation through a |Δ|=1 → |Δ|=2 →
164164

165165
### 3.3 The `kPairs[]` table
166166

167-
The inner-tap relationship is `Weno5Stencil`-specific and hardcoded as
168-
a static table inside the class:
167+
The inner-tap relationship is WENO5-specific and hardcoded as a static
168+
table inside the class:
169169

170170
```cpp
171171
static constexpr int kPairs[18][2] = {
@@ -178,16 +178,16 @@ static constexpr int kPairs[18][2] = {
178178
};
179179
```
180180

181-
Indices match the tuple ordering in `Weno5Stencil::Taps`
182-
(`StencilAccessor.h`) and `WenoPt<i,j,k>::idx` in
183-
`nanovdb/math/Stencils.h`. Center tap (idx 0) is not processed —
181+
Indices match the `WenoStencil<W>::Taps` tuple defined in
182+
`WenoStencil.h` (same ordering as `WenoPt<i,j,k>::idx` in
183+
`nanovdb/math/Stencils.h`). Center tap (idx 0) is not processed —
184184
assumed always in-band.
185185

186186
**Why hardcoded, not template-derived:** a generic scheme would walk
187-
`Weno5Stencil::Taps` at compile time and derive inner-tap indices from
188-
|Δ| and axis alignment. For a single stencil the table is 18 entries,
189-
reads directly, and makes the cascade ordering self-documenting.
190-
Worth revisiting if we add Weno7 or other axis-aligned WENO variants.
187+
`Taps` at compile time and derive inner-tap indices from |Δ| and axis
188+
alignment. For a single stencil the table is 18 entries, reads
189+
directly, and makes the cascade ordering self-documenting. Worth
190+
revisiting if we add Weno7 or other axis-aligned WENO variants.
191191

192192
### 3.4 `extrapolate()` implementation
193193

@@ -378,9 +378,9 @@ constexpr int xm3 = WenoStencil<W>::tapIndex<-3, 0, 0>();
378378
FloatV xm3Value = stencil.values[xm3];
379379
```
380380

381-
`tapIndex<DI,DJ,DK>()` forwards to `detail::findIndex` (shared with
382-
`StencilAccessor`), static-asserting at compile time that the
383-
requested tap exists in the Weno5Stencil::Taps tuple.
381+
`tapIndex<DI,DJ,DK>()` forwards to a private static `findTap` helper
382+
inside `WenoStencil<W>`, static-asserting at compile time that the
383+
requested tap exists in the `Taps` tuple.
384384

385385
---
386386

@@ -428,20 +428,11 @@ taperLER.vdb; compare against `sidecar-stencil-extrap` (which writes
428428
the tap-sum instead of normSqGrad) to isolate the Phase-3 arithmetic
429429
cost.
430430

431-
### 7.2 Consolidate the Weno5Stencil policy
432-
433-
Currently `Weno5Stencil` (the tap-tuple policy struct) lives in
434-
`StencilAccessor.h` and is shared with `WenoStencil<W>` via
435-
`using Taps = Weno5Stencil::Taps`. The policy is arguably a
436-
Weno-specific definition and could move into `WenoStencil.h`;
437-
`StencilAccessor.h` would then `#include <.../WenoStencil.h>` for the
438-
policy. Left as-is to minimise churn across files.
439-
440-
### 7.3 Alternative stencils
431+
### 7.2 Alternative stencils
441432

442433
If/when Weno7 or a non-axis-aligned stencil is needed, the class
443434
would specialise on a stencil-policy template parameter rather than
444-
hardcode `Weno5Stencil`:
435+
hardcoding the 19-tap WENO5 shape:
445436

446437
```cpp
447438
template<typename StencilPolicy, int W>

0 commit comments

Comments
 (0)