11 #ifndef OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED
12 #define OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED
20 #include "openvdb/thread/Threading.h"
22 #include <tbb/blocked_range.h>
23 #include <tbb/parallel_reduce.h>
29 #include <type_traits>
64 template<
class Gr
idType>
88 template<
class Gr
idType>
100 template<
class Gr
idType>
103 std::vector<typename GridType::ValueType>& values,
size_t numValues);
109 template<
typename Gr
idT,
typename TreeIterT =
typename Gr
idT::ValueOnCIter>
115 typename TreeIterT::NodeT,
typename TreeIterT::ValueIterT>::template
116 NodeConverter<typename GridT::TreeType::LeafNodeType>::Type;
126 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
129 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
134 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
140 std::string
str()
const {
return "NaN"; }
147 template <
typename GridT,
148 typename TreeIterT =
typename GridT::ValueOnCIter>
154 typename TreeIterT::ValueIterT> ::template NodeConverter<
155 typename GridT::TreeType::LeafNodeType>::Type;
165 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
168 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
173 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
179 std::string
str()
const {
return "infinite"; }
185 template <
typename GridT,
186 typename TreeIterT =
typename GridT::ValueOnCIter>
192 typename TreeIterT::ValueIterT> ::template NodeConverter<
193 typename GridT::TreeType::LeafNodeType>::Type;
203 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
205 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
210 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
216 std::string
str()
const {
return "not finite"; }
223 template <
typename GridT,
224 typename TreeIterT =
typename GridT::ValueOffCIter>
230 typename TreeIterT::ValueIterT> ::template NodeConverter<
231 typename GridT::TreeType::LeafNodeType>::Type;
236 : absVal(math::
Abs(a)), tolVal(math::
Abs(t))
249 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
252 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
257 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
265 std::ostringstream ss;
266 ss <<
"not equal to +/-"<<absVal<<
" with a tolerance of "<<tolVal;
276 template <
typename GridT,
277 bool MinInclusive =
true,
278 bool MaxInclusive =
true,
279 typename TreeIterT =
typename GridT::ValueOnCIter>
285 typename TreeIterT::ValueIterT> ::template NodeConverter<
286 typename GridT::TreeType::LeafNodeType>::Type;
291 if (minVal > maxVal) {
299 return (MinInclusive ? v<minVal : v<=minVal) ||
300 (MaxInclusive ? v>maxVal : v>=maxVal);
305 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
307 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
312 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
320 std::ostringstream ss;
321 ss <<
"outside the value range " << (MinInclusive ?
"[" :
"]")
322 << minVal <<
"," << maxVal << (MaxInclusive ?
"]" :
"[");
332 template <
typename GridT,
333 typename TreeIterT =
typename GridT::ValueOnCIter>
339 typename TreeIterT::ValueIterT> ::template NodeConverter<
340 typename GridT::TreeType::LeafNodeType>::Type;
350 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
352 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
357 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
365 std::ostringstream ss;
366 ss <<
"smaller than "<<minVal;
376 template <
typename GridT,
377 typename TreeIterT =
typename GridT::ValueOnCIter>
383 typename TreeIterT::ValueIterT> ::template NodeConverter<
384 typename GridT::TreeType::LeafNodeType>::Type;
394 inline typename std::enable_if<VecTraits<T>::IsVec,
bool>::type
396 for (
int i=0; i<VecTraits<T>::Size; ++i)
if ((*
this)(v[i]))
return true;
401 bool operator()(
const TreeIterT &iter)
const {
return (*
this)(*iter); }
409 std::ostringstream ss;
410 ss <<
"larger than "<<maxVal;
424 template<
typename GridT,
425 typename TreeIterT =
typename GridT::ValueOnCIter,
430 static_assert(std::is_floating_point<ValueType>::value,
431 "openvdb::tools::CheckNormGrad requires a scalar, floating-point grid");
434 typename TreeIterT::ValueIterT> ::template NodeConverter<
435 typename GridT::TreeType::LeafNodeType>::Type;
436 using AccT =
typename GridT::ConstAccessor;
440 : acc(grid.getConstAccessor())
445 if ( !grid.hasUniformVoxels() ) {
454 : acc(other.acc.tree())
455 , invdx2(other.invdx2)
456 , minVal2(other.minVal2)
457 , maxVal2(other.maxVal2)
472 const Coord ijk = iter.getCoord();
479 std::ostringstream ss;
494 template<
typename GridT,
495 typename TreeIterT =
typename GridT::ValueOnCIter,
500 static_assert(std::is_floating_point<ValueType>::value,
501 "openvdb::tools::CheckEikonal requires a scalar, floating-point grid");
504 typename TreeIterT::ValueIterT> ::template NodeConverter<
505 typename GridT::TreeType::LeafNodeType>::Type;
509 : stencil(grid), minVal(_min), maxVal(_max)
511 if ( !grid.hasUniformVoxels() ) {
514 if (minVal > maxVal) {
520 : stencil(other.stencil.grid()), minVal(other.minVal), maxVal(other.maxVal)
535 stencil.moveTo(iter);
536 if (!stencil.zeroCrossing())
return false;
537 return (*
this)(stencil.normSqGrad());
543 std::ostringstream ss;
544 ss <<
"outside the range of NormGrad ["<<minVal<<
","<<maxVal<<
"]";
555 template<
typename GridT,
556 typename TreeIterT =
typename GridT::ValueOnCIter,
562 static_assert(std::is_floating_point<ElementType>::value,
563 "openvdb::tools::CheckDivergence requires a floating-point vector grid");
566 typename TreeIterT::ValueIterT>::template NodeConverter<
567 typename GridT::TreeType::LeafNodeType>::Type;
568 using AccT =
typename GridT::ConstAccessor;
574 : acc(grid.getConstAccessor())
575 , invdx(
ValueType(1.0/grid.voxelSize()[0]))
579 if ( !grid.hasUniformVoxels() ) {
582 if (minVal > maxVal) {
597 const Coord ijk = iter.getCoord();
604 std::ostringstream ss;
605 ss <<
"outside the range of divergence ["<<minVal<<
","<<maxVal<<
"]";
617 template <
typename Gr
idT>
621 using MaskType =
typename GridT::template ValueConverter<bool>::Type;
625 mMask->setTransform(grid.transformPtr()->copy());
628 template <
typename CheckT>
629 std::string
check(
const CheckT& check,
630 bool updateMask =
false,
631 bool checkVoxels =
true,
632 bool checkTiles =
true,
633 bool checkBackground =
true)
635 typename MaskType::TreeType* mask = updateMask ? &(mMask->tree()) :
nullptr;
636 CheckValues<CheckT> cc(mask, mGrid, check);
637 std::ostringstream ss;
638 if (checkBackground) ss << cc.checkBackground();
639 if (checkTiles) ss << cc.checkTiles();
640 if (checkVoxels) ss << cc.checkVoxels();
649 typename MaskType::ConstPtr
mask()
const {
return mMask; }
650 typename MaskType::Ptr
mask() {
return mMask; }
663 const GridT&
grid()
const {
return *mGrid; }
674 typename MaskType::Ptr mMask;
678 template <
typename CheckT>
681 using MaskT =
typename MaskType::TreeType;
682 using LeafT =
typename GridT::TreeType::LeafNodeType;
684 const bool mOwnsMask;
690 CheckValues(MaskT* mask,
const GridT* grid,
const CheckT& check)
698 CheckValues(CheckValues& other, tbb::split)
700 , mMask(other.mMask ? new MaskT() : nullptr)
702 , mCheck(other.mCheck)
706 ~CheckValues() {
if (mOwnsMask)
delete mMask; }
708 std::string checkBackground()
710 std::ostringstream ss;
711 if (mCheck(mGrid->background())) {
713 ss <<
"Background is " + mCheck.str() << std::endl;
718 std::string checkTiles()
720 std::ostringstream ss;
722 typename CheckT::TileIterT i(mGrid->tree());
723 for (i.setMaxDepth(GridT::TreeType::RootNodeType::LEVEL - 1); i; ++i) {
726 if (mMask) mMask->fill(i.getBoundingBox(),
true,
true);
729 if (
const Index64 m = mCount - n) {
730 ss << m <<
" tile" << (m==1 ?
" is " :
"s are ") + mCheck.str() << std::endl;
735 std::string checkVoxels()
737 std::ostringstream ss;
738 LeafManagerT leafs(mGrid->tree());
740 tbb::parallel_reduce(leafs.leafRange(), *
this);
741 if (
const Index64 m = mCount - n) {
742 ss << m <<
" voxel" << (m==1 ?
" is " :
"s are ") + mCheck.str() << std::endl;
747 void operator()(
const typename LeafManagerT::LeafRange& r)
749 using VoxelIterT =
typename CheckT::VoxelIterT;
751 for (
typename LeafManagerT::LeafRange::Iterator i=r.begin(); i; ++i) {
752 typename MaskT::LeafNodeType* maskLeaf =
nullptr;
753 for (VoxelIterT j = tree::IterTraits<LeafT, VoxelIterT>::begin(*i); j; ++j) {
756 if (maskLeaf ==
nullptr) maskLeaf = mMask->touchLeaf(j.getCoord());
757 maskLeaf->setValueOn(j.pos(),
true);
762 for (
typename LeafManagerT::LeafRange::Iterator i=r.begin(); i; ++i) {
763 for (VoxelIterT j = tree::IterTraits<LeafT, VoxelIterT>::begin(*i); j; ++j) {
764 if (mCheck(j)) ++mCount;
769 void join(
const CheckValues& other)
772 mCount += other.mCount;
784 template<
class Gr
idType>
789 using MaskType =
typename GridType::template ValueConverter<bool>::Type;
797 typename MaskType::ConstPtr
mask()
const {
return mDiagnose.mask(); }
798 typename MaskType::Ptr
mask() {
return mDiagnose.mask(); }
811 const GridType&
grid()
const {
return mDiagnose.grid(); }
821 static const bool test = std::is_floating_point<ValueType>::value;
822 return test ?
"" :
"Value type is not floating point\n";
830 const bool test = mDiagnose.grid().getGridClass() ==
GRID_LEVEL_SET;
831 return test ?
"" :
"Class type is not \"GRID_LEVEL_SET\"\n";
839 return mDiagnose.grid().hasUniformVoxels() ?
"" :
"Does not have uniform voxels\n";
848 const Real w = mDiagnose.grid().background() / mDiagnose.grid().voxelSize()[0];
850 std::ostringstream ss;
851 ss <<
"The background value ("<< mDiagnose.grid().background()<<
") is less than "
852 << halfWidth <<
" voxel units\n";
863 const bool test = mDiagnose.grid().tree().hasActiveTiles();
864 return test ?
"Has active tile values\n" :
"";
873 return mDiagnose.check(c, updateMask,
true,
true,
true);
881 const ValueType& background = mDiagnose.grid().background();
883 return mDiagnose.check(c, updateMask,
true,
false,
false);
892 const ValueType& background = mDiagnose.grid().background();
894 return mDiagnose.check(c, updateMask,
true,
true,
false);
904 return mDiagnose.check(c, updateMask,
true,
false,
false);
924 std::string
check(
size_t n=9,
bool updateMask =
false)
926 std::string str = this->checkValueType();
927 if (str.empty() && n>1) str = this->checkClassType();
928 if (str.empty() && n>2) str = this->checkTransform();
929 if (str.empty() && n>3) str = this->checkBackground();
930 if (str.empty() && n>4) str = this->checkTiles();
931 if (str.empty() && n>5) str = this->checkFinite(updateMask);
932 if (str.empty() && n>6) str = this->checkRange(updateMask);
933 if (str.empty() && n>7) str = this->checkInactiveValues(updateMask);
934 if (str.empty() && n>8) str = this->checkEikonal(updateMask);
947 template<
class Gr
idType>
952 return c.
check(n,
false);
960 template<
class Gr
idType>
965 using MaskType =
typename GridType::template ValueConverter<bool>::Type;
973 typename MaskType::ConstPtr
mask()
const {
return mDiagnose.mask(); }
974 typename MaskType::Ptr
mask() {
return mDiagnose.mask(); }
987 const GridType&
grid()
const {
return mDiagnose.grid(); }
997 static const bool test = std::is_floating_point<ValueType>::value;
998 return test ?
"" :
"Value type is not floating point";
1007 return test ?
"" :
"Class type is not \"GRID_LEVEL_SET\"";
1016 std::ostringstream ss;
1017 ss <<
"The background value ("<< mDiagnose.grid().background()<<
") is not zero";
1029 return mDiagnose.check(c, updateMask,
true,
true,
true);
1038 return mDiagnose.check(c, updateMask,
true,
true,
true);
1048 return mDiagnose.check(c, updateMask,
true,
true,
false);
1063 std::string
check(
size_t n=6,
bool updateMask =
false)
1065 std::string str = this->checkValueType();
1066 if (str.empty() && n>1) str = this->checkClassType();
1067 if (str.empty() && n>2) str = this->checkBackground();
1068 if (str.empty() && n>3) str = this->checkFinite(updateMask);
1069 if (str.empty() && n>4) str = this->checkInactiveValues(updateMask);
1070 if (str.empty() && n>5) str = this->checkRange(updateMask);
1083 template<
class Gr
idType>
1088 return c.
check(n,
false);
1098 namespace diagnostics_internal {
1101 template<
typename TreeType>
1102 class InactiveVoxelValues
1106 using ValueType =
typename TreeType::ValueType;
1107 using SetType = std::set<ValueType>;
1109 InactiveVoxelValues(LeafArray&,
size_t numValues);
1114 void getInactiveValues(SetType&)
const;
1116 inline InactiveVoxelValues(
const InactiveVoxelValues<TreeType>&, tbb::split);
1117 inline void operator()(
const tbb::blocked_range<size_t>&);
1118 inline void join(
const InactiveVoxelValues<TreeType>&);
1121 LeafArray& mLeafArray;
1122 SetType mInactiveValues;
1126 template<
typename TreeType>
1127 InactiveVoxelValues<TreeType>::InactiveVoxelValues(LeafArray& leafs,
size_t numValues)
1130 , mNumValues(numValues)
1134 template <
typename TreeType>
1136 InactiveVoxelValues<TreeType>::InactiveVoxelValues(
1137 const InactiveVoxelValues<TreeType>& rhs, tbb::split)
1138 : mLeafArray(rhs.mLeafArray)
1140 , mNumValues(rhs.mNumValues)
1144 template<
typename TreeType>
1146 InactiveVoxelValues<TreeType>::runParallel()
1148 tbb::parallel_reduce(mLeafArray.getRange(), *
this);
1152 template<
typename TreeType>
1154 InactiveVoxelValues<TreeType>::runSerial()
1156 (*this)(mLeafArray.getRange());
1160 template<
typename TreeType>
1162 InactiveVoxelValues<TreeType>::operator()(
const tbb::blocked_range<size_t>& range)
1164 typename TreeType::LeafNodeType::ValueOffCIter iter;
1166 for (
size_t n = range.begin(); n < range.end() && !thread::isGroupExecutionCancelled(); ++n) {
1167 for (iter = mLeafArray.leaf(n).cbeginValueOff(); iter; ++iter) {
1168 mInactiveValues.insert(iter.getValue());
1171 if (mInactiveValues.size() > mNumValues) {
1172 thread::cancelGroupExecution();
1177 template<
typename TreeType>
1179 InactiveVoxelValues<TreeType>::join(
const InactiveVoxelValues<TreeType>& rhs)
1181 mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end());
1184 template<
typename TreeType>
1186 InactiveVoxelValues<TreeType>::getInactiveValues(SetType& values)
const
1188 values.insert(mInactiveValues.begin(), mInactiveValues.end());
1195 template<
typename TreeType>
1196 class InactiveTileValues
1199 using IterRange = tree::IteratorRange<typename TreeType::ValueOffCIter>;
1200 using ValueType =
typename TreeType::ValueType;
1201 using SetType = std::set<ValueType>;
1203 InactiveTileValues(
size_t numValues);
1205 void runParallel(IterRange&);
1206 void runSerial(IterRange&);
1208 void getInactiveValues(SetType&)
const;
1210 inline InactiveTileValues(
const InactiveTileValues<TreeType>&, tbb::split);
1211 inline void operator()(IterRange&);
1212 inline void join(
const InactiveTileValues<TreeType>&);
1215 SetType mInactiveValues;
1220 template<
typename TreeType>
1221 InactiveTileValues<TreeType>::InactiveTileValues(
size_t numValues)
1223 , mNumValues(numValues)
1227 template <
typename TreeType>
1229 InactiveTileValues<TreeType>::InactiveTileValues(
1230 const InactiveTileValues<TreeType>& rhs, tbb::split)
1232 , mNumValues(rhs.mNumValues)
1236 template<
typename TreeType>
1238 InactiveTileValues<TreeType>::runParallel(IterRange& range)
1240 tbb::parallel_reduce(range, *
this);
1244 template<
typename TreeType>
1246 InactiveTileValues<TreeType>::runSerial(IterRange& range)
1252 template<
typename TreeType>
1254 InactiveTileValues<TreeType>::operator()(IterRange& range)
1256 for (; range && !thread::isGroupExecutionCancelled(); ++range) {
1257 typename TreeType::ValueOffCIter iter = range.iterator();
1258 for (; iter; ++iter) {
1259 mInactiveValues.insert(iter.getValue());
1262 if (mInactiveValues.size() > mNumValues) {
1263 thread::cancelGroupExecution();
1268 template<
typename TreeType>
1270 InactiveTileValues<TreeType>::join(
const InactiveTileValues<TreeType>& rhs)
1272 mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end());
1275 template<
typename TreeType>
1277 InactiveTileValues<TreeType>::getInactiveValues(SetType& values)
const
1279 values.insert(mInactiveValues.begin(), mInactiveValues.end());
1289 template<
class Gr
idType>
1292 std::vector<typename GridType::ValueType>& values,
size_t numValues)
1294 using TreeType =
typename GridType::TreeType;
1295 using ValueType =
typename GridType::ValueType;
1296 using SetType = std::set<ValueType>;
1298 SetType uniqueValues;
1301 TreeType& tree =
const_cast<TreeType&
>(grid.tree());
1303 diagnostics_internal::InactiveVoxelValues<TreeType> voxelOp(leafs, numValues);
1304 voxelOp.runParallel();
1305 voxelOp.getInactiveValues(uniqueValues);
1309 if (uniqueValues.size() <= numValues) {
1310 typename TreeType::ValueOffCIter iter(grid.tree());
1311 iter.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 1);
1312 diagnostics_internal::InactiveTileValues<TreeType> tileOp(numValues);
1315 tileOp.runParallel(range);
1317 tileOp.getInactiveValues(uniqueValues);
1321 values.reserve(uniqueValues.size());
1323 typename SetType::iterator it = uniqueValues.begin();
1324 for ( ; it != uniqueValues.end(); ++it) {
1325 values.push_back(*it);
1328 return values.size() <= numValues;
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...
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
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
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance.
Definition: Math.h:350
Coord Abs(const Coord &xyz)
Definition: Coord.h:514
DScheme
Different discrete schemes used in the first derivatives.
Definition: FiniteDifference.h:32
@ CD_2ND
Definition: FiniteDifference.h:35
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:764
BiasedGradientScheme
Biased Gradients are limited to non-centered differences.
Definition: FiniteDifference.h:165
@ FIRST_BIAS
Definition: FiniteDifference.h:167
Type Pow2(Type x)
Return x2.
Definition: Math.h:551
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
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:180