From 5b53ddcd38470d94374ad45272e9181683352823 Mon Sep 17 00:00:00 2001
From: Sebastian Eibl <sebastian.eibl@fau.de>
Date: Wed, 31 May 2017 17:07:04 +0200
Subject: [PATCH] made save/load block data work for pe

---
 src/pe/basic.h                         |  1 +
 src/pe/ccd/HashGrids.cpp               | 24 +++++++
 src/pe/ccd/HashGrids.h                 |  1 +
 src/pe/ccd/ICCD.h                      |  3 +-
 src/pe/rigidbody/StorageDataHandling.h | 25 ++++---
 src/pe/utility/CreateWorld.cpp         | 91 ++++++++++++++++++--------
 src/pe/utility/CreateWorld.h           |  8 +++
 tests/pe/CMakeLists.txt                |  3 +
 tests/pe/SerializeDeserialize.cpp      | 60 +++++++++--------
 9 files changed, 152 insertions(+), 64 deletions(-)

diff --git a/src/pe/basic.h b/src/pe/basic.h
index 874531d82..25bf84ca0 100644
--- a/src/pe/basic.h
+++ b/src/pe/basic.h
@@ -47,4 +47,5 @@
 #include "pe/synchronization/SyncNextNeighbors.h"
 #include "pe/synchronization/SyncShadowOwners.h"
 
+#include "pe/utility/CreateWorld.h"
 #include "pe/utility/GetBody.h"
diff --git a/src/pe/ccd/HashGrids.cpp b/src/pe/ccd/HashGrids.cpp
index b135767f8..e126e554d 100644
--- a/src/pe/ccd/HashGrids.cpp
+++ b/src/pe/ccd/HashGrids.cpp
@@ -746,6 +746,30 @@ void HashGrids::clear()
 }
 //*************************************************************************************************
 
+
+//*************************************************************************************************
+/*!\brief clears all bodies from the hash grid and reloads bodies from bodystorage and shadowbodystorage
+ *
+ * \return void
+ */
+void HashGrids::reloadBodies()
+{
+   clear();
+
+   for (auto bodyIt = bodystorage_.begin(); bodyIt != bodystorage_.end(); ++bodyIt)
+   {
+      add( *bodyIt );
+   }
+   if( &bodystorage_ != &bodystorageShadowCopies_ )
+   {
+      for (auto bodyIt = bodystorageShadowCopies_.begin(); bodyIt != bodystorageShadowCopies_.end(); ++bodyIt)
+      {
+         add( *bodyIt );
+      }
+   }
+}
+//*************************************************************************************************
+
 //**Implementation of ICCD interface ********************************************************
 //*************************************************************************************************
 /*!\brief Contact generation between colliding rigid bodies.
diff --git a/src/pe/ccd/HashGrids.h b/src/pe/ccd/HashGrids.h
index 442fabe37..060be9447 100644
--- a/src/pe/ccd/HashGrids.h
+++ b/src/pe/ccd/HashGrids.h
@@ -272,6 +272,7 @@ public:
    /*!\name Utility functions */
    //@{
           void clear       ();
+          void reloadBodies();
    //@}
    //**********************************************************************************************
 
diff --git a/src/pe/ccd/ICCD.h b/src/pe/ccd/ICCD.h
index cb4bf9759..d3922b5ed 100644
--- a/src/pe/ccd/ICCD.h
+++ b/src/pe/ccd/ICCD.h
@@ -38,7 +38,8 @@ public:
    virtual PossibleContacts& generatePossibleContacts( WcTimingTree* tt = NULL ) = 0;
    PossibleContacts& getPossibleContacts() {return contacts_;}
 
-   virtual int getObservedBodyCount() const = 0;
+   virtual void reloadBodies() {};
+   virtual int  getObservedBodyCount() const = 0;
 protected:
    PossibleContacts contacts_;
 };
diff --git a/src/pe/rigidbody/StorageDataHandling.h b/src/pe/rigidbody/StorageDataHandling.h
index 6e60e5f6f..e12df0494 100644
--- a/src/pe/rigidbody/StorageDataHandling.h
+++ b/src/pe/rigidbody/StorageDataHandling.h
@@ -29,6 +29,7 @@
 #include "pe/communication/DynamicMarshalling.h"
 
 #include "blockforest/BlockDataHandling.h"
