11#ifndef OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED
12#define OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED
20#include "openvdb/thread/Threading.h"
23#include <tbb/blocked_range.h>
24#include <tbb/parallel_reduce.h>
65template<
class Gr
idType>
89template<
class Gr
idType>
101template<
class Gr
idType>
104 std::vector<typename GridType::ValueType>& values,
size_t numValues);
110template<
typename Gr
idT,
typename TreeIterT =
typename Gr
idT::ValueOnCIter>
116 typename TreeIterT::NodeT,
typename TreeIterT::ValueIterT>::template
117 NodeConverter<typename GridT::TreeType::LeafNodeType>::Type;
127 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
130 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
135 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
141 std::string
str()
const {
return "NaN"; }
148template <
typename GridT,
149 typename TreeIterT =
typename GridT::ValueOnCIter>
155 typename TreeIterT::ValueIterT> ::template NodeConverter<
156 typename GridT::TreeType::LeafNodeType>::Type;
166 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
169 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
174 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
180 std::string
str()
const {
return "infinite"; }
186template <
typename GridT,
187 typename TreeIterT =
typename GridT::ValueOnCIter>
193 typename TreeIterT::ValueIterT> ::template NodeConverter<
194 typename GridT::TreeType::LeafNodeType>::Type;
204 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
206 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
211 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
217 std::string
str()
const {
return "not finite"; }
224template <
typename GridT,
225 typename TreeIterT =
typename GridT::ValueOffCIter>
231 typename TreeIterT::ValueIterT> ::template NodeConverter<
232 typename GridT::TreeType::LeafNodeType>::Type;
237 : absVal(math::
Abs(a)), tolVal(math::
Abs(t))
250 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
253 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
258 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
266 std::ostringstream ss;
267 ss <<
"not equal to +/-"<<absVal<<
" with a tolerance of "<<tolVal;
277template <
typename GridT,
278 bool MinInclusive =
true,
279 bool MaxInclusive =
true,
280 typename TreeIterT =
typename GridT::ValueOnCIter>
286 typename TreeIterT::ValueIterT> ::template NodeConverter<
287 typename GridT::TreeType::LeafNodeType>::Type;
292 if (minVal > maxVal) {
300 return (MinInclusive ? v<minVal : v<=minVal) ||
301 (MaxInclusive ? v>maxVal : v>=maxVal);
306 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
308 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
313 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
321 std::ostringstream ss;
322 ss <<
"outside the value range " << (MinInclusive ?
"[" :
"]")
323 << minVal <<
"," << maxVal << (MaxInclusive ?
"]" :
"[");
333template <
typename GridT,
334 typename TreeIterT =
typename GridT::ValueOnCIter>
340 typename TreeIterT::ValueIterT> ::template NodeConverter<
341 typename GridT::TreeType::LeafNodeType>::Type;
351 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
353 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
358 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
366 std::ostringstream ss;
367 ss <<
"smaller than "<<minVal;
377template <
typename GridT,
378 typename TreeIterT =
typename GridT::ValueOnCIter>
384 typename TreeIterT::ValueIterT> ::template NodeConverter<
385 typename GridT::TreeType::LeafNodeType>::Type;
395 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
397 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
402 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
410 std::ostringstream ss;
411 ss <<
"larger than "<<maxVal;
425template<
typename GridT,
426 typename TreeIterT =
typename GridT::ValueOnCIter,
432 "openvdb::tools::CheckNormGrad requires a scalar, floating-point grid");
435 typename TreeIterT::ValueIterT> ::template NodeConverter<
436 typename GridT::TreeType::LeafNodeType>::Type;
437 using AccT =
typename GridT::ConstAccessor;
441 : acc(grid.getConstAccessor())
446 if ( !grid.hasUniformVoxels() ) {
455 : acc(other.acc.tree())
456 , invdx2(other.invdx2)
457 , minVal2(other.minVal2)
458 , maxVal2(other.maxVal2)
473 const Coord ijk = iter.getCoord();
480 std::ostringstream ss;
495template<
typename GridT,
496 typename TreeIterT =
typename GridT::ValueOnCIter,
502 "openvdb::tools::CheckEikonal requires a scalar, floating-point grid");
505 typename TreeIterT::ValueIterT> ::template NodeConverter<
506 typename GridT::TreeType::LeafNodeType>::Type;
510 : stencil(grid), minVal(_min), maxVal(_max)
512 if ( !grid.hasUniformVoxels() ) {
515 if (minVal > maxVal) {
521 : stencil(other.stencil.grid()), minVal(other.minVal), maxVal(other.maxVal)
536 stencil.moveTo(iter);
537 if (!stencil.zeroCrossing())
return false;
538 return (*
this)(stencil.normSqGrad());
544 std::ostringstream ss;
545 ss <<
"outside the range of NormGrad ["<<minVal<<
","<<maxVal<<
"]";
556template<
typename GridT,
557 typename TreeIterT =
typename GridT::ValueOnCIter,
564 "openvdb::tools::CheckDivergence requires a floating-point vector grid");
567 typename TreeIterT::ValueIterT>::template NodeConverter<
568 typename GridT::TreeType::LeafNodeType>::Type;
569 using AccT =
typename GridT::ConstAccessor;
575 : acc(grid.getConstAccessor())
576 , invdx(
ValueType(1.0/grid.voxelSize()[0]))
580 if ( !grid.hasUniformVoxels() ) {
583 if (minVal > maxVal) {
598 const Coord ijk = iter.getCoord();
605 std::ostringstream ss;
606 ss <<
"outside the range of divergence ["<<minVal<<
","<<maxVal<<
"]";
618template <
typename Gr
idT>
622 using MaskType =
typename GridT::template ValueConverter<bool>::Type;
626 mMask->setTransform(grid.transformPtr()->copy());
629 template <
typename CheckT>
630 std::string
check(
const CheckT& check,
631 bool updateMask =
false,
632 bool checkVoxels =
true,
633 bool checkTiles =
true,
634 bool checkBackground =
true)
636 typename MaskType::TreeType* mask = updateMask ? &(mMask->tree()) :
nullptr;
637 CheckValues<CheckT> cc(mask, mGrid, check);
638 std::ostringstream ss;
639 if (checkBackground) ss << cc.checkBackground();
640 if (checkTiles) ss << cc.checkTiles();
641 if (checkVoxels) ss << cc.checkVoxels();
650 typename MaskType::ConstPtr
mask()
const {
return mMask; }
651 typename MaskType::Ptr
mask() {
return mMask; }
664 const GridT&
grid()
const {
return *mGrid; }
675 typename MaskType::Ptr mMask;
679 template <
typename CheckT>
682 using MaskT =
typename MaskType::TreeType;
683 using LeafT =
typename GridT::TreeType::LeafNodeType;
685 const bool mOwnsMask;
691 CheckValues(MaskT* mask,
const GridT* grid,
const CheckT& check)
699 CheckValues(CheckValues& other, tbb::split)
701 , mMask(other.mMask ? new MaskT() : nullptr)
703 , mCheck(other.mCheck)
707 ~CheckValues() {
if (mOwnsMask)
delete mMask; }
709 std::string checkBackground()
711 std::ostringstream ss;
712 if (mCheck(mGrid->background())) {
714 ss <<
"Background is " + mCheck.str() << std::endl;
719 std::string checkTiles()
721 std::ostringstream ss;
723 typename CheckT::TileIterT i(mGrid->tree());
724 for (i.setMaxDepth(GridT::TreeType::RootNodeType::LEVEL - 1); i; ++i) {
727 if (mMask) mMask->fill(i.getBoundingBox(),
true,
true);
730 if (
const Index64 m = mCount - n) {
731 ss << m <<
" tile" << (m==1 ?
" is " :
"s are ") + mCheck.str() << std::endl;
736 std::string checkVoxels()
738 std::ostringstream ss;
739 LeafManagerT leafs(mGrid->tree());
741 tbb::parallel_reduce(leafs.leafRange(), *
this);
742 if (
const Index64 m = mCount - n) {
743 ss << m <<
" voxel" << (m==1 ?
" is " :
"s are ") + mCheck.str() << std::endl;
748 void operator()(
const typename LeafManagerT::LeafRange& r)
750 using VoxelIterT =
typename CheckT::VoxelIterT;
752 for (
typename LeafManagerT::LeafRange::Iterator i=r.begin(); i; ++i) {
753 typename MaskT::LeafNodeType* maskLeaf =
nullptr;
754 for (VoxelIterT j = tree::IterTraits<LeafT, VoxelIterT>::begin(*i); j; ++j) {
757 if (maskLeaf ==
nullptr) maskLeaf = mMask->touchLeaf(j.getCoord());
758 maskLeaf->setValueOn(j.pos(),
true);
763 for (
typename LeafManagerT::LeafRange::Iterator i=r.begin(); i; ++i) {
764 for (VoxelIterT j = tree::IterTraits<LeafT, VoxelIterT>::begin(*i); j; ++j) {
765 if (mCheck(j)) ++mCount;
770 void join(
const CheckValues& other)
773 mCount += other.mCount;
785template<
class Gr
idType>
790 using MaskType =
typename GridType::template ValueConverter<bool>::Type;
798 typename MaskType::ConstPtr
mask()
const {
return mDiagnose.mask(); }
799 typename MaskType::Ptr
mask() {
return mDiagnose.mask(); }
823 return test ?
"" :
"Value type is not floating point\n";
831 const bool test = mDiagnose.grid().getGridClass() ==
GRID_LEVEL_SET;
832 return test ?
"" :
"Class type is not \"GRID_LEVEL_SET\"\n";
840 return mDiagnose.grid().hasUniformVoxels() ?
"" :
"Does not have uniform voxels\n";
849 const Real w = mDiagnose.grid().background() / mDiagnose.grid().voxelSize()[0];
851 std::ostringstream ss;
852 ss <<
"The background value ("<< mDiagnose.grid().background()<<
") is less than "
853 << halfWidth <<
" voxel units\n";
864 const bool test = mDiagnose.grid().tree().hasActiveTiles();
865 return test ?
"Has active tile values\n" :
"";
874 return mDiagnose.check(c, updateMask,
true,
true,
true);
882 const ValueType& background = mDiagnose.grid().background();
884 return mDiagnose.check(c, updateMask,
true,
false,
false);
893 const ValueType& background = mDiagnose.grid().background();
895 return mDiagnose.check(c, updateMask,
true,
true,
false);
905 return mDiagnose.check(c, updateMask,
true,
false,
false);
925 std::string
check(
size_t n=9,
bool updateMask =
false)
927 std::string str = this->checkValueType();
928 if (str.empty() && n>1) str = this->checkClassType();
929 if (str.empty() && n>2) str = this->checkTransform();
930 if (str.empty() && n>3) str = this->checkBackground();
931 if (str.empty() && n>4) str = this->checkTiles();
932 if (str.empty() && n>5) str = this->checkFinite(updateMask);
933 if (str.empty() && n>6) str = this->checkRange(updateMask);
934 if (str.empty() && n>7) str = this->checkInactiveValues(updateMask);
935 if (str.empty() && n>8) str = this->checkEikonal(updateMask);
948template<
class Gr
idType>
953 return c.
check(n,
false);
961template<
class Gr
idType>
966 using MaskType =
typename GridType::template ValueConverter<bool>::Type;
974 typename MaskType::ConstPtr
mask()
const {
return mDiagnose.mask(); }
975 typename MaskType::Ptr
mask() {
return mDiagnose.mask(); }
999 return test ?
"" :
"Value type is not floating point";
1008 return test ?
"" :
"Class type is not \"GRID_LEVEL_SET\"";
1017 std::ostringstream ss;
1018 ss <<
"The background value ("<< mDiagnose.grid().background()<<
") is not zero";
1030 return mDiagnose.check(c, updateMask,
true,
true,
true);
1039 return mDiagnose.check(c, updateMask,
true,
true,
true);
1049 return mDiagnose.check(c, updateMask,
true,
true,
false);
1064 std::string
check(
size_t n=6,
bool updateMask =
false)
1066 std::string str = this->checkValueType();
1067 if (str.empty() && n>1) str = this->checkClassType();
1068 if (str.empty() && n>2) str = this->checkBackground();
1069 if (str.empty() && n>3) str = this->checkFinite(updateMask);
1070 if (str.empty() && n>4) str = this->checkInactiveValues(updateMask);
1071 if (str.empty() && n>5) str = this->checkRange(updateMask);
1084template<
class Gr
idType>
1089 return c.
check(n,
false);
1099namespace diagnostics_internal {
1102template<
typename TreeType>
1103class InactiveVoxelValues
1107 using ValueType =
typename TreeType::ValueType;
1108 using SetType = std::set<ValueType>;
1110 InactiveVoxelValues(LeafArray&,
size_t numValues);
1115 void getInactiveValues(SetType&)
const;
1117 inline InactiveVoxelValues(
const InactiveVoxelValues<TreeType>&, tbb::split);
1118 inline void operator()(
const tbb::blocked_range<size_t>&);
1119 inline void join(
const InactiveVoxelValues<TreeType>&);
1122 LeafArray& mLeafArray;
1123 SetType mInactiveValues;
1127template<
typename TreeType>
1128InactiveVoxelValues<TreeType>::InactiveVoxelValues(LeafArray& leafs,
size_t numValues)
1131 , mNumValues(numValues)
1135template <
typename TreeType>
1137InactiveVoxelValues<TreeType>::InactiveVoxelValues(
1138 const InactiveVoxelValues<TreeType>& rhs, tbb::split)
1139 : mLeafArray(rhs.mLeafArray)
1141 , mNumValues(rhs.mNumValues)
1145template<
typename TreeType>
1147InactiveVoxelValues<TreeType>::runParallel()
1149 tbb::parallel_reduce(mLeafArray.getRange(), *
this);
1153template<
typename TreeType>
1155InactiveVoxelValues<TreeType>::runSerial()
1157 (*this)(mLeafArray.getRange());
1161template<
typename TreeType>
1163InactiveVoxelValues<TreeType>::operator()(
const tbb::blocked_range<size_t>& range)
1165 typename TreeType::LeafNodeType::ValueOffCIter iter;
1167 for (
size_t n = range.begin(); n < range.end() && !thread::isGroupExecutionCancelled(); ++n) {
1168 for (iter = mLeafArray.leaf(n).cbeginValueOff(); iter; ++iter) {
1169 mInactiveValues.insert(iter.getValue());
1172 if (mInactiveValues.size() > mNumValues) {
1173 thread::cancelGroupExecution();
1178template<
typename TreeType>
1180InactiveVoxelValues<TreeType>::join(
const InactiveVoxelValues<TreeType>& rhs)
1182 mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end());
1185template<
typename TreeType>
1187InactiveVoxelValues<TreeType>::getInactiveValues(SetType& values)
const
1189 values.insert(mInactiveValues.begin(), mInactiveValues.end());
1196template<
typename TreeType>
1197class InactiveTileValues
1200 using IterRange = tree::IteratorRange<typename TreeType::ValueOffCIter>;
1201 using ValueType =
typename TreeType::ValueType;
1202 using SetType = std::set<ValueType>;
1204 InactiveTileValues(
size_t numValues);
1206 void runParallel(IterRange&);
1207 void runSerial(IterRange&);
1209 void getInactiveValues(SetType&)
const;
1211 inline InactiveTileValues(
const InactiveTileValues<TreeType>&, tbb::split);
1212 inline void operator()(IterRange&);
1213 inline void join(
const InactiveTileValues<TreeType>&);
1216 SetType mInactiveValues;
1221template<
typename TreeType>
1222InactiveTileValues<TreeType>::InactiveTileValues(
size_t numValues)
1224 , mNumValues(numValues)
1228template <
typename TreeType>
1230InactiveTileValues<TreeType>::InactiveTileValues(
1231 const InactiveTileValues<TreeType>& rhs, tbb::split)
1233 , mNumValues(rhs.mNumValues)
1237template<
typename TreeType>
1239InactiveTileValues<TreeType>::runParallel(IterRange& range)
1241 tbb::parallel_reduce(range, *
this);
1245template<
typename TreeType>
1247InactiveTileValues<TreeType>::runSerial(IterRange& range)
1253template<
typename TreeType>
1255InactiveTileValues<TreeType>::operator()(IterRange& range)
1257 for (; range && !thread::isGroupExecutionCancelled(); ++range) {
1258 typename TreeType::ValueOffCIter iter = range.iterator();
1259 for (; iter; ++iter) {
1260 mInactiveValues.insert(iter.getValue());
1263 if (mInactiveValues.size() > mNumValues) {
1264 thread::cancelGroupExecution();
1269template<
typename TreeType>
1271InactiveTileValues<TreeType>::join(
const InactiveTileValues<TreeType>& rhs)
1273 mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end());
1276template<
typename TreeType>
1278InactiveTileValues<TreeType>::getInactiveValues(SetType& values)
const
1280 values.insert(mInactiveValues.begin(), mInactiveValues.end());
1290template<
class Gr
idType>
1293 std::vector<typename GridType::ValueType>& values,
size_t numValues)
1295 using TreeType =
typename GridType::TreeType;
1296 using ValueType =
typename GridType::ValueType;
1297 using SetType = std::set<ValueType>;
1299 SetType uniqueValues;
1302 TreeType& tree =
const_cast<TreeType&
>(grid.tree());
1304 diagnostics_internal::InactiveVoxelValues<TreeType> voxelOp(leafs, numValues);
1305 voxelOp.runParallel();
1306 voxelOp.getInactiveValues(uniqueValues);
1310 if (uniqueValues.size() <= numValues) {
1311 typename TreeType::ValueOffCIter iter(grid.tree());
1312 iter.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 1);
1313 diagnostics_internal::InactiveTileValues<TreeType> tileOp(numValues);
1316 tileOp.runParallel(range);
1318 tileOp.getInactiveValues(uniqueValues);
1322 values.reserve(uniqueValues.size());
1324 typename SetType::iterator it = uniqueValues.begin();
1325 for ( ; it != uniqueValues.end(); ++it) {
1326 values.push_back(*it);
1329 return values.size() <= numValues;
1338#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1340#ifdef OPENVDB_INSTANTIATE_DIAGNOSTICS
1344#define _FUNCTION(TreeT) \
1345 std::string checkLevelSet(const Grid<TreeT>&, size_t)
1349#define _FUNCTION(TreeT) \
1350 std::string checkFogVolume(const Grid<TreeT>&, size_t)
1354#define _FUNCTION(TreeT) \
1355 bool uniqueInactiveValues(const Grid<TreeT>&, std::vector<TreeT::ValueType>&, size_t)
ValueT value
Definition: GridBuilder.h:1287
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Definition: Exceptions.h:65
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
This is a special 19-point stencil that supports optimal fifth-order WENO upwinding,...
Definition: Stencils.h:1366
Definition: TreeIterator.h:1303
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:85
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: NanoVDB.h:795
T Abs(T x)
Definition: NanoVDB.h:747
bool isApproxZero(const Type &x)
Definition: NanoVDB.h:645
T Pow2(T x)
Definition: NanoVDB.h:730
DScheme
Different discrete schemes used in the first derivatives.
Definition: FiniteDifference.h:32
@ CD_2ND
Definition: FiniteDifference.h:35
BiasedGradientScheme
Biased Gradients are limited to non-centered differences.
Definition: FiniteDifference.h:165
@ FIRST_BIAS
Definition: FiniteDifference.h:167
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:343
double Real
Definition: Types.h:60
@ GRID_FOG_VOLUME
Definition: Types.h:338
@ GRID_LEVEL_SET
Definition: Types.h:337
uint64_t Index64
Definition: Types.h:53
@ MERGE_ACTIVE_STATES_AND_NODES
Definition: Types.h:391
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
typename T::ValueType ElementType
Definition: Types.h:208
Divergence operator defined in index space using various first derivative schemes.
Definition: Operators.h:473
Definition: Operators.h:231
Tolerance for floating-point comparison.
Definition: Math.h:147
Definition: TreeIterator.h:60
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition: version.h.in:150