@@ -490,16 +490,23 @@ using namespace openvdb;
490490
491491// 0 Neumann pressure, meaning Dirichlet velocity on its normal face.
492492// 1 interior pressure dofs.
493- // 4 Dirichlet pressure. In this setup it's on the right. It means that it's not a solid collider or an open channel.
493+ // 4 Dirichlet pressure, meaning it's not a solid collider, i.e. an open channel.
494494class SmokeSolver {
495495public:
496- SmokeSolver (float const voxelSize) { init (voxelSize); }
497-
498- void init ( float const vs )
496+ SmokeSolver (float const voxelSize, math::Coord corner) :
497+ mVoxelSize (voxelSize),
498+ mXform (math::Transform::createLinearTransform(voxelSize) )
499499 {
500- mXform = math::Transform::createLinearTransform (mVoxelSize );
500+ assert (corner[0 ] > 1 && corner[1 ] > 1 && corner[2 ] > 1 );
501+
502+ init (corner);
503+ }
504+
505+ void init (math::Coord corner) {
506+ float xDim = static_cast <float >(corner[0 ]);
507+ float yDim = static_cast <float >(corner[1 ]);
508+ float zDim = static_cast <float >(corner[2 ]);
501509
502- int xDim = 3 ; int yDim = 15 ; int zDim = 17 ;
503510 mMinBBox = Vec3s (0 .f , 0 .f , 0 .f );
504511 mMaxBBox = Vec3s (xDim * mVoxelSize , yDim * mVoxelSize , zDim * mVoxelSize );
505512 mMinIdx = mXform ->worldToIndexNodeCentered (mMinBBox );
@@ -512,73 +519,68 @@ class SmokeSolver {
512519 initDivGrids ();
513520 }
514521
515- // In the Flip Example class, this is VelocityBCCorrectionOp
516- void applyDirichletVelocity () {
517- auto flagsAcc = mFlags ->getAccessor ();
518- auto vAcc = mVCurr ->getAccessor ();
519- for (auto iter = mFlags ->beginValueOn (); iter; ++iter) {
520- math::Coord ijk = iter.getCoord ();
521- math::Coord im1jk = ijk.offsetBy (-1 , 0 , 0 );
522- math::Coord ijm1k = ijk.offsetBy (0 , -1 , 0 );
523- math::Coord ijkm1 = ijk.offsetBy (0 , 0 , -1 );
524-
525- int flag = flagsAcc.getValue (ijk);
526- int flagim1jk = flagsAcc.getValue (im1jk);
527- int flagijm1k = flagsAcc.getValue (ijm1k);
528- int flagijkm1 = flagsAcc.getValue (ijkm1);
529- // I'm an interior pressure and I need to check if any of my neighbor is Neumann
530- if (flag == 1 )
531- {
532- if (flagim1jk == 0 )
533- {
534- auto cv = vAcc.getValue (ijk);
535- Vec3f newVel (0 , cv[1 ], cv[2 ]);
536- vAcc.setValue (ijk, newVel);
537- }
522+ void pressureProjection () {
523+ using TreeType = FloatTree;
524+ using ValueType = TreeType::ValueType;
525+ using PCT = openvdb::math::pcg::JacobiPreconditioner<openvdb::tools::poisson::LaplacianMatrix>;
538526
539- if (flagijm1k == 0 ) {
540- auto cv = vAcc.getValue (ijk);
541- Vec3f newVel (cv[0 ], 0 , cv[2 ]);
542- vAcc.setValue (ijk, newVel);
527+ BoundaryOp bop (mFlags , mVCurr , mVoxelSize );
528+ util::NullInterrupter interrupter;
543529
544- }
530+ const double epsilon = math::Delta<ValueType>:: value ();
545531
546- if (flagijkm1 == 0 ) {
547- auto cv = vAcc. getValue (ijk) ;
548- Vec3f newVel (cv[ 0 ], cv[ 1 ], 0 ) ;
549- vAcc. setValue (ijk, newVel);
550- }
532+ mState = math::pcg::terminationDefaults<ValueType>();
533+ mState . iterations = 100 ;
534+ mState . relativeError = mState . absoluteError = epsilon ;
535+ FloatTree::Ptr fluidPressure = tools::poisson::solveWithBoundaryConditionsAndPreconditioner<PCT>(
536+ mDivBefore -> tree (), mInteriorPressure -> tree (), bop, mState , interrupter, /* staggered= */ true );
551537
552- } else if (flag == 0 ) { // I'm a Neumann pressure and I need if any of my Neighbor is interior
553- if (flagim1jk == 1 )
554- {
555- auto cv = vAcc.getValue (ijk);
556- Vec3f newVel (0 , cv[1 ], cv[2 ]);
557- vAcc.setValue (ijk, newVel);
558- }
538+ FloatGrid::Ptr fluidPressureGrid = FloatGrid::create (fluidPressure);
539+ fluidPressureGrid->setTransform (mXform );
540+ mPressure = fluidPressureGrid->copy ();
541+ mPressure ->setName (" pressure" );
542+ }
559543
560- if (flagijm1k == 1 ) {
561- auto cv = vAcc.getValue (ijk);
562- Vec3f newVel (cv[0 ], 0 , cv[2 ]);
563- vAcc.setValue (ijk, newVel);
564- }
544+ void subtractPressureGradFromVel () {
545+ auto vCurrAcc = mVCurr ->getAccessor ();
546+ auto pressureAcc = mPressure ->getConstAccessor ();
547+ auto flagsAcc = mFlags ->getConstAccessor ();
548+ for (auto iter = mVCurr ->beginValueOn (); iter; ++iter) {
549+ math::Coord ijk = iter.getCoord ();
550+ math::Coord im1jk = ijk.offsetBy (-1 , 0 , 0 );
551+ math::Coord ijm1k = ijk.offsetBy (0 , -1 , 0 );
552+ math::Coord ijkm1 = ijk.offsetBy (0 , 0 , -1 );
565553
566- if (flagijkm1 == 1 ) {
567- auto cv = vAcc.getValue (ijk);
568- Vec3f newVel (cv[0 ], cv[1 ], 0 );
569- vAcc.setValue (ijk, newVel);
554+ // Only updates velocity if it is a face of fluid cell
555+ bool neighborsAFluidCell = flagsAcc.getValue (ijk) == 1 || flagsAcc.getValue (im1jk) == 1 || flagsAcc.getValue (ijm1k) == 1 || flagsAcc.getValue (ijkm1) == 1 ;
556+ if (neighborsAFluidCell) {
557+ Vec3s gradijk;
558+ gradijk[0 ] = pressureAcc.getValue (ijk) - pressureAcc.getValue (ijk.offsetBy (-1 , 0 , 0 ));
559+ gradijk[1 ] = pressureAcc.getValue (ijk) - pressureAcc.getValue (ijk.offsetBy (0 , -1 , 0 ));
560+ gradijk[2 ] = pressureAcc.getValue (ijk) - pressureAcc.getValue (ijk.offsetBy (0 , 0 , -1 ));
561+ auto val = vCurrAcc.getValue (ijk) - gradijk * mVoxelSize ;
562+ vCurrAcc.setValue (ijk, val);
570563 }
571- }
572564 }
565+
566+ applyDirichletVelocity (); // VERY IMPORTANT
567+ }
568+
569+ float computeDivergence (FloatGrid::Ptr& divGrid, const Vec3SGrid::Ptr vecGrid) {
570+ divGrid = tools::divergence (*vecGrid);
571+ divGrid->tree ().topologyIntersection (mInteriorPressure ->tree ());
572+ float div = computeLInfinity (*divGrid);
573+ return div;
573574 }
574575
576+ private:
575577 struct BoundaryOp {
576578 BoundaryOp (Int32Grid::ConstPtr flags,
577- Vec3SGrid::ConstPtr dirichletVelocity,
578- float const voxelSize) :
579- flags (flags),
580- dirichletVelocity (dirichletVelocity),
581- voxelSize (voxelSize) {}
579+ Vec3SGrid::ConstPtr dirichletVelocity,
580+ float const voxelSize) :
581+ flags (flags),
582+ dirichletVelocity (dirichletVelocity),
583+ voxelSize (voxelSize) {}
582584
583585 void operator ()(const openvdb::Coord& ijk,
584586 const openvdb::Coord& neighbor,
@@ -593,7 +595,6 @@ class SmokeSolver {
593595
594596 if (isNeumannPressure) {
595597 double delta = 0.0 ;
596- // Neumann pressure from bbox
597598 if (neighbor.x () + 1 == ijk.x () /* left x-face */ ) {
598599 delta += vNgbr[0 ];
599600 }
@@ -619,7 +620,7 @@ class SmokeSolver {
619620 } else if (isDirichletPressure) {
620621 diagonal -= 1.0 ;
621622 source -= dirichletBC;
622- #if 0 // supposedly the same as the two lines above
623+ #if 0 // TODO: double check this logic
623624 // Dirichlet pressure
624625 if (neighbor.x() + 1 == ijk.x() /* left x-face */) {
625626 diagonal -= 1.0;
@@ -654,67 +655,72 @@ class SmokeSolver {
654655 float voxelSize;
655656 };
656657
657- void subtractPressureGradFromVel () {
658- auto vCurrAcc = mVCurr ->getAccessor ();
659- auto pressureAcc = mPressure ->getConstAccessor ();
660- auto flagsAcc = mFlags ->getConstAccessor ();
661- for (auto iter = mVCurr ->beginValueOn (); iter; ++iter) {
662- math::Coord ijk = iter.getCoord ();
663- math::Coord im1jk = ijk.offsetBy (-1 , 0 , 0 );
664- math::Coord ijm1k = ijk.offsetBy (0 , -1 , 0 );
665- math::Coord ijkm1 = ijk.offsetBy (0 , 0 , -1 );
666-
667- // Only updates velocity if it is a face of fluid cell
668- if (flagsAcc.getValue (ijk) == 1 ||
669- flagsAcc.getValue (im1jk) == 1 ||
670- flagsAcc.getValue (ijm1k) == 1 ||
671- flagsAcc.getValue (ijkm1) == 1 ) {
672- Vec3s gradijk;
673- gradijk[0 ] = pressureAcc.getValue (ijk) - pressureAcc.getValue (ijk.offsetBy (-1 , 0 , 0 ));
674- gradijk[1 ] = pressureAcc.getValue (ijk) - pressureAcc.getValue (ijk.offsetBy (0 , -1 , 0 ));
675- gradijk[2 ] = pressureAcc.getValue (ijk) - pressureAcc.getValue (ijk.offsetBy (0 , 0 , -1 ));
676- auto val = vCurrAcc.getValue (ijk) - gradijk * mVoxelSize ;
677- vCurrAcc.setValue (ijk, val);
678- }
679- }
658+ // In the Flip Example class, this is VelocityBCCorrectionOp
659+ void applyDirichletVelocity () {
660+ auto flagsAcc = mFlags ->getAccessor ();
661+ auto vAcc = mVCurr ->getAccessor ();
662+ for (auto iter = mFlags ->beginValueOn (); iter; ++iter) {
663+ math::Coord ijk = iter.getCoord ();
664+ math::Coord im1jk = ijk.offsetBy (-1 , 0 , 0 );
665+ math::Coord ijm1k = ijk.offsetBy (0 , -1 , 0 );
666+ math::Coord ijkm1 = ijk.offsetBy (0 , 0 , -1 );
680667
681- applyDirichletVelocity (); // VERY IMPORTANT
682- }
668+ int flag = flagsAcc.getValue (ijk);
669+ int flagim1jk = flagsAcc.getValue (im1jk);
670+ int flagijm1k = flagsAcc.getValue (ijm1k);
671+ int flagijkm1 = flagsAcc.getValue (ijkm1);
672+
673+ if (flag == 1 ) { // I'm an interior pressure and I need to check if any of my neighbor is Neumann
674+ if (flagim1jk == 0 ) {
675+ auto cv = vAcc.getValue (ijk);
676+ Vec3f newVel (0 , cv[1 ], cv[2 ]);
677+ vAcc.setValue (ijk, newVel);
678+ }
683679
684- void pressureProjection () {
685- using TreeType = FloatTree;
686- using ValueType = TreeType::ValueType;
687- using PCT = openvdb::math::pcg::JacobiPreconditioner<openvdb::tools::poisson::LaplacianMatrix>;
680+ if (flagijm1k == 0 ) {
681+ auto cv = vAcc.getValue (ijk);
682+ Vec3f newVel (cv[0 ], 0 , cv[2 ]);
683+ vAcc.setValue (ijk, newVel);
684+ }
688685
689- BoundaryOp bop (mFlags , mVCurr , mVoxelSize );
690- util::NullInterrupter interrupter;
686+ if (flagijkm1 == 0 ) {
687+ auto cv = vAcc.getValue (ijk);
688+ Vec3f newVel (cv[0 ], cv[1 ], 0 );
689+ vAcc.setValue (ijk, newVel);
690+ }
691691
692- const double epsilon = math::Delta<ValueType>::value ();
692+ } else if (flag == 0 ) { // I'm a Neumann pressure and I need if any of my Neighbor is interior
693+ if (flagim1jk == 1 ) {
694+ auto cv = vAcc.getValue (ijk);
695+ Vec3f newVel (0 , cv[1 ], cv[2 ]);
696+ vAcc.setValue (ijk, newVel);
697+ }
693698
694- mState = math::pcg::terminationDefaults<ValueType>();
695- mState . iterations = 100 ;
696- mState . relativeError = mState . absoluteError = epsilon ;
697- FloatTree::Ptr fluidPressure = tools::poisson::solveWithBoundaryConditionsAndPreconditioner<PCT>(
698- mDivBefore -> tree (), mInteriorPressure -> tree (), bop, mState , interrupter, /* staggered= */ true );
699+ if (flagijm1k == 1 ) {
700+ auto cv = vAcc. getValue (ijk) ;
701+ Vec3f newVel (cv[ 0 ], 0 , cv[ 2 ]) ;
702+ vAcc. setValue (ijk, newVel);
703+ }
699704
700- FloatGrid::Ptr fluidPressureGrid = FloatGrid::create (fluidPressure);
701- fluidPressureGrid->setTransform (mXform );
702- mPressure = fluidPressureGrid->copy ();
703- mPressure ->setName (" pressure" );
705+ if (flagijkm1 == 1 ) {
706+ auto cv = vAcc.getValue (ijk);
707+ Vec3f newVel (cv[0 ], cv[1 ], 0 );
708+ vAcc.setValue (ijk, newVel);
709+ }
710+ }
711+ }
704712 }
705713
706714 template <class GridType >
707715 typename GridType::Ptr
708- initGridBgAndName (typename GridType::ValueType background, std::string name)
709- {
716+ initGridBgAndName (typename GridType::ValueType background, std::string name) {
710717 typename GridType::Ptr grid = GridType::create (background);
711718 grid->setTransform (mXform );
712719 grid->setName (name);
713720 return grid;
714721 }
715722
716- void initFlags ()
717- {
723+ void initFlags () {
718724 mFlags = initGridBgAndName<Int32Grid>(0 , " flags" );
719725 mFlags ->denseFill (CoordBBox (mMinIdx , mMaxIdx ), /* value = */ 1 , /* active = */ true );
720726
@@ -740,26 +746,6 @@ class SmokeSolver {
740746 mDivAfter = initGridBgAndName<FloatGrid>(0 .f , " div_after" );
741747 }
742748
743- float computeLInfinity (const FloatGrid& grid) {
744- float ret = 0 .f ;
745- auto acc = grid.getConstAccessor ();
746- for (auto iter = grid.beginValueOn (); iter; ++iter) {
747- math::Coord ijk = iter.getCoord ();
748- auto val = acc.getValue (ijk);
749- if (std::abs (val) > std::abs (ret)) {
750- ret = val;
751- }
752- }
753- return ret;
754- }
755-
756- float computeDivergence (FloatGrid::Ptr& divGrid, const Vec3SGrid::Ptr vecGrid, const std::string& suffix) {
757- divGrid = tools::divergence (*vecGrid);
758- divGrid->tree ().topologyIntersection (mInteriorPressure ->tree ());
759- float div = computeLInfinity (*divGrid);
760- return div;
761- }
762-
763749 void initVCurr ()
764750 {
765751 mVCurr = initGridBgAndName<Vec3SGrid>(Vec3s::zero (), " vel_curr" );
@@ -768,7 +754,7 @@ class SmokeSolver {
768754
769755 auto flagsAcc = mFlags ->getConstAccessor ();
770756 auto velAcc = mVCurr ->getAccessor ();
771- const float hv = .5f * mXform ->voxelSize ()[0 ]; // half of voxel size
757+ const float hv = .5f * static_cast < float >( mXform ->voxelSize ()[0 ]) ; // half of voxel size
772758 for (auto iter = mVCurr ->beginValueOn (); iter; ++iter) {
773759 auto ijk = iter.getCoord ();
774760 Vec3f center = mXform ->indexToWorld (ijk);
@@ -797,6 +783,20 @@ class SmokeSolver {
797783 }
798784 }
799785
786+ float computeLInfinity (const FloatGrid& grid) {
787+ float ret = 0 .f ;
788+ auto acc = grid.getConstAccessor ();
789+ for (auto iter = grid.beginValueOn (); iter; ++iter) {
790+ math::Coord ijk = iter.getCoord ();
791+ auto val = acc.getValue (ijk);
792+ if (std::abs (val) > std::abs (ret)) {
793+ ret = val;
794+ }
795+ }
796+ return ret;
797+ }
798+
799+ public:
800800 bool mVERBOSE = false ;
801801
802802 float mVoxelSize = 0 .1f ;
@@ -821,9 +821,11 @@ TEST_F(TestPoissonSolver, testRemoveDivergence)
821821{
822822 using namespace openvdb ;
823823
824- SmokeSolver smoke (0 .1f );
824+ float voxelSize = 0 .1f ;
825+ math::Coord topRightCorner (3 , 15 , 17 );
826+ SmokeSolver smoke (voxelSize, topRightCorner);
825827
826- float divBefore = smoke.computeDivergence (smoke.mDivBefore , smoke.mVCurr , " before " );
828+ float divBefore = smoke.computeDivergence (smoke.mDivBefore , smoke.mVCurr );
827829 EXPECT_NEAR (divBefore, -39.425 , 1 .e -4f );
828830
829831 // Make the velocity divergence free by solving Poisson Equation and subtracting the pressure gradient
@@ -836,6 +838,6 @@ TEST_F(TestPoissonSolver, testRemoveDivergence)
836838 EXPECT_TRUE (smoke.mState .relativeError < 1 .e -5f );
837839 EXPECT_TRUE (smoke.mState .absoluteError < 1 .e -3f );
838840
839- float divAfter = smoke.computeDivergence (smoke.mDivAfter , smoke.mVCurr , " after " );
840- EXPECT_TRUE (divAfter < 1 .e -3f );
841+ float divAfter = smoke.computeDivergence (smoke.mDivAfter , smoke.mVCurr );
842+ EXPECT_LT (divAfter, 1 .e -3f );
841843}
0 commit comments