From 6c5f354eaf58758249c1d19cf106581edddf375a Mon Sep 17 00:00:00 2001
From: Sebastian Eibl <sebastian.eibl@fau.de>
Date: Thu, 18 May 2017 14:18:13 +0200
Subject: [PATCH] added speed limiter to HCSITS

---
 src/pe/cr/HCSITS.h      | 43 +++++++++++++++++++++++++++++++++++++++
 src/pe/cr/HCSITS.impl.h | 45 ++++++++++++++++++++++++++---------------
 tests/pe/HCSITS.cpp     | 23 +++++++++++++++++++++
 3 files changed, 95 insertions(+), 16 deletions(-)

diff --git a/src/pe/cr/HCSITS.h b/src/pe/cr/HCSITS.h
index 41f863e37..0af5c6fa9 100644
--- a/src/pe/cr/HCSITS.h
+++ b/src/pe/cr/HCSITS.h
@@ -134,6 +134,7 @@ public:
    virtual inline size_t            getNumberOfContacts()          const WALBERLA_OVERRIDE;
    virtual inline size_t            getNumberOfContactsTreated()   const WALBERLA_OVERRIDE;
    inline const std::map<IBlockID::IDType, ContactCache> getContactCache() const { return blockToContactCache_; }
+   inline real_t                    getSpeedLimitFactor() const;
    //@}
    //**********************************************************************************************
 
@@ -145,6 +146,7 @@ public:
    inline void            setRelaxationModel( RelaxationModel relaxationModel );
    inline void            setErrorReductionParameter( real_t erp );
    inline void            setAbortThreshold( real_t threshold );
+   inline void            setSpeedLimiter( bool active, const real_t speedLimitFactor = real_t(0.0) );
    //@}
    //**********************************************************************************************
 
@@ -153,6 +155,7 @@ public:
    //@{
    inline bool            isSyncRequired()        const;
    inline bool            isSyncRequiredLocally() const;
+   inline bool            isSpeedLimiterActive() const;
    //@}
    //**********************************************************************************************
 
@@ -235,6 +238,9 @@ private:
    size_t numContacts_;
    size_t numContactsTreated_;
 
+   bool   speedLimiterActive_;        //!< is the speed limiter active?
+   real_t speedLimitFactor_;          //!< what multiple of boundingbox edge length is the body allowed to travel in one timestep
+
    //**********************************************************************************************
    /*! \cond WALBERLA_INTERNAL */
    /*!\brief Functor for comparing the system ID of two bodies.
@@ -299,6 +305,11 @@ inline size_t HardContactSemiImplicitTimesteppingSolvers::getNumberOfContactsTre
 {
    return numContactsTreated_;
 }
+
+inline real_t HardContactSemiImplicitTimesteppingSolvers::getSpeedLimitFactor() const
+{
+   return speedLimitFactor_;
+}
 //*************************************************************************************************
 
 
@@ -393,6 +404,23 @@ inline void HardContactSemiImplicitTimesteppingSolvers::setAbortThreshold( real_
 
 
 
+//*************************************************************************************************
+/*!\brief Activates/Deactivates the speed limiter and sets the limit
+*
+* \param active activate/deactivate speed limtier
+* \param speedLimitFactor size of bounding box will be multiplied by this factor to get the maximal distance a body is allowed to travel within one timestep
+* \return void
+*/
+inline void HardContactSemiImplicitTimesteppingSolvers::setSpeedLimiter( bool active, const real_t speedLimitFactor )
+{
+   speedLimiterActive_ = active;
+   speedLimitFactor_   = speedLimitFactor;
+}
+//*************************************************************************************************
+
+
+
+
 //=================================================================================================
 //
 //  QUERY FUNCTIONS
@@ -453,6 +481,21 @@ inline bool HardContactSemiImplicitTimesteppingSolvers::isSyncRequiredLocally()
 }
 //*************************************************************************************************
 
+
+
+
+//*************************************************************************************************
+/*!\brief Returns if speed limiter is currently active and working.
+ *
+ * \return status of the speed limiter
+ */
+inline bool HardContactSemiImplicitTimesteppingSolvers::isSpeedLimiterActive() const
+{
+   return speedLimiterActive_;
+}
+//*************************************************************************************************
+
+
 } // namespace cr
 } // namespace pe
 
