From 6f1037b9436efc139ffac7467460fc501257e8b2 Mon Sep 17 00:00:00 2001
From: Sebastian Eibl <sebastian.eibl@fau.de>
Date: Wed, 31 Jul 2019 11:11:42 +0200
Subject: [PATCH] [BUGFIX] sanitized DropTest

---
 tests/mesa_pd/CMakeLists.txt                  |   7 +-
 tests/mesa_pd/DropTestAnalytic.cpp            | 173 ++++++++++++++++++
 .../{DropTest.cpp => DropTestGeneral.cpp}     |  66 ++++---
 3 files changed, 221 insertions(+), 25 deletions(-)
 create mode 100644 tests/mesa_pd/DropTestAnalytic.cpp
 rename tests/mesa_pd/{DropTest.cpp => DropTestGeneral.cpp} (72%)

diff --git a/tests/mesa_pd/CMakeLists.txt b/tests/mesa_pd/CMakeLists.txt
index 07083c0e8..69278f743 100644
--- a/tests/mesa_pd/CMakeLists.txt
+++ b/tests/mesa_pd/CMakeLists.txt
@@ -63,8 +63,11 @@ waLBerla_execute_test( NAME   MESA_PD_Domain_DynamicRefinement PROCESSES 8)
 waLBerla_compile_test( NAME   MESA_PD_Domain_SerializeDeserialize FILES domain/SerializeDeserialize.cpp DEPENDS blockforest core pe)
 waLBerla_execute_test( NAME   MESA_PD_Domain_SerializeDeserialize PROCESSES 8 )
 
-waLBerla_compile_test( NAME   MESA_PD_DropTest FILES DropTest.cpp DEPENDS core )
-waLBerla_execute_test( NAME   MESA_PD_DropTest )
+waLBerla_compile_test( NAME   MESA_PD_DropTestAnalytic FILES DropTestAnalytic.cpp DEPENDS core )
+waLBerla_execute_test( NAME   MESA_PD_DropTestAnalytic )
+
+waLBerla_compile_test( NAME   MESA_PD_DropTestGeneral FILES DropTestGeneral.cpp DEPENDS core )
+waLBerla_execute_test( NAME   MESA_PD_DropTestGeneral )
 
 waLBerla_compile_test( NAME   MESA_PD_Kernel_ClearNextNeighborSync FILES kernel/ClearNextNeighborSync.cpp DEPENDS core )
 waLBerla_execute_test( NAME   MESA_PD_Kernel_ClearNextNeighborSync PROCESSES 2 )
