OpenVDB  9.0.1
Diagnostics.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 ///
4 /// @file Diagnostics.h
5 ///
6 /// @author Ken Museth
7 ///
8 /// @brief Various diagnostic tools to identify potential issues with
9 /// for example narrow-band level sets or fog volumes
10 ///
11 #ifndef OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED
12 #define OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED
13 
14 #include "openvdb/Grid.h"
15 #include "openvdb/math/Math.h"
16 #include "openvdb/math/Vec3.h"
17 #include "openvdb/math/Stencils.h"
18 #include "openvdb/math/Operators.h"
20 #include "openvdb/thread/Threading.h"
21 #include <openvdb/openvdb.h>
22 
23 #include <tbb/blocked_range.h>
24 #include <tbb/parallel_reduce.h>
25 
26 #include <cmath> // for std::isnan(), std::isfinite()
27 #include <set>
28 #include <sstream>
29 #include <string>
30 #include <type_traits>
31 #include <vector>
32 
33 namespace openvdb {
35 namespace OPENVDB_VERSION_NAME {
36 namespace tools {
37 
38 ////////////////////////////////////////////////////////////////////////////////
39 
40 /// @brief Perform checks on a grid to see if it is a valid symmetric,
41 /// narrow-band level set.
42 ///
43 /// @param grid Grid to be checked
44 /// @param number Number of the checks to be performed (see below)
45 /// @return string with a message indicating the nature of the
46 /// issue. If no issue is detected the return string is empty.
47 ///
48 /// @details @a number refers to the following ordered list of
49 /// checks - always starting from the top.
50 /// Fast checks
51 /// 1: value type is floating point
52 /// 2: has level set class type
53 /// 3: has uniform scale
54 /// 4: background value is positive and n*dx
55 ///
56 /// Slower checks
57 /// 5: no active tiles
58 /// 6: all the values are finite, i.e not NaN or infinite
59 /// 7: active values in range between +-background
60 /// 8: abs of inactive values = background, i.e. assuming a symmetric
61 /// narrow band!
62 ///
63 /// Relatively slow check (however multithreaded)
64 /// 9: norm gradient is close to one, i.e. satisfied the Eikonal equation.
65 template<class GridType>
66 std::string
67 checkLevelSet(const GridType& grid, size_t number=9);
68 
69 ////////////////////////////////////////////////////////////////////////////////
70 
71 /// @brief Perform checks on a grid to see if it is a valid fog volume.
72 ///
73 /// @param grid Grid to be checked
74 /// @param number Number of the checks to be performed (see below)
75 /// @return string with a message indicating the nature of the
76 /// issue. If no issue is detected the return string is empty.
77 ///
78 /// @details @a number refers to the following ordered list of
79 /// checks - always starting from the top.
80 /// Fast checks
81 /// 1: value type is floating point
82 /// 2: has FOG volume class type
83 /// 3: background value is zero
84 ///
85 /// Slower checks
86 /// 4: all the values are finite, i.e not NaN or infinite
87 /// 5: inactive values are zero
88 /// 6: active values are in the range [0,1]
89 template<class GridType>
90 std::string
91 checkFogVolume(const GridType& grid, size_t number=6);
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 
95 /// @brief Threaded method to find unique inactive values.
96 ///
97 /// @param grid A VDB volume.
98 /// @param values List of unique inactive values, returned by this method.
99 /// @param numValues Number of values to look for.
100 /// @return @c false if the @a grid has more than @a numValues inactive values.
101 template<class GridType>
102 bool
103 uniqueInactiveValues(const GridType& grid,
104  std::vector<typename GridType::ValueType>& values, size_t numValues);
105 
106 
107 ////////////////////////////////////////////////////////////////////////////////
108 
109 /// @brief Checks NaN values
110 template<typename GridT, typename TreeIterT = typename GridT::ValueOnCIter>
111 struct CheckNan
112 {
114  using TileIterT = TreeIterT;
115  using VoxelIterT = typename tree::IterTraits<
116  typename TreeIterT::NodeT, typename TreeIterT::ValueIterT>::template
117  NodeConverter<typename GridT::TreeType::LeafNodeType>::Type;
118 
119  /// @brief Default constructor
120  CheckNan() {}
121 
122  /// Return true if the scalar value is NaN
123  inline bool operator()(const ElementType& v) const { return std::isnan(v); }
124 
125  /// @brief This allows for vector values to be checked component-wise
126  template<typename T>
127  inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type
128  operator()(const T& v) const
129  {
130  for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true;//should unroll
131  return false;
132  }
133 
134  /// @brief Return true if the tile at the iterator location is NaN
135  bool operator()(const TreeIterT &iter) const { return (*this)(*iter); }
136 
137  /// @brief Return true if the voxel at the iterator location is NaN
138  bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); }
139 
140  /// @brief Return a string describing a failed check.
141  std::string str() const { return "NaN"; }
142 
143 };// CheckNan
144 
145 ////////////////////////////////////////////////////////////////////////////////
146 
147 /// @brief Checks for infinite values, e.g. 1/0 or -1/0
148 template <typename GridT,
149  typename TreeIterT = typename GridT::ValueOnCIter>
150 struct CheckInf
151 {
153  using TileIterT = TreeIterT;
154  using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
155  typename TreeIterT::ValueIterT> ::template NodeConverter<
156  typename GridT::TreeType::LeafNodeType>::Type;
157 
158  /// @brief Default constructor
159  CheckInf() {}
160 
161  /// Return true if the value is infinite
162  inline bool operator()(const ElementType& v) const { return std::isinf(v); }
163 
164  /// Return true if any of the vector components are infinite.
165  template<typename T>
166  inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type
167  operator()(const T& v) const
168  {
169  for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true;
170  return false;
171  }
172 
173  /// @brief Return true if the tile at the iterator location is infinite
174  bool operator()(const TreeIterT &iter) const { return (*this)(*iter); }
175 
176  /// @brief Return true if the tile at the iterator location is infinite
177  bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); }
178 
179  /// @brief Return a string describing a failed check.
180  std::string str() const { return "infinite"; }
181 };// CheckInf
182 
183 ////////////////////////////////////////////////////////////////////////////////
184 
185 /// @brief Checks for both NaN and inf values, i.e. any value that is not finite.
186 template <typename GridT,
187  typename TreeIterT = typename GridT::ValueOnCIter>
189 {
191  using TileIterT = TreeIterT;
192  using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
193  typename TreeIterT::ValueIterT> ::template NodeConverter<
194  typename GridT::TreeType::LeafNodeType>::Type;
195 
196  /// @brief Default constructor
198 
199  /// Return true if the value is NOT finite, i.e. it's NaN or infinite
200  inline bool operator()(const ElementType& v) const { return !std::isfinite(v); }
201 
202  /// Return true if any of the vector components are NaN or infinite.
203  template<typename T>
204  inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type
205  operator()(const T& v) const {
206  for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true;
207  return false;
208  }
209 
210  /// @brief Return true if the tile at the iterator location is NaN or infinite.
211  bool operator()(const TreeIterT &iter) const { return (*this)(*iter); }
212 
213  /// @brief Return true if the tile at the iterator location is NaN or infinite.
214  bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); }
215 
216  /// @brief Return a string describing a failed check.
217  std::string str() const { return "not finite"; }
218 };// CheckFinite
219 
220 ////////////////////////////////////////////////////////////////////////////////
221 
222 /// @brief Check that the magnitude of a value, a, is close to a fixed
223 /// magnitude, b, given a fixed tolerance c. That is | |a| - |b| | <= c
224 template <typename GridT,
225  typename TreeIterT = typename GridT::ValueOffCIter>
227 {
229  using TileIterT = TreeIterT;
230  using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
231  typename TreeIterT::ValueIterT> ::template NodeConverter<
232  typename GridT::TreeType::LeafNodeType>::Type;
233 
234  /// @brief Default constructor
237  : absVal(math::Abs(a)), tolVal(math::Abs(t))
238  {
239  }
240 
241  /// Return true if the magnitude of the value is not approximately
242  /// equal to totVal.
243  inline bool operator()(const ElementType& v) const
244  {
245  return math::Abs(math::Abs(v) - absVal) > tolVal;
246  }
247 
248  /// Return true if any of the vector components are infinite.
249  template<typename T>
250  inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type
251  operator()(const T& v) const
252  {
253  for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true;
254  return false;
255  }
256 
257  /// @brief Return true if the tile at the iterator location is infinite
258  bool operator()(const TreeIterT &iter) const { return (*this)(*iter); }
259 
260  /// @brief Return true if the tile at the iterator location is infinite
261  bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); }
262 
263  /// @brief Return a string describing a failed check.
264  std::string str() const
265  {
266  std::ostringstream ss;
267  ss << "not equal to +/-"<<absVal<<" with a tolerance of "<<tolVal;
268  return ss.str();
269  }
270 
271  const ElementType absVal, tolVal;
272 };// CheckMagnitude
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 
276 /// @brief Checks a value against a range
277 template <typename GridT,
278  bool MinInclusive = true,//is min part of the range?
279  bool MaxInclusive = true,//is max part of the range?
280  typename TreeIterT = typename GridT::ValueOnCIter>
282 {
284  using TileIterT = TreeIterT;
285  using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
286  typename TreeIterT::ValueIterT> ::template NodeConverter<
287  typename GridT::TreeType::LeafNodeType>::Type;
288 
289  // @brief Constructor taking a range to be tested against.
290  CheckRange(const ElementType& _min, const ElementType& _max) : minVal(_min), maxVal(_max)
291  {
292  if (minVal > maxVal) {
293  OPENVDB_THROW(ValueError, "CheckRange: Invalid range (min > max)");
294  }
295  }
296 
297  /// Return true if the value is smaller than min or larger than max.
298  inline bool operator()(const ElementType& v) const
299  {
300  return (MinInclusive ? v<minVal : v<=minVal) ||
301  (MaxInclusive ? v>maxVal : v>=maxVal);
302  }
303 
304  /// Return true if any of the vector components are out of range.
305  template<typename T>
306  inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type
307  operator()(const T& v) const {
308  for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true;
309  return false;
310  }
311 
312  /// @brief Return true if the voxel at the iterator location is out of range.
313  bool operator()(const TreeIterT &iter) const { return (*this)(*iter); }
314 
315  /// @brief Return true if the tile at the iterator location is out of range.
316  bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); }
317 
318  /// @brief Return a string describing a failed check.
319  std::string str() const
320  {
321  std::ostringstream ss;
322  ss << "outside the value range " << (MinInclusive ? "[" : "]")
323  << minVal << "," << maxVal << (MaxInclusive ? "]" : "[");
324  return ss.str();
325  }
326 
327  const ElementType minVal, maxVal;
328 };// CheckRange
329 
330 ////////////////////////////////////////////////////////////////////////////////
331 
332 /// @brief Checks a value against a minimum
333 template <typename GridT,
334  typename TreeIterT = typename GridT::ValueOnCIter>
335 struct CheckMin
336 {
338  using TileIterT = TreeIterT;
339  using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
340  typename TreeIterT::ValueIterT> ::template NodeConverter<
341  typename GridT::TreeType::LeafNodeType>::Type;
342 
343  // @brief Constructor taking a minimum to be tested against.
344  CheckMin(const ElementType& _min) : minVal(_min) {}
345 
346  /// Return true if the value is smaller than min.
347  inline bool operator()(const ElementType& v) const { return v<minVal; }
348 
349  /// Return true if any of the vector components are smaller than min.
350  template<typename T>
351  inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type
352  operator()(const T& v) const {
353  for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true;
354  return false;
355  }
356 
357  /// @brief Return true if the voxel at the iterator location is smaller than min.
358  bool operator()(const TreeIterT &iter) const { return (*this)(*iter); }
359 
360  /// @brief Return true if the tile at the iterator location is smaller than min.
361  bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); }
362 
363  /// @brief Return a string describing a failed check.
364  std::string str() const
365  {
366  std::ostringstream ss;
367  ss << "smaller than "<<minVal;
368  return ss.str();
369  }
370 
372 };// CheckMin
373 
374 ////////////////////////////////////////////////////////////////////////////////
375 
376 /// @brief Checks a value against a maximum
377 template <typename GridT,
378  typename TreeIterT = typename GridT::ValueOnCIter>
379 struct CheckMax
380 {
382  using TileIterT = TreeIterT;
383  using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
384  typename TreeIterT::ValueIterT> ::template NodeConverter<
385  typename GridT::TreeType::LeafNodeType>::Type;
386 
387  /// @brief Constructor taking a maximum to be tested against.
388  CheckMax(const ElementType& _max) : maxVal(_max) {}
389 
390  /// Return true if the value is larger than max.
391  inline bool operator()(const ElementType& v) const { return v>maxVal; }
392 
393  /// Return true if any of the vector components are larger than max.
394  template<typename T>
395  inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type
396  operator()(const T& v) const {
397  for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true;
398  return false;
399  }
400 
401  /// @brief Return true if the tile at the iterator location is larger than max.
402  bool operator()(const TreeIterT &iter) const { return (*this)(*iter); }
403 
404  /// @brief Return true if the voxel at the iterator location is larger than max.
405  bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); }
406 
407  /// @brief Return a string describing a failed check.
408  std::string str() const
409  {
410  std::ostringstream ss;
411  ss << "larger than "<<maxVal;
412  return ss.str();
413  }
414 
416 };// CheckMax
417 
418 ////////////////////////////////////////////////////////////////////////////////
419 
420 /// @brief Checks the norm of the gradient against a range, i.e.,
421 /// |&nabla;&Phi;| &isin; [min, max]
422 ///
423 /// @note Internally the test is performed as
424 /// |&nabla;&Phi;|&sup2; &isin; [min&sup2;, max&sup2;] for optimization reasons.
425 template<typename GridT,
426  typename TreeIterT = typename GridT::ValueOnCIter,
427  math::BiasedGradientScheme GradScheme = math::FIRST_BIAS>//math::WENO5_BIAS>
429 {
430  using ValueType = typename GridT::ValueType;
432  "openvdb::tools::CheckNormGrad requires a scalar, floating-point grid");
433  using TileIterT = TreeIterT;
434  using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
435  typename TreeIterT::ValueIterT> ::template NodeConverter<
436  typename GridT::TreeType::LeafNodeType>::Type;
437  using AccT = typename GridT::ConstAccessor;
438 
439  /// @brief Constructor taking a grid and a range to be tested against.
440  CheckNormGrad(const GridT& grid, const ValueType& _min, const ValueType& _max)
441  : acc(grid.getConstAccessor())
442  , invdx2(ValueType(1.0/math::Pow2(grid.voxelSize()[0])))
443  , minVal2(_min*_min)
444  , maxVal2(_max*_max)
445  {
446  if ( !grid.hasUniformVoxels() ) {
447  OPENVDB_THROW(ValueError, "CheckNormGrad: The transform must have uniform scale");
448  }
449  if (_min > _max) {
450  OPENVDB_THROW(ValueError, "CheckNormGrad: Invalid range (min > max)");
451  }
452  }
453 
455  : acc(other.acc.tree())
456  , invdx2(other.invdx2)
457  , minVal2(other.minVal2)
458  , maxVal2(other.maxVal2)
459  {
460  }
461 
462  /// Return true if the value is smaller than min or larger than max.
463  inline bool operator()(const ValueType& v) const { return v<minVal2 || v>maxVal2; }
464 
465  /// @brief Return true if zero is outside the range.
466  /// @note We assume that the norm of the gradient of a tile is always zero.
467  inline bool operator()(const TreeIterT&) const { return (*this)(ValueType(0)); }
468 
469  /// @brief Return true if the norm of the gradient at a voxel
470  /// location of the iterator is out of range.
471  inline bool operator()(const VoxelIterT &iter) const
472  {
473  const Coord ijk = iter.getCoord();
474  return (*this)(invdx2 * math::ISGradientNormSqrd<GradScheme>::result(acc, ijk));
475  }
476 
477  /// @brief Return a string describing a failed check.
478  std::string str() const
479  {
480  std::ostringstream ss;
481  ss << "outside the range of NormGrad ["<<math::Sqrt(minVal2)<<","<<math::Sqrt(maxVal2)<<"]";
482  return ss.str();
483  }
484 
486  const ValueType invdx2, minVal2, maxVal2;
487 };// CheckNormGrad
488 
489 ////////////////////////////////////////////////////////////////////////////////
490 
491 /// @brief Checks the norm of the gradient at zero-crossing voxels against a range
492 /// @details CheckEikonal differs from CheckNormGrad in that it only
493 /// checks the norm of the gradient at voxel locations where the
494 /// FD-stencil crosses the zero isosurface!
495 template<typename GridT,
496  typename TreeIterT = typename GridT::ValueOnCIter,
497  typename StencilT = math::WenoStencil<GridT> >//math::GradStencil<GridT>
499 {
500  using ValueType = typename GridT::ValueType;
502  "openvdb::tools::CheckEikonal requires a scalar, floating-point grid");
503  using TileIterT = TreeIterT;
504  using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
505  typename TreeIterT::ValueIterT> ::template NodeConverter<
506  typename GridT::TreeType::LeafNodeType>::Type;
507 
508  /// @brief Constructor taking a grid and a range to be tested against.
509  CheckEikonal(const GridT& grid, const ValueType& _min, const ValueType& _max)
510  : stencil(grid), minVal(_min), maxVal(_max)
511  {
512  if ( !grid.hasUniformVoxels() ) {
513  OPENVDB_THROW(ValueError, "CheckEikonal: The transform must have uniform scale");
514  }
515  if (minVal > maxVal) {
516  OPENVDB_THROW(ValueError, "CheckEikonal: Invalid range (min > max)");
517  }
518  }
519 
521  : stencil(other.stencil.grid()), minVal(other.minVal), maxVal(other.maxVal)
522  {
523  }
524 
525  /// Return true if the value is smaller than min or larger than max.
526  inline bool operator()(const ValueType& v) const { return v<minVal || v>maxVal; }
527 
528  /// @brief Return true if zero is outside the range.
529  /// @note We assume that the norm of the gradient of a tile is always zero.
530  inline bool operator()(const TreeIterT&) const { return (*this)(ValueType(0)); }
531 
532  /// @brief Return true if the norm of the gradient at a
533  /// zero-crossing voxel location of the iterator is out of range.
534  inline bool operator()(const VoxelIterT &iter) const
535  {
536  stencil.moveTo(iter);
537  if (!stencil.zeroCrossing()) return false;
538  return (*this)(stencil.normSqGrad());
539  }
540 
541  /// @brief Return a string describing a failed check.
542  std::string str() const
543  {
544  std::ostringstream ss;
545  ss << "outside the range of NormGrad ["<<minVal<<","<<maxVal<<"]";
546  return ss.str();
547  }
548 
549  mutable StencilT stencil;
550  const ValueType minVal, maxVal;
551 };// CheckEikonal
552 
553 ////////////////////////////////////////////////////////////////////////////////
554 
555 /// @brief Checks the divergence against a range
556 template<typename GridT,
557  typename TreeIterT = typename GridT::ValueOnCIter,
558  math::DScheme DiffScheme = math::CD_2ND>
560 {
561  using ValueType = typename GridT::ValueType;
564  "openvdb::tools::CheckDivergence requires a floating-point vector grid");
565  using TileIterT = TreeIterT;
566  using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
567  typename TreeIterT::ValueIterT>::template NodeConverter<
568  typename GridT::TreeType::LeafNodeType>::Type;
569  using AccT = typename GridT::ConstAccessor;
570 
571  /// @brief Constructor taking a grid and a range to be tested against.
572  CheckDivergence(const GridT& grid,
573  const ValueType& _min,
574  const ValueType& _max)
575  : acc(grid.getConstAccessor())
576  , invdx(ValueType(1.0/grid.voxelSize()[0]))
577  , minVal(_min)
578  , maxVal(_max)
579  {
580  if ( !grid.hasUniformVoxels() ) {
581  OPENVDB_THROW(ValueError, "CheckDivergence: The transform must have uniform scale");
582  }
583  if (minVal > maxVal) {
584  OPENVDB_THROW(ValueError, "CheckDivergence: Invalid range (min > max)");
585  }
586  }
587  /// Return true if the value is smaller than min or larger than max.
588  inline bool operator()(const ElementType& v) const { return v<minVal || v>maxVal; }
589 
590  /// @brief Return true if zero is outside the range.
591  /// @note We assume that the divergence of a tile is always zero.
592  inline bool operator()(const TreeIterT&) const { return (*this)(ElementType(0)); }
593 
594  /// @brief Return true if the divergence at a voxel location of
595  /// the iterator is out of range.
596  inline bool operator()(const VoxelIterT &iter) const
597  {
598  const Coord ijk = iter.getCoord();
599  return (*this)(invdx * math::ISDivergence<DiffScheme>::result(acc, ijk));
600  }
601 
602  /// @brief Return a string describing a failed check.
603  std::string str() const
604  {
605  std::ostringstream ss;
606  ss << "outside the range of divergence ["<<minVal<<","<<maxVal<<"]";
607  return ss.str();
608  }
609 
611  const ValueType invdx, minVal, maxVal;
612 };// CheckDivergence
613 
614 ////////////////////////////////////////////////////////////////////////////////
615 
616 /// @brief Performs multithreaded diagnostics of a grid
617 /// @note More documentation will be added soon!
618 template <typename GridT>
619 class Diagnose
620 {
621 public:
622  using MaskType = typename GridT::template ValueConverter<bool>::Type;
623 
624  Diagnose(const GridT& grid) : mGrid(&grid), mMask(new MaskType()), mCount(0)
625  {
626  mMask->setTransform(grid.transformPtr()->copy());
627  }
628 
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)
635  {
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();
642  mCount += cc.mCount;
643  return ss.str();
644  }
645 
646  //@{
647  /// @brief Return a boolean mask of all the values
648  /// (i.e. tiles and/or voxels) that have failed one or
649  /// more checks.
650  typename MaskType::ConstPtr mask() const { return mMask; }
651  typename MaskType::Ptr mask() { return mMask; }
652  //@}
653 
654  /// @brief Return the number of values (i.e. background, tiles or
655  /// voxels) that have failed one or more checks.
656  Index64 valueCount() const { return mMask->activeVoxelCount(); }
657 
658  /// @brief Return total number of failed checks
659  /// @note If only one check was performed and the mask was updated
660  /// failureCount equals valueCount.
661  Index64 failureCount() const { return mCount; }
662 
663  /// @brief Return a const reference to the grid
664  const GridT& grid() const { return *mGrid; }
665 
666  /// @brief Clear the mask and error counter
667  void clear() { mMask = new MaskType(); mCount = 0; }
668 
669 private:
670  // disallow copy construction and copy by assignment!
671  Diagnose(const Diagnose&);// not implemented
672  Diagnose& operator=(const Diagnose&);// not implemented
673 
674  const GridT* mGrid;
675  typename MaskType::Ptr mMask;
676  Index64 mCount;
677 
678  /// @brief Private class that performs the multithreaded checks
679  template <typename CheckT>
680  struct CheckValues
681  {
682  using MaskT = typename MaskType::TreeType;
683  using LeafT = typename GridT::TreeType::LeafNodeType;
684  using LeafManagerT = typename tree::LeafManager<const typename GridT::TreeType>;
685  const bool mOwnsMask;
686  MaskT* mMask;
687  const GridT* mGrid;
688  const CheckT mCheck;
689  Index64 mCount;
690 
691  CheckValues(MaskT* mask, const GridT* grid, const CheckT& check)
692  : mOwnsMask(false)
693  , mMask(mask)
694  , mGrid(grid)
695  , mCheck(check)
696  , mCount(0)
697  {
698  }
699  CheckValues(CheckValues& other, tbb::split)
700  : mOwnsMask(true)
701  , mMask(other.mMask ? new MaskT() : nullptr)
702  , mGrid(other.mGrid)
703  , mCheck(other.mCheck)
704  , mCount(0)
705  {
706  }
707  ~CheckValues() { if (mOwnsMask) delete mMask; }
708 
709  std::string checkBackground()
710  {
711  std::ostringstream ss;
712  if (mCheck(mGrid->background())) {
713  ++mCount;
714  ss << "Background is " + mCheck.str() << std::endl;
715  }
716  return ss.str();
717  }
718 
719  std::string checkTiles()
720  {
721  std::ostringstream ss;
722  const Index64 n = mCount;
723  typename CheckT::TileIterT i(mGrid->tree());
724  for (i.setMaxDepth(GridT::TreeType::RootNodeType::LEVEL - 1); i; ++i) {
725  if (mCheck(i)) {
726  ++mCount;
727  if (mMask) mMask->fill(i.getBoundingBox(), true, true);
728  }
729  }
730  if (const Index64 m = mCount - n) {
731  ss << m << " tile" << (m==1 ? " is " : "s are ") + mCheck.str() << std::endl;
732  }
733  return ss.str();
734  }
735 
736  std::string checkVoxels()
737  {
738  std::ostringstream ss;
739  LeafManagerT leafs(mGrid->tree());
740  const Index64 n = mCount;
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;
744  }
745  return ss.str();
746  }
747 
748  void operator()(const typename LeafManagerT::LeafRange& r)
749  {
750  using VoxelIterT = typename CheckT::VoxelIterT;
751  if (mMask) {
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) {
755  if (mCheck(j)) {
756  ++mCount;
757  if (maskLeaf == nullptr) maskLeaf = mMask->touchLeaf(j.getCoord());
758  maskLeaf->setValueOn(j.pos(), true);
759  }
760  }
761  }
762  } else {
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;
766  }
767  }
768  }
769  }
770  void join(const CheckValues& other)
771  {
772  if (mMask) mMask->merge(*(other.mMask), openvdb::MERGE_ACTIVE_STATES_AND_NODES);
773  mCount += other.mCount;
774  }
775  };//End of private class CheckValues
776 
777 };// End of public class Diagnose
778 
779 
780 ////////////////////////////////////////////////////////////////////////////////
781 
782 /// @brief Class that performs various types of checks on narrow-band level sets.
783 ///
784 /// @note The most common usage is to simply call CheckLevelSet::check()
785 template<class GridType>
787 {
788 public:
789  using ValueType = typename GridType::ValueType;
790  using MaskType = typename GridType::template ValueConverter<bool>::Type;
791 
792  CheckLevelSet(const GridType& grid) : mDiagnose(grid) {}
793 
794  //@{
795  /// @brief Return a boolean mask of all the values
796  /// (i.e. tiles and/or voxels) that have failed one or
797  /// more checks.
798  typename MaskType::ConstPtr mask() const { return mDiagnose.mask(); }
799  typename MaskType::Ptr mask() { return mDiagnose.mask(); }
800  //@}
801 
802  /// @brief Return the number of values (i.e. background, tiles or
803  /// voxels) that have failed one or more checks.
804  Index64 valueCount() const { return mDiagnose.valueCount(); }
805 
806  /// @brief Return total number of failed checks
807  /// @note If only one check was performed and the mask was updated
808  /// failureCount equals valueCount.
809  Index64 failureCount() const { return mDiagnose.failureCount(); }
810 
811  /// @brief Return a const reference to the grid
812  const GridType& grid() const { return mDiagnose.grid(); }
813 
814  /// @brief Clear the mask and error counter
815  void clear() { mDiagnose.clear(); }
816 
817  /// @brief Return a nonempty message if the grid's value type is a floating point.
818  ///
819  /// @note No run-time overhead
820  static std::string checkValueType()
821  {
822  static const bool test = std::is_floating_point<ValueType>::value;
823  return test ? "" : "Value type is not floating point\n";
824  }
825 
826  /// @brief Return message if the grid's class is a level set.
827  ///
828  /// @note Small run-time overhead
829  std::string checkClassType() const
830  {
831  const bool test = mDiagnose.grid().getGridClass() == GRID_LEVEL_SET;
832  return test ? "" : "Class type is not \"GRID_LEVEL_SET\"\n";
833  }
834 
835  /// @brief Return a nonempty message if the grid's transform does not have uniform scaling.
836  ///
837  /// @note Small run-time overhead
838  std::string checkTransform() const
839  {
840  return mDiagnose.grid().hasUniformVoxels() ? "" : "Does not have uniform voxels\n";
841  }
842 
843  /// @brief Return a nonempty message if the background value is larger than or
844  /// equal to the halfWidth*voxelSize.
845  ///
846  /// @note Small run-time overhead
847  std::string checkBackground(Real halfWidth = LEVEL_SET_HALF_WIDTH) const
848  {
849  const Real w = mDiagnose.grid().background() / mDiagnose.grid().voxelSize()[0];
850  if (w < halfWidth) {
851  std::ostringstream ss;
852  ss << "The background value ("<< mDiagnose.grid().background()<<") is less than "
853  << halfWidth << " voxel units\n";
854  return ss.str();
855  }
856  return "";
857  }
858 
859  /// @brief Return a nonempty message if the grid has no active tile values.
860  ///
861  /// @note Medium run-time overhead
862  std::string checkTiles() const
863  {
864  const bool test = mDiagnose.grid().tree().hasActiveTiles();
865  return test ? "Has active tile values\n" : "";
866  }
867 
868  /// @brief Return a nonempty message if any of the values are not finite. i.e. NaN or inf.
869  ///
870  /// @note Medium run-time overhead
871  std::string checkFinite(bool updateMask = false)
872  {
874  return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/true);
875  }
876 
877  /// @brief Return a nonempty message if the active voxel values are out-of-range.
878  ///
879  /// @note Medium run-time overhead
880  std::string checkRange(bool updateMask = false)
881  {
882  const ValueType& background = mDiagnose.grid().background();
883  CheckRange<GridType> c(-background, background);
884  return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/false, /*background*/false);
885  }
886 
887  /// @brief Return a nonempty message if the the inactive values do not have a
888  /// magnitude equal to the background value.
889  ///
890  /// @note Medium run-time overhead
891  std::string checkInactiveValues(bool updateMask = false)
892  {
893  const ValueType& background = mDiagnose.grid().background();
895  return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/false);
896  }
897 
898  /// @brief Return a nonempty message if the norm of the gradient of the
899  /// active voxels is out of the range minV to maxV.
900  ///
901  /// @note Significant run-time overhead
902  std::string checkEikonal(bool updateMask = false, ValueType minV = 0.5, ValueType maxV = 1.5)
903  {
904  CheckEikonal<GridType> c(mDiagnose.grid(), minV, maxV);
905  return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/false, /*background*/false);
906  }
907 
908  /// @brief Return a nonempty message if an error or issue is detected. Only
909  /// runs tests with a number lower than or equal to n, where:
910  ///
911  /// Fast checks
912  /// 1: value type is floating point
913  /// 2: has level set class type
914  /// 3: has uniform scale
915  /// 4: background value is positive and n*dx
916  ///
917  /// Slower checks
918  /// 5: no active tiles
919  /// 6: all the values are finite, i.e not NaN or infinite
920  /// 7: active values in range between +-background
921  /// 8: abs of inactive values = background, i.e. assuming a symmetric narrow band!
922  ///
923  /// Relatively slow check (however multi-threaded)
924  /// 9: norm of gradient at zero-crossings is one, i.e. satisfied the Eikonal equation.
925  std::string check(size_t n=9, bool updateMask = false)
926  {
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);
936  return str;
937  }
938 
939 private:
940  // disallow copy construction and copy by assignment!
941  CheckLevelSet(const CheckLevelSet&);// not implemented
942  CheckLevelSet& operator=(const CheckLevelSet&);// not implemented
943 
944  // Member data
945  Diagnose<GridType> mDiagnose;
946 };// CheckLevelSet
947 
948 template<class GridType>
949 std::string
950 checkLevelSet(const GridType& grid, size_t n)
951 {
952  CheckLevelSet<GridType> c(grid);
953  return c.check(n, false);
954 }
955 
956 ////////////////////////////////////////////////////////////////////////////////
957 
958 /// @brief Class that performs various types of checks on fog volumes.
959 ///
960 /// @note The most common usage is to simply call CheckFogVolume::check()
961 template<class GridType>
963 {
964 public:
965  using ValueType = typename GridType::ValueType;
966  using MaskType = typename GridType::template ValueConverter<bool>::Type;
967 
968  CheckFogVolume(const GridType& grid) : mDiagnose(grid) {}
969 
970  //@{
971  /// @brief Return a boolean mask of all the values
972  /// (i.e. tiles and/or voxels) that have failed one or
973  /// more checks.
974  typename MaskType::ConstPtr mask() const { return mDiagnose.mask(); }
975  typename MaskType::Ptr mask() { return mDiagnose.mask(); }
976  //@}
977 
978  /// @brief Return the number of values (i.e. background, tiles or
979  /// voxels) that have failed one or more checks.
980  Index64 valueCount() const { return mDiagnose.valueCount(); }
981 
982  /// @brief Return total number of failed checks
983  /// @note If only one check was performed and the mask was updated
984  /// failureCount equals valueCount.
985  Index64 failureCount() const { return mDiagnose.failureCount(); }
986 
987  /// @brief Return a const reference to the grid
988  const GridType& grid() const { return mDiagnose.grid(); }
989 
990  /// @brief Clear the mask and error counter
991  void clear() { mDiagnose.clear(); }
992 
993  /// @brief Return a nonempty message if the grid's value type is a floating point.
994  ///
995  /// @note No run-time overhead
996  static std::string checkValueType()
997  {
998  static const bool test = std::is_floating_point<ValueType>::value;
999  return test ? "" : "Value type is not floating point";
1000  }
1001 
1002  /// @brief Return a nonempty message if the grid's class is a level set.
1003  ///
1004  /// @note Small run-time overhead
1005  std::string checkClassType() const
1006  {
1007  const bool test = mDiagnose.grid().getGridClass() == GRID_FOG_VOLUME;
1008  return test ? "" : "Class type is not \"GRID_LEVEL_SET\"";
1009  }
1010 
1011  /// @brief Return a nonempty message if the background value is not zero.
1012  ///
1013  /// @note Small run-time overhead
1014  std::string checkBackground() const
1015  {
1016  if (!math::isApproxZero(mDiagnose.grid().background())) {
1017  std::ostringstream ss;
1018  ss << "The background value ("<< mDiagnose.grid().background()<<") is not zero";
1019  return ss.str();
1020  }
1021  return "";
1022  }
1023 
1024  /// @brief Return a nonempty message if any of the values are not finite. i.e. NaN or inf.
1025  ///
1026  /// @note Medium run-time overhead
1027  std::string checkFinite(bool updateMask = false)
1028  {
1030  return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/true);
1031  }
1032 
1033  /// @brief Return a nonempty message if any of the inactive values are not zero.
1034  ///
1035  /// @note Medium run-time overhead
1036  std::string checkInactiveValues(bool updateMask = false)
1037  {
1039  return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/true);
1040  }
1041 
1042  /// @brief Return a nonempty message if the active voxel values
1043  /// are out-of-range, i.e. not in the range [0,1].
1044  ///
1045  /// @note Medium run-time overhead
1046  std::string checkRange(bool updateMask = false)
1047  {
1048  CheckRange<GridType> c(0, 1);
1049  return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/false);
1050  }
1051 
1052  /// @brief Return a nonempty message if an error or issue is detected. Only
1053  /// runs tests with a number lower than or equal to n, where:
1054  ///
1055  /// Fast checks
1056  /// 1: value type is floating point
1057  /// 2: has FOG volume class type
1058  /// 3: background value is zero
1059  ///
1060  /// Slower checks
1061  /// 4: all the values are finite, i.e not NaN or infinite
1062  /// 5: inactive values are zero
1063  /// 6: active values are in the range [0,1]
1064  std::string check(size_t n=6, bool updateMask = false)
1065  {
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);
1072  return str;
1073  }
1074 
1075 private:
1076  // disallow copy construction and copy by assignment!
1077  CheckFogVolume(const CheckFogVolume&);// not implemented
1078  CheckFogVolume& operator=(const CheckFogVolume&);// not implemented
1079 
1080  // Member data
1081  Diagnose<GridType> mDiagnose;
1082 };// CheckFogVolume
1083 
1084 template<class GridType>
1085 std::string
1086 checkFogVolume(const GridType& grid, size_t n)
1087 {
1088  CheckFogVolume<GridType> c(grid);
1089  return c.check(n, false);
1090 }
1091 
1092 
1093 ////////////////////////////////////////////////////////////////////////////////
1094 
1095 // Internal utility objects and implementation details
1096 
1097 /// @cond OPENVDB_DOCS_INTERNAL
1098 
1099 namespace diagnostics_internal {
1100 
1101 
1102 template<typename TreeType>
1103 class InactiveVoxelValues
1104 {
1105 public:
1106  using LeafArray = tree::LeafManager<TreeType>;
1107  using ValueType = typename TreeType::ValueType;
1108  using SetType = std::set<ValueType>;
1109 
1110  InactiveVoxelValues(LeafArray&, size_t numValues);
1111 
1112  void runParallel();
1113  void runSerial();
1114 
1115  void getInactiveValues(SetType&) const;
1116 
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>&);
1120 
1121 private:
1122  LeafArray& mLeafArray;
1123  SetType mInactiveValues;
1124  size_t mNumValues;
1125 };// InactiveVoxelValues
1126 
1127 template<typename TreeType>
1128 InactiveVoxelValues<TreeType>::InactiveVoxelValues(LeafArray& leafs, size_t numValues)
1129  : mLeafArray(leafs)
1130  , mInactiveValues()
1131  , mNumValues(numValues)
1132 {
1133 }
1134 
1135 template <typename TreeType>
1136 inline
1137 InactiveVoxelValues<TreeType>::InactiveVoxelValues(
1138  const InactiveVoxelValues<TreeType>& rhs, tbb::split)
1139  : mLeafArray(rhs.mLeafArray)
1140  , mInactiveValues()
1141  , mNumValues(rhs.mNumValues)
1142 {
1143 }
1144 
1145 template<typename TreeType>
1146 void
1147 InactiveVoxelValues<TreeType>::runParallel()
1148 {
1149  tbb::parallel_reduce(mLeafArray.getRange(), *this);
1150 }
1151 
1152 
1153 template<typename TreeType>
1154 void
1155 InactiveVoxelValues<TreeType>::runSerial()
1156 {
1157  (*this)(mLeafArray.getRange());
1158 }
1159 
1160 
1161 template<typename TreeType>
1162 inline void
1163 InactiveVoxelValues<TreeType>::operator()(const tbb::blocked_range<size_t>& range)
1164 {
1165  typename TreeType::LeafNodeType::ValueOffCIter iter;
1166 
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());
1170  }
1171 
1172  if (mInactiveValues.size() > mNumValues) {
1173  thread::cancelGroupExecution();
1174  }
1175  }
1176 }
1177 
1178 template<typename TreeType>
1179 inline void
1180 InactiveVoxelValues<TreeType>::join(const InactiveVoxelValues<TreeType>& rhs)
1181 {
1182  mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end());
1183 }
1184 
1185 template<typename TreeType>
1186 inline void
1187 InactiveVoxelValues<TreeType>::getInactiveValues(SetType& values) const
1188 {
1189  values.insert(mInactiveValues.begin(), mInactiveValues.end());
1190 }
1191 
1192 
1193 ////////////////////////////////////////
1194 
1195 
1196 template<typename TreeType>
1197 class InactiveTileValues
1198 {
1199 public:
1201  using ValueType = typename TreeType::ValueType;
1202  using SetType = std::set<ValueType>;
1203 
1204  InactiveTileValues(size_t numValues);
1205 
1206  void runParallel(IterRange&);
1207  void runSerial(IterRange&);
1208 
1209  void getInactiveValues(SetType&) const;
1210 
1211  inline InactiveTileValues(const InactiveTileValues<TreeType>&, tbb::split);
1212  inline void operator()(IterRange&);
1213  inline void join(const InactiveTileValues<TreeType>&);
1214 
1215 private:
1216  SetType mInactiveValues;
1217  size_t mNumValues;
1218 };
1219 
1220 
1221 template<typename TreeType>
1222 InactiveTileValues<TreeType>::InactiveTileValues(size_t numValues)
1223  : mInactiveValues()
1224  , mNumValues(numValues)
1225 {
1226 }
1227 
1228 template <typename TreeType>
1229 inline
1230 InactiveTileValues<TreeType>::InactiveTileValues(
1231  const InactiveTileValues<TreeType>& rhs, tbb::split)
1232  : mInactiveValues()
1233  , mNumValues(rhs.mNumValues)
1234 {
1235 }
1236 
1237 template<typename TreeType>
1238 void
1239 InactiveTileValues<TreeType>::runParallel(IterRange& range)
1240 {
1241  tbb::parallel_reduce(range, *this);
1242 }
1243 
1244 
1245 template<typename TreeType>
1246 void
1247 InactiveTileValues<TreeType>::runSerial(IterRange& range)
1248 {
1249  (*this)(range);
1250 }
1251 
1252 
1253 template<typename TreeType>
1254 inline void
1255 InactiveTileValues<TreeType>::operator()(IterRange& range)
1256 {
1257  for (; range && !thread::isGroupExecutionCancelled(); ++range) {
1258  typename TreeType::ValueOffCIter iter = range.iterator();
1259  for (; iter; ++iter) {
1260  mInactiveValues.insert(iter.getValue());
1261  }
1262 
1263  if (mInactiveValues.size() > mNumValues) {
1264  thread::cancelGroupExecution();
1265  }
1266  }
1267 }
1268 
1269 template<typename TreeType>
1270 inline void
1271 InactiveTileValues<TreeType>::join(const InactiveTileValues<TreeType>& rhs)
1272 {
1273  mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end());
1274 }
1275 
1276 template<typename TreeType>
1277 inline void
1278 InactiveTileValues<TreeType>::getInactiveValues(SetType& values) const
1279 {
1280  values.insert(mInactiveValues.begin(), mInactiveValues.end());
1281 }
1282 
1283 } // namespace diagnostics_internal
1284 
1285 /// @endcond
1286 
1287 ////////////////////////////////////////
1288 
1289 
1290 template<class GridType>
1291 bool
1293  std::vector<typename GridType::ValueType>& values, size_t numValues)
1294 {
1295  using TreeType = typename GridType::TreeType;
1296  using ValueType = typename GridType::ValueType;
1297  using SetType = std::set<ValueType>;
1298 
1299  SetType uniqueValues;
1300 
1301  { // Check inactive voxels
1302  TreeType& tree = const_cast<TreeType&>(grid.tree());
1303  tree::LeafManager<TreeType> leafs(tree);
1304  diagnostics_internal::InactiveVoxelValues<TreeType> voxelOp(leafs, numValues);
1305  voxelOp.runParallel();
1306  voxelOp.getInactiveValues(uniqueValues);
1307  }
1308 
1309  // Check inactive tiles
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);
1314 
1316  tileOp.runParallel(range);
1317 
1318  tileOp.getInactiveValues(uniqueValues);
1319  }
1320 
1321  values.clear();
1322  values.reserve(uniqueValues.size());
1323 
1324  typename SetType::iterator it = uniqueValues.begin();
1325  for ( ; it != uniqueValues.end(); ++it) {
1326  values.push_back(*it);
1327  }
1328 
1329  return values.size() <= numValues;
1330 }
1331 
1332 
1333 ////////////////////////////////////////
1334 
1335 
1336 // Explicit Template Instantiation
1337 
1338 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1339 
1340 #ifdef OPENVDB_INSTANTIATE_DIAGNOSTICS
1342 #endif
1343 
1344 #define _FUNCTION(TreeT) \
1345  std::string checkLevelSet(const Grid<TreeT>&, size_t)
1347 #undef _FUNCTION
1348 
1349 #define _FUNCTION(TreeT) \
1350  std::string checkFogVolume(const Grid<TreeT>&, size_t)
1352 #undef _FUNCTION
1353 
1354 #define _FUNCTION(TreeT) \
1355  bool uniqueInactiveValues(const Grid<TreeT>&, std::vector<TreeT::ValueType>&, size_t)
1357 #undef _FUNCTION
1358 
1359 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
1360 
1361 
1362 } // namespace tools
1363 } // namespace OPENVDB_VERSION_NAME
1364 } // namespace openvdb
1365 
1366 #endif // OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED
bool operator()(const TreeIterT &iter) const
Return true if the tile at the iterator location is infinite.
Definition: Diagnostics.h:174
TreeIterT TileIterT
Definition: Diagnostics.h:382
MaskType::ConstPtr mask() const
Return a boolean mask of all the values (i.e. tiles and/or voxels) that have failed one or more check...
Definition: Diagnostics.h:650
const ElementType maxVal
Definition: Diagnostics.h:415
std::string checkBackground() const
Return a nonempty message if the background value is not zero.
Definition: Diagnostics.h:1014
Checks a value against a maximum.
Definition: Diagnostics.h:379
TreeIterT TileIterT
Definition: Diagnostics.h:338
std::string checkFinite(bool updateMask=false)
Return a nonempty message if any of the values are not finite. i.e. NaN or inf.
Definition: Diagnostics.h:1027
void clear()
Clear the mask and error counter.
Definition: Diagnostics.h:815
bool operator()(const VoxelIterT &iter) const
Return true if the norm of the gradient at a zero-crossing voxel location of the iterator is out of r...
Definition: Diagnostics.h:534
CheckDivergence(const GridT &grid, const ValueType &_min, const ValueType &_max)
Constructor taking a grid and a range to be tested against.
Definition: Diagnostics.h:572
Class that performs various types of checks on narrow-band level sets.
Definition: Diagnostics.h:786
typename VecTraits< typename GridT::ValueType >::ElementType ElementType
Definition: Diagnostics.h:283
bool operator()(const ElementType &v) const
Return true if the value is smaller than min.
Definition: Diagnostics.h:347
std::string checkTransform() const
Return a nonempty message if the grid&#39;s transform does not have uniform scaling.
Definition: Diagnostics.h:838
bool operator()(const ElementType &v) const
Return true if the scalar value is NaN.
Definition: Diagnostics.h:123
std::string checkTiles() const
Return a nonempty message if the grid has no active tile values.
Definition: Diagnostics.h:862
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition: version.h.in:150
bool operator()(const TreeIterT &iter) const
Return true if the tile at the iterator location is NaN or infinite.
Definition: Diagnostics.h:211
const GridType & grid() const
Return a const reference to the grid.
Definition: Diagnostics.h:988
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Checks the divergence against a range.
Definition: Diagnostics.h:559
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
bool operator()(const VoxelIterT &iter) const
Return true if the divergence at a voxel location of the iterator is out of range.
Definition: Diagnostics.h:596
bool operator()(const ValueType &v) const
Return true if the value is smaller than min or larger than max.
Definition: Diagnostics.h:463
typename GridType::ValueType ValueType
Definition: Diagnostics.h:965
CheckMagnitude(const ElementType &a, const ElementType &t=math::Tolerance< ElementType >::value())
Default constructor.
Definition: Diagnostics.h:235
Checks for both NaN and inf values, i.e. any value that is not finite.
Definition: Diagnostics.h:188
This is a special 19-point stencil that supports optimal fifth-order WENO upwinding, second-order central differencing, Laplacian, and zero-crossing test.
Definition: Stencils.h:1365
Diagnose(const GridT &grid)
Definition: Diagnostics.h:624
bool operator()(const VoxelIterT &iter) const
Return true if the tile at the iterator location is infinite.
Definition: Diagnostics.h:261
std::string check(size_t n=6, bool updateMask=false)
Return a nonempty message if an error or issue is detected. Only runs tests with a number lower than ...
Definition: Diagnostics.h:1064
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:506
typename VecTraits< typename GridT::ValueType >::ElementType ElementType
Definition: Diagnostics.h:381
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:264
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:478
std::string checkRange(bool updateMask=false)
Return a nonempty message if the active voxel values are out-of-range.
Definition: Diagnostics.h:880
bool operator()(const TreeIterT &iter) const
Return true if the tile at the iterator location is larger than max.
Definition: Diagnostics.h:402
Checks for infinite values, e.g. 1/0 or -1/0.
Definition: Diagnostics.h:150
bool operator()(const VoxelIterT &iter) const
Return true if the tile at the iterator location is smaller than min.
Definition: Diagnostics.h:361
MaskType::ConstPtr mask() const
Return a boolean mask of all the values (i.e. tiles and/or voxels) that have failed one or more check...
Definition: Diagnostics.h:974
Check that the magnitude of a value, a, is close to a fixed magnitude, b, given a fixed tolerance c...
Definition: Diagnostics.h:226
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:364
bool operator()(const ElementType &v) const
Definition: Diagnostics.h:243
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
typename GridT::ValueType ValueType
Definition: Diagnostics.h:500
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:385
Checks a value against a minimum.
Definition: Diagnostics.h:335
std::enable_if< VecTraits< T >::IsVec, bool >::type operator()(const T &v) const
Return true if any of the vector components are smaller than min.
Definition: Diagnostics.h:352
std::enable_if< VecTraits< T >::IsVec, bool >::type operator()(const T &v) const
Return true if any of the vector components are infinite.
Definition: Diagnostics.h:251
Definition: FiniteDifference.h:167
TreeIterT TileIterT
Definition: Diagnostics.h:503
std::string checkInactiveValues(bool updateMask=false)
Return a nonempty message if the the inactive values do not have a magnitude equal to the background ...
Definition: Diagnostics.h:891
const ValueType minVal2
Definition: Diagnostics.h:486
Tolerance for floating-point comparison.
Definition: Math.h:147
std::string checkClassType() const
Return message if the grid&#39;s class is a level set.
Definition: Diagnostics.h:829
typename VecTraits< typename GridT::ValueType >::ElementType ElementType
Definition: Diagnostics.h:228
const GridType & grid() const
Return a const reference to the grid.
Definition: Diagnostics.h:812
Definition: Exceptions.h:65
Index64 failureCount() const
Return total number of failed checks.
Definition: Diagnostics.h:661
typename GridT::ValueType ValueType
Definition: Diagnostics.h:561
CheckMax(const ElementType &_max)
Constructor taking a maximum to be tested against.
Definition: Diagnostics.h:388
DScheme
Different discrete schemes used in the first derivatives.
Definition: FiniteDifference.h:32
typename VecTraits< typename GridT::ValueType >::ElementType ElementType
Definition: Diagnostics.h:152
bool operator()(const VoxelIterT &iter) const
Return true if the tile at the iterator location is out of range.
Definition: Diagnostics.h:316
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:117
std::string checkLevelSet(const GridType &grid, size_t number=9)
Perform checks on a grid to see if it is a valid symmetric, narrow-band level set.
Definition: Diagnostics.h:950
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:180
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:542
TreeIterT TileIterT
Definition: Diagnostics.h:565
MaskType::Ptr mask()
Return a boolean mask of all the values (i.e. tiles and/or voxels) that have failed one or more check...
Definition: Diagnostics.h:975
bool operator()(const ElementType &v) const
Return true if the value is infinite.
Definition: Diagnostics.h:162
typename VecTraits< ValueType >::ElementType ElementType
Definition: Diagnostics.h:562
std::enable_if< VecTraits< T >::IsVec, bool >::type operator()(const T &v) const
This allows for vector values to be checked component-wise.
Definition: Diagnostics.h:128
bool operator()(const TreeIterT &iter) const
Return true if the tile at the iterator location is NaN.
Definition: Diagnostics.h:135
std::enable_if< VecTraits< T >::IsVec, bool >::type operator()(const T &v) const
Return true if any of the vector components are out of range.
Definition: Diagnostics.h:307
CheckInf()
Default constructor.
Definition: Diagnostics.h:159
std::string checkBackground(Real halfWidth=LEVEL_SET_HALF_WIDTH) const
Return a nonempty message if the background value is larger than or equal to the halfWidth*voxelSize...
Definition: Diagnostics.h:847
Checks the norm of the gradient against a range, i.e., |∇Φ| ∈ [min, max].
Definition: Diagnostics.h:428
bool operator()(const TreeIterT &) const
Return true if zero is outside the range.
Definition: Diagnostics.h:530
AccT acc
Definition: Diagnostics.h:610
const ElementType minVal
Definition: Diagnostics.h:371
double Real
Definition: Types.h:60
typename T::ValueType ElementType
Definition: Types.h:208
bool operator()(const TreeIterT &) const
Return true if zero is outside the range.
Definition: Diagnostics.h:467
CheckEikonal(const GridT &grid, const ValueType &_min, const ValueType &_max)
Constructor taking a grid and a range to be tested against.
Definition: Diagnostics.h:509
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:194
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:341
bool operator()(const VoxelIterT &iter) const
Return true if the tile at the iterator location is infinite.
Definition: Diagnostics.h:177
std::string checkInactiveValues(bool updateMask=false)
Return a nonempty message if any of the inactive values are not zero.
Definition: Diagnostics.h:1036
typename GridType::template ValueConverter< bool >::Type MaskType
Definition: Diagnostics.h:622
TreeIterT TileIterT
Definition: Diagnostics.h:153
Divergence operator defined in index space using various first derivative schemes.
Definition: Operators.h:472
typename VecTraits< typename GridT::ValueType >::ElementType ElementType
Definition: Diagnostics.h:113
bool operator()(const TreeIterT &) const
Return true if zero is outside the range.
Definition: Diagnostics.h:592
CheckNormGrad(const GridT &grid, const ValueType &_min, const ValueType &_max)
Constructor taking a grid and a range to be tested against.
Definition: Diagnostics.h:440
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:764
AccT acc
Definition: Diagnostics.h:485
MaskType::Ptr mask()
Return a boolean mask of all the values (i.e. tiles and/or voxels) that have failed one or more check...
Definition: Diagnostics.h:799
typename GridType::template ValueConverter< bool >::Type MaskType
Definition: Diagnostics.h:790
static std::string checkValueType()
Return a nonempty message if the grid&#39;s value type is a floating point.
Definition: Diagnostics.h:996
MaskType::Ptr mask()
Return a boolean mask of all the values (i.e. tiles and/or voxels) that have failed one or more check...
Definition: Diagnostics.h:651
Index64 valueCount() const
Return the number of values (i.e. background, tiles or voxels) that have failed one or more checks...
Definition: Diagnostics.h:656
bool operator()(const VoxelIterT &iter) const
Return true if the norm of the gradient at a voxel location of the iterator is out of range...
Definition: Diagnostics.h:471
CheckLevelSet(const GridType &grid)
Definition: Diagnostics.h:792
bool operator()(const ElementType &v) const
Return true if the value is smaller than min or larger than max.
Definition: Diagnostics.h:588
Definition: TreeIterator.h:59
const ValueType minVal
Definition: Diagnostics.h:611
static std::string checkValueType()
Return a nonempty message if the grid&#39;s value type is a floating point.
Definition: Diagnostics.h:820
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:232
const ElementType minVal
Definition: Diagnostics.h:327
uint64_t Index64
Definition: Types.h:53
std::string check(const CheckT &check, bool updateMask=false, bool checkVoxels=true, bool checkTiles=true, bool checkBackground=true)
Definition: Diagnostics.h:630
Definition: Exceptions.h:13
CheckMin(const ElementType &_min)
Definition: Diagnostics.h:344
Index64 valueCount() const
Return the number of values (i.e. background, tiles or voxels) that have failed one or more checks...
Definition: Diagnostics.h:980
ValueT value
Definition: GridBuilder.h:1287
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:217
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:436
CheckNormGrad(const CheckNormGrad &other)
Definition: Diagnostics.h:454
Checks a value against a range.
Definition: Diagnostics.h:281
MaskType::ConstPtr mask() const
Return a boolean mask of all the values (i.e. tiles and/or voxels) that have failed one or more check...
Definition: Diagnostics.h:798
std::string checkFogVolume(const GridType &grid, size_t number=6)
Perform checks on a grid to see if it is a valid fog volume.
Definition: Diagnostics.h:1086
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:84
bool operator()(const TreeIterT &iter) const
Return true if the voxel at the iterator location is out of range.
Definition: Diagnostics.h:313
bool operator()(const TreeIterT &iter) const
Return true if the tile at the iterator location is infinite.
Definition: Diagnostics.h:258
Definition: Types.h:417
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:568
typename VecTraits< typename GridT::ValueType >::ElementType ElementType
Definition: Diagnostics.h:337
bool operator()(const ElementType &v) const
Return true if the value is smaller than min or larger than max.
Definition: Diagnostics.h:298
std::string checkClassType() const
Return a nonempty message if the grid&#39;s class is a level set.
Definition: Diagnostics.h:1005
bool operator()(const VoxelIterT &iter) const
Return true if the voxel at the iterator location is larger than max.
Definition: Diagnostics.h:405
TreeIterT TileIterT
Definition: Diagnostics.h:191
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:408
void clear()
Clear the mask and error counter.
Definition: Diagnostics.h:991
Checks the norm of the gradient at zero-crossing voxels against a range.
Definition: Diagnostics.h:498
typename GridType::ValueType ValueType
Definition: Diagnostics.h:789
CheckNan()
Default constructor.
Definition: Diagnostics.h:120
TreeIterT TileIterT
Definition: Diagnostics.h:114
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
std::string checkEikonal(bool updateMask=false, ValueType minV=0.5, ValueType maxV=1.5)
Return a nonempty message if the norm of the gradient of the active voxels is out of the range minV t...
Definition: Diagnostics.h:902
Definition: FiniteDifference.h:35
Definition: Operators.h:230
void clear()
Clear the mask and error counter.
Definition: Diagnostics.h:667
bool operator()(const ValueType &v) const
Return true if the value is smaller than min or larger than max.
Definition: Diagnostics.h:526
std::enable_if< VecTraits< T >::IsVec, bool >::type operator()(const T &v) const
Return true if any of the vector components are NaN or infinite.
Definition: Diagnostics.h:205
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:156
std::string checkRange(bool updateMask=false)
Return a nonempty message if the active voxel values are out-of-range, i.e. not in the range [0...
Definition: Diagnostics.h:1046
std::string check(size_t n=9, bool updateMask=false)
Return a nonempty message if an error or issue is detected. Only runs tests with a number lower than ...
Definition: Diagnostics.h:925
Definition: Types.h:416
std::string checkFinite(bool updateMask=false)
Return a nonempty message if any of the values are not finite. i.e. NaN or inf.
Definition: Diagnostics.h:871
typename VecTraits< typename GridT::ValueType >::ElementType ElementType
Definition: Diagnostics.h:190
CheckEikonal(const CheckEikonal &other)
Definition: Diagnostics.h:520
bool operator()(const TreeIterT &iter) const
Return true if the voxel at the iterator location is smaller than min.
Definition: Diagnostics.h:358
typename GridType::template ValueConverter< bool >::Type MaskType
Definition: Diagnostics.h:966
CheckFogVolume(const GridType &grid)
Definition: Diagnostics.h:968
bool uniqueInactiveValues(const GridType &grid, std::vector< typename GridType::ValueType > &values, size_t numValues)
Threaded method to find unique inactive values.
Definition: Diagnostics.h:1292
std::enable_if< VecTraits< T >::IsVec, bool >::type operator()(const T &v) const
Return true if any of the vector components are larger than max.
Definition: Diagnostics.h:396
bool operator()(const ElementType &v) const
Return true if the value is NOT finite, i.e. it&#39;s NaN or infinite.
Definition: Diagnostics.h:200
TreeIterT TileIterT
Definition: Diagnostics.h:229
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147
CheckFinite()
Default constructor.
Definition: Diagnostics.h:197
Index64 failureCount() const
Return total number of failed checks.
Definition: Diagnostics.h:985
const GridT & grid() const
Return a const reference to the grid.
Definition: Diagnostics.h:664
bool operator()(const VoxelIterT &iter) const
Return true if the tile at the iterator location is NaN or infinite.
Definition: Diagnostics.h:214
Coord Abs(const Coord &xyz)
Definition: Coord.h:514
Checks NaN values.
Definition: Diagnostics.h:111
Type Pow2(Type x)
Return x2.
Definition: Math.h:551
StencilT stencil
Definition: Diagnostics.h:549
Definition: TreeIterator.h:1302
bool operator()(const ElementType &v) const
Return true if the value is larger than max.
Definition: Diagnostics.h:391
A LeafManager manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional au...
typename GridT::ValueType ValueType
Definition: Diagnostics.h:430
Class that performs various types of checks on fog volumes.
Definition: Diagnostics.h:962
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:603
CheckRange(const ElementType &_min, const ElementType &_max)
Definition: Diagnostics.h:290
TreeIterT TileIterT
Definition: Diagnostics.h:284
Performs multithreaded diagnostics of a grid.
Definition: Diagnostics.h:619
BiasedGradientScheme
Biased Gradients are limited to non-centered differences.
Definition: FiniteDifference.h:165
typename GridT::ConstAccessor AccT
Definition: Diagnostics.h:569
TreeIterT TileIterT
Definition: Diagnostics.h:433
const ElementType tolVal
Definition: Diagnostics.h:271
const ValueType minVal
Definition: Diagnostics.h:550
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:319
typename tree::IterTraits< typename TreeIterT::NodeT, typename TreeIterT::ValueIterT >::template NodeConverter< typename GridT::TreeType::LeafNodeType >::Type VoxelIterT
Definition: Diagnostics.h:287
std::enable_if< VecTraits< T >::IsVec, bool >::type operator()(const T &v) const
Return true if any of the vector components are infinite.
Definition: Diagnostics.h:167
bool operator()(const VoxelIterT &iter) const
Return true if the voxel at the iterator location is NaN.
Definition: Diagnostics.h:138
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:422
Index64 valueCount() const
Return the number of values (i.e. background, tiles or voxels) that have failed one or more checks...
Definition: Diagnostics.h:804
std::string str() const
Return a string describing a failed check.
Definition: Diagnostics.h:141
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202
Index64 failureCount() const
Return total number of failed checks.
Definition: Diagnostics.h:809
typename GridT::ConstAccessor AccT
Definition: Diagnostics.h:437