15#ifndef NANOVDB_GRIDSTATS_H_HAS_BEEN_INCLUDED
16#define NANOVDB_GRIDSTATS_H_HAS_BEEN_INCLUDED
23#include <tbb/parallel_reduce.h>
26#if defined(__CUDACC__)
27#include <cuda/std/limits>
51template<
typename BuildT>
56template<typename ValueT, int Rank = TensorTraits<ValueT>::Rank>
60template<
typename ValueT>
69#if defined(__CUDACC__)
70 : mMin(cuda::std::numeric_limits<ValueT>::max())
71 , mMax(cuda::std::numeric_limits<ValueT>::lowest())
73 : mMin(std::numeric_limits<ValueT>::max())
74 , mMax(std::numeric_limits<ValueT>::lowest())
90 if (v < mMin) mMin = v;
95 if (v > mMax) mMax = v;
107 this->min(other.mMin);
108 this->max(other.mMax);
120 template <
typename NodeT>
123 node.setMin(this->min());
124 node.setMax(this->max());
129template<
typename VecT>
133 using Real =
typename VecT::ValueType;
145 : scalar(v.lengthSqr())
153 if (p < mMin) mMin = p;
154 if (mMax < p) mMax = p;
161#if defined(__CUDACC__)
162 : mMin(cuda::std::numeric_limits<Real>::max())
163 , mMax(cuda::std::numeric_limits<Real>::lowest())
165 : mMin(std::numeric_limits<Real>::max())
166 , mMax(std::numeric_limits<Real>::lowest())
183 if (tmp < mMin) mMin = tmp;
189 if (mMax < tmp) mMax = tmp;
196 if (other.mMin < mMin) mMin = other.mMin;
197 if (mMax < other.mMax) mMax = other.mMax;
209 template <
typename NodeT>
212 node.setMin(this->min());
213 node.setMax(this->max());
219template<typename ValueT, int Rank = TensorTraits<ValueT>::Rank>
230template<
typename ValueT>
260 const double delta = double(val) - mAvg;
261 mAvg += delta / double(mSize);
262 mAux += delta * (double(val) - mAvg);
268 const double denom = 1.0 / double(mSize + n);
269 const double delta = double(val) - mAvg;
270 mAvg += denom * delta * double(n);
271 mAux += denom * delta * delta * double(mSize) * double(n);
280 if (other.mSize > 0) {
281 const double denom = 1.0 / double(mSize + other.mSize);
282 const double delta = other.mAvg - mAvg;
283 mAvg += denom * delta * double(other.mSize);
284 mAux += other.mAux + denom * delta * delta * double(mSize) * double(other.mSize);
286 mSize += other.mSize;
308 __hostdev__ double var()
const {
return mSize < 2 ? 0.0 : mAux / double(mSize); }
319 template <
typename NodeT>
322 node.setMin(this->min());
323 node.setMax(this->max());
324 node.setAvg(this->avg());
325 node.setDev(this->
std());
337template<
typename ValueT>
358 typename BaseT::Pair tmp(val);
361 const double delta = tmp.scalar - mAvg;
362 mAvg += delta / double(mSize);
363 mAux += delta * (tmp.scalar - mAvg);
369 typename BaseT::Pair tmp(val);
370 const double denom = 1.0 / double(mSize + n);
371 const double delta = tmp.scalar - mAvg;
372 mAvg += denom * delta * double(n);
373 mAux += denom * delta * delta * double(mSize) * double(n);
382 if (other.mSize > 0) {
383 const double denom = 1.0 / double(mSize + other.mSize);
384 const double delta = other.mAvg - mAvg;
385 mAvg += denom * delta * double(other.mSize);
386 mAux += other.mAux + denom * delta * delta * double(mSize) * double(other.mSize);
388 mSize += other.mSize;
410 __hostdev__ double var()
const {
return mSize < 2 ? 0.0 : mAux / double(mSize); }
421 template <
typename NodeT>
424 node.setMin(this->min());
425 node.setMax(this->max());
426 node.setAvg(this->avg());
427 node.setDev(this->
std());
432template<
typename ValueT>
446 template <
typename NodeT>
453template<
typename Gr
idT,
typename StatsT = Stats<
typename Gr
idT::ValueType>>
457 using TreeT =
typename GridT::TreeType;
458 using ValueT =
typename TreeT::ValueType;
459 using BuildT =
typename TreeT::BuildType;
460 using Node0 =
typename TreeT::Node0;
461 using Node1 =
typename TreeT::Node1;
462 using Node2 =
typename TreeT::Node2;
463 using RootT =
typename TreeT::Node3;
464 static_assert(std::is_same<ValueT, typename StatsT::ValueType>::value,
"Mismatching type");
468 void process( GridT& );
469 void process( TreeT& );
470 void process( RootT& );
473 template<
typename NodeT>
476 template<
typename DataT,
int Rank>
478 template<
typename DataT,
int Rank>
480 template<
typename DataT>
483 template<
typename T,
typename FlagT>
484 typename std::enable_if<!std::is_floating_point<T>::value>::type
485 setFlag(
const T&,
const T&, FlagT& flag)
const { flag &= ~FlagT(1); }
487 template<
typename T,
typename FlagT>
488 typename std::enable_if<std::is_floating_point<T>::value>::type
489 setFlag(
const T& min,
const T& max, FlagT& flag)
const;
494 void operator()(GridT& grid, ValueT delta = ValueT(0));
498template<
typename Gr
idT,
typename StatsT>
509 bbox[0].minComponent(other.
bbox[0]);
510 bbox[1].maxComponent(other.
bbox[1]);
517template<
typename Gr
idT,
typename StatsT>
521 this->process( grid );
526template<
typename Gr
idT,
typename StatsT>
527template<
typename DataT,
int Rank>
531 data->setMin(e.min());
532 data->setMax(e.max());
535template<
typename Gr
idT,
typename StatsT>
536template<
typename DataT,
int Rank>
537inline void GridStats<GridT, StatsT>::
538 setStats(DataT* data,
const Stats<ValueT, Rank>& s)
540 data->setMin(s.min());
541 data->setMax(s.max());
542 data->setAvg(s.avg());
543 data->setDev(s.std());
548template<
typename Gr
idT,
typename StatsT>
549template<
typename T,
typename FlagT>
550inline typename std::enable_if<std::is_floating_point<T>::value>::type
551GridStats<GridT, StatsT>::
552 setFlag(
const T& min,
const T& max, FlagT& flag)
const
554 if (mDelta > 0 && (min > mDelta || max < -mDelta)) {
563template<
typename Gr
idT,
typename StatsT>
564void GridStats<GridT, StatsT>::process( GridT &grid )
566 this->process( grid.tree() );
569 auto& data = *grid.data();
570 const auto& indexBBox = grid.tree().root().bbox();
571 if (indexBBox.empty()) {
572 data.mWorldBBox = BBox<Vec3d>();
573 data.setBBoxOn(
false);
583 grid.mWorldBBox =
CoordBBox(indexBBox[0], indexBBox[1].offsetBy(1)).transform(grid.map());
584 grid.setBBoxOn(
true);
588 data.setMinMaxOn(StatsT::hasMinMax());
589 data.setAverageOn(StatsT::hasAverage());
590 data.setStdDeviationOn(StatsT::hasStdDeviation());
595template<
typename Gr
idT,
typename StatsT>
596inline void GridStats<GridT, StatsT>::process(
typename GridT::TreeType &tree )
598 this->process( tree.root() );
603template<
typename Gr
idT,
typename StatsT>
604void GridStats<GridT, StatsT>::process(RootT &root)
606 using ChildT = Node2;
607 auto &data = *root.data();
608 if (data.mTableSize == 0) {
609 data.mMinimum = data.mMaximum = data.mBackground;
610 data.mAverage = data.mStdDevi = 0;
614 for (uint32_t i = 0; i < data.mTableSize; ++i) {
615 auto* tile = data.tile(i);
616 if (tile->isChild()) {
617 total.add( this->process( *data.getChild(tile) ) );
618 }
else if (tile->state) {
619 const Coord ijk = tile->origin();
620 total.bbox[0].minComponent(ijk);
621 total.bbox[1].maxComponent(ijk + Coord(ChildT::DIM - 1));
622 if (StatsT::hasStats()) {
623 total.stats.add(tile->value, ChildT::NUM_VALUES);
627 this->setStats(&data, total.stats);
628 if (total.bbox.empty()) {
629 std::cerr <<
"\nWarning in GridStats: input tree only contained inactive root tiles!"
630 <<
"\nWhile not strictly an error it's rather suspicious!\n";
632 data.mBBox = total.bbox;
638template<
typename Gr
idT,
typename StatsT>
639template<
typename NodeT>
640typename GridStats<GridT, StatsT>::NodeStats
641GridStats<GridT, StatsT>::process(NodeT &node)
644 using ChildT =
typename NodeT::ChildNodeType;
647 auto* data = node.data();
650 if (
const auto tileCount = data->mValueMask.countOn()) {
652 for (
auto it = data->mValueMask.beginOn(); it; ++it) {
653 if (StatsT::hasStats()) {
654 total.stats.add( data->mTable[*it].value, ChildT::NUM_VALUES );
656 const Coord ijk = node.offsetToGlobalCoord(*it);
657 total.bbox[0].minComponent(ijk);
658 total.bbox[1].maxComponent(ijk + Coord(int32_t(ChildT::DIM) - 1));
663 if (
const size_t childCount = data->mChildMask.countOn()) {
664#ifndef NANOVDB_USE_TBB
665 for (
auto it = data->mChildMask.beginOn(); it; ++it) {
666 total.add( this->process( *data->getChild(*it) ) );
669 std::unique_ptr<ChildT*[]> childNodes(
new ChildT*[childCount]);
670 ChildT **ptr = childNodes.get();
671 for (
auto it = data->mChildMask.beginOn(); it; ++it) {
672 *ptr++ = data->getChild( *it );
674 using RangeT = tbb::blocked_range<size_t>;
675 total.add( tbb::parallel_reduce(RangeT(0, childCount), NodeStats(),
676 [&](
const RangeT &r, NodeStats local)->NodeStats {
677 for(
size_t i=r.begin(); i!=r.end(); ++i){
678 local.add( this->process( *childNodes[i] ) );
681 [](NodeStats a,
const NodeStats &b)->NodeStats {
return a.add( b ); }
686 data->mBBox = total.bbox;
687 if (total.bbox.empty()) {
688 data->mFlags |= uint32_t(1);
689 data->mFlags &= ~uint32_t(2);
691 data->mFlags |= uint32_t(2);
692 if (StatsT::hasStats()) {
693 this->setStats(data, total.stats);
694 this->setFlag(data->mMinimum, data->mMaximum, data->mFlags);
702template<
typename Gr
idT,
typename StatsT>
703typename GridStats<GridT, StatsT>::NodeStats
704GridStats<GridT, StatsT>::process(Node0 &leaf)
707 if (leaf.updateBBox()) {
708 local.bbox[0] = local.bbox[1] = leaf.mBBoxMin;
709 local.bbox[1] += Coord(leaf.mBBoxDif[0], leaf.mBBoxDif[1], leaf.mBBoxDif[2]);
710 if (StatsT::hasStats()) {
711 for (
auto it = leaf.cbeginValueOn(); it; ++it) local.stats.add(*it);
712 this->setStats(&leaf, local.stats);
713 this->setFlag(leaf.getMin(), leaf.getMax(), leaf.mFlags);
721template<
typename BuildT>
725 using ValueT =
typename GridT::ValueType;
728 }
else if (mode ==
StatsMode::BBox || std::is_same<bool, ValueT>::value) {
738 throw std::runtime_error(
"gridStats: Unsupported statistics mode.");
748template<
typename NodeT>
752 auto b = CoordBBox::createCube(node->origin(), node->dim());
753 assert( bbox.hasOverlap(b) );
754 if ( bbox.isInside(b) ) {
759 b.min() &= NodeT::DIM-1u;
760 b.min() >>= NodeT::ChildNodeType::TOTAL;
761 b.max() &= NodeT::DIM-1u;
762 b.max() >>= NodeT::ChildNodeType::TOTAL;
763 assert( !b.empty() );
765 for (
const Coord& ijk = *it; it; ++it) {
766 mask.setOn(ijk[2] + (ijk[1] << NodeT::LOG2DIM) + (ijk[0] << 2*NodeT::LOG2DIM));
776template<
typename BuildT>
777Extrema<typename NanoGrid<BuildT>::ValueType>
781 using ValueT =
typename GridT::ValueType;
789 const RootT &root = grid.
tree().root();
790 const auto &bbox3 = root.bbox();
791 if (bbox.isInside(bbox3)) {
792 extrema.
min(root.minimum());
793 extrema.
max(root.maximum());
794 extrema.
add(root.background());
795 }
else if (bbox.hasOverlap(bbox3)) {
796 const auto *data3 = root.data();
797 for (uint32_t i=0; i<data3->mTableSize; ++i) {
798 const auto *tile = data3->tile(i);
799 CoordBBox bbox2 = CoordBBox::createCube(tile->origin(), Node2::dim());
800 if (!bbox.hasOverlap(bbox2))
continue;
801 if (tile->isChild()) {
802 const Node2 *node2 = data3->getChild(tile);
803 if (bbox.isInside(bbox2)) {
804 extrema.
min(node2->minimum());
805 extrema.
max(node2->maximum());
807 auto *data2 = node2->data();
808 const auto bboxMask2 = getBBoxMask(bbox, node2);
809 for (
auto it2 = bboxMask2.beginOn(); it2; ++it2) {
810 if (data2->mChildMask.isOn(*it2)) {
811 const Node1* node1 = data2->getChild(*it2);
812 CoordBBox bbox1 = CoordBBox::createCube(node1->origin(), Node1::dim());
813 if (bbox.isInside(bbox1)) {
814 extrema.
min(node1->minimum());
815 extrema.
max(node1->maximum());
817 auto *data1 = node1->data();
818 const auto bboxMask1 = getBBoxMask(bbox, node1);
819 for (
auto it1 = bboxMask1.beginOn(); it1; ++it1) {
820 if (data1->mChildMask.isOn(*it1)) {
821 const Node0* node0 = data1->getChild(*it1);
822 CoordBBox bbox0 = CoordBBox::createCube(node0->origin(), Node0::dim());
823 if (bbox.isInside(bbox0)) {
824 extrema.
min(node0->minimum());
825 extrema.
max(node0->maximum());
827 auto *data0 = node0->data();
828 const auto bboxMask0 = getBBoxMask(bbox, node0);
829 for (
auto it0 = bboxMask0.beginOn(); it0; ++it0) {
830 extrema.
add(data0->getValue(*it0));
834 extrema.
add(data1->mTable[*it1].value);
839 extrema.
add(data2->mTable[*it2].value);
844 extrema.
add(tile->value);
848 extrema.
add(root.background());
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
Implements a light-weight self-contained VDB data-structure in a single file! In other words,...
#define __hostdev__
Definition NanoVDB.h:213
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:62
__hostdev__ void setStats(NodeT &node) const
Definition GridStats.h:121
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:115
static __hostdev__ constexpr size_t size()
Definition GridStats.h:118
__hostdev__ Extrema & add(const ValueT &v, uint64_t)
Definition GridStats.h:104
__hostdev__ Extrema & max(const ValueT &v)
Definition GridStats.h:93
__hostdev__ const ValueT & min() const
Definition GridStats.h:111
ValueT ValueType
Definition GridStats.h:67
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:114
__hostdev__ Extrema()
Definition GridStats.h:68
__hostdev__ const ValueT & max() const
Definition GridStats.h:112
__hostdev__ Extrema & add(const Extrema &other)
Definition GridStats.h:105
ValueT mMax
Definition GridStats.h:64
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:116
__hostdev__ Extrema & add(const ValueT &v)
Definition GridStats.h:98
__hostdev__ Extrema(const ValueT &a, const ValueT &b)
Definition GridStats.h:83
__hostdev__ Extrema & min(const ValueT &v)
Definition GridStats.h:88
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:117
__hostdev__ Extrema(const ValueT &v)
Definition GridStats.h:78
__hostdev__ void setStats(NodeT &node) const
Definition GridStats.h:210
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:204
static __hostdev__ constexpr size_t size()
Definition GridStats.h:207
__hostdev__ Extrema & min(const VecT &v)
Definition GridStats.h:180
__hostdev__ Extrema & add(const Pair &p)
Definition GridStats.h:151
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:203
typename VecT::ValueType Real
Definition GridStats.h:133
__hostdev__ Extrema()
Definition GridStats.h:160
__hostdev__ Extrema & add(const VecT &v, uint64_t)
Definition GridStats.h:193
__hostdev__ const VecT & max() const
Definition GridStats.h:201
__hostdev__ Extrema & max(const VecT &v)
Definition GridStats.h:186
__hostdev__ Extrema(const VecT &v)
Definition GridStats.h:170
__hostdev__ Extrema & add(const Extrema &other)
Definition GridStats.h:194
__hostdev__ Extrema(const VecT &a, const VecT &b)
Definition GridStats.h:175
__hostdev__ const VecT & min() const
Definition GridStats.h:200
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:205
__hostdev__ Extrema & add(const VecT &v)
Definition GridStats.h:192
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:206
VecT ValueType
Definition GridStats.h:159
Definition GridStats.h:57
Allows for the construction of NanoVDB grids without any dependency.
Definition GridStats.h:455
void operator()(GridT &grid, ValueT delta=ValueT(0))
Definition GridStats.h:518
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition NanoVDB.h:3699
const TreeT & tree() const
Return a const reference to the tree.
Definition NanoVDB.h:3753
__hostdev__ Stats & add(const Stats &other)
Add the samples from the other Stats instance.
Definition GridStats.h:278
__hostdev__ void setStats(NodeT &node) const
Definition GridStats.h:320
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:292
__hostdev__ double stdDev() const
Definition GridStats.h:316
__hostdev__ Stats()
Definition GridStats.h:241
ValueT ValueType
Definition GridStats.h:240
__hostdev__ double mean() const
Definition GridStats.h:301
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:291
size_t mSize
Definition GridStats.h:236
double RealT
Definition GridStats.h:235
__hostdev__ Stats & add(const ValueT &val)
Add a single sample.
Definition GridStats.h:256
__hostdev__ double var() const
Return the population variance.
Definition GridStats.h:308
__hostdev__ Stats & add(const ValueT &val, uint64_t n)
Add n samples with constant value val.
Definition GridStats.h:266
__hostdev__ double avg() const
Return the arithmetic mean, i.e. average, value.
Definition GridStats.h:300
__hostdev__ double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance.
Definition GridStats.h:315
__hostdev__ Stats(const ValueT &val)
Definition GridStats.h:248
__hostdev__ size_t size() const
Definition GridStats.h:296
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:293
double mAux
Definition GridStats.h:237
__hostdev__ double variance() const
Definition GridStats.h:309
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:294
__hostdev__ Stats & add(const Stats &other)
Add the samples from the other Stats instance.
Definition GridStats.h:380
__hostdev__ void setStats(NodeT &node) const
Definition GridStats.h:422
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:394
__hostdev__ double stdDev() const
Definition GridStats.h:418
__hostdev__ Stats()
Definition GridStats.h:348
ValueT ValueType
Definition GridStats.h:347
__hostdev__ double mean() const
Definition GridStats.h:403
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:393
size_t mSize
Definition GridStats.h:343
double RealT
Definition GridStats.h:342
__hostdev__ Stats & add(const ValueT &val)
Add a single sample.
Definition GridStats.h:356
__hostdev__ double var() const
Return the population variance.
Definition GridStats.h:410
__hostdev__ Stats & add(const ValueT &val, uint64_t n)
Add n samples with constant value val.
Definition GridStats.h:367
__hostdev__ double avg() const
Return the arithmetic mean, i.e. average, value.
Definition GridStats.h:402
__hostdev__ double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance.
Definition GridStats.h:417
__hostdev__ size_t size() const
Definition GridStats.h:398
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:395
double mAux
Definition GridStats.h:344
__hostdev__ double variance() const
Definition GridStats.h:411
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:396
Definition GridStats.h:220
void add(double val)
Add a single sample.
Definition Stats.h:102
double min() const
Return the minimum value.
Definition Stats.h:121
double max() const
Return the maximum value.
Definition Stats.h:124
Convert a base-pointer to an openvdb grid, denoted srcGrid, to a nanovdb grid of the same type,...
Definition NanoVDB.h:247
Grid< NanoTree< BuildT > > NanoGrid
Definition NanoVDB.h:6449
Extrema< typename NanoGrid< BuildT >::ValueType > getExtrema(const NanoGrid< BuildT > &grid, const CoordBBox &bbox)
return the extrema of all the values in a grid that intersects the specified bounding box.
Definition GridStats.h:778
BBox< Coord > CoordBBox
Definition NanoVDB.h:2535
StatsMode
Grid flags which indicate what extra information is present in the grid buffer.
Definition GridStats.h:38
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:722
Definition NanoVDB.h:2295
Definition GridStats.h:135
VecT vector
Definition GridStats.h:137
__hostdev__ Pair(Real s)
Definition GridStats.h:139
__hostdev__ bool operator<(const Pair &rhs) const
Definition GridStats.h:149
Real scalar
Definition GridStats.h:136
__hostdev__ Pair(const VecT &v)
Definition GridStats.h:144
Definition GridStats.h:500
NodeStats()
Definition GridStats.h:504
StatsT stats
Definition GridStats.h:501
CoordBBox bbox
Definition GridStats.h:502
NodeStats & add(const NodeStats &other)
Definition GridStats.h:506
typename GridT::TreeType type
Definition NanoVDB.h:3976
Struct to derive node type from its level in a given grid, tree or root while preserving constness.
Definition NanoVDB.h:3404
No-op Stats class.
Definition GridStats.h:434
static __hostdev__ constexpr bool hasAverage()
Definition GridStats.h:443
__hostdev__ NoopStats & add(const ValueT &, uint64_t)
Definition GridStats.h:439
static __hostdev__ constexpr size_t size()
Definition GridStats.h:441
__hostdev__ void setStats(NodeT &) const
Definition GridStats.h:447
ValueT ValueType
Definition GridStats.h:435
static __hostdev__ constexpr bool hasMinMax()
Definition GridStats.h:442
__hostdev__ NoopStats & add(const NoopStats &)
Definition GridStats.h:440
__hostdev__ NoopStats & add(const ValueT &)
Definition GridStats.h:438
static __hostdev__ constexpr bool hasStdDeviation()
Definition GridStats.h:444
__hostdev__ NoopStats(const ValueT &)
Definition GridStats.h:437
__hostdev__ NoopStats()
Definition GridStats.h:436
static __hostdev__ constexpr bool hasStats()
Definition GridStats.h:445
static constexpr bool value
Definition NanoVDB.h:443