diff --git a/tests/mesa_pd/DropTestAnalytic.cpp b/tests/mesa_pd/DropTestAnalytic.cpp
new file mode 100644
index 000000000..6cdd51190
--- /dev/null
+++ b/tests/mesa_pd/DropTestAnalytic.cpp
@@ -0,0 +1,173 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file   DropTestAnalytic.cpp
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+#include <mesa_pd/collision_detection/AnalyticContactDetection.h>
+
+#include <mesa_pd/data/ParticleAccessor.h>
+#include <mesa_pd/data/ParticleStorage.h>
+#include <mesa_pd/data/ShapeStorage.h>
+
+#include <mesa_pd/kernel/DoubleCast.h>
+#include <mesa_pd/kernel/ExplicitEulerWithShape.h>
+#include <mesa_pd/kernel/ParticleSelector.h>
+#include <mesa_pd/kernel/SpringDashpot.h>
+
+#include <core/Abort.h>
+#include <core/Environment.h>
+#include <core/logging/Logging.h>
+#include <core/waLBerlaBuildInfo.h>
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <type_traits>
+
+namespace walberla {
+namespace mesa_pd {
+
+class ParticleAccessorWithShape : public data::ParticleAccessor
+{
+public:
+   ParticleAccessorWithShape(std::shared_ptr<data::ParticleStorage>& ps, std::shared_ptr<data::ShapeStorage>& ss)
+         : ParticleAccessor(ps)
+         , ss_(ss)
+   {}
+
+   const auto& getInvMass(const size_t p_idx) const {return ss_->shapes[ps_->getShapeID(p_idx)]->getInvMass();}
+
+   const auto& getInvInertiaBF(const size_t p_idx) const {return ss_->shapes[ps_->getShapeID(p_idx)]->getInvInertiaBF();}
+
+   data::BaseShape* getShape(const size_t p_idx) const {return ss_->shapes[ps_->getShapeID(p_idx)].get();}
+private:
+   std::shared_ptr<data::ShapeStorage> ss_;
+};
+
+int main( int argc, char ** argv )
+{
+   using namespace walberla::timing;
+
+   Environment env(argc, argv);
+   walberla::mpi::MPIManager::instance()->useWorldComm();
+
+   if (std::is_same<walberla::real_t, float>::value)
+   {
+      WALBERLA_LOG_WARNING("waLBerla build in sp mode: skipping test due to low precision");
+      return EXIT_SUCCESS;
+   }
+
+   //init data structures
+   auto ps = std::make_shared<data::ParticleStorage>(100);
+   auto ss = std::make_shared<data::ShapeStorage>();
+   ParticleAccessorWithShape accessor(ps, ss);
+
+   auto p                       = ps->create();
+   p->getPositionRef()          = Vec3(real_t(0), real_t(0), real_t(0));
+   p->getInteractionRadiusRef() = std::numeric_limits<real_t>::infinity();
+   p->getShapeIDRef()           = ss->create<data::HalfSpace>( Vec3(real_t(0), real_t(0), real_t(1)) );
+   p->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+   p->getTypeRef()              = 0;
+   using namespace walberla::mesa_pd::data::particle_flags;
+   set(p->getFlagsRef(), INFINITE);
+   set(p->getFlagsRef(), FIXED);
+   set(p->getFlagsRef(), GLOBAL);
+
+   auto sp                       = ps->create();
+   sp->getPositionRef()          = Vec3(real_t(0), real_t(0), real_t(0.01));
+   sp->getInteractionRadiusRef() = real_t(1);
+   sp->getShapeIDRef()           = ss->create<data::Sphere>( real_t(0.004) );
+   ss->shapes[sp->getShapeID()]->updateMassAndInertia(real_t(2707));
+   WALBERLA_LOG_DEVEL_VAR(ss->shapes[sp->getShapeID()]->getInvMass());
+   WALBERLA_LOG_DEVEL_VAR(ss->shapes[sp->getShapeID()]->getInvInertiaBF());
+   sp->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
+   sp->getTypeRef()              = 0;
+
+   int64_t simulationSteps = 200000;
+   real_t dt = real_t(0.00001);
+
+   // Init kernels
+   kernel::ExplicitEulerWithShape        explicitEulerWithShape( dt );
+   kernel::SpringDashpot                 dem(1);
+   auto meff = real_t(1.0) / ss->shapes[sp->getShapeID()]->getInvMass();
+   dem.setParametersFromCOR(0,0,real_t(0.9), dt * real_t(20), meff);
+   dem.setDampingT (0, 0, real_t(6.86e1));
+   dem.setFriction (0, 0, real_t(1.2));
+   WALBERLA_LOG_DEVEL_VAR(dem.getStiffness(0,0));
+   WALBERLA_LOG_DEVEL_VAR(dem.getDampingN(0,0));
+   WALBERLA_LOG_DEVEL_VAR(dem.calcCollisionTime(0,0,meff));
+   WALBERLA_LOG_DEVEL_VAR(dem.calcCoefficientOfRestitution(0,0,meff));
+
+   collision_detection::AnalyticContactDetection gcd;
+   kernel::DoubleCast                 double_cast;
+
+   for (int64_t i=0; i < simulationSteps; ++i)
+   {
+      ps->forEachParticle(false,
+                          kernel::SelectLocal(),
+                          accessor,
+                          [&](const size_t idx, auto& ac)
+      {
+         ac.setForce(idx,
+                     Vec3(real_t(0), real_t(0), real_t(-9.81)) *
+                     real_t(1.0) / ss->shapes[ac.getShapeID(idx)]->getInvMass() );
+      }, accessor);
+
+      ps->forEachParticlePairHalf(false,
+                                  kernel::SelectAll(),
+                                  accessor,
+                                  [&](const size_t idx1, const size_t idx2, auto& ac)
+      {
+         if (double_cast(idx1, idx2, ac, gcd, ac ))
+         {
+            if (ss->shapes[ac.getShapeID(idx1)]->getShapeType() == data::HalfSpace::SHAPE_TYPE)
+            {
+               meff = real_t(1.0) / ss->shapes[ac.getShapeID(idx2)]->getInvMass();
+            } else
+            {
+               meff = real_t(1.0) / ss->shapes[ac.getShapeID(idx1)]->getInvMass();
+            }
+
+            dem.setParametersFromCOR(0,0,real_t(0.9), dt * real_t(20), meff);
+            dem(gcd.getIdx1(), gcd.getIdx2(), ac, gcd.getContactPoint(), gcd.getContactNormal(), gcd.getPenetrationDepth());
+         }
+      },
+      accessor );
+
+      ps->forEachParticle(false,
+                          kernel::SelectLocal(),
+                          accessor,
+                          explicitEulerWithShape,
+                          accessor);
+
+//      if(i%1 == 0)
+//         WALBERLA_LOG_DEVEL_VAR(sp->getPosition()[2]);
+   }
+
+   WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(sp->getPosition()[2], real_t(0.004),     real_t(1e-7));
+
+   return EXIT_SUCCESS;
+}
+
+} // namespace mesa_pd
+} // namespace walberla
+
+int main( int argc, char* argv[] )
+{
+   return walberla::mesa_pd::main( argc, argv );
+}
diff --git a/tests/mesa_pd/DropTest.cpp b/tests/mesa_pd/DropTestGeneral.cpp
similarity index 72%
rename from tests/mesa_pd/DropTest.cpp
rename to tests/mesa_pd/DropTestGeneral.cpp
index d9d249e99..e729b1221 100644
--- a/tests/mesa_pd/DropTest.cpp
+++ b/tests/mesa_pd/DropTestGeneral.cpp
@@ -13,7 +13,7 @@
 //  You should have received a copy of the GNU General Public License along
 //  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