+#include "core/Abort.h"
 
 namespace walberla{
 namespace pe{
@@ -37,14 +38,14 @@ namespace pe{
 template<typename BodyTuple>
 class StorageDataHandling : public domain_decomposition::BlockDataHandling<Storage>{
 public:
-    Storage * initialize( IBlock * const /*block*/ ) {return new Storage();}
-
-    /// must be thread-safe !
-    virtual inline void serialize( IBlock * const block, const BlockDataID & id, mpi::SendBuffer & buffer );
-    /// must be thread-safe !
-    virtual inline  Storage * deserialize( IBlock * const block );
-    /// must be thread-safe !
-    virtual inline void deserialize( IBlock * const block, const BlockDataID & id, mpi::RecvBuffer & buffer );
+   Storage * initialize( IBlock * const /*block*/ ) {return new Storage();}
+
+   /// must be thread-safe !
+   virtual inline void serialize( IBlock * const block, const BlockDataID & id, mpi::SendBuffer & buffer );
+   /// must be thread-safe !
+   virtual inline  Storage * deserialize( IBlock * const block );
+   /// must be thread-safe !
+   virtual inline void deserialize( IBlock * const block, const BlockDataID & id, mpi::RecvBuffer & buffer );
 };
 
 template<typename BodyTuple>
@@ -55,6 +56,10 @@ inline void StorageDataHandling<BodyTuple>::serialize( IBlock * const block, con
    buffer << localBodyStorage.size();
    for (auto bodyIt = localBodyStorage.begin(); bodyIt != localBodyStorage.end(); ++bodyIt)
    {
+      if ( !block->getAABB().contains( bodyIt->getPosition()) )
+      {
+         WALBERLA_ABORT( "Body to be stored not contained within block!" );
+      }
       marshal( buffer, RigidBodyCopyNotification( **bodyIt ) );
       MarshalDynamically<BodyTuple>::execute( buffer, **bodyIt );
    }
@@ -84,6 +89,10 @@ inline void StorageDataHandling<BodyTuple>::deserialize( IBlock * const block, c
       BodyID bd = UnmarshalDynamically<BodyTuple>::execute(buffer, objparam.geomType_, math::AABB(-inf, -inf, -inf, inf, inf, inf), block->getAABB());
       bd->setRemote( false );
 
+      if ( !block->getAABB().contains( bd->getPosition()) )
+      {
+         WALBERLA_ABORT("Loaded body not contained within block!" );
+      }
       WALBERLA_ASSERT_EQUAL(localBodyStorage.find( bd->getSystemID() ), localBodyStorage.end());
       localBodyStorage.add(bd);
 
diff --git a/src/pe/utility/CreateWorld.cpp b/src/pe/utility/CreateWorld.cpp
index 94a6854f4..35dc07984 100644
--- a/src/pe/utility/CreateWorld.cpp
+++ b/src/pe/utility/CreateWorld.cpp
@@ -14,7 +14,6 @@
 //  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
 //
 //! \file CreateWorld.cpp
-//! \author Klaus Iglberger
 //! \author Sebastian Eibl <sebastian.eibl@fau.de>
 //
 //======================================================================================================================
@@ -34,12 +33,10 @@
 namespace walberla {
 namespace pe {
 
-shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& mainConf)
+shared_ptr<BlockForest> createBlockForest(const math::AABB simulationDomain,
+                                          Vector3<uint_t> blocks,
+                                          const Vector3<bool> isPeriodic)
 {
-   math::AABB simulationDomain   = math::AABB( Vec3(0,0,0), mainConf.getParameter<Vec3>("simulationDomain", Vec3(10, 10, 10)));
-   Vector3<uint_t> blocks        = mainConf.getParameter<Vector3<uint_t>>("blocks", Vector3<uint_t>(3, 3, 3));
-   Vector3<bool> isPeriodic      = mainConf.getParameter<Vector3<bool>>("isPeriodic", Vector3<bool>(true, true, true));
-
    if (isPeriodic[0] && blocks[0]<2)
    {
       WALBERLA_LOG_WARNING_ON_ROOT( "To few blocks in periodic x direction (" << blocks[0] << ")! Setting to 2..." );
@@ -56,46 +53,61 @@ shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& m
       blocks[2] = 2;
    }
 
-//   const uint_t numberOfProcesses = blocks[0] * blocks[1] * blocks[2];
+   return blockforest::createBlockForest( simulationDomain,
+                                          blocks[0], blocks[1], blocks[2],
+         blocks[0], blocks[1], blocks[2],
+         isPeriodic[0],isPeriodic[1],isPeriodic[2],
+         false );
+}
 
-   if( !mainConf.isDefined( "sbfFile" ) )
+shared_ptr<BlockForest> createBlockForest(const math::AABB simulationDomain,
+                                          Vector3<uint_t> blocks,
+                                          const Vector3<bool> isPeriodic,
+                                          const bool setupRun,
+                                          const std::string sbffile)
+{
+   if (isPeriodic[0] && blocks[0]<2)
    {
-      WALBERLA_LOG_INFO_ON_ROOT( "No setup file specified: Creation without setup file!" );
-
-      return blockforest::createBlockForest( simulationDomain,
-                                             blocks[0], blocks[1], blocks[2],
-                                             blocks[0], blocks[1], blocks[2],
-                                             isPeriodic[0],isPeriodic[1],isPeriodic[2],
-                                             false );
+      WALBERLA_LOG_WARNING_ON_ROOT( "To few blocks in periodic x direction (" << blocks[0] << ")! Setting to 2..." );
+      blocks[0] = 2;
+   }
+   if (isPeriodic[1] && blocks[1]<2)
+   {
+      WALBERLA_LOG_WARNING_ON_ROOT( "To few blocks in periodic y direction (" << blocks[1] << ")! Setting to 2..." );
+      blocks[1] = 2;
+   }
+   if (isPeriodic[2] && blocks[2]<2)
+   {
+      WALBERLA_LOG_WARNING_ON_ROOT( "To few blocks in periodic z direction (" << blocks[2] << ")! Setting to 2..." );
+      blocks[2] = 2;
    }
 
-   // sbf file given -> try to load or save domain decomposition
-   std::string sbffile = mainConf.getParameter< std::string >( "sbfFile" );
    WALBERLA_LOG_INFO_ON_ROOT( "Setup file specified: Using " << sbffile );
 
-   bool setupRun = mainConf.getParameter< bool >( "setupRun", true );
    if (setupRun)
    {
-      WALBERLA_LOG_INFO_ON_ROOT("Setup run. For production run specify 'setupRun = true'");
+      WALBERLA_LOG_INFO_ON_ROOT("Setup run. For production run specify 'setupRun = false'");
 
       if( MPIManager::instance()->numProcesses() > 1 )
-         WALBERLA_ABORT( "In this mode you need to start with just one process!" );
+         WALBERLA_LOG_WARNING_ON_ROOT( "Setup run with more than one process! Only root is doing work! I hope you know what you are doing!" );
 
-      WALBERLA_LOG_INFO_ON_ROOT( "Creating the block structure ..." );
+      WALBERLA_ROOT_SECTION()
+      {
+         WALBERLA_LOG_INFO_ON_ROOT( "Creating the block structure ..." );
 
-      SetupBlockForest sforest;
+         SetupBlockForest sforest;
 
-      sforest.addWorkloadMemorySUIDAssignmentFunction( blockforest::uniformWorkloadAndMemoryAssignment );
+         sforest.addWorkloadMemorySUIDAssignmentFunction( blockforest::uniformWorkloadAndMemoryAssignment );
 
-      sforest.init( simulationDomain, blocks[0], blocks[1], blocks[2], isPeriodic[0], isPeriodic[1], isPeriodic[2] );
+         sforest.init( simulationDomain, blocks[0], blocks[1], blocks[2], isPeriodic[0], isPeriodic[1], isPeriodic[2] );
 
-      // calculate process distribution
+         // calculate process distribution
+         sforest.balanceLoad( blockforest::StaticLevelwiseCurveBalance(true), blocks[0] * blocks[1] * blocks[2] );
 
-      sforest.balanceLoad( blockforest::StaticLevelwiseCurveBalance(true), blocks[0] * blocks[1] * blocks[2] );
+         sforest.saveToFile( sbffile.c_str() );
 
-      sforest.saveToFile( sbffile.c_str() );
-
-      WALBERLA_LOG_INFO_ON_ROOT( "SetupBlockForest successfully saved to file!" )
+         WALBERLA_LOG_INFO_ON_ROOT( "SetupBlockForest successfully saved to file!" );
+      }
 
       return shared_ptr<BlockForest>();
    }
@@ -108,5 +120,26 @@ shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& m
    return shared_ptr< BlockForest >( new BlockForest( uint_c( MPIManager::instance()->rank() ), sbffile.c_str(), true, false ) );
 }
 
+shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& mainConf)
+{
+   math::AABB simulationDomain   = math::AABB( Vec3(0,0,0), mainConf.getParameter<Vec3>("simulationDomain", Vec3(10, 10, 10)));
+   Vector3<uint_t> blocks        = mainConf.getParameter<Vector3<uint_t>>("blocks", Vector3<uint_t>(3, 3, 3));
+   Vector3<bool> isPeriodic      = mainConf.getParameter<Vector3<bool>>("isPeriodic", Vector3<bool>(true, true, true));
+
+   if( !mainConf.isDefined( "sbfFile" ) )
+   {
+      WALBERLA_LOG_INFO_ON_ROOT( "No setup file specified: Creation without setup file!" );
+
+      return createBlockForest( simulationDomain, blocks, isPeriodic);
+   }
+
+   // sbf file given -> try to load or save domain decomposition
+   std::string sbffile = mainConf.getParameter< std::string >( "sbfFile" );
+   WALBERLA_LOG_INFO_ON_ROOT( "Setup file specified: Using " << sbffile );
+
+   bool setupRun = mainConf.getParameter< bool >( "setupRun", true );
+   return createBlockForest(simulationDomain, blocks, isPeriodic, setupRun, sbffile);
+}
+
 } // namespace pe
 } // namespace walberla
diff --git a/src/pe/utility/CreateWorld.h b/src/pe/utility/CreateWorld.h
index 20d5b3424..69842960e 100644
--- a/src/pe/utility/CreateWorld.h
+++ b/src/pe/utility/CreateWorld.h
@@ -31,6 +31,14 @@
 namespace walberla {
 namespace pe {
 
+shared_ptr<BlockForest> createBlockForest(const math::AABB simulationDomain,
+                                          Vector3<uint_t> blocks,
+                                          const Vector3<bool> isPeriodic);
+shared_ptr<BlockForest> createBlockForest(const math::AABB simulationDomain,
+                                          Vector3<uint_t> blocks,
+                                          const Vector3<bool> isPeriodic,
+                                          const bool setupRun,
+                                          const std::string sbffile);
 shared_ptr<BlockForest> createBlockForestFromConfig(const Config::BlockHandle& mainConf);
 
 } // namespace pe
diff --git a/tests/pe/CMakeLists.txt b/tests/pe/CMakeLists.txt
index bf6297265..40ff645e1 100644
--- a/tests/pe/CMakeLists.txt
+++ b/tests/pe/CMakeLists.txt
@@ -4,6 +4,9 @@
 #
 ###################################################################################################
 
+waLBerla_link_files_to_builddir( *.cfg )
+waLBerla_link_files_to_builddir( *.sbf )
+
 waLBerla_compile_test( NAME   PE_BODYFLAGS FILES BodyFlags.cpp DEPENDS core  )
 waLBerla_execute_test( NAME   PE_BODYFLAGS PROCESSES 8)
 
diff --git a/tests/pe/SerializeDeserialize.cpp b/tests/pe/SerializeDeserialize.cpp
index 6fb932c02..ae03c0f49 100644
--- a/tests/pe/SerializeDeserialize.cpp
+++ b/tests/pe/SerializeDeserialize.cpp
@@ -36,7 +36,6 @@
 
 using namespace walberla;
 using namespace walberla::pe;
-using namespace walberla::blockforest;
 
 typedef boost::tuple<Sphere> BodyTuple ;
 
@@ -44,22 +43,17 @@ void createDump()
 {
    using namespace walberla::grid_generator;
 
-   BodyStorage globalStorage;
+   shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
 
    // create blocks
-   shared_ptr< StructuredBlockForest > forest = blockforest::createUniformBlockGrid(
-            uint_c( 2), uint_c( 2), uint_c( 2), // 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)
-            real_c(10),                         // dx: length of one cell in physical coordinates
-            0,                                  // max blocks per process
-            false, false,                       // include metis / force metis
-            false, false, false );                 // full periodicity
+   auto forest = shared_ptr< BlockForest >( new BlockForest( uint_c( MPIManager::instance()->rank() ), "SerializeDeserialize.sbf", true, false ) );
 
-   BlockDataID storageID           = forest->addBlockData( createStorageDataHandling<BodyTuple>() );
+   auto storageID           = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
+   auto ccdID               = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD");
 
    for (auto it = SCIterator(forest->getDomain(), Vec3(-1,-1,-1), 3); it != SCIterator(); ++it)
    {
-      createSphere( globalStorage, forest->getBlockStorage(), storageID, 0, *it, 1);
+      createSphere( *globalBodyStorage, *forest, storageID, 0, *it, 1);
    }
 
    WALBERLA_LOG_DEVEL_ON_ROOT("dumping body storage");
@@ -68,9 +62,11 @@ void createDump()
    for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
    {
       BodyStorage& localStorage = (*(blockIt->getData< Storage >( storageID )))[0];
-      WALBERLA_LOG_DEVEL("DUMPING BLOCK");
-      WALBERLA_LOG_DEVEL("aabb: " << blockIt->getAABB());
+      WALBERLA_LOG_DEVEL("DUMPING BLOCK (" << blockIt->getId() << ") " << blockIt->getAABB() );
       WALBERLA_LOG_DEVEL("#bodies: " << localStorage.size());
+
+      ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID );
+      WALBERLA_CHECK_EQUAL( ccd->getObservedBodyCount(), 1000 );
    }
 }
 
@@ -78,33 +74,34 @@ void checkDump()
 {
    using namespace walberla::grid_generator;
 
-//   BodyStorage globalStorage;
+   shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
 
    // create blocks
-   shared_ptr< StructuredBlockForest > forest = blockforest::createUniformBlockGrid(
-            uint_c( 2), uint_c( 2), uint_c( 2), // 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)
-            real_c(10),                         // dx: length of one cell in physical coordinates
-            0,                                  // max blocks per process
-            false, false,                       // include metis / force metis
-            false, false, false );                 // full periodicity
-
+   auto forest = shared_ptr< BlockForest >( new BlockForest( uint_c( MPIManager::instance()->rank() ), "SerializeDeserialize.sbf", true, false ) );
 
+   auto storageID    = forest->loadBlockData("BodyStorageDump.dump", createStorageDataHandling<BodyTuple>(), "Storage");
+   auto ccdID        = forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "CCD");
 
-   BlockDataID storageID = forest->loadBlockData("BodyStorageDump.dump", createStorageDataHandling<BodyTuple>());
+   for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
+   {
+      ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID );
+      ccd->reloadBodies();
+   }
 
    for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
    {
+      ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID );
+      WALBERLA_CHECK_EQUAL( ccd->getObservedBodyCount(), 1000 );
+
       BodyStorage& localStorage = (*(blockIt->getData< Storage >( storageID )))[0];
-      WALBERLA_LOG_DEVEL("CHECKING BLOCK");
-      WALBERLA_LOG_DEVEL("aabb: " << blockIt->getAABB());
+      WALBERLA_LOG_DEVEL("CHECKING BLOCK (" << blockIt->getId() << ") " << blockIt->getAABB() );
       WALBERLA_LOG_DEVEL("#bodies: " << localStorage.size());
       auto bodyIt = LocalBodyIterator::begin(*blockIt, storageID);
       for (auto it = SCIterator(forest->getDomain(), Vec3(-1,-1,-1), 3); it != SCIterator(); ++it)
       {
          if (blockIt->getAABB().contains(*it))
          {
-            WALBERLA_CHECK_FLOAT_EQUAL( bodyIt->getPosition(), *it);
+            WALBERLA_CHECK_FLOAT_EQUAL( bodyIt->getPosition(), *it, blockIt->getAABB());
             ++bodyIt;
          }
       }
@@ -116,10 +113,21 @@ int main( int argc, char ** argv )
    walberla::debug::enterTestMode();
 
    walberla::MPIManager::instance()->initializeMPI( &argc, &argv );
+   MPIManager::instance()->useWorldComm();
 
    SetBodyTypeIDs<BodyTuple>::execute();
 
+//   save SetupBlockForest, if you want to do that run with only one process
+   createBlockForest( math::AABB(0,0,0,60,60,60),
+                      Vector3<uint_t>(2,2,2),                   // number of blocks
+                      Vector3<bool>(false, false, false),       // periodicity
+                      true,                                     // setup run?
+                      "SerializeDeserialize.sbf" );             // sbf filename
+
+   WALBERLA_LOG_DEVEL_ON_ROOT("*** DUMPING ***");
    createDump();
+   WALBERLA_MPI_BARRIER();
+   WALBERLA_LOG_DEVEL_ON_ROOT("*** CHECKING ***");
    checkDump();
 
    return EXIT_SUCCESS;
-- 
GitLab