From f4733daf2807aac8982b91f1c35c86401da4a212 Mon Sep 17 00:00:00 2001
From: Sebastian Eibl <sebastian.eibl@fau.de>
Date: Fri, 18 Dec 2020 15:07:44 +0100
Subject: [PATCH] [ADD] kernel for the VBondModel, integrated vdW contact

---
 .../kernel/VBondModel/IntegratedVDWContact.h  | 162 ++++++++++++++++++
 tests/mesa_pd/CMakeLists.txt                  |   3 +
 .../VBondModel/IntegratedVDWContact.test.cpp  |  80 +++++++++
 3 files changed, 245 insertions(+)
 create mode 100644 src/mesa_pd/kernel/VBondModel/IntegratedVDWContact.h
 create mode 100644 tests/mesa_pd/kernel/VBondModel/IntegratedVDWContact.test.cpp

diff --git a/src/mesa_pd/kernel/VBondModel/IntegratedVDWContact.h b/src/mesa_pd/kernel/VBondModel/IntegratedVDWContact.h
new file mode 100644
index 000000000..b7315d50b
--- /dev/null
+++ b/src/mesa_pd/kernel/VBondModel/IntegratedVDWContact.h
@@ -0,0 +1,162 @@
+//======================================================================================================================
+//
+//  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
+//! \author Igor Ostanin <i.ostanin@skoltech.ru>
+//! \author Grigorii Drozdov <drozd013@umn.edu>
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+//======================================================================================================================
+//
+//  THIS FILE IS GENERATED - PLEASE CHANGE THE TEMPLATE !!!
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <mesa_pd/common/ParticleFunctions.h>
+#include <mesa_pd/data/DataTypes.h>
+#include <mesa_pd/data/IAccessor.h>
+
+#include <core/math/Constants.h>
+#include <core/logging/Logging.h>
+
+#include <vector>
+
+namespace walberla {
+namespace mesa_pd {
+namespace kernel {
+namespace VBondModel {
+
+/**
+ * Advanced DEM kernel
+ */
+class IntegratedVDWContact
+{
+public:
+   template<typename Accessor>
+   real_t operator()(const size_t p_idx1,
+                     const size_t p_idx2,
+                     Accessor &ac) const;
+
+   static constexpr double eps_ = 0.07124;
+   static constexpr double A_ = 0.0223;
+   static constexpr double B_ = 1.31;
+   static constexpr double alf_ = 9.5;
+   static constexpr double bet_ = 4.0;
+};
+
+/**
+ *
+ * @tparam Accessor
+ * @param p_idx1
+ * @param p_idx2
+ * @param ac
+ * @return vdW adhesion energy
+ */
+template<typename Accessor>
+inline
+real_t IntegratedVDWContact::operator()(const size_t p_idx1,
+                                        const size_t p_idx2,
+                                        Accessor &ac) const
+{
+   constexpr real_t K_n = 200.0; // Good for fabrics modeling
+
+   // particle centers
+   Vec3 O1 = ac.getPosition(p_idx1);
+   Vec3 O2 = ac.getPosition(p_idx2);
+
+   // axial vectors
+   Vec3 b1 = ac.getRotation(p_idx1) * Vec3(1.0, 0.0, 0.0);
+   Vec3 b2 = ac.getRotation(p_idx2) * Vec3(1.0, 0.0, 0.0);
+
+   // vdW adhesion + linear repulsion potential.
+   const real_t r0 = R_CNT * (2 + std::pow((alf_ * A_ / (bet_ * B_)), 1 / (alf_ - bet_)));
+   const real_t u0 = 4 * eps_ * (A_ / pow(r0 / R_CNT - 2, (alf_)) - B_ / pow(r0 / R_CNT - 2, (bet_)));
+
+   real_t U = 0, dU = 0; ///< total potential
+   Vec3 force12(0), dforce12(0);  // Force 12
+   Vec3 force21(0), dforce21(0);  // Force 21
+   Vec3 moment12(0), dmoment12(0); // Total torque 12
+   Vec3 moment21(0), dmoment21(0); // Total torque 21
+
+   constexpr int Np = 5; // Number of integration points over each axis
+   constexpr double Npinv = 1.0 / Np;
+   for (int i = 0; i < Np; ++i) // integral dl1
+   {
+      for (int j = 0; j < Np; ++j) // integral dl2
+      {
+         // Levers
+         Vec3 l1 = (-0.5 * T + (0.5 + i) * T * Npinv) * b1;
+         Vec3 l2 = (-0.5 * T + (0.5 + j) * T * Npinv) * b2;
+
+         /// radius vector between dl1 and dl2
+         Vec3 R12 = (O2 + l2) - (O1 + l1);
+
+         Vec3 n12 = R12.getNormalized();
+         real_t r12 = R12.length();
+
+         if (r12 < r0) // elastic interaction
+         {
+            dU = u0 + K_n * (r12 - r0) * (r12 - r0) * Npinv * Npinv;
+            dforce12 = n12 * K_n * ((r12 - r0)) * Npinv * Npinv;
+            dforce21 = -dforce12;
+         }
+         if (r12 >= r0) // vdW interaction
+         {
+            const double powAlpha1 = pow(r12 / R_CNT - 2.0, (alf_ + 1.0));
+            const double powBeta1 = pow(r12 / R_CNT - 2.0, (bet_ + 1));
+            dU = 4.0 * eps_ * (A_ / pow(r12 / R_CNT - 2.0, (alf_)) - B_ / pow(r12 / R_CNT - 2.0, (bet_))) * Npinv *
+                 Npinv;
+            dforce12 =
+                  n12 * 4.0 * eps_ * (-(alf_ * A_) / powAlpha1 + (bet_ * B_) / powBeta1) / R_CNT * Npinv * Npinv;
+            dforce21 =
+                  -n12 * 4.0 * eps_ * (-(alf_ * A_) / powAlpha1 + (bet_ * B_) / powBeta1) / R_CNT * Npinv * Npinv;
+         }
+
+         dmoment12 = l2 % dforce12;
+         dmoment21 = l1 % dforce21;
+
+         U += dU;
+         force12 += dforce12;
+         force21 += dforce21;
+         moment12 += dmoment12;
+         moment21 += dmoment21;
+      }
+   }
+
+   addForceAtomic(p_idx1, ac, force12);
+   addForceAtomic(p_idx2, ac, force21);
+   addTorqueAtomic(p_idx1, ac,  -moment21);
+   addTorqueAtomic(p_idx2, ac,  -moment12);
+
+   // Viscous addition
+   constexpr real_t dampFactor = 1052.0; // Calibrated in accordance with 2014 JAM
+   real_t damp = beta_ * dampFactor;
+   Vec3 relVelocity = ac.getLinearVel(p_idx1) - ac.getLinearVel(p_idx2);
+   Vec3 visc_force = -damp * relVelocity;
+   //WALBERLA_LOG_DEVEL( "Visc force: = " << visc_force );
+   addForceAtomic(p_idx1, ac,  visc_force);
+   addForceAtomic(p_idx2, ac, -visc_force);
+
+   return U; // vdW adhesion energy
+}
+
+} //namespace VBondModel
+} //namespace kernel
+} //namespace mesa_pd
+} //namespace walberla
\ No newline at end of file
diff --git a/tests/mesa_pd/CMakeLists.txt b/tests/mesa_pd/CMakeLists.txt
index ad034a098..8c4dce129 100644
--- a/tests/mesa_pd/CMakeLists.txt
+++ b/tests/mesa_pd/CMakeLists.txt
@@ -158,6 +158,9 @@ waLBerla_execute_test( NAME   MESA_PD_Kernel_SyncNextNeighborsBlockForest PROCES
 waLBerla_compile_test( NAME   MESA_PD_Kernel_TemperatureIntegration FILES kernel/TemperatureIntegration.cpp DEPENDS core )
 waLBerla_execute_test( NAME   MESA_PD_Kernel_TemperatureIntegration )
 
+waLBerla_compile_test( NAME   MESA_PD_Kernel_VBondModel_IntegratedVDWContact FILES kernel/VBondModel/IntegratedVDWContact.test.cpp DEPENDS core )
+waLBerla_execute_test( NAME   MESA_PD_Kernel_VBondModel_IntegratedVDWContact )
+
 waLBerla_compile_test( NAME   MESA_PD_Kernel_VelocityVerlet FILES kernel/VelocityVerlet.cpp DEPENDS core )
 waLBerla_execute_test( NAME   MESA_PD_Kernel_VelocityVerlet )
 
diff --git a/tests/mesa_pd/kernel/VBondModel/IntegratedVDWContact.test.cpp b/tests/mesa_pd/kernel/VBondModel/IntegratedVDWContact.test.cpp
new file mode 100644
index 000000000..9f1251cf0
--- /dev/null
+++ b/tests/mesa_pd/kernel/VBondModel/IntegratedVDWContact.test.cpp
@@ -0,0 +1,80 @@
+//======================================================================================================================
+//
+//  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
+//! \author Igor Ostanin <i.ostanin@skoltech.ru>
+//! \author Grigorii Drozdov <drozd013@umn.edu>
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+#include <mesa_pd/data/ParticleAccessor.h>
+#include <mesa_pd/data/ParticleStorage.h>
+
+#include <mesa_pd/kernel/VBondModel/IntegratedVDWContact.h>
+
+#include <core/Environment.h>
+#include <core/logging/Logging.h>
+
+#include <iostream>
+
+namespace walberla {
+namespace mesa_pd {
+
+int main( int argc, char ** argv )
+{
+   Environment env(argc, argv);
+   WALBERLA_UNUSED(env);
+   mpi::MPIManager::instance()->useWorldComm();
+
+   if (std::is_same<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);
+
+   data::Particle&& p1        = *ps->create();
+   p1.getPositionRef()        = Vec3(0,0,0);
+   p1.getForceRef()           = Vec3(0,0,0);
+   p1.getTypeRef()            = 0;
+
+   data::Particle&& p2        = *ps->create();
+   p2.getPositionRef()        = Vec3(0,0,0);
+   p2.getForceRef()           = Vec3(0,0,0);
+   p2.getTypeRef()            = 0;
+
+   data::ParticleAccessor accessor(ps);
+
+   //init kernels
+   kernel::VBondModel::IntegratedVDWContact vdWContact;
+
+   //check equilibrium distance
+   vdWContact(0, 1, accessor);
+   WALBERLA_CHECK_FLOAT_EQUAL( p1.getForce(), Vec3(0,0,0) );
+   WALBERLA_CHECK_FLOAT_EQUAL( p2.getForce(), Vec3(0,0,0) );
+
+   return EXIT_SUCCESS;
+}
+
+} //namespace mesa_pd
+} //namespace walberla
+
+int main( int argc, char ** argv )
+{
+   return walberla::mesa_pd::main(argc, argv);
+}
-- 
GitLab