OpenVDB 9.0.0
GridStats.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: MPL-2.0
3
4/*!
5 \file 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_GRIDSTATS_H_HAS_BEEN_INCLUDED
16#define NANOVDB_GRIDSTATS_H_HAS_BEEN_INCLUDED
17
18#include "../NanoVDB.h"
19#include "Range.h"
20#include "ForEach.h"
21
22#ifdef NANOVDB_USE_TBB
23#include <tbb/parallel_reduce.h>
24#endif
25
26#include <atomic>
27#include <iostream>
28
29namespace nanovdb {
30
31/// @brief Grid flags which indicate what extra information is present in the grid buffer
32enum class StatsMode : uint32_t {
33 Disable = 0,// disable the computation of any type of statistics (obviously the FASTEST!)
34 BBox = 1,// only compute the bbox of active values per node and total activeVoxelCount
35 MinMax = 2,// additionally compute extrema values
36 All = 3,// compute all of the statics, i.e. bbox, min/max, average and standard deviation
37 Default = 3,// default computational mode for statistics
38 End = 4,
39};
40
41/// @brief Re-computes the min/max, stats and bbox information for an existing NanoVDB Grid
42///
43/// @param grid Grid whose stats to update
44/// @param mode Mode of computation for the statistics.
45template<typename BuildT>
46void gridStats(NanoGrid<BuildT>& grid, StatsMode mode = StatsMode::Default);
47
48//================================================================================================
49
50template<typename ValueT, int Rank = TensorTraits<ValueT>::Rank>
51class Extrema;
52
53/// @brief Template specialization of Extrema on scalar value types, i.e. rank = 0
54template<typename ValueT>
55class Extrema<ValueT, 0>
56{
57protected:
58 ValueT mMin, mMax;
59
60public:
61 using ValueType = ValueT;
63 : mMin(std::numeric_limits<ValueT>::max())
64 , mMax(std::numeric_limits<ValueT>::lowest())
65 {
66 }
67 Extrema(const ValueT& v)
68 : mMin(v)
69 , mMax(v)
70 {
71 }
72 Extrema(const ValueT& a, const ValueT& b)
73 : mMin(a)
74 , mMax(b)
75 {
76 }
77 Extrema& operator=(const Extrema&) = default;
78 Extrema& min(const ValueT& v)
79 {
80 if (v < mMin) {
81 mMin = v;
82 }
83 return *this;
84 }
85 Extrema& max(const ValueT& v)
86 {
87 if (v > mMax) {
88 mMax = v;
89 }
90 return *this;
91 }
92 Extrema& add(const ValueT& v)
93 {
94 this->min(v);
95 this->max(v);
96 return *this;
97 }
98 Extrema& add(const ValueT& v, uint64_t) { return this->add(v); }
99 Extrema& add(const Extrema& other)
100 {
101 this->min(other.mMin);
102 this->max(other.mMax);
103 return *this;
104 }
105 const ValueT& min() const { return mMin; }
106 const ValueT& max() const { return mMax; }
107 operator bool() const { return mMin <= mMax; }
108 static constexpr bool hasMinMax() { return !std::is_same<bool, ValueT>::value; }
109 static constexpr bool hasAverage() { return false; }
110 static constexpr bool hasStdDeviation() { return false; }
111 static constexpr size_t size() { return 0; }
112}; // Extrema<T, 0>
113
114/// @brief Template specialization of Extrema on vector value types, i.e. rank = 1
115template<typename VecT>
116class Extrema<VecT, 1>
117{
118protected:
119 using Real = typename VecT::ValueType; // this works with both nanovdb and openvdb vectors
120 struct Pair
121 {
123 VecT vector;
124
125 Pair(Real s)// is only used by Extrema() default c-tor
126 : scalar(s)
127 , vector(s)
128 {
129 }
130 Pair(const VecT& v)
131 : scalar(v.lengthSqr())
132 , vector(v)
133 {
134 }
135 Pair& operator=(const Pair&) = default;
136 bool operator<(const Pair& rhs) const { return scalar < rhs.scalar; }
137 } mMin, mMax;
138 Extrema& add(const Pair& p)
139 {
140 if (p < mMin) {
141 mMin = p;
142 }
143 if (mMax < p) {
144 mMax = p;
145 }
146 return *this;
147 }
148
149public:
150 using ValueType = VecT;
152 : mMin(std::numeric_limits<Real>::max())
153 , mMax(std::numeric_limits<Real>::lowest())
154 {
155 }
156 Extrema(const VecT& v)
157 : mMin(v)
158 , mMax(v)
159 {
160 }
161 Extrema(const VecT& a, const VecT& b)
162 : mMin(a)
163 , mMax(b)
164 {
165 }
166 Extrema& operator=(const Extrema&) = default;
167 Extrema& min(const VecT& v)
168 {
169 Pair tmp(v);
170 if (tmp < mMin) {
171 mMin = tmp;
172 }
173 return *this;
174 }
175 Extrema& max(const VecT& v)
176 {
177 Pair tmp(v);
178 if (mMax < tmp) {
179 mMax = tmp;
180 }
181 return *this;
182 }
183 Extrema& add(const VecT& v) { return this->add(Pair(v)); }
184 Extrema& add(const VecT& v, uint64_t) { return this->add(Pair(v)); }
185 Extrema& add(const Extrema& other)
186 {
187 if (other.mMin < mMin) {
188 mMin = other.mMin;
189 }
190 if (mMax < other.mMax) {
191 mMax = other.mMax;
192 }
193 return *this;
194 }
195 const VecT& min() const { return mMin.vector; }
196 const VecT& max() const { return mMax.vector; }
197 operator bool() const { return !(mMax < mMin); }
198 static constexpr bool hasMinMax() { return !std::is_same<bool, Real>::value; }
199 static constexpr bool hasAverage() { return false; }
200 static constexpr bool hasStdDeviation() { return false; }
201 static constexpr size_t size() { return 0; }
202}; // Extrema<T, 1>
203
204//================================================================================================
205
206template<typename ValueT, int Rank = TensorTraits<ValueT>::Rank>
207class Stats;
208
209/// @brief This class computes statistics (minimum value, maximum
210/// value, mean, variance and standard deviation) of a population
211/// of floating-point values.
212///
213/// @details variance = Mean[ (X-Mean[X])^2 ] = Mean[X^2] - Mean[X]^2,
214/// standard deviation = sqrt(variance)
215///
216/// @note This class employs incremental computation and double precision.
217template<typename ValueT>
218class Stats<ValueT, 0> : public Extrema<ValueT, 0>
219{
220protected:
222 using RealT = double; // for accuracy the internal precission must be 64 bit floats
223 size_t mSize;
224 double mAvg, mAux;
225
226public:
227 using ValueType = ValueT;
229 : BaseT()
230 , mSize(0)
231 , mAvg(0.0)
232 , mAux(0.0)
233 {
234 }
235 Stats(const ValueT& val)
236 : BaseT(val)
237 , mSize(1)
238 , mAvg(RealT(val))
239 , mAux(0.0)
240 {
241 }
242 /// @brief Add a single sample
243 Stats& add(const ValueT& val)
244 {
245 BaseT::add(val);
246 mSize += 1;
247 const double delta = double(val) - mAvg;
248 mAvg += delta / double(mSize);
249 mAux += delta * (double(val) - mAvg);
250 return *this;
251 }
252 /// @brief Add @a n samples with constant value @a val.
253 Stats& add(const ValueT& val, uint64_t n)
254 {
255 const double denom = 1.0 / double(mSize + n);
256 const double delta = double(val) - mAvg;
257 mAvg += denom * delta * double(n);
258 mAux += denom * delta * delta * double(mSize) * double(n);
259 BaseT::add(val);
260 mSize += n;
261 return *this;
262 }
263
264 /// Add the samples from the other Stats instance.
265 Stats& add(const Stats& other)
266 {
267 if (other.mSize > 0) {
268 const double denom = 1.0 / double(mSize + other.mSize);
269 const double delta = other.mAvg - mAvg;
270 mAvg += denom * delta * double(other.mSize);
271 mAux += other.mAux + denom * delta * delta * double(mSize) * double(other.mSize);
272 BaseT::add(other);
273 mSize += other.mSize;
274 }
275 return *this;
276 }
277
278 static constexpr bool hasMinMax() { return !std::is_same<bool, ValueT>::value; }
279 static constexpr bool hasAverage() { return !std::is_same<bool, ValueT>::value; }
280 static constexpr bool hasStdDeviation() { return !std::is_same<bool, ValueT>::value; }
281
282 size_t size() const { return mSize; }
283
284 //@{
285 /// Return the arithmetic mean, i.e. average, value.
286 double avg() const { return mAvg; }
287 double mean() const { return mAvg; }
288 //@}
289
290 //@{
291 /// @brief Return the population variance.
292 ///
293 /// @note The unbiased sample variance = population variance * num/(num-1)
294 double var() const { return mSize < 2 ? 0.0 : mAux / double(mSize); }
295 double variance() const { return this->var(); }
296 //@}
297
298 //@{
299 /// @brief Return the standard deviation (=Sqrt(variance)) as
300 /// defined from the (biased) population variance.
301 double std() const { return sqrt(this->var()); }
302 double stdDev() const { return this->std(); }
303 //@}
304}; // end Stats<T, 0>
305
306/// @brief This class computes statistics (minimum value, maximum
307/// value, mean, variance and standard deviation) of a population
308/// of floating-point values.
309///
310/// @details variance = Mean[ (X-Mean[X])^2 ] = Mean[X^2] - Mean[X]^2,
311/// standard deviation = sqrt(variance)
312///
313/// @note This class employs incremental computation and double precision.
314template<typename ValueT>
315class Stats<ValueT, 1> : public Extrema<ValueT, 1>
316{
317protected:
319 using RealT = double; // for accuracy the internal precission must be 64 bit floats
320 size_t mSize;
321 double mAvg, mAux;
322
323public:
324 using ValueType = ValueT;
326 : BaseT()
327 , mSize(0)
328 , mAvg(0.0)
329 , mAux(0.0)
330 {
331 }
332 /// @brief Add a single sample
333 Stats& add(const ValueT& val)
334 {
335 typename BaseT::Pair tmp(val);
336 BaseT::add(tmp);
337 mSize += 1;
338 const double delta = tmp.scalar - mAvg;
339 mAvg += delta / double(mSize);
340 mAux += delta * (tmp.scalar - mAvg);
341 return *this;
342 }
343 /// @brief Add @a n samples with constant value @a val.
344 Stats& add(const ValueT& val, uint64_t n)
345 {
346 typename BaseT::Pair tmp(val);
347 const double denom = 1.0 / double(mSize + n);
348 const double delta = tmp.scalar - mAvg;
349 mAvg += denom * delta * double(n);
350 mAux += denom * delta * delta * double(mSize) * double(n);
351 BaseT::add(tmp);
352 mSize += n;
353 return *this;
354 }
355
356 /// Add the samples from the other Stats instance.
357 Stats& add(const Stats& other)
358 {
359 if (other.mSize > 0) {
360 const double denom = 1.0 / double(mSize + other.mSize);
361 const double delta = other.mAvg - mAvg;
362 mAvg += denom * delta * double(other.mSize);
363 mAux += other.mAux + denom * delta * delta * double(mSize) * double(other.mSize);
364 BaseT::add(other);
365 mSize += other.mSize;
366 }
367 return *this;
368 }
369
370 static constexpr bool hasMinMax() { return !std::is_same<bool, ValueT>::value; }
371 static constexpr bool hasAverage() { return !std::is_same<bool, ValueT>::value; }
372 static constexpr bool hasStdDeviation() { return !std::is_same<bool, ValueT>::value; }
373
374 size_t size() const { return mSize; }
375
376 //@{
377 /// Return the arithmetic mean, i.e. average, value.
378 double avg() const { return mAvg; }
379 double mean() const { return mAvg; }
380 //@}
381
382 //@{
383 /// @brief Return the population variance.
384 ///
385 /// @note The unbiased sample variance = population variance * num/(num-1)
386 double var() const { return mSize < 2 ? 0.0 : mAux / double(mSize); }
387 double variance() const { return this->var(); }
388 //@}
389
390 //@{
391 /// @brief Return the standard deviation (=Sqrt(variance)) as
392 /// defined from the (biased) population variance.
393 double std() const { return sqrt(this->var()); }
394 double stdDev() const { return this->std(); }
395 //@}
396}; // end Stats<T, 1>
397
398/// @brief No-op Stats class
399template<typename ValueT>
401{
402 using ValueType = ValueT;
404 NoopStats(const ValueT&) {}
405 NoopStats& add(const ValueT&) { return *this; }
406 NoopStats& add(const ValueT&, uint64_t) { return *this; }
407 NoopStats& add(const NoopStats&) { return *this; }
408 static constexpr size_t size() { return 0; }
409 static constexpr bool hasMinMax() { return false; }
410 static constexpr bool hasAverage() { return false; }
411 static constexpr bool hasStdDeviation() { return false; }
412}; // end NoopStats<T>
413
414//================================================================================================
415
416/// @brief Allows for the construction of NanoVDB grids without any dependecy
417template<typename GridT, typename StatsT = Stats<typename GridT::ValueType>>
419{
420 struct NodeStats;
421 using TreeT = typename GridT::TreeType;
422 using ValueT = typename TreeT::ValueType;
423 using BuildT = typename TreeT::BuildType;
424 using Node0 = typename TreeT::Node0; // leaf
425 using Node1 = typename TreeT::Node1; // lower
426 using Node2 = typename TreeT::Node2; // upper
427 using RootT = typename TreeT::Node3; // root
428 static_assert(std::is_same<ValueT, typename StatsT::ValueType>::value, "Mismatching type");
429 static constexpr bool DO_STATS = StatsT::hasMinMax() || StatsT::hasAverage() || StatsT::hasStdDeviation();
430
431 ValueT mDelta; // skip node if: node.max < -mDelta || node.min > mDelta
432
433 void process( GridT& );// process grid and all tree nodes
434 void process( TreeT& );// process Tree, root node and child nodes
435 void process( RootT& );// process root node and child nodes
436 NodeStats process( Node0& );// process leaf node
437
438 template<typename NodeT>
439 NodeStats process( NodeT& );// process internal node and child nodes
440
441 template<typename DataT, int Rank>
442 void setStats(DataT*, const Extrema<ValueT, Rank>&);
443 template<typename DataT, int Rank>
444 void setStats(DataT*, const Stats<ValueT, Rank>&);
445 template<typename DataT>
446 void setStats(DataT*, const NoopStats<ValueT>&) {}
447
448 template<typename T, typename FlagT>
450 setFlag(const T&, const T&, FlagT& flag) const { flag &= ~FlagT(1); } // unset first bit
451
452 template<typename T, typename FlagT>
454 setFlag(const T& min, const T& max, FlagT& flag) const;
455
456public:
457 GridStats() = default;
458
459 void operator()(GridT& grid, ValueT delta = ValueT(0));
460
461}; // GridStats
462
463template<typename GridT, typename StatsT>
464struct GridStats<GridT, StatsT>::NodeStats
465{
466 StatsT stats;
467 //uint64_t activeCount;
469
470 NodeStats(): stats(), bbox() {}//activeCount(0), bbox() {};
471
472 NodeStats& add(const NodeStats &other)
473 {
474 stats.add( other.stats );// no-op for NoopStats?!
475 //activeCount += other.activeCount;
476 bbox[0].minComponent(other.bbox[0]);
477 bbox[1].maxComponent(other.bbox[1]);
478 return *this;
479 }
480};// GridStats::NodeStats
481
482//================================================================================================
483
484template<typename GridT, typename StatsT>
485void GridStats<GridT, StatsT>::operator()(GridT& grid, ValueT delta)
486{
487 mDelta = delta; // delta = voxel size for level sets, else 0
488 this->process( grid );
489}
490
491//================================================================================================
492
493template<typename GridT, typename StatsT>
494template<typename DataT, int Rank>
496 setStats(DataT* data, const Extrema<ValueT, Rank>& e)
497{
498 data->setMin(e.min());
499 data->setMax(e.max());
500}
501
502template<typename GridT, typename StatsT>
503template<typename DataT, int Rank>
504inline void GridStats<GridT, StatsT>::
505 setStats(DataT* data, const Stats<ValueT, Rank>& s)
506{
507 data->setMin(s.min());
508 data->setMax(s.max());
509 data->setAvg(s.avg());
510 data->setDev(s.std());
511}
512
513//================================================================================================
514
515template<typename GridT, typename StatsT>
516template<typename T, typename FlagT>
518GridStats<GridT, StatsT>::
519 setFlag(const T& min, const T& max, FlagT& flag) const
520{
521 if (mDelta > 0 && (min > mDelta || max < -mDelta)) {
522 flag |= FlagT(1); // set 1st bit on to enable rendering
523 } else {
524 flag &= ~FlagT(1); // set 1st bit off to disable rendering
525 }
526}
527
528//================================================================================================
529
530template<typename GridT, typename StatsT>
531void GridStats<GridT, StatsT>::process( GridT &grid )
532{
533 this->process( grid.tree() );// this processes tree, root and all nodes
534
535 // set world space AABB
536 auto& data = *grid.data();
537 const auto& indexBBox = grid.tree().root().bbox();
538 if (indexBBox.empty()) {
539 data.mWorldBBox = BBox<Vec3R>();
540 data.setBBoxOn(false);
541 } else {
542 // Note that below max is offset by one since CoordBBox.max is inclusive
543 // while bbox<Vec3R>.max is exclusive. However, min is inclusive in both
544 // CoordBBox and BBox<Vec3R>. This also guarantees that a grid with a single
545 // active voxel, does not have an empty world bbox! E.g. if a grid with a
546 // unit index-to-world transformation only contains the active voxel (0,0,0)
547 // then indeBBox = (0,0,0) -> (0,0,0) and then worldBBox = (0.0, 0.0, 0.0)
548 // -> (1.0, 1.0, 1.0). This is a consequence of the different definitions
549 // of index and world bounding boxes inherited from OpenVDB!
550 const Coord min = indexBBox[0];
551 const Coord max = indexBBox[1] + Coord(1);
552
553 auto& worldBBox = data.mWorldBBox;
554 const auto& map = grid.map();
555 worldBBox[0] = worldBBox[1] = map.applyMap(Vec3d(min[0], min[1], min[2]));
556 worldBBox.expand(map.applyMap(Vec3d(min[0], min[1], max[2])));
557 worldBBox.expand(map.applyMap(Vec3d(min[0], max[1], min[2])));
558 worldBBox.expand(map.applyMap(Vec3d(max[0], min[1], min[2])));
559 worldBBox.expand(map.applyMap(Vec3d(max[0], max[1], min[2])));
560 worldBBox.expand(map.applyMap(Vec3d(max[0], min[1], max[2])));
561 worldBBox.expand(map.applyMap(Vec3d(min[0], max[1], max[2])));
562 worldBBox.expand(map.applyMap(Vec3d(max[0], max[1], max[2])));
563 data.setBBoxOn(true);
564 }
565
566 // set bit flags
567 data.setMinMaxOn(StatsT::hasMinMax());
568 data.setAverageOn(StatsT::hasAverage());
569 data.setStdDeviationOn(StatsT::hasStdDeviation());
570} // GridStats::process( Grid )
571
572//================================================================================================
573
574template<typename GridT, typename StatsT>
575inline void GridStats<GridT, StatsT>::process( typename GridT::TreeType &tree )
576{
577 this->process( tree.root() );
578}
579
580//================================================================================================
581
582template<typename GridT, typename StatsT>
583void GridStats<GridT, StatsT>::process(RootT &root)
584{
585 using ChildT = Node2;
586 auto &data = *root.data();
587 if (data.mTableSize == 0) { // empty root node
588 data.mMinimum = data.mMaximum = data.mBackground;
589 data.mAverage = data.mStdDevi = 0;
590 //data.mActiveVoxelCount = 0;
591 data.mBBox = CoordBBox();
592 } else {
593 NodeStats total;
594 for (uint32_t i = 0; i < data.mTableSize; ++i) {
595 auto* tile = data.tile(i);
596 if (tile->isChild()) { // process child node
597 total.add( this->process( *data.getChild(tile) ) );
598 } else if (tile->state) { // active tile
599 //total.activeCount += ChildT::NUM_VALUES;
600 const Coord ijk = tile->origin();
601 total.bbox[0].minComponent(ijk);
602 total.bbox[1].maxComponent(ijk + Coord(ChildT::DIM - 1));
603 if (DO_STATS) { // resolved at compiletime
604 total.stats.add(tile->value, ChildT::NUM_VALUES);
605 }
606 }
607 }
608 this->setStats(&data, total.stats);
609 if (total.bbox.empty()) {
610 std::cerr << "\nWarning: input tree only contained inactive root tiles!"
611 << "\nWhile not strictly an error it's rather suspicious!\n";
612 }
613 //data.mActiveVoxelCount = total.activeCount;
614 data.mBBox = total.bbox;
615 }
616} // GridStats::process( RootNode )
617
618//================================================================================================
619
620template<typename GridT, typename StatsT>
621template<typename NodeT>
622typename GridStats<GridT, StatsT>::NodeStats
623GridStats<GridT, StatsT>::process(NodeT &node)
624{
625 static_assert(is_same<NodeT,Node1>::value || is_same<NodeT,Node2>::value, "Incorrect node type");
626 using ChildT = typename NodeT::ChildNodeType;
627
628 NodeStats total;
629 auto* data = node.data();
630
631 // Serial processing of active tiles
632 if (const auto tileCount = data->mValueMask.countOn()) {
633 //total.activeCount = tileCount * ChildT::NUM_VALUES; // active tiles
634 for (auto it = data->mValueMask.beginOn(); it; ++it) {
635 if (DO_STATS) { // resolved at compiletime
636 total.stats.add( data->mTable[*it].value, ChildT::NUM_VALUES );
637 }
638 const Coord ijk = node.offsetToGlobalCoord(*it);
639 total.bbox[0].minComponent(ijk);
640 total.bbox[1].maxComponent(ijk + Coord(int32_t(ChildT::DIM) - 1));
641 }
642 }
643
644 // Serial or parallel processing of child nodes
645 if (const size_t childCount = data->mChildMask.countOn()) {
646#ifndef NANOVDB_USE_TBB
647 for (auto it = data->mChildMask.beginOn(); it; ++it) {
648 total.add( this->process( *data->getChild(*it) ) );
649 }
650#else
651 std::unique_ptr<ChildT*[]> childNodes(new ChildT*[childCount]);
652 ChildT **ptr = childNodes.get();
653 for (auto it = data->mChildMask.beginOn(); it; ++it) {
654 *ptr++ = data->getChild( *it );
655 }
656 using RangeT = tbb::blocked_range<size_t>;
657 total.add( tbb::parallel_reduce(RangeT(0, childCount), NodeStats(),
658 [&](const RangeT &r, NodeStats local)->NodeStats {
659 for(size_t i=r.begin(); i!=r.end(); ++i){
660 local.add( this->process( *childNodes[i] ) );
661 }
662 return local;},
663 [](NodeStats a, const NodeStats &b)->NodeStats { return a.add( b ); }
664 ));
665#endif
666 }
667
668 data->mBBox = total.bbox;
669 if (total.bbox.empty()) {
670 data->mFlags &= ~uint32_t(1); // set 1st bit off since node to disable rendering of node
671 data->mFlags &= ~uint32_t(2); // set 2nd bit off since node does not contain active values
672 } else {
673 data->mFlags |= uint32_t(2); // set 2nd bit on since node contains active values
674 if (DO_STATS) { // resolved at compiletime
675 this->setStats(data, total.stats);
676 this->setFlag(data->mMinimum, data->mMaximum, data->mFlags);
677 }
678 }
679 return total;
680} // GridStats::process( InternalNode )
681
682//================================================================================================
683
684template<typename GridT, typename StatsT>
685typename GridStats<GridT, StatsT>::NodeStats
686GridStats<GridT, StatsT>::process(Node0 &leaf)
687{
688 static_assert(Node0::SIZE == 512u, "Invalid size of leaf nodes");
689 NodeStats local;
690 auto *data = leaf.data();
691 if (auto activeCount = data->mValueMask.countOn()) {
692 data->mFlags |= uint8_t(2); // sets 2nd bit on since leaf contains active voxel
693 //local.activeCount += activeCount;
694 leaf.updateBBox(); // optionally update active bounding box
695 local.bbox[0] = local.bbox[1] = data->mBBoxMin;
696 local.bbox[1] += Coord(data->mBBoxDif[0], data->mBBoxDif[1], data->mBBoxDif[2]);
697 if (DO_STATS) { // resolved at compiletime
698 for (auto it = data->mValueMask.beginOn(); it; ++it) {
699 local.stats.add(data->getValue(*it));
700 }
701 this->setStats(data, local.stats);
702 this->setFlag(data->getMin(), data->getMax(), data->mFlags);
703 }
704 } else {
705 data->mFlags &= ~uint8_t(2); // sets 2nd bit off since leaf does not contain active voxel
706 }
707 return local;
708} // GridStats::process( LeafNode )
709
710//================================================================================================
711
712template<typename BuildT>
714{
715 using GridT = NanoGrid<BuildT>;
716 using ValueT = typename GridT::ValueType;
717 if (mode == StatsMode::Disable) {
718 return;
721 stats(grid);
722 } else if (mode == StatsMode::MinMax) {
724 stats(grid);
725 } else if (mode == StatsMode::All) {
727 stats(grid);
728 } else {
729 throw std::runtime_error("gridStats: Unsupported statistics mode.");
730 }
731}
732
733} // namespace nanovdb
734
735#endif // NANOVDB_GRIDSTATS_H_HAS_BEEN_INCLUDED
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
ValueT value
Definition: GridBuilder.h:1287
Custom Range class that is compatible with the tbb::blocked_range classes.
Template specialization of Extrema on scalar value types, i.e. rank = 0.
Definition: GridStats.h:56
static constexpr size_t size()
Definition: GridStats.h:111
Extrema & min(const ValueT &v)
Definition: GridStats.h:78
Extrema & add(const ValueT &v, uint64_t)
Definition: GridStats.h:98
Extrema(const ValueT &v)
Definition: GridStats.h:67
Extrema()
Definition: GridStats.h:62
Extrema & operator=(const Extrema &)=default
Extrema & add(const Extrema &other)
Definition: GridStats.h:99
ValueT ValueType
Definition: GridStats.h:61
const ValueT & max() const
Definition: GridStats.h:106
Extrema & max(const ValueT &v)
Definition: GridStats.h:85
ValueT mMax
Definition: GridStats.h:58
Extrema & add(const ValueT &v)
Definition: GridStats.h:92
static constexpr bool hasAverage()
Definition: GridStats.h:109
static constexpr bool hasMinMax()
Definition: GridStats.h:108
Extrema(const ValueT &a, const ValueT &b)
Definition: GridStats.h:72
const ValueT & min() const
Definition: GridStats.h:105
static constexpr bool hasStdDeviation()
Definition: GridStats.h:110
Extrema & min(const VecT &v)
Definition: GridStats.h:167
Extrema & add(const VecT &v, uint64_t)
Definition: GridStats.h:184
static constexpr size_t size()
Definition: GridStats.h:201
Extrema(const VecT &a, const VecT &b)
Definition: GridStats.h:161
Extrema()
Definition: GridStats.h:151
Extrema & add(const Pair &p)
Definition: GridStats.h:138
Extrema & operator=(const Extrema &)=default
Extrema & max(const VecT &v)
Definition: GridStats.h:175
const VecT & min() const
Definition: GridStats.h:195
Extrema & add(const Extrema &other)
Definition: GridStats.h:185
Extrema & add(const VecT &v)
Definition: GridStats.h:183
typename VecT::ValueType Real
Definition: GridStats.h:119
static constexpr bool hasAverage()
Definition: GridStats.h:199
static constexpr bool hasMinMax()
Definition: GridStats.h:198
Extrema(const VecT &v)
Definition: GridStats.h:156
static constexpr bool hasStdDeviation()
Definition: GridStats.h:200
const VecT & max() const
Definition: GridStats.h:196
VecT ValueType
Definition: GridStats.h:150
Definition: GridStats.h:51
Allows for the construction of NanoVDB grids without any dependecy.
Definition: GridStats.h:419
void operator()(GridT &grid, ValueT delta=ValueT(0))
Definition: GridStats.h:485
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:2308
double var() const
Return the population variance.
Definition: GridStats.h:294
size_t size() const
Definition: GridStats.h:282
Stats(const ValueT &val)
Definition: GridStats.h:235
double mean() const
Definition: GridStats.h:287
size_t mSize
Definition: GridStats.h:223
double RealT
Definition: GridStats.h:222
Stats & add(const ValueT &val, uint64_t n)
Add n samples with constant value val.
Definition: GridStats.h:253
double variance() const
Definition: GridStats.h:295
Stats & add(const ValueT &val)
Add a single sample.
Definition: GridStats.h:243
double stdDev() const
Definition: GridStats.h:302
static constexpr bool hasAverage()
Definition: GridStats.h:279
static constexpr bool hasMinMax()
Definition: GridStats.h:278
Stats & add(const Stats &other)
Add the samples from the other Stats instance.
Definition: GridStats.h:265
double mAux
Definition: GridStats.h:224
double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance.
Definition: GridStats.h:301
static constexpr bool hasStdDeviation()
Definition: GridStats.h:280
double avg() const
Return the arithmetic mean, i.e. average, value.
Definition: GridStats.h:286
Stats()
Definition: GridStats.h:228
double var() const
Return the population variance.
Definition: GridStats.h:386
size_t size() const
Definition: GridStats.h:374
double mean() const
Definition: GridStats.h:379
ValueT ValueType
Definition: GridStats.h:324
size_t mSize
Definition: GridStats.h:320
double RealT
Definition: GridStats.h:319
Stats & add(const ValueT &val, uint64_t n)
Add n samples with constant value val.
Definition: GridStats.h:344
double variance() const
Definition: GridStats.h:387
Stats & add(const ValueT &val)
Add a single sample.
Definition: GridStats.h:333
double stdDev() const
Definition: GridStats.h:394
static constexpr bool hasAverage()
Definition: GridStats.h:371
static constexpr bool hasMinMax()
Definition: GridStats.h:370
Stats & add(const Stats &other)
Add the samples from the other Stats instance.
Definition: GridStats.h:357
double mAux
Definition: GridStats.h:321
double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance.
Definition: GridStats.h:393
static constexpr bool hasStdDeviation()
Definition: GridStats.h:372
double avg() const
Return the arithmetic mean, i.e. average, value.
Definition: GridStats.h:378
Stats()
Definition: GridStats.h:325
Definition: GridStats.h:207
Definition: Camera.h:16
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
StatsMode
Grid flags which indicate what extra information is present in the grid buffer.
Definition: GridStats.h:32
Vec3< double > Vec3d
Definition: NanoVDB.h:1174
void gridStats(NanoGrid< BuildT > &grid, StatsMode mode=StatsMode::Default)
Re-computes the min/max, stats and bbox information for an existing NanoVDB Grid.
Definition: GridStats.h:713
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
Definition: Coord.h:586
Definition: NanoVDB.h:1524
VecT vector
Definition: GridStats.h:123
Pair(Real s)
Definition: GridStats.h:125
Pair(const VecT &v)
Definition: GridStats.h:130
bool operator<(const Pair &rhs) const
Definition: GridStats.h:136
Real scalar
Definition: GridStats.h:122
Pair & operator=(const Pair &)=default
Definition: GridStats.h:465
NodeStats()
Definition: GridStats.h:470
StatsT stats
Definition: GridStats.h:466
CoordBBox bbox
Definition: GridStats.h:468
NodeStats & add(const NodeStats &other)
Definition: GridStats.h:472
No-op Stats class.
Definition: GridStats.h:401
NoopStats(const ValueT &)
Definition: GridStats.h:404
static constexpr size_t size()
Definition: GridStats.h:408
NoopStats & add(const ValueT &, uint64_t)
Definition: GridStats.h:406
NoopStats & add(const NoopStats &)
Definition: GridStats.h:407
ValueT ValueType
Definition: GridStats.h:402
NoopStats & add(const ValueT &)
Definition: GridStats.h:405
static constexpr bool hasAverage()
Definition: GridStats.h:410
static constexpr bool hasMinMax()
Definition: GridStats.h:409
NoopStats()
Definition: GridStats.h:403
static constexpr bool hasStdDeviation()
Definition: GridStats.h:411
static constexpr bool value
Definition: NanoVDB.h:328