OpenVDB 13.1.0
Loading...
Searching...
No Matches
Stencils.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3//
4/// @author Ken Museth
5///
6/// @date April 9, 2021
7///
8/// @file Stencils.h
9///
10/// @brief Defines various finite-difference stencils that allow for the
11/// computation of gradients of order 1 to 5, mean curvatures,
12/// gaussian curvatures, principal curvatures, tri-linear interpolation,
13/// zero-crossing, laplacian, and closest point transform.
14
15#ifndef NANOVDB_MATH_STENCILS_HAS_BEEN_INCLUDED
16#define NANOVDB_MATH_STENCILS_HAS_BEEN_INCLUDED
17
18#include <nanovdb/math/Math.h>// for __hostdev__, Vec3, Min, Max, Pow2, Pow3, Pow4
19
20namespace nanovdb {
21
22namespace math {
23
24// ---------------------------- WENO5 ----------------------------
25
26/// @brief Implementation of nominally fifth-order finite-difference WENO
27/// @details This function returns the numerical flux. See "High Order Finite Difference and
28/// Finite Volume WENO Schemes and Discontinuous Galerkin Methods for CFD" - Chi-Wang Shu
29/// ICASE Report No 2001-11 (page 6). Also see ICASE No 97-65 for a more complete reference
30/// (Shu, 1997).
31/// Given v1 = f(x-2dx), v2 = f(x-dx), v3 = f(x), v4 = f(x+dx) and v5 = f(x+2dx),
32/// return an interpolated value f(x+dx/2) with the special property that
33/// ( f(x+dx/2) - f(x-dx/2) ) / dx = df/dx (x) + error,
34/// where the error is fifth-order in smooth regions: O(dx) <= error <=O(dx^5)
35template<typename ValueType, typename RealT = ValueType>
36__hostdev__ inline ValueType
37WENO5(const ValueType& v1,
38 const ValueType& v2,
39 const ValueType& v3,
40 const ValueType& v4,
41 const ValueType& v5,
42 RealT scale2 = 1.0)// openvdb uses scale2 = 0.01
43{
44 static const RealT C = 13.0 / 12.0;
45 // WENO is formulated for non-dimensional equations, here the optional scale2
46 // is a reference value (squared) for the function being interpolated. For
47 // example if 'v' is of order 1000, then scale2 = 10^6 is ok. But in practice
48 // leave scale2 = 1.
49 const RealT eps = RealT(1.0e-6) * scale2;
50 // {\tilde \omega_k} = \gamma_k / ( \beta_k + \epsilon)^2 in Shu's ICASE report)
51 const RealT A1 = RealT(0.1)/Pow2(C*Pow2(v1-2*v2+v3)+RealT(0.25)*Pow2(v1-4*v2+3*v3)+eps),
52 A2 = RealT(0.6)/Pow2(C*Pow2(v2-2*v3+v4)+RealT(0.25)*Pow2(v2-v4)+eps),
53 A3 = RealT(0.3)/Pow2(C*Pow2(v3-2*v4+v5)+RealT(0.25)*Pow2(3*v3-4*v4+v5)+eps);
54
55 return static_cast<ValueType>((A1*(2*v1 - 7*v2 + 11*v3) +
56 A2*(5*v3 - v2 + 2*v4) +
57 A3*(2*v3 + 5*v4 - v5))/(6*(A1+A2+A3)));
58}
59
60// ---------------------------- GodunovsNormSqrd ----------------------------
61
62template <typename RealT>
63__hostdev__ inline RealT
64GodunovsNormSqrd(bool isOutside,
65 RealT dP_xm, RealT dP_xp,
66 RealT dP_ym, RealT dP_yp,
67 RealT dP_zm, RealT dP_zp)
68{
69 RealT dPLen2;
70 if (isOutside) { // outside
71 dPLen2 = Max(Pow2(Max(dP_xm, RealT(0))), Pow2(Min(dP_xp, RealT(0)))); // (dP/dx)2
72 dPLen2 += Max(Pow2(Max(dP_ym, RealT(0))), Pow2(Min(dP_yp, RealT(0)))); // (dP/dy)2
73 dPLen2 += Max(Pow2(Max(dP_zm, RealT(0))), Pow2(Min(dP_zp, RealT(0)))); // (dP/dz)2
74 } else { // inside
75 dPLen2 = Max(Pow2(Min(dP_xm, RealT(0))), Pow2(Max(dP_xp, RealT(0)))); // (dP/dx)2
76 dPLen2 += Max(Pow2(Min(dP_ym, RealT(0))), Pow2(Max(dP_yp, RealT(0)))); // (dP/dy)2
77 dPLen2 += Max(Pow2(Min(dP_zm, RealT(0))), Pow2(Max(dP_zp, RealT(0)))); // (dP/dz)2
78 }
79 return dPLen2; // |\nabla\phi|^2
80}
81
82template<typename RealT>
83__hostdev__ inline RealT
84GodunovsNormSqrd(bool isOutside,
85 const Vec3<RealT>& gradient_m,
86 const Vec3<RealT>& gradient_p)
87{
88 return GodunovsNormSqrd<RealT>(isOutside,
89 gradient_m[0], gradient_p[0],
90 gradient_m[1], gradient_p[1],
91 gradient_m[2], gradient_p[2]);
92}
93
94// ---------------------------- BaseStencil ----------------------------
95
96// BaseStencil uses curiously recurring template pattern (CRTP)
97template<typename DerivedType, int SIZE, typename GridT>
99{
100public:
101 using ValueType = typename GridT::ValueType;
102 using GridType = GridT;
103 using TreeType = typename GridT::TreeType;
104 using AccessorType = typename GridT::AccessorType;// ReadAccessor<ValueType>;
105
106 /// @brief Initialize the stencil buffer with the values of voxel (i, j, k)
107 /// and its neighbors.
108 /// @param ijk Index coordinates of stencil center
109 __hostdev__ inline void moveTo(const Coord& ijk)
110 {
111 mCenter = ijk;
112 mValues[0] = mAcc.getValue(ijk);
113 static_cast<DerivedType&>(*this).init(mCenter);
114 }
115
116 /// @brief Initialize the stencil buffer with the values of voxel (i, j, k)
117 /// and its neighbors. The method also takes a value of the center
118 /// element of the stencil, assuming it is already known.
119 /// @param ijk Index coordinates of stencil center
120 /// @param centerValue Value of the center element of the stencil
121 __hostdev__ inline void moveTo(const Coord& ijk, const ValueType& centerValue)
122 {
123 mCenter = ijk;
124 mValues[0] = centerValue;
125 static_cast<DerivedType&>(*this).init(mCenter);
126 }
127
128 /// @brief Initialize the stencil buffer with the values of voxel
129 /// (x, y, z) and its neighbors.
130 ///
131 /// @note This version is slightly faster than the one above, since
132 /// the center voxel's value is read directly from the iterator.
133 template<typename IterType>
134 __hostdev__ inline void moveTo(const IterType& iter)
135 {
136 mCenter = iter.getCoord();
137 mValues[0] = *iter;
138 static_cast<DerivedType&>(*this).init(mCenter);
139 }
140
141 /// @brief Initialize the stencil buffer with the values of voxel (x, y, z)
142 /// and its neighbors.
143 /// @param xyz Floating point voxel coordinates of stencil center
144 /// @details This method will check to see if it is necessary to
145 /// update the stencil based on the cached index coordinates of
146 /// the center point.
147 template<typename RealType>
148 __hostdev__ inline void moveTo(const Vec3<RealType>& xyz)
149 {
150 Coord ijk = RoundDown(xyz);
151 if (ijk != mCenter) this->moveTo(ijk);
152 }
153
154 /// @brief Return the value from the stencil buffer with linear
155 /// offset pos.
156 ///
157 /// @note The default (@a pos = 0) corresponds to the first element
158 /// which is typically the center point of the stencil.
159 __hostdev__ inline const ValueType& getValue(unsigned int pos = 0) const
160 {
161 NANOVDB_ASSERT(pos < SIZE);
162 return mValues[pos];
163 }
164
165 /// @brief Return the value at the specified location relative to the center of the stencil
166 template<int i, int j, int k>
167 __hostdev__ inline const ValueType& getValue() const
168 {
169 return mValues[static_cast<const DerivedType&>(*this).template pos<i,j,k>()];
170 }
171
172 /// @brief Set the value at the specified location relative to the center of the stencil
173 template<int i, int j, int k>
174 __hostdev__ inline void setValue(const ValueType& value)
175 {
176 mValues[static_cast<const DerivedType&>(*this).template pos<i,j,k>()] = value;
177 }
178
179 /// @brief Return the size of the stencil buffer.
180 __hostdev__ static int size() { return SIZE; }
181
182 /// @brief Return the mean value of the current stencil.
184 {
185 ValueType sum = 0.0;
186 for (int i = 0; i < SIZE; ++i) sum += mValues[i];
187 return sum / ValueType(SIZE);
188 }
189
190 /// @brief Return the smallest value in the stencil buffer.
191 __hostdev__ inline ValueType min() const
192 {
193 ValueType v = mValues[0];
194 for (int i=1; i<SIZE; ++i) {
195 if (mValues[i] < v) v = mValues[i];
196 }
197 return v;
198 }
199
200 /// @brief Return the largest value in the stencil buffer.
201 __hostdev__ inline ValueType max() const
202 {
203 ValueType v = mValues[0];
204 for (int i=1; i<SIZE; ++i) {
205 if (mValues[i] > v) v = mValues[i];
206 }
207 return v;
208 }
209
210 /// @brief Return the coordinates of the center point of the stencil.
211 __hostdev__ inline const Coord& getCenterCoord() const { return mCenter; }
212
213 /// @brief Return the value at the center of the stencil
214 __hostdev__ inline const ValueType& getCenterValue() const { return mValues[0]; }
215
216 /// @brief Return true if the center of the stencil intersects the
217 /// iso-contour specified by the isoValue
218 __hostdev__ inline bool intersects(const ValueType &isoValue = ValueType(0) ) const
219 {
220 const bool less = this->getValue< 0, 0, 0>() < isoValue;
221 return (less ^ (this->getValue<-1, 0, 0>() < isoValue)) ||
222 (less ^ (this->getValue< 1, 0, 0>() < isoValue)) ||
223 (less ^ (this->getValue< 0,-1, 0>() < isoValue)) ||
224 (less ^ (this->getValue< 0, 1, 0>() < isoValue)) ||
225 (less ^ (this->getValue< 0, 0,-1>() < isoValue)) ||
226 (less ^ (this->getValue< 0, 0, 1>() < isoValue)) ;
227 }
228 struct Mask {
229 uint8_t bits;
231 __hostdev__ void set(int i) { bits |= (1 << i); }
232 __hostdev__ bool test(int i) const { return bits & (1 << i); }
233 __hostdev__ bool any() const { return bits > 0u; }
234 __hostdev__ bool all() const { return bits == 255u; }
235 __hostdev__ bool none() const { return bits == 0u; }
236 __hostdev__ int count() const { return util::countOn(bits); }
237 };// Mask
238
239 /// @brief Return true a bit-mask where the 6 lower bits indicates if the
240 /// center of the stencil intersects the iso-contour specified by the isoValue.
241 ///
242 /// @note There are 2^6 = 64 different possible cases, including no intersections!
243 ///
244 /// @details The ordering of bit mask is ( -x, +x, -y, +y, -z, +z ), so to
245 /// check if there is an intersection in -y use (mask & (1u<<2)) where mask is
246 /// ther return value from this function. To check if there are any
247 /// intersections use mask!=0u, and for no intersections use mask==0u.
248 /// To count the number of intersections use __builtin_popcount(mask).
249 __hostdev__ inline Mask intersectionMask(ValueType isoValue = ValueType(0)) const
250 {
251 Mask mask;
252 const bool less = this->getValue< 0, 0, 0>() < isoValue;
253 if (less ^ (this->getValue<-1, 0, 0>() < isoValue)) mask.set(0);// |= 1u;
254 if (less ^ (this->getValue< 1, 0, 0>() < isoValue)) mask.set(1);// |= 2u;
255 if (less ^ (this->getValue< 0,-1, 0>() < isoValue)) mask.set(2);// |= 4u;
256 if (less ^ (this->getValue< 0, 1, 0>() < isoValue)) mask.set(3);// |= 8u;
257 if (less ^ (this->getValue< 0, 0,-1>() < isoValue)) mask.set(4);// |= 16u;
258 if (less ^ (this->getValue< 0, 0, 1>() < isoValue)) mask.set(5);// |= 32u;
259 return mask;
260 }
261
262 /// @brief Return a const reference to the grid from which this
263 /// stencil was constructed.
264 __hostdev__ inline const GridType& grid() const { return *mGrid; }
265
266 /// @brief Return a const reference to the ValueAccessor
267 /// associated with this Stencil.
268 __hostdev__ inline const AccessorType& accessor() const { return mAcc; }
269
270protected:
271 // Constructor is protected to prevent direct instantiation.
273 : mGrid(&grid)
274 , mAcc(grid)
275 , mCenter(Coord::max())
276 {
277 }
278
283
284}; // BaseStencil class
285
286
287// ---------------------------- BoxStencil ----------------------------
288
289
290namespace { // anonymous namespace for stencil-layout map
291
292 // the eight point box stencil
293 template<int i, int j, int k> struct BoxPt {};
294 template<> struct BoxPt< 0, 0, 0> { enum { idx = 0 }; };
295 template<> struct BoxPt< 0, 0, 1> { enum { idx = 1 }; };
296 template<> struct BoxPt< 0, 1, 1> { enum { idx = 2 }; };
297 template<> struct BoxPt< 0, 1, 0> { enum { idx = 3 }; };
298 template<> struct BoxPt< 1, 0, 0> { enum { idx = 4 }; };
299 template<> struct BoxPt< 1, 0, 1> { enum { idx = 5 }; };
300 template<> struct BoxPt< 1, 1, 1> { enum { idx = 6 }; };
301 template<> struct BoxPt< 1, 1, 0> { enum { idx = 7 }; };
302
303}
304
305template<typename GridT>
306class BoxStencil: public BaseStencil<BoxStencil<GridT>, 8, GridT>
307{
308 using SelfT = BoxStencil<GridT>;
309 using BaseType = BaseStencil<SelfT, 8, GridT>;
310public:
311 using GridType = GridT;
312 using TreeType = typename GridT::TreeType;
313 using ValueType = typename GridT::ValueType;
314
315 static constexpr int SIZE = 8;
316
317 __hostdev__ BoxStencil(const GridType& grid) : BaseType(grid) {}
318
319 /// Return linear offset for the specified stencil point relative to its center
320 template<int i, int j, int k>
321 __hostdev__ unsigned int pos() const { return BoxPt<i,j,k>::idx; }
322
323 /// @brief Return true if the center of the stencil intersects the
324 /// iso-contour specified by the isoValue
325 __hostdev__ inline bool intersects(ValueType isoValue = ValueType(0)) const
326 {
327 const bool less = mValues[0] < isoValue;
328 return (less ^ (mValues[1] < isoValue)) ||
329 (less ^ (mValues[2] < isoValue)) ||
330 (less ^ (mValues[3] < isoValue)) ||
331 (less ^ (mValues[4] < isoValue)) ||
332 (less ^ (mValues[5] < isoValue)) ||
333 (less ^ (mValues[6] < isoValue)) ||
334 (less ^ (mValues[7] < isoValue)) ;
335 }
336
337 /// @brief Return the trilinear interpolation at the normalized position.
338 /// @param xyz Floating point coordinate position. Index space and NOT world space.
339 /// @warning It is assumed that the stencil has already been moved
340 /// to the relevant voxel position, e.g. using moveTo(xyz).
341 /// @note Trilinear interpolation kernal reads as:
342 /// v000 (1-u)(1-v)(1-w) + v001 (1-u)(1-v)w + v010 (1-u)v(1-w) + v011 (1-u)vw
343 /// + v100 u(1-v)(1-w) + v101 u(1-v)w + v110 uv(1-w) + v111 uvw
345 {
346 const ValueType u = xyz[0] - mCenter[0];
347 const ValueType v = xyz[1] - mCenter[1];
348 const ValueType w = xyz[2] - mCenter[2];
349
350 NANOVDB_ASSERT(u>=0 && u<=1);
351 NANOVDB_ASSERT(v>=0 && v<=1);
352 NANOVDB_ASSERT(w>=0 && w<=1);
353
354 ValueType V = BaseType::template getValue<0,0,0>();
355 ValueType A = V + (BaseType::template getValue<0,0,1>() - V) * w;
356 V = BaseType::template getValue< 0, 1, 0>();
357 ValueType B = V + (BaseType::template getValue<0,1,1>() - V) * w;
358 ValueType C = A + (B - A) * v;
359
360 V = BaseType::template getValue<1,0,0>();
361 A = V + (BaseType::template getValue<1,0,1>() - V) * w;
362 V = BaseType::template getValue<1,1,0>();
363 B = V + (BaseType::template getValue<1,1,1>() - V) * w;
364 ValueType D = A + (B - A) * v;
365
366 return C + (D - C) * u;
367 }
368
369 /// @brief Return the gradient in world space of the trilinear interpolation kernel.
370 /// @param xyz Floating point coordinate position.
371 /// @warning It is assumed that the stencil has already been moved
372 /// to the relevant voxel position, e.g. using moveTo(xyz).
373 /// @note Computed as partial derivatives of the trilinear interpolation kernel:
374 /// v000 (1-u)(1-v)(1-w) + v001 (1-u)(1-v)w + v010 (1-u)v(1-w) + v011 (1-u)vw
375 /// + v100 u(1-v)(1-w) + v101 u(1-v)w + v110 uv(1-w) + v111 uvw
377 {
378 const ValueType u = xyz[0] - mCenter[0];
379 const ValueType v = xyz[1] - mCenter[1];
380 const ValueType w = xyz[2] - mCenter[2];
381
382 NANOVDB_ASSERT(u>=0 && u<=1);
383 NANOVDB_ASSERT(v>=0 && v<=1);
384 NANOVDB_ASSERT(w>=0 && w<=1);
385
386 ValueType D[4]={BaseType::template getValue<0,0,1>()-BaseType::template getValue<0,0,0>(),
387 BaseType::template getValue<0,1,1>()-BaseType::template getValue<0,1,0>(),
388 BaseType::template getValue<1,0,1>()-BaseType::template getValue<1,0,0>(),
389 BaseType::template getValue<1,1,1>()-BaseType::template getValue<1,1,0>()};
390
391 // Z component
392 ValueType A = D[0] + (D[1]- D[0]) * v;
393 ValueType B = D[2] + (D[3]- D[2]) * v;
394 Vec3<ValueType> grad(0, 0, A + (B - A) * u);
395
396 D[0] = BaseType::template getValue<0,0,0>() + D[0] * w;
397 D[1] = BaseType::template getValue<0,1,0>() + D[1] * w;
398 D[2] = BaseType::template getValue<1,0,0>() + D[2] * w;
399 D[3] = BaseType::template getValue<1,1,0>() + D[3] * w;
400
401 // X component
402 A = D[0] + (D[1] - D[0]) * v;
403 B = D[2] + (D[3] - D[2]) * v;
404
405 grad[0] = B - A;
406
407 // Y component
408 A = D[1] - D[0];
409 B = D[3] - D[2];
410
411 grad[1] = A + (B - A) * u;
412
413 return BaseType::mGrid->map().applyIJT(grad);
414 }
415
416private:
417 __hostdev__ inline void init(const Coord& ijk)
418 {
419 mValues[ 1] = mAcc.getValue(ijk.offsetBy( 0, 0, 1));
420 mValues[ 2] = mAcc.getValue(ijk.offsetBy( 0, 1, 1));
421 mValues[ 3] = mAcc.getValue(ijk.offsetBy( 0, 1, 0));
422 mValues[ 4] = mAcc.getValue(ijk.offsetBy( 1, 0, 0));
423 mValues[ 5] = mAcc.getValue(ijk.offsetBy( 1, 0, 1));
424 mValues[ 6] = mAcc.getValue(ijk.offsetBy( 1, 1, 1));
425 mValues[ 7] = mAcc.getValue(ijk.offsetBy( 1, 1, 0));
426 }
427
428 template<typename, int, typename> friend class BaseStencil; // allow base class to call init()
429 using BaseType::mAcc;
430 using BaseType::mValues;
431 using BaseType::mCenter;
432};// BoxStencil class
433
434
435// ---------------------------- GradStencil ----------------------------
436
437namespace { // anonymous namespace for stencil-layout map
438
439 template<int i, int j, int k> struct GradPt {};
440 template<> struct GradPt< 0, 0, 0> { enum { idx = 0 }; };
441 template<> struct GradPt< 1, 0, 0> { enum { idx = 2 }; };
442 template<> struct GradPt< 0, 1, 0> { enum { idx = 4 }; };
443 template<> struct GradPt< 0, 0, 1> { enum { idx = 6 }; };
444 template<> struct GradPt<-1, 0, 0> { enum { idx = 1 }; };
445 template<> struct GradPt< 0,-1, 0> { enum { idx = 3 }; };
446 template<> struct GradPt< 0, 0,-1> { enum { idx = 5 }; };
447}
448
449/// This is a simple 7-point nearest neighbor stencil that supports
450/// gradient by second-order central differencing, first-order upwinding,
451/// Laplacian, closest-point transform and zero-crossing test.
452///
453/// @note For optimal random access performance this class
454/// includes its own grid accessor.
455template<typename GridT>
456class GradStencil : public BaseStencil<GradStencil<GridT>, 7, GridT>
457{
458 using SelfT = GradStencil<GridT>;
459 using BaseType = BaseStencil<SelfT, 7, GridT>;
460public:
461 using GridType = GridT;
462 using TreeType = typename GridT::TreeType;
463 using ValueType = typename GridT::ValueType;
464
465 static constexpr int SIZE = 7;
466
468 : BaseType(grid)
469 , mInv2Dx(ValueType(0.5 / grid.voxelSize()[0]))
470 , mInvDx2(ValueType(4.0 * mInv2Dx * mInv2Dx))
471 {
472 }
473
475 : BaseType(grid)
476 , mInv2Dx(ValueType(0.5 / dx))
477 , mInvDx2(ValueType(4.0 * mInv2Dx * mInv2Dx))
478 {
479 }
480
481 /// @brief Return the norm square of the single-sided upwind gradient
482 /// (computed via Godunov's scheme) at the previously buffered location.
483 ///
484 /// @note This method should not be called until the stencil
485 /// buffer has been populated via a call to moveTo(ijk).
487 {
488 return mInvDx2 * GodunovsNormSqrd(mValues[0] > ValueType(0),
489 mValues[0] - mValues[1],
490 mValues[2] - mValues[0],
491 mValues[0] - mValues[3],
492 mValues[4] - mValues[0],
493 mValues[0] - mValues[5],
494 mValues[6] - mValues[0]);
495 }
496
497 /// @brief Return the gradient computed at the previously buffered
498 /// location by second order central differencing.
499 ///
500 /// @note This method should not be called until the stencil
501 /// buffer has been populated via a call to moveTo(ijk).
503 {
504 return Vec3<ValueType>(mValues[2] - mValues[1],
505 mValues[4] - mValues[3],
506 mValues[6] - mValues[5])*mInv2Dx;
507 }
508 /// @brief Return the first-order upwind gradient corresponding to the direction V.
509 ///
510 /// @note This method should not be called until the stencil
511 /// buffer has been populated via a call to moveTo(ijk).
513 {
514 return Vec3<ValueType>(
515 V[0]>0 ? mValues[0] - mValues[1] : mValues[2] - mValues[0],
516 V[1]>0 ? mValues[0] - mValues[3] : mValues[4] - mValues[0],
517 V[2]>0 ? mValues[0] - mValues[5] : mValues[6] - mValues[0])*2*mInv2Dx;
518 }
519
520 /// Return the Laplacian computed at the previously buffered
521 /// location by second-order central differencing.
523 {
524 return mInvDx2 * (mValues[1] + mValues[2] +
525 mValues[3] + mValues[4] +
526 mValues[5] + mValues[6] - 6*mValues[0]);
527 }
528
529 /// Return @c true if the sign of the value at the center point of the stencil
530 /// is different from the signs of any of its six nearest neighbors.
531 __hostdev__ inline bool zeroCrossing() const
532 {
533 return (mValues[0]>0 ? (mValues[1]<0 || mValues[2]<0 || mValues[3]<0 || mValues[4]<0 || mValues[5]<0 || mValues[6]<0)
534 : (mValues[1]>0 || mValues[2]>0 || mValues[3]>0 || mValues[4]>0 || mValues[5]>0 || mValues[6]>0));
535 }
536
537 /// @brief Compute the closest-point transform to a level set.
538 /// @return the closest point in index space to the surface
539 /// from which the level set was derived.
540 ///
541 /// @note This method assumes that the grid represents a level set
542 /// with distances in world units and a simple affine transfrom
543 /// with uniform scaling.
545 {
546 const Coord& ijk = BaseType::getCenterCoord();
547 const ValueType d = ValueType(mValues[0] * 0.5 * mInvDx2); // distance in voxels / (2dx^2)
548 const auto value = Vec3<ValueType>(ijk[0] - d*(mValues[2] - mValues[1]),
549 ijk[1] - d*(mValues[4] - mValues[3]),
550 ijk[2] - d*(mValues[6] - mValues[5]));
551 return value;
552 }
553
554 /// Return linear offset for the specified stencil point relative to its center
555 template<int i, int j, int k>
556 __hostdev__ unsigned int pos() const { return GradPt<i,j,k>::idx; }
557
558private:
559
560 __hostdev__ inline void init(const Coord& ijk)
561 {
562 mValues[ 1] = mAcc.getValue(ijk.offsetBy(-1, 0, 0));
563 mValues[ 2] = mAcc.getValue(ijk.offsetBy( 1, 0, 0));
564
565 mValues[ 3] = mAcc.getValue(ijk.offsetBy( 0,-1, 0));
566 mValues[ 4] = mAcc.getValue(ijk.offsetBy( 0, 1, 0));
567
568 mValues[ 5] = mAcc.getValue(ijk.offsetBy( 0, 0,-1));
569 mValues[ 6] = mAcc.getValue(ijk.offsetBy( 0, 0, 1));
570 }
571
572 template<typename, int, typename> friend class BaseStencil; // allow base class to call init()
573 using BaseType::mAcc;
574 using BaseType::mValues;
575 const ValueType mInv2Dx, mInvDx2;
576}; // GradStencil class
577
578
579// ---------------------------- WenoStencil ----------------------------
580
581namespace { // anonymous namespace for stencil-layout map
582
583 template<int i, int j, int k> struct WenoPt {};
584 template<> struct WenoPt< 0, 0, 0> { enum { idx = 0 }; };
585
586 template<> struct WenoPt<-3, 0, 0> { enum { idx = 1 }; };
587 template<> struct WenoPt<-2, 0, 0> { enum { idx = 2 }; };
588 template<> struct WenoPt<-1, 0, 0> { enum { idx = 3 }; };
589 template<> struct WenoPt< 1, 0, 0> { enum { idx = 4 }; };
590 template<> struct WenoPt< 2, 0, 0> { enum { idx = 5 }; };
591 template<> struct WenoPt< 3, 0, 0> { enum { idx = 6 }; };
592
593 template<> struct WenoPt< 0,-3, 0> { enum { idx = 7 }; };
594 template<> struct WenoPt< 0,-2, 0> { enum { idx = 8 }; };
595 template<> struct WenoPt< 0,-1, 0> { enum { idx = 9 }; };
596 template<> struct WenoPt< 0, 1, 0> { enum { idx =10 }; };
597 template<> struct WenoPt< 0, 2, 0> { enum { idx =11 }; };
598 template<> struct WenoPt< 0, 3, 0> { enum { idx =12 }; };
599
600 template<> struct WenoPt< 0, 0,-3> { enum { idx =13 }; };
601 template<> struct WenoPt< 0, 0,-2> { enum { idx =14 }; };
602 template<> struct WenoPt< 0, 0,-1> { enum { idx =15 }; };
603 template<> struct WenoPt< 0, 0, 1> { enum { idx =16 }; };
604 template<> struct WenoPt< 0, 0, 2> { enum { idx =17 }; };
605 template<> struct WenoPt< 0, 0, 3> { enum { idx =18 }; };
606
607}
608
609/// @brief This is a special 19-point stencil that supports optimal fifth-order WENO
610/// upwinding, second-order central differencing, Laplacian, and zero-crossing test.
611///
612/// @note For optimal random access performance this class
613/// includes its own grid accessor.
614template<typename GridT, typename RealT = typename GridT::ValueType>
615class WenoStencil: public BaseStencil<WenoStencil<GridT>, 19, GridT>
616{
617 using SelfT = WenoStencil<GridT>;
618 using BaseType = BaseStencil<SelfT, 19, GridT>;
619public:
620 using GridType = GridT;
621 using TreeType = typename GridT::TreeType;
622 using ValueType = typename GridT::ValueType;
623
624 static constexpr int SIZE = 19;
625
627 : BaseType(grid)
628 , mDx2(ValueType(Pow2(grid.voxelSize()[0])))
629 , mInv2Dx(ValueType(0.5 / grid.voxelSize()[0]))
630 , mInvDx2(ValueType(1.0 / mDx2))
631 {
632 }
633
635 : BaseType(grid)
636 , mDx2(ValueType(dx * dx))
637 , mInv2Dx(ValueType(0.5 / dx))
638 , mInvDx2(ValueType(1.0 / mDx2))
639 {
640 }
641
642 /// @brief Return the norm-square of the WENO upwind gradient (computed via
643 /// WENO upwinding and Godunov's scheme) at the previously buffered location.
644 ///
645 /// @note This method should not be called until the stencil
646 /// buffer has been populated via a call to moveTo(ijk).
648 {
649 const ValueType* v = mValues;
650 const RealT
651 dP_xm = WENO5<RealT>(v[ 2]-v[ 1],v[ 3]-v[ 2],v[ 0]-v[ 3],v[ 4]-v[ 0],v[ 5]-v[ 4],mDx2),
652 dP_xp = WENO5<RealT>(v[ 6]-v[ 5],v[ 5]-v[ 4],v[ 4]-v[ 0],v[ 0]-v[ 3],v[ 3]-v[ 2],mDx2),
653 dP_ym = WENO5<RealT>(v[ 8]-v[ 7],v[ 9]-v[ 8],v[ 0]-v[ 9],v[10]-v[ 0],v[11]-v[10],mDx2),
654 dP_yp = WENO5<RealT>(v[12]-v[11],v[11]-v[10],v[10]-v[ 0],v[ 0]-v[ 9],v[ 9]-v[ 8],mDx2),
655 dP_zm = WENO5<RealT>(v[14]-v[13],v[15]-v[14],v[ 0]-v[15],v[16]-v[ 0],v[17]-v[16],mDx2),
656 dP_zp = WENO5<RealT>(v[18]-v[17],v[17]-v[16],v[16]-v[ 0],v[ 0]-v[15],v[15]-v[14],mDx2);
657 return mInvDx2*static_cast<ValueType>(
658 GodunovsNormSqrd(v[0]>isoValue, dP_xm, dP_xp, dP_ym, dP_yp, dP_zm, dP_zp));
659 }
660
661 /// Return the optimal fifth-order upwind gradient corresponding to the
662 /// direction V.
663 ///
664 /// @note This method should not be called until the stencil
665 /// buffer has been populated via a call to moveTo(ijk).
667 {
668 const ValueType* v = mValues;
669 return 2*mInv2Dx * Vec3<ValueType>(
670 V[0]>0 ? WENO5<RealT>(v[ 2]-v[ 1],v[ 3]-v[ 2],v[ 0]-v[ 3], v[ 4]-v[ 0],v[ 5]-v[ 4],mDx2)
671 : WENO5<RealT>(v[ 6]-v[ 5],v[ 5]-v[ 4],v[ 4]-v[ 0], v[ 0]-v[ 3],v[ 3]-v[ 2],mDx2),
672 V[1]>0 ? WENO5<RealT>(v[ 8]-v[ 7],v[ 9]-v[ 8],v[ 0]-v[ 9], v[10]-v[ 0],v[11]-v[10],mDx2)
673 : WENO5<RealT>(v[12]-v[11],v[11]-v[10],v[10]-v[ 0], v[ 0]-v[ 9],v[ 9]-v[ 8],mDx2),
674 V[2]>0 ? WENO5<RealT>(v[14]-v[13],v[15]-v[14],v[ 0]-v[15], v[16]-v[ 0],v[17]-v[16],mDx2)
675 : WENO5<RealT>(v[18]-v[17],v[17]-v[16],v[16]-v[ 0], v[ 0]-v[15],v[15]-v[14],mDx2));
676 }
677 /// Return the gradient computed at the previously buffered
678 /// location by second-order central differencing.
679 ///
680 /// @note This method should not be called until the stencil
681 /// buffer has been populated via a call to moveTo(ijk).
683 {
684 return mInv2Dx * Vec3<ValueType>(mValues[ 4] - mValues[ 3],
685 mValues[10] - mValues[ 9],
686 mValues[16] - mValues[15]);
687 }
688
689 /// Return the Laplacian computed at the previously buffered
690 /// location by second-order central differencing.
691 ///
692 /// @note This method should not be called until the stencil
693 /// buffer has been populated via a call to moveTo(ijk).
695 {
696 return mInvDx2 * (
697 mValues[ 3] + mValues[ 4] +
698 mValues[ 9] + mValues[10] +
699 mValues[15] + mValues[16] - 6*mValues[0]);
700 }
701
702 /// Return @c true if the sign of the value at the center point of the stencil
703 /// differs from the sign of any of its six nearest neighbors
704 __hostdev__ inline bool zeroCrossing() const
705 {
706 const ValueType* v = mValues;
707 return (v[ 0]>0 ? (v[ 3]<0 || v[ 4]<0 || v[ 9]<0 || v[10]<0 || v[15]<0 || v[16]<0)
708 : (v[ 3]>0 || v[ 4]>0 || v[ 9]>0 || v[10]>0 || v[15]>0 || v[16]>0));
709 }
710
711 /// Return linear offset for the specified stencil point relative to its center
712 template<int i, int j, int k>
713 __hostdev__ unsigned int pos() const { return WenoPt<i,j,k>::idx; }
714
715private:
716 __hostdev__ inline void init(const Coord& ijk)
717 {
718 mValues[ 1] = mAcc.getValue(ijk.offsetBy(-3, 0, 0));
719 mValues[ 2] = mAcc.getValue(ijk.offsetBy(-2, 0, 0));
720 mValues[ 3] = mAcc.getValue(ijk.offsetBy(-1, 0, 0));
721 mValues[ 4] = mAcc.getValue(ijk.offsetBy( 1, 0, 0));
722 mValues[ 5] = mAcc.getValue(ijk.offsetBy( 2, 0, 0));
723 mValues[ 6] = mAcc.getValue(ijk.offsetBy( 3, 0, 0));
724
725 mValues[ 7] = mAcc.getValue(ijk.offsetBy( 0, -3, 0));
726 mValues[ 8] = mAcc.getValue(ijk.offsetBy( 0, -2, 0));
727 mValues[ 9] = mAcc.getValue(ijk.offsetBy( 0, -1, 0));
728 mValues[10] = mAcc.getValue(ijk.offsetBy( 0, 1, 0));
729 mValues[11] = mAcc.getValue(ijk.offsetBy( 0, 2, 0));
730 mValues[12] = mAcc.getValue(ijk.offsetBy( 0, 3, 0));
731
732 mValues[13] = mAcc.getValue(ijk.offsetBy( 0, 0, -3));
733 mValues[14] = mAcc.getValue(ijk.offsetBy( 0, 0, -2));
734 mValues[15] = mAcc.getValue(ijk.offsetBy( 0, 0, -1));
735 mValues[16] = mAcc.getValue(ijk.offsetBy( 0, 0, 1));
736 mValues[17] = mAcc.getValue(ijk.offsetBy( 0, 0, 2));
737 mValues[18] = mAcc.getValue(ijk.offsetBy( 0, 0, 3));
738 }
739
740 template<typename, int, typename> friend class BaseStencil; // allow base class to call init()
741 using BaseType::mAcc;
742 using BaseType::mValues;
743 const ValueType mDx2, mInv2Dx, mInvDx2;
744}; // WenoStencil class
745
746
747// ---------------------------- CurvatureStencil ----------------------------
748
749namespace { // anonymous namespace for stencil-layout map
750
751 template<int i, int j, int k> struct CurvPt {};
752 template<> struct CurvPt< 0, 0, 0> { enum { idx = 0 }; };
753
754 template<> struct CurvPt<-1, 0, 0> { enum { idx = 1 }; };
755 template<> struct CurvPt< 1, 0, 0> { enum { idx = 2 }; };
756
757 template<> struct CurvPt< 0,-1, 0> { enum { idx = 3 }; };
758 template<> struct CurvPt< 0, 1, 0> { enum { idx = 4 }; };
759
760 template<> struct CurvPt< 0, 0,-1> { enum { idx = 5 }; };
761 template<> struct CurvPt< 0, 0, 1> { enum { idx = 6 }; };
762
763 template<> struct CurvPt<-1,-1, 0> { enum { idx = 7 }; };
764 template<> struct CurvPt< 1,-1, 0> { enum { idx = 8 }; };
765 template<> struct CurvPt<-1, 1, 0> { enum { idx = 9 }; };
766 template<> struct CurvPt< 1, 1, 0> { enum { idx =10 }; };
767
768 template<> struct CurvPt<-1, 0,-1> { enum { idx =11 }; };
769 template<> struct CurvPt< 1, 0,-1> { enum { idx =12 }; };
770 template<> struct CurvPt<-1, 0, 1> { enum { idx =13 }; };
771 template<> struct CurvPt< 1, 0, 1> { enum { idx =14 }; };
772
773 template<> struct CurvPt< 0,-1,-1> { enum { idx =15 }; };
774 template<> struct CurvPt< 0, 1,-1> { enum { idx =16 }; };
775 template<> struct CurvPt< 0,-1, 1> { enum { idx =17 }; };
776 template<> struct CurvPt< 0, 1, 1> { enum { idx =18 }; };
777
778}
779
780template<typename GridT, typename RealT = typename GridT::ValueType>
781class CurvatureStencil: public BaseStencil<CurvatureStencil<GridT>, 19, GridT>
782{
783 using SelfT = CurvatureStencil<GridT>;
784 using BaseType = BaseStencil<SelfT, 19, GridT>;
785public:
786 using GridType = GridT;
787 using TreeType = typename GridT::TreeType;
788 using ValueType = typename GridT::ValueType;
789
790 static constexpr int SIZE = 19;
791
793 : BaseType(grid)
794 , mInv2Dx(ValueType(0.5 / grid.voxelSize()[0]))
795 , mInvDx2(ValueType(4.0 * mInv2Dx * mInv2Dx))
796 {
797 }
798
800 : BaseType(grid)
801 , mInv2Dx(ValueType(0.5 / dx))
802 , mInvDx2(ValueType(4.0 * mInv2Dx * mInv2Dx))
803 {
804 }
805
806 /// @brief Return the mean curvature at the previously buffered location.
807 ///
808 /// @note This method should not be called until the stencil
809 /// buffer has been populated via a call to moveTo(ijk).
811 {
812 RealT alpha, normGrad;
813 return this->meanCurvature(alpha, normGrad) ?
814 ValueType(alpha*mInv2Dx/Pow3(normGrad)) : 0;
815 }
816
817 /// @brief Return the Gaussian curvature at the previously buffered location.
818 ///
819 /// @note This method should not be called until the stencil
820 /// buffer has been populated via a call to moveTo(ijk).
822 {
823 RealT alpha, normGrad;
824 return this->gaussianCurvature(alpha, normGrad) ?
825 ValueType(alpha*mInvDx2/Pow4(normGrad)) : 0;
826 }
827
828 /// @brief Return both the mean and the Gaussian curvature at the
829 /// previously buffered location.
830 ///
831 /// @note This method should not be called until the stencil
832 /// buffer has been populated via a call to moveTo(ijk).
833 __hostdev__ inline void curvatures(ValueType &mean, ValueType& gauss) const
834 {
835 RealT alphaM, alphaG, normGrad;
836 if (this->curvatures(alphaM, alphaG, normGrad)) {
837 mean = ValueType(alphaM*mInv2Dx/Pow3(normGrad));
838 gauss = ValueType(alphaG*mInvDx2/Pow4(normGrad));
839 } else {
840 mean = gauss = 0;
841 }
842 }
843
844 /// Return the mean curvature multiplied by the norm of the
845 /// central-difference gradient. This method is very useful for
846 /// mean-curvature flow of level sets!
847 ///
848 /// @note This method should not be called until the stencil
849 /// buffer has been populated via a call to moveTo(ijk).
851 {
852 RealT alpha, normGrad;
853 return this->meanCurvature(alpha, normGrad) ?
854 ValueType(alpha*mInvDx2/(2*Pow2(normGrad))) : 0;
855 }
856
857 /// Return the mean Gaussian multiplied by the norm of the
858 /// central-difference gradient.
859 ///
860 /// @note This method should not be called until the stencil
861 /// buffer has been populated via a call to moveTo(ijk).
863 {
864 RealT alpha, normGrad;
865 return this->gaussianCurvature(alpha, normGrad) ?
866 ValueType(2*alpha*mInv2Dx*mInvDx2/Pow3(normGrad)) : 0;
867 }
868
869 /// @brief Return both the mean and the Gaussian curvature at the
870 /// previously buffered location.
871 ///
872 /// @note This method should not be called until the stencil
873 /// buffer has been populated via a call to moveTo(ijk).
875 {
876 RealT alphaM, alphaG, normGrad;
877 if (this->curvatures(alphaM, alphaG, normGrad)) {
878 mean = ValueType(alphaM*mInvDx2/(2*Pow2(normGrad)));
879 gauss = ValueType(2*alphaG*mInv2Dx*mInvDx2/Pow3(normGrad));
880 } else {
881 mean = gauss = 0;
882 }
883 }
884
885 /// @brief Computes the minimum and maximum principal curvature at the
886 /// previously buffered location.
887 ///
888 /// @note This method should not be called until the stencil
889 /// buffer has been populated via a call to moveTo(ijk).
891 {
892 min = max = 0;
893 RealT alphaM, alphaG, normGrad;
894 if (this->curvatures(alphaM, alphaG, normGrad)) {
895 const RealT mean = alphaM*mInv2Dx/Pow3(normGrad);
896 const RealT tmp = Sqrt(mean*mean - alphaG*mInvDx2/Pow4(normGrad));
897 min = ValueType(mean - tmp);
898 max = ValueType(mean + tmp);
899 }
900 }
901
902 /// Return the Laplacian computed at the previously buffered
903 /// location by second-order central differencing.
904 ///
905 /// @note This method should not be called until the stencil
906 /// buffer has been populated via a call to moveTo(ijk).
908 {
909 return mInvDx2 * (
910 mValues[1] + mValues[2] +
911 mValues[3] + mValues[4] +
912 mValues[5] + mValues[6] - 6*mValues[0]);
913 }
914
915 /// Return the gradient computed at the previously buffered
916 /// location by second-order central differencing.
917 ///
918 /// @note This method should not be called until the stencil
919 /// buffer has been populated via a call to moveTo(ijk).
921 {
922 return Vec3<ValueType>(
923 mValues[2] - mValues[1],
924 mValues[4] - mValues[3],
925 mValues[6] - mValues[5])*mInv2Dx;
926 }
927
928 /// Return linear offset for the specified stencil point relative to its center
929 template<int i, int j, int k>
930 __hostdev__ unsigned int pos() const { return CurvPt<i,j,k>::idx; }
931
932private:
933 __hostdev__ inline void init(const Coord &ijk)
934 {
935 mValues[ 1] = mAcc.getValue(ijk.offsetBy(-1, 0, 0));
936 mValues[ 2] = mAcc.getValue(ijk.offsetBy( 1, 0, 0));
937
938 mValues[ 3] = mAcc.getValue(ijk.offsetBy( 0, -1, 0));
939 mValues[ 4] = mAcc.getValue(ijk.offsetBy( 0, 1, 0));
940
941 mValues[ 5] = mAcc.getValue(ijk.offsetBy( 0, 0, -1));
942 mValues[ 6] = mAcc.getValue(ijk.offsetBy( 0, 0, 1));
943
944 mValues[ 7] = mAcc.getValue(ijk.offsetBy(-1, -1, 0));
945 mValues[ 8] = mAcc.getValue(ijk.offsetBy( 1, -1, 0));
946 mValues[ 9] = mAcc.getValue(ijk.offsetBy(-1, 1, 0));
947 mValues[10] = mAcc.getValue(ijk.offsetBy( 1, 1, 0));
948
949 mValues[11] = mAcc.getValue(ijk.offsetBy(-1, 0, -1));
950 mValues[12] = mAcc.getValue(ijk.offsetBy( 1, 0, -1));
951 mValues[13] = mAcc.getValue(ijk.offsetBy(-1, 0, 1));
952 mValues[14] = mAcc.getValue(ijk.offsetBy( 1, 0, 1));
953
954 mValues[15] = mAcc.getValue(ijk.offsetBy( 0, -1, -1));
955 mValues[16] = mAcc.getValue(ijk.offsetBy( 0, 1, -1));
956 mValues[17] = mAcc.getValue(ijk.offsetBy( 0, -1, 1));
957 mValues[18] = mAcc.getValue(ijk.offsetBy( 0, 1, 1));
958 }
959
960 __hostdev__ inline RealT Dx() const { return 0.5*(mValues[2] - mValues[1]); }// * 1/dx
961 __hostdev__ inline RealT Dy() const { return 0.5*(mValues[4] - mValues[3]); }// * 1/dx
962 __hostdev__ inline RealT Dz() const { return 0.5*(mValues[6] - mValues[5]); }// * 1/dx
963 __hostdev__ inline RealT Dxx() const { return mValues[2] - 2 * mValues[0] + mValues[1]; }// * 1/dx2
964 __hostdev__ inline RealT Dyy() const { return mValues[4] - 2 * mValues[0] + mValues[3]; }// * 1/dx2}
965 __hostdev__ inline RealT Dzz() const { return mValues[6] - 2 * mValues[0] + mValues[5]; }// * 1/dx2
966 __hostdev__ inline RealT Dxy() const { return 0.25 * (mValues[10] - mValues[ 8] + mValues[ 7] - mValues[ 9]); }// * 1/dx2
967 __hostdev__ inline RealT Dxz() const { return 0.25 * (mValues[14] - mValues[12] + mValues[11] - mValues[13]); }// * 1/dx2
968 __hostdev__ inline RealT Dyz() const { return 0.25 * (mValues[18] - mValues[16] + mValues[15] - mValues[17]); }// * 1/dx2
969
970 __hostdev__ inline bool meanCurvature(RealT& alpha, RealT& normGrad) const
971 {
972 // For performance all finite differences are unscaled wrt dx
973 const RealT Dx = this->Dx(), Dy = this->Dy(), Dz = this->Dz(),
974 Dx2 = Dx*Dx, Dy2 = Dy*Dy, Dz2 = Dz*Dz, normGrad2 = Dx2 + Dy2 + Dz2;
975 if (normGrad2 <= Tolerance<RealT>::value()) {
976 alpha = normGrad = 0;
977 return false;
978 }
979 const RealT Dxx = this->Dxx(), Dyy = this->Dyy(), Dzz = this->Dzz();
980 alpha = Dx2*(Dyy + Dzz) + Dy2*(Dxx + Dzz) + Dz2*(Dxx + Dyy) -
981 2*(Dx*(Dy*this->Dxy() + Dz*this->Dxz()) + Dy*Dz*this->Dyz());// * 1/dx^4
982 normGrad = Sqrt(normGrad2); // * 1/dx
983 return true;
984 }
985
986 __hostdev__ inline bool gaussianCurvature(RealT& alpha, RealT& normGrad) const
987 {
988 // For performance all finite differences are unscaled wrt dx
989 const RealT Dx = this->Dx(), Dy = this->Dy(), Dz = this->Dz(),
990 Dx2 = Dx*Dx, Dy2 = Dy*Dy, Dz2 = Dz*Dz, normGrad2 = Dx2 + Dy2 + Dz2;
991 if (normGrad2 <= Tolerance<RealT>::value()) {
992 alpha = normGrad = 0;
993 return false;
994 }
995 const RealT Dxx = this->Dxx(), Dyy = this->Dyy(), Dzz = this->Dzz(),
996 Dxy = this->Dxy(), Dxz = this->Dxz(), Dyz = this->Dyz();
997 alpha = Dx2*(Dyy*Dzz - Dyz*Dyz) + Dy2*(Dxx*Dzz - Dxz*Dxz) + Dz2*(Dxx*Dyy - Dxy*Dxy) +
998 2*( Dy*Dz*(Dxy*Dxz - Dyz*Dxx) + Dx*Dz*(Dxy*Dyz - Dxz*Dyy) + Dx*Dy*(Dxz*Dyz - Dxy*Dzz) );// * 1/dx^6
999 normGrad = Sqrt(normGrad2); // * 1/dx
1000 return true;
1001 }
1002
1003 __hostdev__ inline bool curvatures(RealT& alphaM, RealT& alphaG, RealT& normGrad) const
1004 {
1005 // For performance all finite differences are unscaled wrt dx
1006 const RealT Dx = this->Dx(), Dy = this->Dy(), Dz = this->Dz(),
1007 Dx2 = Dx*Dx, Dy2 = Dy*Dy, Dz2 = Dz*Dz, normGrad2 = Dx2 + Dy2 + Dz2;
1008 if (normGrad2 <= Tolerance<RealT>::value()) {
1009 alphaM = alphaG =normGrad = 0;
1010 return false;
1011 }
1012 const RealT Dxx = this->Dxx(), Dyy = this->Dyy(), Dzz = this->Dzz(),
1013 Dxy = this->Dxy(), Dxz = this->Dxz(), Dyz = this->Dyz();
1014 alphaM = Dx2*(Dyy + Dzz) + Dy2*(Dxx + Dzz) + Dz2*(Dxx + Dyy) -
1015 2*(Dx*(Dy*Dxy + Dz*Dxz) + Dy*Dz*Dyz);// *1/dx^4
1016 alphaG = Dx2*(Dyy*Dzz - Dyz*Dyz) + Dy2*(Dxx*Dzz - Dxz*Dxz) + Dz2*(Dxx*Dyy - Dxy*Dxy) +
1017 2*( Dy*Dz*(Dxy*Dxz - Dyz*Dxx) + Dx*Dz*(Dxy*Dyz - Dxz*Dyy) + Dx*Dy*(Dxz*Dyz - Dxy*Dzz) );// *1/dx^6
1018 normGrad = Sqrt(normGrad2); // * 1/dx
1019 return true;
1020 }
1021
1022 template<typename, int, typename> friend class BaseStencil; // allow base class to call init()
1023 using BaseType::mAcc;
1024 using BaseType::mValues;
1025 const ValueType mInv2Dx, mInvDx2;
1026}; // CurvatureStencil class
1027
1028}// namespace math
1029
1030} // end nanovdb namespace
1031
1032#endif // NANOVDB_MATH_STENCILS_HAS_BEEN_INCLUDED
__hostdev__ const ValueType & getCenterValue() const
Return the value at the center of the stencil.
Definition Stencils.h:214
ValueType mValues[SIZE]
Definition Stencils.h:281
__hostdev__ const ValueType & getValue() const
Return the value at the specified location relative to the center of the stencil.
Definition Stencils.h:167
__hostdev__ void moveTo(const Coord &ijk, const ValueType &centerValue)
Initialize the stencil buffer with the values of voxel (i, j, k) and its neighbors....
Definition Stencils.h:121
__hostdev__ void moveTo(const Vec3< RealType > &xyz)
Initialize the stencil buffer with the values of voxel (x, y, z) and its neighbors.
Definition Stencils.h:148
__hostdev__ const ValueType & getValue(unsigned int pos=0) const
Return the value from the stencil buffer with linear offset pos.
Definition Stencils.h:159
__hostdev__ void moveTo(const IterType &iter)
Initialize the stencil buffer with the values of voxel (x, y, z) and its neighbors.
Definition Stencils.h:134
__hostdev__ Mask intersectionMask(ValueType isoValue=ValueType(0)) const
Return true a bit-mask where the 6 lower bits indicates if the center of the stencil intersects the i...
Definition Stencils.h:249
__hostdev__ ValueType min() const
Return the smallest value in the stencil buffer.
Definition Stencils.h:191
typename GridT::AccessorType AccessorType
Definition Stencils.h:104
__hostdev__ bool intersects(const ValueType &isoValue=ValueType(0)) const
Return true if the center of the stencil intersects the iso-contour specified by the isoValue.
Definition Stencils.h:218
Coord mCenter
Definition Stencils.h:282
const GridType * mGrid
Definition Stencils.h:279
__hostdev__ void moveTo(const Coord &ijk)
Initialize the stencil buffer with the values of voxel (i, j, k) and its neighbors.
Definition Stencils.h:109
__hostdev__ const AccessorType & accessor() const
Return a const reference to the ValueAccessor associated with this Stencil.
Definition Stencils.h:268
typename GridT::TreeType TreeType
Definition Stencils.h:103
typename GridT::ValueType ValueType
Definition Stencils.h:101
__hostdev__ void setValue(const ValueType &value)
Set the value at the specified location relative to the center of the stencil.
Definition Stencils.h:174
__hostdev__ const GridType & grid() const
Return a const reference to the grid from which this stencil was constructed.
Definition Stencils.h:264
__hostdev__ ValueType max() const
Return the largest value in the stencil buffer.
Definition Stencils.h:201
__hostdev__ BaseStencil(const GridType &grid)
Definition Stencils.h:272
__hostdev__ const Coord & getCenterCoord() const
Return the coordinates of the center point of the stencil.
Definition Stencils.h:211
__hostdev__ ValueType mean() const
Return the mean value of the current stencil.
Definition Stencils.h:183
AccessorType mAcc
Definition Stencils.h:280
GridT GridType
Definition Stencils.h:102
static __hostdev__ int size()
Return the size of the stencil buffer.
Definition Stencils.h:180
static constexpr int SIZE
Definition Stencils.h:315
__hostdev__ BoxStencil(const GridType &grid)
Definition Stencils.h:317
__hostdev__ ValueType interpolation(const Vec3< ValueType > &xyz) const
Return the trilinear interpolation at the normalized position.
Definition Stencils.h:344
__hostdev__ bool intersects(ValueType isoValue=ValueType(0)) const
Return true if the center of the stencil intersects the.
Definition Stencils.h:325
__hostdev__ Vec3< ValueType > gradient(const Vec3< ValueType > &xyz) const
Return the gradient in world space of the trilinear interpolation kernel.
Definition Stencils.h:376
__hostdev__ unsigned int pos() const
Return linear offset for the specified stencil point relative to its center.
Definition Stencils.h:321
typename GridT::TreeType TreeType
Definition Stencils.h:312
typename GridT::ValueType ValueType
Definition Stencils.h:313
friend class BaseStencil
Definition Stencils.h:428
GridT GridType
Definition Stencils.h:311
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition Math.h:346
__hostdev__ Coord offsetBy(ValueType dx, ValueType dy, ValueType dz) const
Definition Math.h:546
static constexpr int SIZE
Definition Stencils.h:790
__hostdev__ void principalCurvatures(ValueType &min, ValueType &max) const
Computes the minimum and maximum principal curvature at the previously buffered location.
Definition Stencils.h:890
__hostdev__ Vec3< ValueType > gradient() const
Definition Stencils.h:920
__hostdev__ ValueType gaussianCurvatureNormGrad() const
Definition Stencils.h:862
__hostdev__ CurvatureStencil(const GridType &grid)
Definition Stencils.h:792
__hostdev__ CurvatureStencil(const GridType &grid, double dx)
Definition Stencils.h:799
__hostdev__ ValueType meanCurvature() const
Return the mean curvature at the previously buffered location.
Definition Stencils.h:810
__hostdev__ void curvaturesNormGrad(ValueType &mean, ValueType &gauss) const
Return both the mean and the Gaussian curvature at the previously buffered location.
Definition Stencils.h:874
__hostdev__ void curvatures(ValueType &mean, ValueType &gauss) const
Return both the mean and the Gaussian curvature at the previously buffered location.
Definition Stencils.h:833
__hostdev__ ValueType gaussianCurvature() const
Return the Gaussian curvature at the previously buffered location.
Definition Stencils.h:821
__hostdev__ unsigned int pos() const
Return linear offset for the specified stencil point relative to its center.
Definition Stencils.h:930
typename GridT::TreeType TreeType
Definition Stencils.h:787
typename GridT::ValueType ValueType
Definition Stencils.h:788
friend class BaseStencil
Definition Stencils.h:1022
__hostdev__ ValueType meanCurvatureNormGrad() const
Definition Stencils.h:850
GridT GridType
Definition Stencils.h:786
__hostdev__ ValueType laplacian() const
Definition Stencils.h:907
__hostdev__ GradStencil(const GridType &grid, double dx)
Definition Stencils.h:474
static constexpr int SIZE
Definition Stencils.h:465
__hostdev__ Vec3< ValueType > gradient() const
Return the gradient computed at the previously buffered location by second order central differencing...
Definition Stencils.h:502
__hostdev__ ValueType normSqGrad() const
Return the norm square of the single-sided upwind gradient (computed via Godunov's scheme) at the pre...
Definition Stencils.h:486
__hostdev__ GradStencil(const GridType &grid)
Definition Stencils.h:467
__hostdev__ Vec3< ValueType > gradient(const Vec3< ValueType > &V) const
Return the first-order upwind gradient corresponding to the direction V.
Definition Stencils.h:512
__hostdev__ unsigned int pos() const
Return linear offset for the specified stencil point relative to its center.
Definition Stencils.h:556
__hostdev__ bool zeroCrossing() const
Definition Stencils.h:531
__hostdev__ Vec3< ValueType > cpt()
Compute the closest-point transform to a level set.
Definition Stencils.h:544
typename GridT::TreeType TreeType
Definition Stencils.h:462
typename GridT::ValueType ValueType
Definition Stencils.h:463
friend class BaseStencil
Definition Stencils.h:572
GridT GridType
Definition Stencils.h:461
__hostdev__ ValueType laplacian() const
Definition Stencils.h:522
A simple vector class with three components, similar to openvdb::math::Vec3.
Definition Math.h:1362
static constexpr int SIZE
Definition Stencils.h:624
__hostdev__ Vec3< ValueType > gradient() const
Definition Stencils.h:682
__hostdev__ Vec3< ValueType > gradient(const Vec3< ValueType > &V) const
Definition Stencils.h:666
__hostdev__ unsigned int pos() const
Return linear offset for the specified stencil point relative to its center.
Definition Stencils.h:713
__hostdev__ bool zeroCrossing() const
Definition Stencils.h:704
__hostdev__ ValueType normSqGrad(ValueType isoValue=ValueType(0)) const
Return the norm-square of the WENO upwind gradient (computed via WENO upwinding and Godunov's scheme)...
Definition Stencils.h:647
typename GridT::TreeType TreeType
Definition Stencils.h:621
typename GridT::ValueType ValueType
Definition Stencils.h:622
friend class BaseStencil
Definition Stencils.h:740
__hostdev__ WenoStencil(const GridType &grid, double dx)
Definition Stencils.h:634
__hostdev__ WenoStencil(const GridType &grid)
Definition Stencils.h:626
GridT GridType
Definition Stencils.h:620
__hostdev__ ValueType laplacian() const
Definition Stencils.h:694
#define __hostdev__
Definition SampleFromVoxels.h:29
Definition DitherLUT.h:19
__hostdev__ T Pow3(T x)
Definition Math.h:218
__hostdev__ RealT GodunovsNormSqrd(bool isOutside, RealT dP_xm, RealT dP_xp, RealT dP_ym, RealT dP_yp, RealT dP_zm, RealT dP_zp)
Definition Stencils.h:64
__hostdev__ ValueType WENO5(const ValueType &v1, const ValueType &v2, const ValueType &v3, const ValueType &v4, const ValueType &v5, RealT scale2=1.0)
Implementation of nominally fifth-order finite-difference WENO.
Definition Stencils.h:37
__hostdev__ T Pow2(T x)
Definition Math.h:212
__hostdev__ T Pow4(T x)
Definition Math.h:224
__hostdev__ CoordT RoundDown(const Vec3T< RealT > &xyz)
Definition Math.h:270
__hostdev__ Type Max(Type a, Type b)
Definition Math.h:154
__hostdev__ float Sqrt(float x)
Return the square root of a floating-point value.
Definition Math.h:277
__hostdev__ Type Min(Type a, Type b)
Definition Math.h:133
uint32_t countOn(uint64_t v)
Definition Util.h:668
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:31
Math functions and classes.
#define NANOVDB_ASSERT(x)
Definition Util.h:53
__hostdev__ bool all() const
Definition Stencils.h:234
__hostdev__ bool none() const
Definition Stencils.h:235
uint8_t bits
Definition Stencils.h:229
__hostdev__ int count() const
Definition Stencils.h:236
__hostdev__ Mask()
Definition Stencils.h:230
__hostdev__ bool test(int i) const
Definition Stencils.h:232
__hostdev__ void set(int i)
Definition Stencils.h:231
__hostdev__ bool any() const
Definition Stencils.h:233