-//! \file   DropTest.cpp
+//! \file   DropTestGeneral.cpp
 //! \author Sebastian Eibl <sebastian.eibl@fau.de>
 //
 //======================================================================================================================
@@ -83,14 +83,18 @@ int main( int argc, char ** argv )
    p->getShapeIDRef()           = ss->create<data::HalfSpace>( Vec3(real_t(0), real_t(0), real_t(1)) );
    p->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
    p->getTypeRef()              = 0;
+   using namespace walberla::mesa_pd::data::particle_flags;
+   set(p->getFlagsRef(), INFINITE);
+   set(p->getFlagsRef(), FIXED);
+   set(p->getFlagsRef(), GLOBAL);
 
    auto sp                       = ps->create();
    sp->getPositionRef()          = Vec3(real_t(0), real_t(0), real_t(0.01));
    sp->getInteractionRadiusRef() = real_t(1);
    sp->getShapeIDRef()           = ss->create<data::Sphere>( real_t(0.004) );
-   ss->shapes[1]->updateMassAndInertia(real_t(2707));
-   WALBERLA_LOG_DEVEL_VAR(ss->shapes[1]->getInvMass());
-   WALBERLA_LOG_DEVEL_VAR(ss->shapes[1]->getInvInertiaBF());
+   ss->shapes[sp->getShapeID()]->updateMassAndInertia(real_t(2707));
+   WALBERLA_LOG_DEVEL_VAR(ss->shapes[sp->getShapeID()]->getInvMass());
+   WALBERLA_LOG_DEVEL_VAR(ss->shapes[sp->getShapeID()]->getInvInertiaBF());
    sp->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
    sp->getTypeRef()              = 0;
 
@@ -98,9 +102,9 @@ int main( int argc, char ** argv )
    bx->getPositionRef()          = Vec3(real_t(1), real_t(0), real_t(0.01));
    bx->getInteractionRadiusRef() = real_t(1);
    bx->getShapeIDRef()           = ss->create<data::Box>( Vec3(real_t(0.008*0.8)) );
-   ss->shapes[2]->updateMassAndInertia(real_t(2707));
-   WALBERLA_LOG_DEVEL_VAR(ss->shapes[2]->getInvMass());
-   WALBERLA_LOG_DEVEL_VAR(ss->shapes[2]->getInvInertiaBF());
+   ss->shapes[bx->getShapeID()]->updateMassAndInertia(real_t(2707));
+   WALBERLA_LOG_DEVEL_VAR(ss->shapes[bx->getShapeID()]->getInvMass());
+   WALBERLA_LOG_DEVEL_VAR(ss->shapes[bx->getShapeID()]->getInvInertiaBF());
    bx->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
    bx->getTypeRef()              = 0;
 
@@ -108,60 +112,76 @@ int main( int argc, char ** argv )
    el->getPositionRef()          = Vec3(real_t(2), real_t(0), real_t(0.01));
    el->getInteractionRadiusRef() = real_t(1);
    el->getShapeIDRef()           = ss->create<data::Ellipsoid>( Vec3(real_t(0.004)) );
