OpenVDB  9.1.1
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 
29 namespace nanovdb {
30 
31 /// @brief Grid flags which indicate what extra information is present in the grid buffer
32 enum 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.
45 template<typename BuildT>
47 
48 //================================================================================================
49 
50 template<typename ValueT, int Rank = TensorTraits<ValueT>::Rank>
51 class Extrema;
52 
53 /// @brief Template specialization of Extrema on scalar value types, i.e. rank = 0
54 template<typename ValueT>
55 class Extrema<ValueT, 0>
56 {
57 protected:
58  ValueT mMin, mMax;
59 
60 public:
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
115 template<typename VecT>
116 class Extrema<VecT, 1>
117 {
118 protected:
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 
149 public:
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 
206 template<typename ValueT, int Rank = TensorTraits<ValueT>::Rank>
207 class 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.
217 template<typename ValueT>
218 class Stats<ValueT, 0> : public Extrema<ValueT, 0>
219 {
220 protected:
222  using RealT = double; // for accuracy the internal precission must be 64 bit floats
223  size_t mSize;
224  double mAvg, mAux;
225 
226 public:
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.
314 template<typename ValueT>
315 class Stats<ValueT, 1> : public Extrema<ValueT, 1>
316 {
317 protected:
319  using RealT = double; // for accuracy the internal precission must be 64 bit floats
320  size_t mSize;
321  double mAvg, mAux;
322 
323 public:
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
399 template<typename ValueT>
400 struct NoopStats
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
417 template<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 
456 public:
457  GridStats() = default;
458 
459  void operator()(GridT& grid, ValueT delta = ValueT(0));
460 
461 }; // GridStats
462 
463 template<typename GridT, typename StatsT>
464 struct 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 
484 template<typename GridT, typename StatsT>
485 void 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 
493 template<typename GridT, typename StatsT>
494 template<typename DataT, int Rank>
495 inline void GridStats<GridT, StatsT>::
496  setStats(DataT* data, const Extrema<ValueT, Rank>& e)
497 {
498  data->setMin(e.min());
499  data->setMax(e.max());
500 }
501 
502 template<typename GridT, typename StatsT>
503 template<typename DataT, int Rank>
504 inline 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 
515 template<typename GridT, typename StatsT>
516 template<typename T, typename FlagT>
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 
530 template<typename GridT, typename StatsT>
531 void 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 
574 template<typename GridT, typename StatsT>
575 inline void GridStats<GridT, StatsT>::process( typename GridT::TreeType &tree )
576 {
577  this->process( tree.root() );
578 }
579 
580 //================================================================================================
581 
582 template<typename GridT, typename StatsT>
583 void 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 
620 template<typename GridT, typename StatsT>
621 template<typename NodeT>
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 
684 template<typename GridT, typename StatsT>
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 
712 template<typename BuildT>
714 {
715  using GridT = NanoGrid<BuildT>;
716  using ValueT = typename GridT::ValueType;
717  if (mode == StatsMode::Disable) {
718  return;
719  } else if (mode == StatsMode::BBox || std::is_same<bool, ValueT>::value) {
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
static constexpr bool hasMinMax()
Definition: GridStats.h:409
double RealT
Definition: GridStats.h:222
double variance() const
Return the population variance.
Definition: GridStats.h:295
Extrema & add(const Extrema &other)
Definition: GridStats.h:185
static constexpr bool hasAverage()
Definition: GridStats.h:279
NoopStats()
Definition: GridStats.h:403
VecT ValueType
Definition: GridStats.h:150
double mAvg
Definition: GridStats.h:224
Template specialization of Extrema on scalar value types, i.e. rank = 0.
Definition: GridStats.h:55
double variance() const
Return the population variance.
Definition: GridStats.h:387
static constexpr bool hasAverage()
Definition: GridStats.h:371
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:386
double mAvg
Definition: GridStats.h:321
static constexpr bool hasStdDeviation()
Definition: GridStats.h:411
StatsT stats
Definition: GridStats.h:466
const ValueT & min() const
Definition: GridStats.h:105
double var() const
Return the population variance.
Definition: GridStats.h:294
static constexpr bool hasMinMax()
Definition: GridStats.h:198
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
static constexpr bool hasStdDeviation()
Definition: GridStats.h:200
static constexpr bool hasStdDeviation()
Definition: GridStats.h:280
CoordBBox bbox
Definition: GridStats.h:468
static constexpr bool hasStdDeviation()
Definition: GridStats.h:372
Stats & add(const ValueT &val, uint64_t n)
Add n samples with constant value val.
Definition: GridStats.h:344
NodeStats()
Definition: GridStats.h:470
static constexpr size_t size()
Definition: GridStats.h:408
double avg() const
Return the arithmetic mean, i.e. average, value.
Definition: GridStats.h:378
Stats & add(const ValueT &val, uint64_t n)
Add n samples with constant value val.
Definition: GridStats.h:253
ValueT mMin
Definition: GridStats.h:58
double avg() const
Return the arithmetic mean, i.e. average, value.
Definition: GridStats.h:286
const VecT & max() const
Definition: GridStats.h:196
Definition: Coord.h:587
NoopStats & add(const NoopStats &)
Definition: GridStats.h:407
static constexpr bool hasAverage()
Definition: GridStats.h:199
Stats & add(const Stats &other)
Add the samples from the other Stats instance.
Definition: GridStats.h:265
Extrema & add(const VecT &v, uint64_t)
Definition: GridStats.h:184
Stats & add(const Stats &other)
Add the samples from the other Stats instance.
Definition: GridStats.h:357
Pair(const VecT &v)
Definition: GridStats.h:130
Definition: NanoVDB.h:184
Extrema()
Definition: GridStats.h:62
static constexpr bool hasStdDeviation()
Definition: GridStats.h:110
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
Stats()
Definition: GridStats.h:325
Extrema & add(const ValueT &v)
Definition: GridStats.h:92
static constexpr bool hasMinMax()
Definition: GridStats.h:370
Stats()
Definition: GridStats.h:228
Custom Range class that is compatible with the tbb::blocked_range classes.
ValueT ValueType
Definition: GridStats.h:402
Extrema()
Definition: GridStats.h:151
Extrema(const VecT &a, const VecT &b)
Definition: GridStats.h:161
NodeStats & add(const NodeStats &other)
Definition: GridStats.h:472
ValueT ValueType
Definition: GridStats.h:324
static constexpr bool hasMinMax()
Definition: GridStats.h:278
bool operator<(const Pair &rhs) const
Definition: GridStats.h:136
NoopStats(const ValueT &)
Definition: GridStats.h:404
Definition: NanoVDB.h:1524
static constexpr bool hasAverage()
Definition: GridStats.h:109
Extrema(const VecT &v)
Definition: GridStats.h:156
size_t mSize
Definition: GridStats.h:223
Definition: GridStats.h:51
Extrema & min(const ValueT &v)
Definition: GridStats.h:78
size_t mSize
Definition: GridStats.h:320
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
ValueT value
Definition: GridBuilder.h:1287
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
NoopStats & add(const ValueT &, uint64_t)
Definition: GridStats.h:406
Definition: GridStats.h:464
double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance...
Definition: GridStats.h:301
Allows for the construction of NanoVDB grids without any dependecy.
Definition: GridStats.h:418
double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance...
Definition: GridStats.h:393
const VecT & min() const
Definition: GridStats.h:195
Extrema & add(const Extrema &other)
Definition: GridStats.h:99
void operator()(GridT &grid, ValueT delta=ValueT(0))
Definition: GridStats.h:485
Extrema & min(const VecT &v)
Definition: GridStats.h:167
Real scalar
Definition: GridStats.h:122
Stats & add(const ValueT &val)
Add a single sample.
Definition: GridStats.h:333
double mean() const
Return the arithmetic mean, i.e. average, value.
Definition: GridStats.h:287
Stats & add(const ValueT &val)
Add a single sample.
Definition: GridStats.h:243
ValueT ValueType
Definition: GridStats.h:61
double mean() const
Return the arithmetic mean, i.e. average, value.
Definition: GridStats.h:379
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
StatsMode
Grid flags which indicate what extra information is present in the grid buffer.
Definition: GridStats.h:32
No-op Stats class.
Definition: GridStats.h:400
Pair(Real s)
Definition: GridStats.h:125
double stdDev() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance...
Definition: GridStats.h:302
Extrema & max(const VecT &v)
Definition: GridStats.h:175
typename VecT::ValueType Real
Definition: GridStats.h:119
static constexpr bool hasAverage()
Definition: GridStats.h:410
const ValueT & max() const
Definition: GridStats.h:106
double stdDev() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance...
Definition: GridStats.h:394
static constexpr size_t size()
Definition: GridStats.h:111
Definition: GridStats.h:207
static constexpr size_t size()
Definition: GridStats.h:201
Extrema(const ValueT &v)
Definition: GridStats.h:67
Extrema & add(const ValueT &v, uint64_t)
Definition: GridStats.h:98
VecT vector
Definition: GridStats.h:123
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition: NanoVDB.h:859
Extrema(const ValueT &a, const ValueT &b)
Definition: GridStats.h:72
Extrema & add(const Pair &p)
Definition: GridStats.h:138
Extrema & add(const VecT &v)
Definition: GridStats.h:183
static constexpr bool hasMinMax()
Definition: GridStats.h:108
size_t size() const
Definition: GridStats.h:282
C++11 implementation of std::is_same.
Definition: NanoVDB.h:326
Stats(const ValueT &val)
Definition: GridStats.h:235
Extrema & max(const ValueT &v)
Definition: GridStats.h:85
size_t size() const
Definition: GridStats.h:374
NoopStats & add(const ValueT &)
Definition: GridStats.h:405
double RealT
Definition: GridStats.h:319