diff --git a/apps/benchmarks/CMakeLists.txt b/apps/benchmarks/CMakeLists.txt
index a81420b475e6378a3f453ebd4ae16c2c0c895e8d..31e6417ae85f60488e8938511b4db0a2f2533af2 100644
--- a/apps/benchmarks/CMakeLists.txt
+++ b/apps/benchmarks/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_subdirectory( ComplexGeometry )
+add_subdirectory( DEM )
 add_subdirectory( MeshDistance )
 add_subdirectory( CouetteFlow )
 add_subdirectory( ForcesOnSphereNearPlaneInShearFlow )
diff --git a/apps/benchmarks/DEM/CMakeLists.txt b/apps/benchmarks/DEM/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..138e92026d74c900b1f25cd172cef82de1b2bff2
--- /dev/null
+++ b/apps/benchmarks/DEM/CMakeLists.txt
@@ -0,0 +1 @@
+waLBerla_add_executable( NAME DEM FILES DEM.cpp DEPENDS blockforest core pe )
diff --git a/apps/benchmarks/DEM/DEM.cpp b/apps/benchmarks/DEM/DEM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..52b6e856a4fb47403d3fb0e9db448c3b1756e460
--- /dev/null
+++ b/apps/benchmarks/DEM/DEM.cpp
@@ -0,0 +1,153 @@
+//======================================================================================================================
+//
+//  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 DEM.cpp
+//! \brief demonstration of basic functionality of DEM
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+#include "pe/basic.h"
+
+#include <blockforest/Initialization.h>
+#include <core/DataTypes.h>
+
+#include <string>
+
+namespace walberla {
+
+namespace dem {
+real_t calcCoefficientOfRestitution(const real_t k, const real_t gamma, const real_t meff)
+{
+   auto a = real_t(0.5) * gamma / meff;
+   return std::exp(-a * math::PI / std::sqrt(k / meff - a*a));
+}
+
+real_t calcCollisionTime(const real_t k, const real_t gamma, const real_t meff)
+{
+   auto a = real_t(0.5) * gamma / meff;
+   return math::PI / std::sqrt( k/meff - a*a);
+}
+}
+
+int main( int argc, char** argv )
+{
+   using namespace walberla;
+   using namespace walberla::pe;
+
+   typedef boost::tuple<Sphere, Plane> BodyTuple ;
+
+   walberla::MPIManager::instance()->initializeMPI( &argc, &argv );
+
+   real_t dt         = real_c(0.0001);                                  //!< integration time
+   real_t radius     = real_c(1);                                       //!< particle radius
+   real_t density    = real_c(2707);                                    //!< particle density
+   real_t m          = Sphere::calcMass( radius, density);              //!< particle mass
+   std::string model = "kg";                                            //!< input model
+   real_t k          = real_c(8.11e6);                                  //!< linear spring stiffness
+   real_t gamma      = real_c(6.86e1);                                  //!< damper
+   real_t e          = dem::calcCoefficientOfRestitution(k, gamma, m);  //!< coefficient of restitution
+   real_t t          = dem::calcCollisionTime(k, gamma, m);             //!< collision time
+
+   for( int i = 1; i < argc; ++i )
+   {
+      if( std::strcmp( argv[i], "-dt" )                      == 0 ) dt      = real_c( std::stod( argv[++i] ) );
+      else if( std::strcmp( argv[i], "-radius" )             == 0 ) radius  = real_c( std::stod( argv[++i] ) );
+      else if( std::strcmp( argv[i], "-density" )            == 0 ) density = real_c( std::stod( argv[++i] ) );
+      else if( std::strcmp( argv[i], "-kg" )                 == 0 )
+      {
+         k     = real_c( std::stod( argv[++i] ) );
+         gamma = real_c( std::stod( argv[++i] ) );
+         model = "kg";
+      }
+      else if( std::strcmp( argv[i], "-et" )                 == 0 )
+      {
+         e = real_c( std::atof( argv[++i] ) );
+         t = real_c( std::atof( argv[++i] ) );
+         model = "et";
+      }
+      else WALBERLA_ABORT("Found invalid command line argument: \"" << argv[i] << "\" - aborting...");
+   }
+
+   m          = Sphere::calcMass( radius, density);
+   if (model=="kg")
+   {
+      e          = dem::calcCoefficientOfRestitution(k, gamma, m);  //!< coefficient of restitution
+      t          = dem::calcCollisionTime(k, gamma, m);             //!< collision time
+   } else
+      WALBERLA_ABORT("unsupported model");
+
+   shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
+
+   // create blocks
+   shared_ptr< StructuredBlockForest > forest = blockforest::createUniformBlockGrid(
+                                                   math::AABB(-5,-5,0,5,5,10),
+                                                   uint_c( 1), uint_c( 1), uint_c( 1), // number of blocks in x,y,z direction
+                                                   uint_c( 1), uint_c( 1), uint_c( 1), // how many cells per block (x,y,z)
+                                                   true,                               // max blocks per process
+                                                   false, false, false,                // full periodicity
+                                                   false);
+
+   SetBodyTypeIDs<BodyTuple>::execute();
+
+   auto storageID           = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
+   auto hccdID              = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "HCCD");
+   auto fcdID               = forest->addBlockData(fcd::createGenericFCDDataHandling<BodyTuple, fcd::AnalyticCollideFunctor>(), "FCD");
+   cr::DEM cr(globalBodyStorage, forest->getBlockStoragePointer(), storageID, hccdID, fcdID);
+
+   const real_t   static_cof  ( real_t(0.4) / real_t(2) );    // Coefficient of static friction. Roughly 0.85 with high variation depending on surface roughness for low stresses. Note: pe doubles the input coefficient of friction for material-material contacts.
+   const real_t   dynamic_cof ( static_cof ); // Coefficient of dynamic friction. Similar to static friction for low speed friction.
+   MaterialID material = createMaterial( "granular", density, e, static_cof, dynamic_cof, real_t( 0.5 ), 1, k, gamma, 0 );
+
+   pe::createPlane( *globalBodyStorage, 0, Vec3(0, 0, 1), forest->getDomain().minCorner(), material );
+
+   SphereID sp = pe::createSphere(
+                    *globalBodyStorage,
+                    forest->getBlockStorage(),
+                    storageID,
+                    999999999,
+                    Vec3(0,0,1),
+                    real_c(1.0),
+                    material);
+   WALBERLA_CHECK_NOT_NULLPTR(sp);
+   sp->setLinearVel( Vec3(0,0,-1) );
+
+   uint_t steps = 0;
+   do
+   {
+      cr.timestep( dt );
+      ++steps;
+   } while (cr.getNumberOfContacts() != 0);
+
+   WALBERLA_LOG_RESULT(std::setw(30) << "steps: "                      << steps );
+   WALBERLA_LOG_RESULT(std::setw(30) << "final velocity: "             << sp->getLinearVel()[2]);
+   WALBERLA_LOG_RESULT(std::setw(30) << "final position: "             << sp->getPosition()[2]);
+   WALBERLA_LOG_RESULT(std::setw(30) << "integration time: "           << dt);
+   WALBERLA_LOG_RESULT(std::setw(30) << "particle radius: "            << radius);
+   WALBERLA_LOG_RESULT(std::setw(30) << "particle density: "           << density);
+   WALBERLA_LOG_RESULT(std::setw(30) << "particle mass: "              << m);
+   WALBERLA_LOG_RESULT(std::setw(30) << "linear spring stiffness: "    << k);
+   WALBERLA_LOG_RESULT(std::setw(30) << "damper: "                     << gamma);
+   WALBERLA_LOG_RESULT(std::setw(30) << "coefficient of restitution: " << e);
+   WALBERLA_LOG_RESULT(std::setw(30) << "collision time: "             << t);
+
+   return EXIT_SUCCESS;
+}
+}
+
+int main( int argc, char** argv )
+{
+   return walberla::main(argc, argv);
+}