-   ss->shapes[3]->updateMassAndInertia(real_t(2707));
-   WALBERLA_LOG_DEVEL_VAR(ss->shapes[3]->getInvMass());
-   WALBERLA_LOG_DEVEL_VAR(ss->shapes[3]->getInvInertiaBF());
+   ss->shapes[el->getShapeID()]->updateMassAndInertia(real_t(2707));
+   WALBERLA_LOG_DEVEL_VAR(ss->shapes[el->getShapeID()]->getInvMass());
+   WALBERLA_LOG_DEVEL_VAR(ss->shapes[el->getShapeID()]->getInvInertiaBF());
    el->getOwnerRef()             = walberla::mpi::MPIManager::instance()->rank();
    el->getTypeRef()              = 0;
 
-   int64_t simulationSteps = 2000;
-   real_t dt = real_t(0.000001);
+   int64_t simulationSteps = 200000;
+   real_t dt = real_t(0.00001);
 
    // Init kernels
    kernel::ExplicitEulerWithShape        explicitEulerWithShape( dt );
    kernel::SpringDashpot                 dem(1);
-   dem.setStiffness(0, 0, real_t(8.11e6));
-   dem.setDampingN (0, 0, real_t(6.86e1));
+   auto meff = real_t(1.0) / ss->shapes[sp->getShapeID()]->getInvMass();
+   dem.setParametersFromCOR(0,0,real_t(0.9), dt * real_t(20), meff);
    dem.setDampingT (0, 0, real_t(6.86e1));
    dem.setFriction (0, 0, real_t(1.2));
+   WALBERLA_LOG_DEVEL_VAR(dem.getStiffness(0,0));
+   WALBERLA_LOG_DEVEL_VAR(dem.getDampingN(0,0));
+   WALBERLA_LOG_DEVEL_VAR(dem.calcCollisionTime(0,0,meff));
+   WALBERLA_LOG_DEVEL_VAR(dem.calcCoefficientOfRestitution(0,0,meff));
 
    collision_detection::GeneralContactDetection gcd;
    kernel::DoubleCast                 double_cast;
 
-
    for (int64_t i=0; i < simulationSteps; ++i)
    {
       ps->forEachParticle(false,
                           kernel::SelectLocal(),
                           accessor,
-                          [&](const size_t idx, auto& ac){ac.setForce(idx, Vec3(real_t(0), real_t(0), real_t(-9.81)) );},
-      accessor);
+                          [&](const size_t idx, auto& ac)
+      {
+         ac.setForce(idx,
+                     Vec3(real_t(0), real_t(0), real_t(-9.81)) *
+                     real_t(1.0) / ss->shapes[ac.getShapeID(idx)]->getInvMass() );
+      }, accessor);
 
-      ps->forEachParticlePairHalf(true,
+      ps->forEachParticlePairHalf(false,
                                   kernel::SelectAll(),
                                   accessor,
                                   [&](const size_t idx1, const size_t idx2, auto& ac)
       {
          if (double_cast(idx1, idx2, ac, gcd, ac ))
          {
+            if (ss->shapes[ac.getShapeID(idx1)]->getShapeType() == data::HalfSpace::SHAPE_TYPE)
+            {
+               meff = real_t(1.0) / ss->shapes[ac.getShapeID(idx2)]->getInvMass();
+            } else
+            {
+               meff = real_t(1.0) / ss->shapes[ac.getShapeID(idx1)]->getInvMass();
+            }
+
+            dem.setParametersFromCOR(0,0,real_t(0.9), dt * real_t(20), meff);
             dem(gcd.getIdx1(), gcd.getIdx2(), ac, gcd.getContactPoint(), gcd.getContactNormal(), gcd.getPenetrationDepth());
          }
       },
       accessor );
 
-      ps->forEachParticle(true,
+      ps->forEachParticle(false,
                           kernel::SelectLocal(),
                           accessor,
                           explicitEulerWithShape,
                           accessor);
 
 //      if(i%1 == 0)
-//         WALBERLA_LOG_DEVEL(bx->getPosition()[2]);
+//         WALBERLA_LOG_DEVEL_VAR(sp->getPosition()[2]);
    }
 
-   WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(sp->getPosition()[2], real_t(0.004),     real_t(1e-3));
-   WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(bx->getPosition()[2], real_t(0.004*0.8), real_t(1e-3));
-   WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(el->getPosition()[2], real_t(0.004),     real_t(1e-3));
+   WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(sp->getPosition()[2], real_t(0.004),     real_t(1e-7));
+   WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(bx->getPosition()[2], real_t(0.004*0.8), real_t(1e-7));
+   WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(el->getPosition()[2], real_t(0.004),     real_t(1e-7));
 
    return EXIT_SUCCESS;
 }
-- 
GitLab