OpenVDB 14.0.0
Loading...
Searching...
No Matches
GridStats.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/*!
5 \file nanovdb/tools/GridStats.h
6
7 \author Ken Museth
8
9 \date August 29, 2020
10
11 \brief Re-computes min/max/avg/var/bbox information for each node in a
12 pre-existing NanoVDB grid.
13*/
14
15#ifndef NANOVDB_TOOLS_GRIDSTATS_H_HAS_BEEN_INCLUDED
16#define NANOVDB_TOOLS_GRIDSTATS_H_HAS_BEEN_INCLUDED
17
18#include <nanovdb/NanoVDB.h>
20
21#ifdef NANOVDB_USE_TBB
22#include <memory>
23#include <tbb/blocked_range.h>
24#include <tbb/parallel_reduce.h>
25#endif
26
27#if defined(__CUDACC__)
28#include <cuda/std/limits>// for cuda::std::numeric_limits
29#else
30#include <limits.h>// for std::numeric_limits
31#endif
32
33#include <atomic>
34#include <iostream>
35
36namespace nanovdb {
37
38namespace tools {//=======================================================================
39
40/// @brief Grid flags which indicate what extra information is present in the grid buffer
41enum class StatsMode : uint32_t {
42 Disable = 0,// disable the computation of any type of statistics (obviously the FASTEST!)
43 BBox = 1,// only compute the bbox of active values per node and total activeVoxelCount
44 MinMax = 2,// additionally compute extrema values
45 All = 3,// compute all of the statics, i.e. bbox, min/max, average and standard deviation
46 Default = 3,// default computational mode for statistics
47 End = 4,
48};
49
50/// @brief Re-computes the min/max, stats and bbox information for an existing NanoVDB Grid
51/// @param grid Grid whose stats to update
52/// @param mode Mode of computation for the statistics.
53template<typename BuildT>
55
56template<typename ValueT, int Rank = TensorTraits<ValueT>::Rank>
57class Extrema;
58
59/// @brief Determine the extrema of all the values in a grid that
60/// intersects the specified bounding box.
61/// @tparam BuildT Build type of the input grid
62/// @param grid typed grid
63/// @param bbox index bounding box in which min/max are computed
64/// @return Extream of values insixe @c bbox
65template<typename BuildT>
67getExtrema(const NanoGrid<BuildT>& grid, const CoordBBox &bbox);
68
69//================================================================================================
70
71/// @brief Template specialization of Extrema on scalar value types, i.e. rank = 0
72template<typename ValueT>
73class Extrema<ValueT, 0>
74{
75protected:
76 ValueT mMin, mMax;
77
78public:
79 using ValueType = ValueT;
81#if defined(__CUDACC__)
82 // note "::cuda" is needed since we also define a cuda namespace
83 : mMin(::cuda::std::numeric_limits<ValueT>::max())
84 , mMax(::cuda::std::numeric_limits<ValueT>::lowest())
85#else
86 : mMin(std::numeric_limits<ValueT>::max())
87 , mMax(std::numeric_limits<ValueT>::lowest())
88#endif
89 {
90 }
91 __hostdev__ Extrema(const ValueT& v)
92 : mMin(v)
93 , mMax(v)
94 {
95 }
96 __hostdev__ Extrema(const ValueT& a, const ValueT& b)
97 : mMin(a)
98 , mMax(b)
99 {
100 }
101 __hostdev__ Extrema& min(const ValueT& v)
102 {
103 if (v < mMin) mMin = v;
104 return *this;
105 }
106 __hostdev__ Extrema& max(const ValueT& v)
107 {
108 if (v > mMax) mMax = v;
109 return *this;
110 }
111 __hostdev__ Extrema& add(const ValueT& v)
112 {
113 this->min(v);
114 this->max(v);
115 return *this;
116 }
117 __hostdev__ Extrema& add(const ValueT& v, uint64_t) { return this->add(v); }
118 __hostdev__ Extrema& add(const Extrema& other)
119 {
120 this->min(other.mMin);
121 this->max(other.mMax);
122 return *this;
123 }
124 __hostdev__ const ValueT& min() const { return mMin; }
125 __hostdev__ const ValueT& max() const { return mMax; }
126 __hostdev__ operator bool() const { return mMin <= mMax; }
127 __hostdev__ static constexpr bool hasMinMax() { return !util::is_same<bool, ValueT>::value; }
128 __hostdev__ static constexpr bool hasAverage() { return false; }
129 __hostdev__ static constexpr bool hasStdDeviation() { return false; }
130 __hostdev__ static constexpr bool hasStats() { return !util::is_same<bool, ValueT>::value; }
131 __hostdev__ static constexpr size_t size() { return 0; }
132
133 template <typename NodeT>
134 __hostdev__ void setStats(NodeT &node) const
135 {
136 node.setMin(this->min());
137 node.setMax(this->max());
138 }
139}; // Extrema<T, 0>
140
141/// @brief Template specialization of Extrema on vector value types, i.e. rank = 1
142template<typename VecT>
143class Extrema<VecT, 1>
144{
145protected:
146 using Real = typename VecT::ValueType; // this works with both nanovdb and openvdb vectors
147 struct Pair
148 {
150 VecT vector;
151
152 __hostdev__ Pair(Real s)// is only used by Extrema() default c-tor
153 : scalar(s)
154 , vector(s)
155 {
156 }
157 __hostdev__ Pair(const VecT& v)
158 : scalar(v.lengthSqr())
159 , vector(v)
160 {
161 }
162 __hostdev__ bool operator<(const Pair& rhs) const { return scalar < rhs.scalar; }
163 } mMin, mMax;
165 {
166 if (p < mMin) mMin = p;
167 if (mMax < p) mMax = p;
168 return *this;
169 }
170
171public:
172 using ValueType = VecT;
174#if defined(__CUDACC__)
175 // note "::cuda" is needed since we also define a cuda namespace
176 : mMin(::cuda::std::numeric_limits<Real>::max())
177 , mMax(::cuda::std::numeric_limits<Real>::lowest())
178#else
179 : mMin(std::numeric_limits<Real>::max())
180 , mMax(std::numeric_limits<Real>::lowest())
181#endif
182 {
183 }
184 __hostdev__ Extrema(const VecT& v)
185 : mMin(v)
186 , mMax(v)
187 {
188 }
189 __hostdev__ Extrema(const VecT& a, const VecT& b)
190 : mMin(a)
191 , mMax(b)
192 {
193 }
194 __hostdev__ Extrema& min(const VecT& v)
195 {
196 Pair tmp(v);
197 if (tmp < mMin) mMin = tmp;
198 return *this;
199 }
200 __hostdev__ Extrema& max(const VecT& v)
201 {
202 Pair tmp(v);
203 if (mMax < tmp) mMax = tmp;
204 return *this;
205 }
206 __hostdev__ Extrema& add(const VecT& v) { return this->add(Pair(v)); }
207 __hostdev__ Extrema& add(const VecT& v, uint64_t) { return this->add(Pair(v)); }
209 {
210 if (other.mMin < mMin) mMin = other.mMin;
211 if (mMax < other.mMax) mMax = other.mMax;
212 return *this;
213 }
214 __hostdev__ const VecT& min() const { return mMin.vector; }
215 __hostdev__ const VecT& max() const { return mMax.vector; }
216 __hostdev__ operator bool() const { return !(mMax < mMin); }
217 __hostdev__ static constexpr bool hasMinMax() { return !util::is_same<bool, Real>::value; }
218 __hostdev__ static constexpr bool hasAverage() { return false; }
219 __hostdev__ static constexpr bool hasStdDeviation() { return false; }
220 __hostdev__ static constexpr bool hasStats() { return !util::is_same<bool, Real>::value; }
221 __hostdev__ static constexpr size_t size() { return 0; }
222
223 template <typename NodeT>
224 __hostdev__ void setStats(NodeT &node) const
225 {
226 node.setMin(this->min());
227 node.setMax(this->max());
228 }
229}; // Extrema<T, 1>
230
231/// @brief Template specialization of Extrema on scalar Half precision value types, i.e. rank = 0
232template<>
234{
235 using ValueT = nanovdb::Half;
236protected:
237 ValueT mMin, mMax;
238
239public:
240 using ValueType = ValueT;
242 {
243 mMin.raw = 0x7BFF;
244 mMax.raw = 0xFBFF;
245 }
246 __hostdev__ Extrema(const ValueT& v)
247 : mMin(v)
248 , mMax(v)
249 {
250 }
251 __hostdev__ Extrema(const ValueT& a, const ValueT& b)
252 : mMin(a)
253 , mMax(b)
254 {
255 }
256 __hostdev__ Extrema& min(const ValueT& v)
257 {
259 return *this;
260 }
261 __hostdev__ Extrema& max(const ValueT& v)
262 {
264 return *this;
265 }
266 __hostdev__ Extrema& add(const ValueT& v)
267 {
268 this->min(v);
269 this->max(v);
270 return *this;
271 }
272 __hostdev__ Extrema& add(const ValueT& v, uint64_t) { return this->add(v); }
274 {
275 this->min(other.mMin);
276 this->max(other.mMax);
277 return *this;
278 }
279 __hostdev__ const ValueT& min() const { return mMin; }
280 __hostdev__ const ValueT& max() const { return mMax; }
281 __hostdev__ operator bool() const { return math::HalfToFloat(mMin.raw) <= math::HalfToFloat(mMax.raw); }
282 __hostdev__ static constexpr bool hasMinMax() { return !util::is_same<bool, ValueT>::value; }
283 __hostdev__ static constexpr bool hasAverage() { return false; }
284 __hostdev__ static constexpr bool hasStdDeviation() { return false; }
285 __hostdev__ static constexpr bool hasStats() { return !util::is_same<bool, ValueT>::value; }
286 __hostdev__ static constexpr size_t size() { return 0; }
287
288 template <typename NodeT>
289 __hostdev__ void setStats(NodeT &node) const
290 {
291 node.setMin(this->min());
292 node.setMax(this->max());
293 }
294}; // Extrema<T, 0>
295
296
297//================================================================================================
298
299template<typename ValueT, int Rank = TensorTraits<ValueT>::Rank>
300class Stats;
301
302/// @brief This class computes statistics (minimum value, maximum
303/// value, mean, variance and standard deviation) of a population
304/// of floating-point values.
305///
306/// @details variance = Mean[ (X-Mean[X])^2 ] = Mean[X^2] - Mean[X]^2,
307/// standard deviation = sqrt(variance)
308///
309/// @note This class employs incremental computation and double precision.
310template<typename ValueT>
311class Stats<ValueT, 0> : public Extrema<ValueT, 0>
312{
313protected:
315 using RealT = double; // for accuracy the internal precission must be 64 bit floats
316 size_t mSize;
317 double mAvg, mAux;
318
319public:
320 using ValueType = ValueT;
322 : BaseT()
323 , mSize(0)
324 , mAvg(0.0)
325 , mAux(0.0)
326 {
327 }
328 __hostdev__ Stats(const ValueT& val)
329 : BaseT(val)
330 , mSize(1)
331 , mAvg(RealT(val))
332 , mAux(0.0)
333 {
334 }
335 /// @brief Add a single sample
336 __hostdev__ Stats& add(const ValueT& val)
337 {
338 BaseT::add(val);
339 mSize += 1;
340 const double delta = double(val) - mAvg;
341 mAvg += delta / double(mSize);
342 mAux += delta * (double(val) - mAvg);
343 return *this;
344 }
345 /// @brief Add @a n samples with constant value @a val.
346 __hostdev__ Stats& add(const ValueT& val, uint64_t n)
347 {
348 const double denom = 1.0 / double(mSize + n);
349 const double delta = double(val) - mAvg;
350 mAvg += denom * delta * double(n);
351 mAux += denom * delta * delta * double(mSize) * double(n);
352 BaseT::add(val);
353 mSize += n;
354 return *this;
355 }
356
357 /// Add the samples from the other Stats instance.
358 __hostdev__ Stats& add(const Stats& other)
359 {
360 if (other.mSize > 0) {
361 const double denom = 1.0 / double(mSize + other.mSize);
362 const double delta = other.mAvg - mAvg;
363 mAvg += denom * delta * double(other.mSize);
364 mAux += other.mAux + denom * delta * delta * double(mSize) * double(other.mSize);
365 BaseT::add(other);
366 mSize += other.mSize;
367 }
368 return *this;
369 }
370
371 __hostdev__ static constexpr bool hasMinMax() { return !util::is_same<bool, ValueT>::value; }
372 __hostdev__ static constexpr bool hasAverage() { return !util::is_same<bool, ValueT>::value; }
374 __hostdev__ static constexpr bool hasStats() { return !util::is_same<bool, ValueT>::value; }
375
376 __hostdev__ size_t size() const { return mSize; }
377
378 //@{
379 /// Return the arithmetic mean, i.e. average, value.
380 __hostdev__ double avg() const { return mAvg; }
381 __hostdev__ double mean() const { return mAvg; }
382 //@}
383
384 //@{
385 /// @brief Return the population variance.
386 ///
387 /// @note The unbiased sample variance = population variance * num/(num-1)
388 __hostdev__ double var() const { return mSize < 2 ? 0.0 : mAux / double(mSize); }
389 __hostdev__ double variance() const { return this->var(); }
390 //@}
391
392 //@{
393 /// @brief Return the standard deviation (=Sqrt(variance)) as
394 /// defined from the (biased) population variance.
395 __hostdev__ double std() const { return sqrt(this->var()); }
396 __hostdev__ double stdDev() const { return this->std(); }
397 //@}
398
399 template <typename NodeT>
400 __hostdev__ void setStats(NodeT &node) const
401 {
402 node.setMin(this->min());
403 node.setMax(this->max());
404 node.setAvg(this->avg());
405 node.setDev(this->std());
406 }
407}; // end Stats<T, 0>
408
409/// @brief This class computes statistics (minimum value, maximum
410/// value, mean, variance and standard deviation) of a population
411/// of floating-point values.
412///
413/// @details variance = Mean[ (X-Mean[X])^2 ] = Mean[X^2] - Mean[X]^2,
414/// standard deviation = sqrt(variance)
415///
416/// @note This class employs incremental computation and double precision.
417template<typename ValueT>
418class Stats<ValueT, 1> : public Extrema<ValueT, 1>
419{
420protected:
422 using RealT = double; // for accuracy the internal precision must be 64 bit floats
423 size_t mSize;
424 double mAvg, mAux;
425
426public:
427 using ValueType = ValueT;
429 : BaseT()
430 , mSize(0)
431 , mAvg(0.0)
432 , mAux(0.0)
433 {
434 }
435 /// @brief Add a single sample
436 __hostdev__ Stats& add(const ValueT& val)
437 {
438 typename BaseT::Pair tmp(val);
439 BaseT::add(tmp);
440 mSize += 1;
441 const double delta = tmp.scalar - mAvg;
442 mAvg += delta / double(mSize);
443 mAux += delta * (tmp.scalar - mAvg);
444 return *this;
445 }
446 /// @brief Add @a n samples with constant value @a val.
447 __hostdev__ Stats& add(const ValueT& val, uint64_t n)
448 {
449 typename BaseT::Pair tmp(val);
450 const double denom = 1.0 / double(mSize + n);
451 const double delta = tmp.scalar - mAvg;
452 mAvg += denom * delta * double(n);
453 mAux += denom * delta * delta * double(mSize) * double(n);
454 BaseT::add(tmp);
455 mSize += n;
456 return *this;
457 }
458
459 /// Add the samples from the other Stats instance.
460 __hostdev__ Stats& add(const Stats& other)
461 {
462 if (other.mSize > 0) {
463 const double denom = 1.0 / double(mSize + other.mSize);
464 const double delta = other.mAvg - mAvg;
465 mAvg += denom * delta * double(other.mSize);
466 mAux += other.mAux + denom * delta * delta * double(mSize) * double(other.mSize);
467 BaseT::add(other);
468 mSize += other.mSize;
469 }
470 return *this;
471 }
472
473 __hostdev__ static constexpr bool hasMinMax() { return !util::is_same<bool, ValueT>::value; }
474 __hostdev__ static constexpr bool hasAverage() { return !util::is_same<bool, ValueT>::value; }
476 __hostdev__ static constexpr bool hasStats() { return !util::is_same<bool, ValueT>::value; }
477
478 __hostdev__ size_t size() const { return mSize; }
479
480 //@{
481 /// Return the arithmetic mean, i.e. average, value.
482 __hostdev__ double avg() const { return mAvg; }
483 __hostdev__ double mean() const { return mAvg; }
484 //@}
485
486 //@{
487 /// @brief Return the population variance.
488 ///
489 /// @note The unbiased sample variance = population variance * num/(num-1)
490 __hostdev__ double var() const { return mSize < 2 ? 0.0 : mAux / double(mSize); }
491 __hostdev__ double variance() const { return this->var(); }
492 //@}
493
494 //@{
495 /// @brief Return the standard deviation (=Sqrt(variance)) as
496 /// defined from the (biased) population variance.
497 __hostdev__ double std() const { return sqrt(this->var()); }
498 __hostdev__ double stdDev() const { return this->std(); }
499 //@}
500
501 template <typename NodeT>
502 __hostdev__ void setStats(NodeT &node) const
503 {
504 node.setMin(this->min());
505 node.setMax(this->max());
506 node.setAvg(this->avg());
507 node.setDev(this->std());
508 }
509}; // end Stats<T, 1>
510
511/// @brief This class computes statistics (minimum value, maximum
512/// value, mean, variance and standard deviation) of a population
513/// of half precision floating-point values.
514///
515/// @details variance = Mean[ (X-Mean[X])^2 ] = Mean[X^2] - Mean[X]^2,
516/// standard deviation = sqrt(variance)
517///
518/// @note This class employs incremental computation and double precision.
519template<>
520class Stats<nanovdb::Half, 0> : public Extrema<nanovdb::Half, 0>
521{
522 using ValueT = nanovdb::Half;
523protected:
525 using RealT = double; // for accuracy the internal precission must be 64 bit floats
526 size_t mSize;
527 double mAvg, mAux;
528
529public:
530 using ValueType = ValueT;
531 __hostdev__ double raw_to_double(const ValueT& v)
532 {
533 float vf = math::HalfToFloat(v.raw);
534 return double(vf);
535 }
537 : BaseT()
538 , mSize(0)
539 , mAvg(0.0)
540 , mAux(0.0)
541 {
542 }
543 __hostdev__ Stats(const ValueT& val)
544 : BaseT(val)
545 , mSize(1)
546 , mAvg(RealT(raw_to_double(val)))
547 , mAux(0.0)
548 {
549 }
550 /// @brief Add a single sample
551 __hostdev__ Stats& add(const ValueT& val)
552 {
553 BaseT::add(val);
554 mSize += 1;
555 const double delta = raw_to_double(val) - mAvg;
556 mAvg += delta / double(mSize);
557 mAux += delta * (raw_to_double(val) - mAvg);
558 return *this;
559 }
560 /// @brief Add @a n samples with constant value @a val.
561 __hostdev__ Stats& add(const ValueT& val, uint64_t n)
562 {
563 const double denom = 1.0 / double(mSize + n);
564 const double delta = raw_to_double(val) - mAvg;
565 mAvg += denom * delta * double(n);
566 mAux += denom * delta * delta * double(mSize) * double(n);
567 BaseT::add(val);
568 mSize += n;
569 return *this;
570 }
571
572 /// Add the samples from the other Stats instance.
573 __hostdev__ Stats& add(const Stats& other)
574 {
575 if (other.mSize > 0) {
576 const double denom = 1.0 / double(mSize + other.mSize);
577 const double delta = other.mAvg - mAvg;
578 mAvg += denom * delta * double(other.mSize);
579 mAux += other.mAux + denom * delta * delta * double(mSize) * double(other.mSize);
580 BaseT::add(other);
581 mSize += other.mSize;
582 }
583 return *this;
584 }
585
586 __hostdev__ static constexpr bool hasMinMax() { return !util::is_same<bool, ValueT>::value; }
587 __hostdev__ static constexpr bool hasAverage() { return !util::is_same<bool, ValueT>::value; }
589 __hostdev__ static constexpr bool hasStats() { return !util::is_same<bool, ValueT>::value; }
590
591 __hostdev__ size_t size() const { return mSize; }
592
593 //@{
594 /// Return the arithmetic mean, i.e. average, value.
595 __hostdev__ double avg() const { return mAvg; }
596 __hostdev__ double mean() const { return mAvg; }
597 //@}
598
599 //@{
600 /// @brief Return the population variance.
601 ///
602 /// @note The unbiased sample variance = population variance * num/(num-1)
603 __hostdev__ double var() const { return mSize < 2 ? 0.0 : mAux / double(mSize); }
604 __hostdev__ double variance() const { return this->var(); }
605 //@}
606
607 //@{
608 /// @brief Return the standard deviation (=Sqrt(variance)) as
609 /// defined from the (biased) population variance.
610 __hostdev__ double std() const { return sqrt(this->var()); }
611 __hostdev__ double stdDev() const { return this->std(); }
612 //@}
613
614 template <typename NodeT>
615 __hostdev__ void setStats(NodeT &node) const
616 {
617 node.setMin(this->min());
618 node.setMax(this->max());
619 node.setAvg(this->avg());
620 node.setDev(this->std());
621 }
622}; // end Stats<T, 0>
623
624/// @brief No-op Stats class
625template<typename ValueT>
627{
628 using ValueType = ValueT;
630 __hostdev__ NoopStats(const ValueT&) {}
631 __hostdev__ NoopStats& add(const ValueT&) { return *this; }
632 __hostdev__ NoopStats& add(const ValueT&, uint64_t) { return *this; }
633 __hostdev__ NoopStats& add(const NoopStats&) { return *this; }
634 __hostdev__ static constexpr size_t size() { return 0; }
635 __hostdev__ static constexpr bool hasMinMax() { return false; }
636 __hostdev__ static constexpr bool hasAverage() { return false; }
637 __hostdev__ static constexpr bool hasStdDeviation() { return false; }
638 __hostdev__ static constexpr bool hasStats() { return false; }
639 template <typename NodeT>
640 __hostdev__ void setStats(NodeT&) const{}
641}; // end NoopStats<T>
642
643//================================================================================================
644
645/// @brief Allows for the construction of NanoVDB grids without any dependency
646template<typename GridT, typename StatsT = Stats<typename GridT::ValueType>>
648{
649 struct NodeStats;
650 using TreeT = typename GridT::TreeType;
651 using ValueT = typename TreeT::ValueType;
652 using BuildT = typename TreeT::BuildType;
653 using Node0 = typename TreeT::Node0; // leaf
654 using Node1 = typename TreeT::Node1; // lower
655 using Node2 = typename TreeT::Node2; // upper
656 using RootT = typename TreeT::Node3; // root
657 static_assert(util::is_same<ValueT, typename StatsT::ValueType>::value, "Mismatching type");
658
659 ValueT mDelta; // skip rendering of node if: node.max < -mDelta || node.min > mDelta
660
661 void process( GridT& );// process grid and all tree nodes
662 void process( TreeT& );// process Tree, root node and child nodes
663 void process( RootT& );// process root node and child nodes
664 NodeStats process( Node0& );// process leaf node
665
666 template<typename NodeT>
667 NodeStats process( NodeT& );// process internal node and child nodes
668
669 template<typename DataT, int Rank>
670 void setStats(DataT*, const Extrema<ValueT, Rank>&);
671 template<typename DataT, int Rank>
672 void setStats(DataT*, const Stats<ValueT, Rank>&);
673 template<typename DataT>
674 void setStats(DataT*, const NoopStats<ValueT>&) {}
675
676 template<typename T, typename FlagT>
677 typename std::enable_if<!std::is_floating_point<T>::value>::type
678 setFlag(const T&, const T&, FlagT& flag) const { flag &= ~FlagT(1); } // unset 1st bit to enable rendering
679
680 template<typename T, typename FlagT>
681 typename std::enable_if<std::is_floating_point<T>::value>::type
682 setFlag(const T& min, const T& max, FlagT& flag) const;
683
684public:
685 GridStats() = default;
686
687 void update(GridT& grid, ValueT delta = ValueT());
688
689}; // GridStats
690
691template<typename GridT, typename StatsT>
692struct GridStats<GridT, StatsT>::NodeStats
693{
694 StatsT stats;
696
697 NodeStats(): stats(), bbox() {}//activeCount(0), bbox() {};
698
699 NodeStats& add(const NodeStats &other)
700 {
701 stats.add( other.stats );// no-op for NoopStats?!
702 bbox[0].minComponent(other.bbox[0]);
703 bbox[1].maxComponent(other.bbox[1]);
704 return *this;
705 }
706};// GridStats::NodeStats
707
708//================================================================================================
709
710template<typename GridT, typename StatsT>
711void GridStats<GridT, StatsT>::update(GridT& grid, ValueT delta)
712{
713 mDelta = delta; // delta = voxel size for level sets, else 0
714 this->process( grid );
715}
716
717//================================================================================================
718
719template<typename GridT, typename StatsT>
720template<typename DataT, int Rank>
722 setStats(DataT* data, const Extrema<ValueT, Rank>& e)
723{
724 data->setMin(e.min());
725 data->setMax(e.max());
726}
727
728template<typename GridT, typename StatsT>
729template<typename DataT, int Rank>
730inline void GridStats<GridT, StatsT>::
731 setStats(DataT* data, const Stats<ValueT, Rank>& s)
732{
733 data->setMin(s.min());
734 data->setMax(s.max());
735 using FloatT = typename RootT::FloatType;// statistics type shared by all nodes in the tree
736 data->setAvg(static_cast<FloatT>(s.avg()));
737 data->setDev(static_cast<FloatT>(s.std()));
738}
739
740//================================================================================================
741
742template<typename GridT, typename StatsT>
743template<typename T, typename FlagT>
744inline typename std::enable_if<std::is_floating_point<T>::value>::type
745GridStats<GridT, StatsT>::
746 setFlag(const T& min, const T& max, FlagT& flag) const
747{
748 if (mDelta > 0 && (min > mDelta || max < -mDelta)) {// LS: min > dx || max < -dx
749 flag |= FlagT(1u);// set 1st bit to disable rendering
750 } else {
751 flag &= ~FlagT(1u);// unset 1st bit to enable rendering
752 }
753}
754
755//================================================================================================
756
757template<typename GridT, typename StatsT>
758void GridStats<GridT, StatsT>::process( GridT &grid )
759{
760 this->process( grid.tree() );// this processes tree, root and all nodes
761
762 // set world space AABB
763 auto& data = *grid.data();
764 const auto& indexBBox = grid.tree().root().bbox();
765 if (indexBBox.empty()) {
766 data.mWorldBBox = Vec3dBBox();
767 data.setBBoxOn(false);
768 } else {
769 // Note that below max is offset by one since CoordBBox.max is inclusive
770 // while bbox<Vec3d>.max is exclusive. However, min is inclusive in both
771 // CoordBBox and Vec3dBBox. This also guarantees that a grid with a single
772 // active voxel, does not have an empty world bbox! E.g. if a grid with a
773 // unit index-to-world transformation only contains the active voxel (0,0,0)
774 // then indeBBox = (0,0,0) -> (0,0,0) and then worldBBox = (0.0, 0.0, 0.0)
775 // -> (1.0, 1.0, 1.0). This is a consequence of the different definitions
776 // of index and world bounding boxes inherited from OpenVDB!
777 grid.mWorldBBox = CoordBBox(indexBBox[0], indexBBox[1].offsetBy(1)).transform(grid.map());
778 grid.setBBoxOn(true);
779 }
780
781 // set bit flags
782 data.setMinMaxOn(StatsT::hasMinMax());
783 data.setAverageOn(StatsT::hasAverage());
784 data.setStdDeviationOn(StatsT::hasStdDeviation());
785} // GridStats::process( Grid )
786
787//================================================================================================
788
789template<typename GridT, typename StatsT>
790inline void GridStats<GridT, StatsT>::process( typename GridT::TreeType &tree )
791{
792 this->process( tree.root() );
793}
794
795//================================================================================================
796
797template<typename GridT, typename StatsT>
798void GridStats<GridT, StatsT>::process(RootT &root)
799{
800 using ChildT = Node2;
801 auto &data = *root.data();
802 if (data.mTableSize == 0) { // empty root node
803 data.mMinimum = data.mMaximum = data.mBackground;
804 data.mAverage = data.mStdDevi = 0;
805 data.mBBox = CoordBBox();
806 } else {
807 NodeStats total;
808 for (uint32_t i = 0; i < data.mTableSize; ++i) {
809 auto* tile = data.tile(i);
810 if (tile->isChild()) { // process child node
811 total.add( this->process( *data.getChild(tile) ) );
812 } else if (tile->state) { // active tile
813 const Coord ijk = tile->origin();
814 total.bbox[0].minComponent(ijk);
815 total.bbox[1].maxComponent(ijk + Coord(ChildT::DIM - 1));
816 if (StatsT::hasStats()) { // resolved at compile time
817 total.stats.add(tile->value, ChildT::NUM_VALUES);
818 }
819 }
820 }
821 this->setStats(&data, total.stats);
822 if (total.bbox.empty()) {
823 std::cerr << "\nWarning in GridStats: input tree only contained inactive root tiles!"
824 << "\nWhile not strictly an error it's rather suspicious!\n";
825 }
826 data.mBBox = total.bbox;
827 }
828} // GridStats::process( RootNode )
829
830//================================================================================================
831
832template<typename GridT, typename StatsT>
833template<typename NodeT>
835GridStats<GridT, StatsT>::process(NodeT &node)
836{
837 static_assert(util::is_same<NodeT,Node1>::value || util::is_same<NodeT,Node2>::value, "Incorrect node type");
838 using ChildT = typename NodeT::ChildNodeType;
839
840 NodeStats total;
841 auto* data = node.data();
842
843 // Serial processing of active tiles
844 if (const auto tileCount = data->mValueMask.countOn()) {
845 //total.activeCount = tileCount * ChildT::NUM_VALUES; // active tiles
846 for (auto it = data->mValueMask.beginOn(); it; ++it) {
847 if (StatsT::hasStats()) { // resolved at compile time
848 total.stats.add( data->mTable[*it].value, ChildT::NUM_VALUES );
849 }
850 const Coord ijk = node.offsetToGlobalCoord(*it);
851 total.bbox[0].minComponent(ijk);
852 total.bbox[1].maxComponent(ijk + Coord(int32_t(ChildT::DIM) - 1));
853 }
854 }
855
856 // Serial or parallel processing of child nodes
857 if (const size_t childCount = data->mChildMask.countOn()) {
858#ifndef NANOVDB_USE_TBB
859 for (auto it = data->mChildMask.beginOn(); it; ++it) {
860 total.add( this->process( *data->getChild(*it) ) );
861 }
862#else
863 std::unique_ptr<ChildT*[]> childNodes(new ChildT*[childCount]);
864 ChildT **ptr = childNodes.get();
865 for (auto it = data->mChildMask.beginOn(); it; ++it) {
866 *ptr++ = data->getChild( *it );
867 }
868 using RangeT = tbb::blocked_range<size_t>;
869 total.add( tbb::parallel_reduce(RangeT(0, childCount), NodeStats(),
870 [&](const RangeT &r, NodeStats local)->NodeStats {
871 for(size_t i=r.begin(); i!=r.end(); ++i){
872 local.add( this->process( *childNodes[i] ) );
873 }
874 return local;},
875 [](NodeStats a, const NodeStats &b)->NodeStats { return a.add( b ); }
876 ));
877#endif
878 }
879
880 data->mBBox = total.bbox;
881 if (total.bbox.empty()) {
882 data->mFlags |= uint32_t(1); // set 1st bit on to disable rendering of node
883 data->mFlags &= ~uint32_t(2); // set 2nd bit off since node does not contain active values
884 } else {
885 data->mFlags |= uint32_t(2); // set 2nd bit on since node contains active values
886 if (StatsT::hasStats()) { // resolved at compile time
887 this->setStats(data, total.stats);
888 this->setFlag(data->mMinimum, data->mMaximum, data->mFlags);
889 }
890 }
891 return total;
892} // GridStats::process( InternalNode )
893
894//================================================================================================
895
896template<typename GridT, typename StatsT>
898GridStats<GridT, StatsT>::process(Node0 &leaf)
899{
900 NodeStats local;
901 if (leaf.updateBBox()) {// optionally update active bounding box (updates data->mFlags)
902 local.bbox[0] = local.bbox[1] = leaf.mBBoxMin;
903 local.bbox[1] += Coord(leaf.mBBoxDif[0], leaf.mBBoxDif[1], leaf.mBBoxDif[2]);
904 if (StatsT::hasStats()) {// resolved at compile time
905 for (auto it = leaf.cbeginValueOn(); it; ++it) local.stats.add(*it);
906 this->setStats(&leaf, local.stats);
907 this->setFlag(leaf.getMin(), leaf.getMax(), leaf.mFlags);
908 }
909 }
910 return local;
911} // GridStats::process( LeafNode )
912
913//================================================================================================
914
915template<typename BuildT>
917{
918 NANOVDB_ASSERT(grid);
919 using GridT = NanoGrid<BuildT>;
920 using ValueT = typename GridT::ValueType;
921 if (mode == StatsMode::Disable) {
922 return;
925 stats.update(*grid);
926 } else if (mode == StatsMode::MinMax) {
928 stats.update(*grid);
929 } else if (mode == StatsMode::All) {
931 stats.update(*grid);
932 } else {
933 throw std::runtime_error("updateGridStats: Unsupported statistics mode.");
934 }
935}// updateGridStats
936
937//================================================================================================
938
939namespace {
940
941// returns a bitmask (of size 32^3 or 16^3) that marks all the entries
942// in a node table that intersects with the specified bounding box.
943template<typename NodeT>
944Mask<NodeT::LOG2DIM> getBBoxMask(const CoordBBox &bbox, const NodeT* node)
945{
946 Mask<NodeT::LOG2DIM> mask;// typically 32^3 or 16^3 bit mask
947 auto b = CoordBBox::createCube(node->origin(), node->dim());
948 assert( bbox.hasOverlap(b) );
949 if ( bbox.isInside(b) ) {
950 mask.setOn();//node is completely inside the bbox so early out
951 } else {
952 b.intersect(bbox);// trim bounding box
953 // transform bounding box from global to local coordinates
954 b.min() &= NodeT::DIM-1u;
955 b.min() >>= NodeT::ChildNodeType::TOTAL;
956 b.max() &= NodeT::DIM-1u;
957 b.max() >>= NodeT::ChildNodeType::TOTAL;
958 assert( !b.empty() );
959 auto it = b.begin();// iterates over all the child nodes or tiles that intersects bbox
960 for (const Coord& ijk = *it; it; ++it) {
961 mask.setOn(ijk[2] + (ijk[1] << NodeT::LOG2DIM) + (ijk[0] << 2*NodeT::LOG2DIM));
962 }
963 }
964 return mask;
965}// getBBoxMask
966
967}// end of unnamed namespace
968
969/// @brief return the extrema of all the values in a grid that
970/// intersects the specified bounding box.
971template<typename BuildT>
973getExtrema(const NanoGrid<BuildT>& grid, const CoordBBox &bbox)
974{
975 using GridT = NanoGrid<BuildT>;
976 using ValueT = typename GridT::ValueType;
977 using TreeT = typename GridTree<GridT>::type;
978 using RootT = typename NodeTrait<TreeT, 3>::type;// root node
979 using Node2 = typename NodeTrait<TreeT, 2>::type;// upper internal node
980 using Node1 = typename NodeTrait<TreeT, 1>::type;// lower internal node
981 using Node0 = typename NodeTrait<TreeT, 0>::type;// leaf node
982
983 Extrema<ValueT> extrema;
984 const RootT &root = grid.tree().root();
985 const auto &bbox3 = root.bbox();
986 if (bbox.isInside(bbox3)) {// bbox3 is contained inside bbox
987 extrema.min(root.minimum());
988 extrema.max(root.maximum());
989 extrema.add(root.background());
990 } else if (bbox.hasOverlap(bbox3)) {
991 const auto *data3 = root.data();
992 for (uint32_t i=0; i<data3->mTableSize; ++i) {
993 const auto *tile = data3->tile(i);
994 CoordBBox bbox2 = CoordBBox::createCube(tile->origin(), Node2::dim());
995 if (!bbox.hasOverlap(bbox2)) continue;
996 if (tile->isChild()) {
997 const Node2 *node2 = data3->getChild(tile);
998 if (bbox.isInside(bbox2)) {
999 extrema.min(node2->minimum());
1000 extrema.max(node2->maximum());
1001 } else {// partial intersections at level 2
1002 auto *data2 = node2->data();
1003 const auto bboxMask2 = getBBoxMask(bbox, node2);
1004 for (auto it2 = bboxMask2.beginOn(); it2; ++it2) {
1005 if (data2->mChildMask.isOn(*it2)) {
1006 const Node1* node1 = data2->getChild(*it2);
1007 CoordBBox bbox1 = CoordBBox::createCube(node1->origin(), Node1::dim());
1008 if (bbox.isInside(bbox1)) {
1009 extrema.min(node1->minimum());
1010 extrema.max(node1->maximum());
1011 } else {// partial intersection at level 1
1012 auto *data1 = node1->data();
1013 const auto bboxMask1 = getBBoxMask(bbox, node1);
1014 for (auto it1 = bboxMask1.beginOn(); it1; ++it1) {
1015 if (data1->mChildMask.isOn(*it1)) {
1016 const Node0* node0 = data1->getChild(*it1);
1017 CoordBBox bbox0 = CoordBBox::createCube(node0->origin(), Node0::dim());
1018 if (bbox.isInside(bbox0)) {
1019 extrema.min(node0->minimum());
1020 extrema.max(node0->maximum());
1021 } else {// partial intersection at level 0
1022 auto *data0 = node0->data();
1023 const auto bboxMask0 = getBBoxMask(bbox, node0);
1024 for (auto it0 = bboxMask0.beginOn(); it0; ++it0) {
1025 extrema.add(data0->getValue(*it0));
1026 }
1027 }// end partial intersection at level 0
1028 } else {// tile at level 1
1029 extrema.add(data1->mTable[*it1].value);
1030 }
1031 }
1032 }// end of partial intersection at level 1
1033 } else {// tile at level 2
1034 extrema.add(data2->mTable[*it2].value);
1035 }
1036 }// loop over tiles and nodes at level 2
1037 }// end of partial intersection at level 1
1038 } else {// tile at root level
1039 extrema.add(tile->value);
1040 }
1041 }// loop over root table
1042 } else {// bbox does not overlap the grid
1043 extrema.add(root.background());
1044 }
1045 return extrema;
1046}// getExtrema
1047
1048}// namespace tools
1049
1050} // namespace nanovdb
1051
1052#endif // NANOVDB_TOOLS_GRIDSTATS_H_HAS_BEEN_INCLUDED
Implements a light-weight self-contained VDB data-structure in a single file! In other words,...
#define __hostdev__
Definition SampleFromVoxels.h:29
const TreeT & tree() const
Return a const reference to the tree.
Definition NanoVDB.h:2211
Type containing raw 16 bits for half precision floating point values (IEEE 754 Half)
Definition NanoVDB.h:187
uint16_t raw
Definition NanoVDB.h:189
Bit-mask to encode active states and facilitate sequential iterators and a fast codec for I/O compres...
Definition NanoVDB.h:1054
void setOn(uint32_t n)
Set the specified bit on.
Definition NanoVDB.h:1242
__hostdev__ void setStats(NodeT &node) const
Definition GridStats.h:224
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:218
static __hostdev__ constexpr size_t size()
Definition GridStats.h:221
__hostdev__ Extrema & min(const VecT &v)
Definition GridStats.h:194
struct nanovdb::tools::Extrema< VecT, 1 >::Pair mMin
__hostdev__ Extrema & add(const Pair &p)
Definition GridStats.h:164
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:217
typename VecT::ValueType Real
Definition GridStats.h:146
__hostdev__ Extrema()
Definition GridStats.h:173
struct nanovdb::tools::Extrema< VecT, 1 >::Pair mMax
__hostdev__ Extrema & add(const VecT &v, uint64_t)
Definition GridStats.h:207
__hostdev__ const VecT & max() const
Definition GridStats.h:215
__hostdev__ Extrema & max(const VecT &v)
Definition GridStats.h:200
__hostdev__ Extrema(const VecT &v)
Definition GridStats.h:184
__hostdev__ Extrema & add(const Extrema &other)
Definition GridStats.h:208
__hostdev__ Extrema(const VecT &a, const VecT &b)
Definition GridStats.h:189
__hostdev__ const VecT & min() const
Definition GridStats.h:214
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:219
__hostdev__ Extrema & add(const VecT &v)
Definition GridStats.h:206
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:220
VecT ValueType
Definition GridStats.h:172
__hostdev__ void setStats(NodeT &node) const
Definition GridStats.h:289
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:283
static __hostdev__ constexpr size_t size()
Definition GridStats.h:286
__hostdev__ Extrema & add(const ValueT &v, uint64_t)
Definition GridStats.h:272
__hostdev__ Extrema & max(const ValueT &v)
Definition GridStats.h:261
__hostdev__ const ValueT & min() const
Definition GridStats.h:279
ValueT ValueType
Definition GridStats.h:240
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:282
__hostdev__ Extrema()
Definition GridStats.h:241
__hostdev__ const ValueT & max() const
Definition GridStats.h:280
ValueT mMin
Definition GridStats.h:237
__hostdev__ Extrema & add(const Extrema &other)
Definition GridStats.h:273
ValueT mMax
Definition GridStats.h:237
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:284
__hostdev__ Extrema & add(const ValueT &v)
Definition GridStats.h:266
__hostdev__ Extrema(const ValueT &a, const ValueT &b)
Definition GridStats.h:251
__hostdev__ Extrema & min(const ValueT &v)
Definition GridStats.h:256
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:285
__hostdev__ Extrema(const ValueT &v)
Definition GridStats.h:246
Definition GridStats.h:57
Allows for the construction of NanoVDB grids without any dependency.
Definition GridStats.h:648
void update(GridT &grid, ValueT delta=ValueT())
Definition GridStats.h:711
__hostdev__ Stats & add(const Stats &other)
Add the samples from the other Stats instance.
Definition GridStats.h:358
__hostdev__ void setStats(NodeT &node) const
Definition GridStats.h:400
double mAvg
Definition GridStats.h:317
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:372
__hostdev__ double stdDev() const
Definition GridStats.h:396
__hostdev__ Stats()
Definition GridStats.h:321
ValueT ValueType
Definition GridStats.h:320
__hostdev__ double mean() const
Definition GridStats.h:381
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:371
size_t mSize
Definition GridStats.h:316
double RealT
Definition GridStats.h:315
__hostdev__ Stats & add(const ValueT &val)
Add a single sample.
Definition GridStats.h:336
__hostdev__ double var() const
Return the population variance.
Definition GridStats.h:388
__hostdev__ Stats & add(const ValueT &val, uint64_t n)
Add n samples with constant value val.
Definition GridStats.h:346
__hostdev__ double avg() const
Return the arithmetic mean, i.e. average, value.
Definition GridStats.h:380
__hostdev__ double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance.
Definition GridStats.h:395
__hostdev__ Stats(const ValueT &val)
Definition GridStats.h:328
__hostdev__ size_t size() const
Definition GridStats.h:376
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:373
double mAux
Definition GridStats.h:317
Extrema< ValueT, 0 > BaseT
Definition GridStats.h:314
__hostdev__ double variance() const
Definition GridStats.h:389
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:374
__hostdev__ Stats & add(const Stats &other)
Add the samples from the other Stats instance.
Definition GridStats.h:460
__hostdev__ void setStats(NodeT &node) const
Definition GridStats.h:502
double mAvg
Definition GridStats.h:424
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:474
__hostdev__ double stdDev() const
Definition GridStats.h:498
__hostdev__ Stats()
Definition GridStats.h:428
ValueT ValueType
Definition GridStats.h:427
__hostdev__ double mean() const
Definition GridStats.h:483
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:473
size_t mSize
Definition GridStats.h:423
double RealT
Definition GridStats.h:422
__hostdev__ Stats & add(const ValueT &val)
Add a single sample.
Definition GridStats.h:436
__hostdev__ double var() const
Return the population variance.
Definition GridStats.h:490
__hostdev__ Stats & add(const ValueT &val, uint64_t n)
Add n samples with constant value val.
Definition GridStats.h:447
__hostdev__ double avg() const
Return the arithmetic mean, i.e. average, value.
Definition GridStats.h:482
__hostdev__ double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance.
Definition GridStats.h:497
__hostdev__ size_t size() const
Definition GridStats.h:478
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:475
double mAux
Definition GridStats.h:424
__hostdev__ double variance() const
Definition GridStats.h:491
Extrema< ValueT, 1 > BaseT
Definition GridStats.h:421
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:476
__hostdev__ Stats & add(const Stats &other)
Add the samples from the other Stats instance.
Definition GridStats.h:573
__hostdev__ void setStats(NodeT &node) const
Definition GridStats.h:615
double mAvg
Definition GridStats.h:527
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:587
__hostdev__ double stdDev() const
Definition GridStats.h:611
__hostdev__ Stats()
Definition GridStats.h:536
ValueT ValueType
Definition GridStats.h:530
__hostdev__ double mean() const
Definition GridStats.h:596
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:586
size_t mSize
Definition GridStats.h:526
double RealT
Definition GridStats.h:525
__hostdev__ Stats & add(const ValueT &val)
Add a single sample.
Definition GridStats.h:551
__hostdev__ double var() const
Return the population variance.
Definition GridStats.h:603
__hostdev__ Stats & add(const ValueT &val, uint64_t n)
Add n samples with constant value val.
Definition GridStats.h:561
__hostdev__ double avg() const
Return the arithmetic mean, i.e. average, value.
Definition GridStats.h:595
__hostdev__ double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance.
Definition GridStats.h:610
__hostdev__ Stats(const ValueT &val)
Definition GridStats.h:543
__hostdev__ size_t size() const
Definition GridStats.h:591
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:588
__hostdev__ double raw_to_double(const ValueT &v)
Definition GridStats.h:531
double mAux
Definition GridStats.h:527
Extrema< ValueT, 0 > BaseT
Definition GridStats.h:524
__hostdev__ double variance() const
Definition GridStats.h:604
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:589
Definition GridStats.h:300
void add(double val)
Add a single sample.
Definition Stats.h:103
double min() const
Return the minimum value.
Definition Stats.h:122
double max() const
Return the maximum value.
Definition Stats.h:125
__hostdev__ float HalfToFloat(uint16_t h_raw)
Definition HalfLite.h:27
Definition CreateNanoGrid.h:106
Extrema< typename NanoGrid< BuildT >::ValueType > getExtrema(const NanoGrid< BuildT > &grid, const CoordBBox &bbox)
Determine the extrema of all the values in a grid that intersects the specified bounding box.
Definition GridStats.h:973
StatsMode
Grid flags which indicate what extra information is present in the grid buffer.
Definition GridStats.h:41
@ BBox
Definition GridStats.h:43
@ Default
Definition GridStats.h:46
@ End
Definition GridStats.h:47
@ All
Definition GridStats.h:45
@ MinMax
Definition GridStats.h:44
@ Disable
Definition GridStats.h:42
void updateGridStats(NanoGrid< BuildT > *grid, StatsMode mode=StatsMode::Default)
Re-computes the min/max, stats and bbox information for an existing NanoVDB Grid.
Definition GridStats.h:916
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:34
Grid< NanoTree< BuildT > > NanoGrid
Definition NanoVDB.h:4699
math::BBox< Vec3d > Vec3dBBox
Definition Math.h:2839
math::BBox< Coord > CoordBBox
Definition Math.h:2838
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition Composite.h:110
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition Composite.h:106
Definition Coord.h:590
#define NANOVDB_ASSERT(x)
Definition Util.h:53
typename GridT::TreeType type
Definition NanoVDB.h:2427
Struct to derive node type from its level in a given grid, tree or root while preserving constness.
Definition NanoVDB.h:1708
VecT vector
Definition GridStats.h:150
__hostdev__ Pair(Real s)
Definition GridStats.h:152
__hostdev__ bool operator<(const Pair &rhs) const
Definition GridStats.h:162
Real scalar
Definition GridStats.h:149
__hostdev__ Pair(const VecT &v)
Definition GridStats.h:157
Definition GridStats.h:693
NodeStats()
Definition GridStats.h:697
StatsT stats
Definition GridStats.h:694
CoordBBox bbox
Definition GridStats.h:695
NodeStats & add(const NodeStats &other)
Definition GridStats.h:699
No-op Stats class.
Definition GridStats.h:627
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:636
__hostdev__ NoopStats & add(const ValueT &, uint64_t)
Definition GridStats.h:632
static __hostdev__ constexpr size_t size()
Definition GridStats.h:634
__hostdev__ void setStats(NodeT &) const
Definition GridStats.h:640
ValueT ValueType
Definition GridStats.h:628
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:635
__hostdev__ NoopStats & add(const NoopStats &)
Definition GridStats.h:633
__hostdev__ NoopStats & add(const ValueT &)
Definition GridStats.h:631
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:637
__hostdev__ NoopStats(const ValueT &)
Definition GridStats.h:630
__hostdev__ NoopStats()
Definition GridStats.h:629
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:638
static constexpr bool value
Definition Util.h:359