OpenVDB  3.1.0
VolumeAdvect.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2015 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 //
32 //
41 
42 #ifndef OPENVDB_TOOLS_VOLUME_ADVECT_HAS_BEEN_INCLUDED
43 #define OPENVDB_TOOLS_VOLUME_ADVECT_HAS_BEEN_INCLUDED
44 
45 #include <tbb/parallel_for.h>
46 #include <boost/bind.hpp>
47 #include <boost/function.hpp>
48 #include <openvdb/Types.h>
49 #include <openvdb/math/Math.h>
50 #include <openvdb/util/NullInterrupter.h>
51 #include "Interpolation.h"// for Sampler
52 #include "VelocityFields.h" // for VelocityIntegrator
53 #include "Morphology.h"//for dilateVoxels
54 #include "Prune.h"// for prune
55 #include "Statistics.h" // for extrema
56 
57 namespace openvdb {
59 namespace OPENVDB_VERSION_NAME {
60 namespace tools {
61 
62 
63 namespace Scheme {
69 }
70 
96 template<typename VelocityGridT = Vec3fGrid,
97  bool StaggeredVelocity = false,
98  typename InterrupterType = util::NullInterrupter>
100 {
101 public:
102 
110  VolumeAdvection(const VelocityGridT& velGrid, InterrupterType* interrupter = NULL)
111  : mVelGrid(velGrid)
112  , mInterrupter(interrupter)
113  , mIntegrator( Scheme::SEMI )
114  , mLimiter( Scheme::CLAMP )
115  , mGrainSize( 128 )
116  , mSubSteps( 1 )
117  {
118  math::Extrema e = extrema(velGrid.cbeginValueAll(), /*threading*/true);
119  e.add(velGrid.background().length());
120  mMaxVelocity = e.max();
121  }
122 
124  {
125  }
126 
132  int spatialOrder() const { return (mIntegrator == Scheme::MAC ||
133  mIntegrator == Scheme::BFECC) ? 2 : 1; }
134 
140  int temporalOrder() const {
141  switch (mIntegrator) {
142  case Scheme::SEMI: return 1;
143  case Scheme::MID: return 2;
144  case Scheme::RK3: return 3;
145  case Scheme::RK4: return 4;
146  case Scheme::BFECC:return 2;
147  case Scheme::MAC: return 2;
148  }
149  return 0;//should never reach this point
150  }
151 
153  void setIntegrator(Scheme::SemiLagrangian integrator) { mIntegrator = integrator; }
154 
156  Scheme::SemiLagrangian getIntegrator() const { return mIntegrator; }
157 
159  void setLimiter(Scheme::Limiter limiter) { mLimiter = limiter; }
160 
162  Scheme::Limiter getLimiter() const { return mLimiter; }
163 
166  bool isLimiterOn() const { return this->spatialOrder()>1 &&
167  mLimiter != Scheme::NO_LIMITER; }
168 
171  size_t getGrainSize() const { return mGrainSize; }
172 
177  void setGrainSize(size_t grainsize) { mGrainSize = grainsize; }
178 
181  int getSubSteps() const { return mSubSteps; }
182 
188  void setSubSteps(int substeps) { mSubSteps = math::Max(1, substeps); }
189 
192  double getMaxVelocity() const { return mMaxVelocity; }
193 
204  template<typename VolumeGridT>
205  int getMaxDistance(const VolumeGridT& inGrid, double dt) const
206  {
207  if (!inGrid.hasUniformVoxels()) {
208  OPENVDB_THROW(RuntimeError, "Volume grid does not have uniform voxels!");
209  }
210  const double d = mMaxVelocity*math::Abs(dt)/inGrid.voxelSize()[0];
211  return static_cast<int>( math::RoundUp(d) );
212  }
213 
232  template<typename VolumeGridT,
233  typename VolumeSamplerT>//only C++11 allows for a default argument
234  typename VolumeGridT::Ptr advect(const VolumeGridT& inGrid, double timeStep)
235  {
236  typename VolumeGridT::Ptr outGrid = inGrid.deepCopy();
237  const double dt = timeStep/mSubSteps;
238  const int n = this->getMaxDistance(inGrid, dt);
239  dilateVoxels( outGrid->tree(), n );
240  this->template cook<VolumeGridT, VolumeSamplerT>(*outGrid, inGrid, dt);
241 
242  for (int step = 1; step < mSubSteps; ++step) {
243  typename VolumeGridT::Ptr tmpGrid = outGrid->deepCopy();
244  dilateVoxels( tmpGrid->tree(), n );
245  this->template cook<VolumeGridT, VolumeSamplerT>(*tmpGrid, *outGrid, dt);
246  outGrid.swap( tmpGrid );
247  }
248 
249  return outGrid;
250  }
251 
279  template<typename VolumeGridT,
280  typename MaskGridT,
281  typename VolumeSamplerT>//only C++11 allows for a default argument
282  typename VolumeGridT::Ptr advect(const VolumeGridT& inGrid, const MaskGridT& mask, double timeStep)
283  {
284  if (inGrid.transform() != mask.transform()) {
285  OPENVDB_THROW(RuntimeError, "Volume grid and mask grid are misaligned! Consider "
286  "resampling either of the two grids into the index space of the other.");
287  }
288  typename VolumeGridT::Ptr outGrid = inGrid.deepCopy();
289  const double dt = timeStep/mSubSteps;
290  const int n = this->getMaxDistance(inGrid, dt);
291  dilateVoxels( outGrid->tree(), n );
292  outGrid->topologyIntersection( mask );
293  pruneInactive( outGrid->tree(), mGrainSize>0, mGrainSize );
294  this->template cook<VolumeGridT, VolumeSamplerT>(*outGrid, inGrid, dt);
295  outGrid->topologyUnion( inGrid );
296 
297  for (int step = 1; step < mSubSteps; ++step) {
298  typename VolumeGridT::Ptr tmpGrid = outGrid->deepCopy();
299  dilateVoxels( tmpGrid->tree(), n );
300  tmpGrid->topologyIntersection( mask );
301  pruneInactive( tmpGrid->tree(), mGrainSize>0, mGrainSize );
302  this->template cook<VolumeGridT, VolumeSamplerT>(*tmpGrid, *outGrid, dt);
303  tmpGrid->topologyUnion( inGrid );
304  outGrid.swap( tmpGrid );
305  }
306  return outGrid;
307  }
308 
309 private:
310  // disallow copy construction and copy by assignment!
311  VolumeAdvection(const VolumeAdvection&);// not implemented
312  VolumeAdvection& operator=(const VolumeAdvection&);// not implemented
313 
314  void start(const char* str) const
315  {
316  if (mInterrupter) mInterrupter->start(str);
317  }
318  void stop() const
319  {
320  if (mInterrupter) mInterrupter->end();
321  }
322  bool interrupt() const
323  {
324  if (mInterrupter && util::wasInterrupted(mInterrupter)) {
325  tbb::task::self().cancel_group_execution();
326  return true;
327  }
328  return false;
329  }
330 
331  template<typename VolumeGridT, typename VolumeSamplerT>
332  void cook(VolumeGridT& outGrid, const VolumeGridT& inGrid, double dt)
333  {
334  outGrid.tree().voxelizeActiveTiles();
335  switch (mIntegrator) {
336  case Scheme::SEMI: {
337  Advect<VolumeGridT, 1, VolumeSamplerT> adv(inGrid, *this);
338  adv.cook(outGrid, dt);
339  break;
340  }
341  case Scheme::MID: {
342  Advect<VolumeGridT, 2, VolumeSamplerT> adv(inGrid, *this);
343  adv.cook(outGrid, dt);
344  break;
345  }
346  case Scheme::RK3: {
347  Advect<VolumeGridT, 3, VolumeSamplerT> adv(inGrid, *this);
348  adv.cook(outGrid, dt);
349  break;
350  }
351  case Scheme::RK4: {
352  Advect<VolumeGridT, 4, VolumeSamplerT> adv(inGrid, *this);
353  adv.cook(outGrid, dt);
354  break;
355  }
356  case Scheme::BFECC: {
357  Advect<VolumeGridT, 1, VolumeSamplerT> adv(inGrid, *this);
358  adv.cook(outGrid, dt);
359  break;
360  }
361  case Scheme::MAC: {
362  Advect<VolumeGridT, 1, VolumeSamplerT> adv(inGrid, *this);
363  adv.cook(outGrid, dt);
364  break;
365  }
366  default:
367  OPENVDB_THROW(ValueError, "Spatial difference scheme not supported!");
368  }
369  pruneInactive(outGrid.tree(), mGrainSize>0, mGrainSize);
370  }
371 
372  // Private class that implements the multi-threaded advection
373  template<typename VolumeGridT, size_t OrderRK, typename SamplerT> struct Advect;
374 
375  // Private member data of VolumeAdvection
376  const VelocityGridT& mVelGrid;
377  double mMaxVelocity;
378  InterrupterType* mInterrupter;
379  Scheme::SemiLagrangian mIntegrator;
380  Scheme::Limiter mLimiter;
381  size_t mGrainSize;
382  int mSubSteps;
383 };//end of VolumeAdvection class
384 
385 // Private class that implements the multi-threaded advection
386 template<typename VelocityGridT, bool StaggeredVelocity, typename InterrupterType>
387 template<typename VolumeGridT, size_t OrderRK, typename SamplerT>
388 struct VolumeAdvection<VelocityGridT, StaggeredVelocity, InterrupterType>::Advect
389 {
390  typedef typename VolumeGridT::TreeType TreeT;
391  typedef typename VolumeGridT::ConstAccessor AccT;
392  typedef typename TreeT::ValueType ValueT;
393  typedef typename tree::LeafManager<TreeT> LeafManagerT;
394  typedef typename LeafManagerT::LeafNodeType LeafNodeT;
395  typedef typename LeafManagerT::LeafRange LeafRangeT;
396  typedef VelocityIntegrator<VelocityGridT, StaggeredVelocity> VelocityIntegratorT;
397  typedef typename VelocityIntegratorT::ElementType RealT;
398  typedef typename TreeT::LeafNodeType::ValueOnIter VoxelIterT;
399 
400 
401  Advect(const VolumeGridT& inGrid, const VolumeAdvection& parent)
402  : mTask(0)
403  , mInGrid(&inGrid)
404  , mVelocityInt(parent.mVelGrid)
405  , mParent(&parent)
406  {
407  }
408  inline void cook(const LeafRangeT& range)
409  {
410  if (mParent->mGrainSize > 0) {
411  tbb::parallel_for(range, *this);
412  } else {
413  (*this)(range);
414  }
415  }
416  void operator()(const LeafRangeT& range) const
417  {
418  assert(mTask);
419  mTask(const_cast<Advect*>(this), range);
420  }
421  void cook(VolumeGridT& outGrid, double time_step)
422  {
423  mParent->start("Advecting volume");
424  LeafManagerT manager(outGrid.tree(), mParent->spatialOrder()==2 ? 1 : 0);
425  const LeafRangeT range = manager.leafRange(mParent->mGrainSize);
426 
427  const RealT dt = static_cast<RealT>(-time_step);//method of characteristics backtracks
428  if (mParent->mIntegrator == Scheme::MAC) {
429  mTask = boost::bind(&Advect::rk, _1, _2, dt, 0, *mInGrid);//out[0]=forward
430  this->cook(range);
431  mTask = boost::bind(&Advect::rk, _1, _2,-dt, 1, outGrid);//out[1]=backward
432  this->cook(range);
433  mTask = boost::bind(&Advect::mac, _1, _2);//out[0] = out[0] + (in[0] - out[1])/2
434  this->cook(range);
435  } else if (mParent->mIntegrator == Scheme::BFECC) {
436  mTask = boost::bind(&Advect::rk, _1, _2, dt, 0, *mInGrid);//out[0]=forward
437  this->cook(range);
438  mTask = boost::bind(&Advect::rk, _1, _2,-dt, 1, outGrid);//out[1]=backward
439  this->cook(range);
440  mTask = boost::bind(&Advect::bfecc, _1, _2);//out[0] = (3*in[0] - out[1])/2
441  this->cook(range);
442  mTask = boost::bind(&Advect::rk, _1, _2, dt, 1, outGrid);//out[1]=forward
443  this->cook(range);
444  manager.swapLeafBuffer(1);// out[0] = out[1]
445  } else {// SEMI, MID, RK3 and RK4
446  mTask = boost::bind(&Advect::rk, _1, _2, dt, 0, *mInGrid);//forward
447  this->cook(range);
448  }
449 
450  if (mParent->spatialOrder()==2) manager.removeAuxBuffers();
451 
452  mTask = boost::bind(&Advect::limiter, _1, _2, dt);// out[0] = limiter( out[0] )
453  this->cook(range);
454 
455  mParent->stop();
456  }
457  // Last step of the MacCormack scheme: out[0] = out[0] + (in[0] - out[1])/2
458  void mac(const LeafRangeT& range) const
459  {
460  if (mParent->interrupt()) return;
461  assert( mParent->mIntegrator == Scheme::MAC );
462  AccT acc = mInGrid->getAccessor();
463  for (typename LeafRangeT::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
464  ValueT* out0 = leafIter.buffer( 0 ).data();// forward
465  const ValueT* out1 = leafIter.buffer( 1 ).data();// backward
466  const LeafNodeT* leaf = acc.probeConstLeaf( leafIter->origin() );
467  if (leaf !=NULL) {
468  const ValueT* in0 = leaf->buffer().data();
469  for (VoxelIterT voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
470  const Index i = voxelIter.pos();
471  out0[i] += RealT(0.5) * ( in0[i] - out1[i] );
472  }
473  } else {
474  for (VoxelIterT voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
475  const Index i = voxelIter.pos();
476  out0[i] += RealT(0.5) * ( acc.getValue(voxelIter.getCoord()) - out1[i] );
477  }//loop over active voxels
478  }
479  }//loop over leaf nodes
480  }
481  // Intermediate step in the BFECC scheme: out[0] = (3*in[0] - out[1])/2
482  void bfecc(const LeafRangeT& range) const
483  {
484  if (mParent->interrupt()) return;
485  assert( mParent->mIntegrator == Scheme::BFECC );
486  AccT acc = mInGrid->getAccessor();
487  for (typename LeafRangeT::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
488  ValueT* out0 = leafIter.buffer( 0 ).data();// forward
489  const ValueT* out1 = leafIter.buffer( 1 ).data();// backward
490  const LeafNodeT* leaf = acc.probeConstLeaf(leafIter->origin());
491  if (leaf !=NULL) {
492  const ValueT* in0 = leaf->buffer().data();
493  for (VoxelIterT voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
494  const Index i = voxelIter.pos();
495  out0[i] = RealT(0.5)*( RealT(3)*in0[i] - out1[i] );
496  }//loop over active voxels
497  } else {
498  for (VoxelIterT voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
499  const Index i = voxelIter.pos();
500  out0[i] = RealT(0.5)*( RealT(3)*acc.getValue(voxelIter.getCoord()) - out1[i] );
501  }//loop over active voxels
502  }
503  }//loop over leaf nodes
504  }
505  // Semi-Lagrangian integration with Runge-Kutta of various orders (1->4)
506  void rk(const LeafRangeT& range, RealT dt, size_t n, const VolumeGridT& grid) const
507  {
508  if (mParent->interrupt()) return;
509  const math::Transform& xform = mInGrid->transform();
510  AccT acc = grid.getAccessor();
511  for (typename LeafRangeT::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
512  ValueT* phi = leafIter.buffer( n ).data();
513  for (VoxelIterT voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
514  ValueT& value = phi[voxelIter.pos()];
515  Vec3d wPos = xform.indexToWorld(voxelIter.getCoord());
516  mVelocityInt.template rungeKutta<OrderRK, Vec3d>(dt, wPos);
517  value = SamplerT::sample(acc, xform.worldToIndex(wPos));
518  }//loop over active voxels
519  }//loop over leaf nodes
520  }
521  void limiter(const LeafRangeT& range, RealT dt) const
522  {
523  if (mParent->interrupt()) return;
524  const bool doLimiter = mParent->isLimiterOn();
525  const bool doClamp = mParent->mLimiter == Scheme::CLAMP;
526  ValueT data[2][2][2], vMin, vMax;
527  const math::Transform& xform = mInGrid->transform();
528  AccT acc = mInGrid->getAccessor();
529  const ValueT backg = mInGrid->background();
530  for (typename LeafRangeT::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
531  ValueT* phi = leafIter.buffer( 0 ).data();
532  for (VoxelIterT voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
533  ValueT& value = phi[voxelIter.pos()];
534 
535  if ( doLimiter ) {
536  assert(OrderRK == 1);
537  Vec3d wPos = xform.indexToWorld(voxelIter.getCoord());
538  mVelocityInt.template rungeKutta<1, Vec3d>(dt, wPos);// Explicit Euler
539  Vec3d iPos = xform.worldToIndex(wPos);
540  Coord ijk = Coord::floor( iPos );
541  BoxSampler::getValues(data, acc, ijk);
542  BoxSampler::extrema(data, vMin, vMax);
543  if ( doClamp ) {
544  value = math::Clamp( value, vMin, vMax);
545  } else if (value < vMin || value > vMax ) {
546  iPos -= Vec3R(ijk[0], ijk[1], ijk[2]);//unit coordinates
547  value = BoxSampler::trilinearInterpolation( data, iPos );
548  }
549  }
550 
551  if (math::isApproxEqual(value, backg, math::Delta<ValueT>::value())) {
552  value = backg;
553  leafIter->setValueOff( voxelIter.pos() );
554  }
555  }//loop over active voxels
556  }//loop over leaf nodes
557  }
558  // Public member data of the private Advect class
559  typename boost::function<void (Advect*, const LeafRangeT&)> mTask;
560  const VolumeGridT* mInGrid;
561  const VelocityIntegratorT mVelocityInt;// lightweight!
562  const VolumeAdvection* mParent;
563 };// end of private member class Advect
564 
565 } // namespace tools
566 } // namespace OPENVDB_VERSION_NAME
567 } // namespace openvdb
568 
569 #endif // OPENVDB_TOOLS_VOLUME_ADVECT_HAS_BEEN_INCLUDED
570 
571 // Copyright (c) 2012-2015 DreamWorks Animation LLC
572 // All rights reserved. This software is distributed under the
573 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
SemiLagrangian
Numerical advections schemes.
Definition: VolumeAdvect.h:65
Index32 Index
Definition: Types.h:58
size_t getGrainSize() const
Definition: VolumeAdvect.h:171
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
Definition: VolumeAdvect.h:68
Scheme::SemiLagrangian getIntegrator() const
Return the integrator (see details in the table above)
Definition: VolumeAdvect.h:156
This class computes the minimum and maximum values of a population of floating-point values...
Definition: Stats.h:55
void setSubSteps(int substeps)
Set the number of sub-steps per integration.
Definition: VolumeAdvect.h:188
void setGrainSize(size_t grainsize)
Set the grain-size used for multi-threading.
Definition: VolumeAdvect.h:177
Definition: VolumeAdvect.h:65
void setIntegrator(Scheme::SemiLagrangian integrator)
Set the integrator (see details in the table above)
Definition: VolumeAdvect.h:153
Defines two simple wrapper classes for advection velocity fields as well as VelocitySampler and Veloc...
int32_t Abs(int32_t i)
Return the absolute value of the given quantity.
Definition: Math.h:293
float RoundUp(float x)
Return x rounded up to the nearest integer.
Definition: Math.h:735
math::Vec3< Real > Vec3R
Definition: Types.h:76
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
double getMaxVelocity() const
Return the maximum magnitude of the velocity in the advection velocity field defined during construct...
Definition: VolumeAdvect.h:192
Functions to efficiently compute histograms, extremas (min/max) and statistics (mean, variance, etc.) of grid values.
Scheme::Limiter getLimiter() const
Retrun the limiter (see details above)
Definition: VolumeAdvect.h:162
Definition: VolumeAdvect.h:65
Performs advections of an arbitrary type of volume in a static velocity field. The advections is perf...
Definition: VolumeAdvect.h:99
OPENVDB_STATIC_SPECIALIZATION void dilateVoxels(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE)
Topologically dilate all leaf-level active voxels in a tree using one of three nearest neighbor conne...
Definition: Morphology.h:778
bool isApproxEqual(const Type &a, const Type &b)
Return true if a is equal to b to within the default floating-point comparison tolerance.
Definition: Math.h:370
Defined various multi-threaded utility functions for trees.
Definition: VolumeAdvect.h:68
Limiter
Flux-limiters employed to stabalize the second-order advection schemes MacCormack and BFECC...
Definition: VolumeAdvect.h:68
Definition: VolumeAdvect.h:65
bool isLimiterOn() const
Return true if a limiter will be applied based on the current settings.
Definition: VolumeAdvect.h:166
Definition: VolumeAdvect.h:65
#define OPENVDB_VERSION_NAME
Definition: version.h:43
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
int spatialOrder() const
Return the spatial order of accuracy of the advection scheme.
Definition: VolumeAdvect.h:132
void setLimiter(Scheme::Limiter limiter)
Set the limiter (see details above)
Definition: VolumeAdvect.h:159
int getSubSteps() const
Definition: VolumeAdvect.h:181
Vec3SGrid Vec3fGrid
Definition: openvdb.h:77
Definition: Exceptions.h:86
Implementation of morphological dilation and erosion.
VolumeGridT::Ptr advect(const VolumeGridT &inGrid, double timeStep)
Definition: VolumeAdvect.h:234
Definition: Exceptions.h:39
virtual ~VolumeAdvection()
Definition: VolumeAdvect.h:123
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values.
Definition: Math.h:561
Vec3< double > Vec3d
Definition: Vec3.h:643
void add(double val)
Add a single sample.
Definition: Stats.h:69
int temporalOrder() const
Return the temporal order of accuracy of the advection scheme.
Definition: VolumeAdvect.h:140
Definition: VolumeAdvect.h:68
Definition: VolumeAdvect.h:65
void pruneInactive(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with background tiles any nodes whose values are a...
Definition: Prune.h:367
VolumeAdvection(const VelocityGridT &velGrid, InterrupterType *interrupter=NULL)
Constructor.
Definition: VolumeAdvect.h:110
math::Extrema extrema(const IterT &iter, bool threaded=true)
Iterate over a scalar grid and compute extrema (min/max) of the values of the voxels that are visited...
Definition: Statistics.h:379
Type Clamp(Type x, Type min, Type max)
Return x clamped to [min, max].
Definition: Math.h:246
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
int getMaxDistance(const VolumeGridT &inGrid, double dt) const
Definition: VolumeAdvect.h:205
Definition: VolumeAdvect.h:65
VolumeGridT::Ptr advect(const VolumeGridT &inGrid, const MaskGridT &mask, double timeStep)
Definition: VolumeAdvect.h:282
double max() const
Return the maximum value.
Definition: Stats.h:91