diff --git a/src/pe/cr/HCSITS.impl.h b/src/pe/cr/HCSITS.impl.h
index d2c8b9ba7..8be3ec9fd 100644
--- a/src/pe/cr/HCSITS.impl.h
+++ b/src/pe/cr/HCSITS.impl.h
@@ -102,6 +102,8 @@ inline HardContactSemiImplicitTimesteppingSolvers::HardContactSemiImplicitTimest
    , maximumPenetration_ ( real_c(0.0) )
    , numContacts_      ( 0 )
    , numContactsTreated_( 0)
+   , speedLimiterActive_( false )
+   , speedLimitFactor_ ( real_c(1.0) )
    , requireSync_      ( false )
 {
    // Logging the successful setup of the collision system
@@ -364,17 +366,17 @@ inline void HardContactSemiImplicitTimesteppingSolvers::timestep( const real_t d
             delta_max = relaxApproximateInelasticCoulombContactsByDecoupling( dtinv, contactCache, bodyCache );
             break;
 
-//         case ApproximateInelasticCoulombContactByOrthogonalProjections:
-//            delta_max = relaxInelasticCoulombContactsByOrthogonalProjections( dtinv, true, contactCache, bodyCache );
-//            break;
+            //         case ApproximateInelasticCoulombContactByOrthogonalProjections:
+            //            delta_max = relaxInelasticCoulombContactsByOrthogonalProjections( dtinv, true, contactCache, bodyCache );
+            //            break;
 
          case InelasticCoulombContactByDecoupling:
             delta_max = relaxInelasticCoulombContactsByDecoupling( dtinv, contactCache, bodyCache );
             break;
 
-//         case InelasticCoulombContactByOrthogonalProjections:
-//            delta_max = relaxInelasticCoulombContactsByOrthogonalProjections( dtinv, false, contactCache, bodyCache );
-//            break;
+            //         case InelasticCoulombContactByOrthogonalProjections:
+            //            delta_max = relaxInelasticCoulombContactsByOrthogonalProjections( dtinv, false, contactCache, bodyCache );
+            //            break;
 
          case InelasticGeneralizedMaximumDissipationContact:
             delta_max = relaxInelasticGeneralizedMaximumDissipationContacts( dtinv, contactCache, bodyCache );
@@ -455,10 +457,10 @@ inline void HardContactSemiImplicitTimesteppingSolvers::timestep( const real_t d
       BodyStorage& shadowStorage = (*storage)[1];
 
       for( auto body = ConcatIterator<BodyStorage::Iterator>
-                                     (localStorage.begin(),
-                                      localStorage.end(),
-                                      shadowStorage.begin(),
-                                      shadowStorage.end()); body != ConcatIterator<BodyStorage::Iterator>(); ++body )
+           (localStorage.begin(),
+            localStorage.end(),
+            shadowStorage.begin(),
+            shadowStorage.end()); body != ConcatIterator<BodyStorage::Iterator>(); ++body )
       {
          if (!body->isCommunicating())
          {
@@ -1665,7 +1667,7 @@ inline void HardContactSemiImplicitTimesteppingSolvers::synchronizeVelocities( )
    if (tt_ != NULL) tt_->stop("Velocity Sync Update Processing");
 
    if (tt_ != NULL) tt_->start("Velocity Sync Globals");
-/*
+   /*
    {
       size_t i;
       std::vector<real_t> reductionBuffer( globalBodyStorage_->size() * 6, real_c(0) );
@@ -1775,6 +1777,17 @@ inline void HardContactSemiImplicitTimesteppingSolvers::integratePositions( Body
 
    if( body->isAwake() )
    {
+      if ( isSpeedLimiterActive() )
+      {
+         const auto speed = v.length();
+         const auto aabb  = body->getAABB();
+         const auto edge  = std::min(aabb.xSize(), std::min(aabb.ySize(), aabb.zSize()));
+         if (speed * dt > edge * getSpeedLimitFactor() )
+         {
+            v = v * (edge * getSpeedLimitFactor() / dt / speed );
+         }
+      }
+
       // Calculating the translational displacement
       body->setPosition( body->getPosition() + v * dt );
 
@@ -1821,19 +1834,19 @@ void configure( const Config::BlockHandle& config, pe::cr::HCSITS& cr )
    cr::HCSITS::RelaxationModel HCSITSRelaxationModel;
    if (HCSITSRelaxationModelStr == "InelasticFrictionlessContact")
    {
-       HCSITSRelaxationModel = cr::HCSITS::InelasticFrictionlessContact;
+      HCSITSRelaxationModel = cr::HCSITS::InelasticFrictionlessContact;
    } else if (HCSITSRelaxationModelStr == "ApproximateInelasticCoulombContactByDecoupling")
    {
-       HCSITSRelaxationModel = cr::HCSITS::ApproximateInelasticCoulombContactByDecoupling;
+      HCSITSRelaxationModel = cr::HCSITS::ApproximateInelasticCoulombContactByDecoupling;
    } else if (HCSITSRelaxationModelStr == "InelasticCoulombContactByDecoupling")
    {
-       HCSITSRelaxationModel = cr::HCSITS::InelasticCoulombContactByDecoupling;
+      HCSITSRelaxationModel = cr::HCSITS::InelasticCoulombContactByDecoupling;
    } else if (HCSITSRelaxationModelStr == "InelasticGeneralizedMaximumDissipationContact")
    {
-       HCSITSRelaxationModel = cr::HCSITS::InelasticGeneralizedMaximumDissipationContact;
+      HCSITSRelaxationModel = cr::HCSITS::InelasticGeneralizedMaximumDissipationContact;
    } else
    {
-       WALBERLA_ABORT("Unknown HCSITSRelaxationModel: " << HCSITSRelaxationModelStr);
+      WALBERLA_ABORT("Unknown HCSITSRelaxationModel: " << HCSITSRelaxationModelStr);
    }
 
    Vec3 globalLinearAcceleration = config.getParameter<Vec3>("globalLinearAcceleration", Vec3(0, 0, 0));
diff --git a/tests/pe/HCSITS.cpp b/tests/pe/HCSITS.cpp
index ae0472195..93faeca36 100644
--- a/tests/pe/HCSITS.cpp
+++ b/tests/pe/HCSITS.cpp
@@ -77,6 +77,25 @@ void normalReactionTest(cr::HCSITS& cr, SphereID sp)
    WALBERLA_CHECK_FLOAT_EQUAL( sp->getLinearVel(), Vec3(0,0,0) );
 }
 
+void speedLimiterTest(cr::HCSITS& cr, SphereID sp)
+{
+   cr.setErrorReductionParameter( real_t(1.0) );
+
+   sp->setPosition(  Vec3(5,5,6) );
+   sp->setLinearVel( Vec3(0,0,0) );
+   cr.setSpeedLimiter( true, real_t(0.2) );
+   cr.timestep( real_c( real_t(1.0) ) );
+   WALBERLA_CHECK_FLOAT_EQUAL( sp->getPosition() , Vec3(5,5,real_t(6.1)) );
+   WALBERLA_CHECK_FLOAT_EQUAL( sp->getLinearVel(), Vec3(0,0,real_t(0.1)) );
+
+   sp->setPosition(  Vec3(5,5,5.5) );
+   sp->setLinearVel( Vec3(0,0,0) );
+   cr.setSpeedLimiter( true, real_t(0.2) );
+   cr.timestep( real_c( real_t(1.0) ) );
+   WALBERLA_CHECK_FLOAT_EQUAL( sp->getPosition() , Vec3(5,5,real_t(5.94)) );
+   WALBERLA_CHECK_FLOAT_EQUAL( sp->getLinearVel(), Vec3(0,0,real_t(0.44)) );
+}
+
 int main( int argc, char** argv )
 {
    walberla::debug::enterTestMode();
@@ -135,5 +154,9 @@ int main( int argc, char** argv )
    cr.setRelaxationModel( cr::HardContactSemiImplicitTimesteppingSolvers::InelasticGeneralizedMaximumDissipationContact );
    normalReactionTest(cr, sp);
 
+   WALBERLA_LOG_PROGRESS("SpeedLimiter Test: InelasticFrictionlessContact");
+   cr.setRelaxationModel( cr::HardContactSemiImplicitTimesteppingSolvers::InelasticFrictionlessContact );
+   speedLimiterTest(cr, sp);
+
    return EXIT_SUCCESS;
 }
-- 
GitLab