From 18ef0878dfa9b9ad3b49ef8823e0e39b2dea7c9f Mon Sep 17 00:00:00 2001
From: Sebastian Eibl <sebastian.eibl@fau.de>
Date: Thu, 21 Dec 2017 12:56:23 +0100
Subject: [PATCH] refinement tests for pe

---
 tests/pe/CMakeLists.txt        |   6 +
 tests/pe/DynamicRefinement.cpp | 195 +++++++++++++++++++++++++++++++
 tests/pe/MinMaxRefinement.cpp  | 203 +++++++++++++++++++++++++++++++++
 3 files changed, 404 insertions(+)
 create mode 100644 tests/pe/DynamicRefinement.cpp
 create mode 100644 tests/pe/MinMaxRefinement.cpp

diff --git a/tests/pe/CMakeLists.txt b/tests/pe/CMakeLists.txt
index 940099119..8268c9a15 100644
--- a/tests/pe/CMakeLists.txt
+++ b/tests/pe/CMakeLists.txt
@@ -35,6 +35,9 @@ waLBerla_execute_test( NAME   PE_DESTROYBODY )
 waLBerla_compile_test( NAME   PE_DOCUMENTATIONSNIPPETS FILES PeDocumentationSnippets.cpp DEPENDS core  )
 waLBerla_execute_test( NAME   PE_DOCUMENTATIONSNIPPETS )
 
+waLBerla_compile_test( NAME   PE_DYNAMICREFINEMENT FILES DynamicRefinement.cpp DEPENDS core blockforest  )
+waLBerla_execute_test( NAME   PE_DYNAMICREFINEMENT )
+
 waLBerla_compile_test( NAME   PE_FORCESYNC FILES ForceSync.cpp DEPENDS core blockforest  )
 waLBerla_execute_test( NAME   PE_FORCESYNC )
 
@@ -54,6 +57,9 @@ waLBerla_execute_test( NAME   PE_MARSHALLING )
 waLBerla_compile_test( NAME   PE_MATERIAL FILES Material.cpp DEPENDS core  )
 waLBerla_execute_test( NAME   PE_MATERIAL )
 
+waLBerla_compile_test( NAME   PE_MINMAXREFINEMENT FILES MinMaxRefinement.cpp DEPENDS core blockforest  )
+waLBerla_execute_test( NAME   PE_MINMAXREFINEMENT PROCESSES 8 )
+
 waLBerla_compile_test( NAME   PE_OVERLAP FILES Overlap.cpp DEPENDS core  )
 waLBerla_execute_test( NAME   PE_OVERLAP )
 
diff --git a/tests/pe/DynamicRefinement.cpp b/tests/pe/DynamicRefinement.cpp
new file mode 100644
index 000000000..0b6e0b469
--- /dev/null
+++ b/tests/pe/DynamicRefinement.cpp
@@ -0,0 +1,195 @@
+//======================================================================================================================
+//
+//  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 DynamicRefinement.cpp
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+#include "pe/basic.h"
+#include "pe/synchronization/ClearSynchronization.h"
+#include "pe/utility/GetBody.h"
+#include "pe/utility/DestroyBody.h"
+
+#include "blockforest/Initialization.h"
+#include "core/all.h"
+#include "domain_decomposition/all.h"
+
+#include "core/debug/TestSubsystem.h"
+
+using namespace walberla;
+using namespace walberla::pe;
+
+typedef boost::tuple<Sphere> BodyTuple ;
+
+class ReGrid
+{
+public:
+
+   ReGrid( const BlockDataID storageID, const size_t minParticles, const size_t maxParticles) :
+      storageID_( storageID ), minParticles_(minParticles), maxParticles_(maxParticles)
+   {}
+
+   void operator()( std::vector< std::pair< const Block *, uint_t > > & minTargetLevels,
+                    std::vector< const Block * > &, const BlockForest & forest );
+
+private:
+   const BlockDataID storageID_;
+   const size_t      minParticles_;
+   const size_t      maxParticles_;
+};
+
+void ReGrid::operator()( std::vector< std::pair< const Block *, uint_t > > & minTargetLevels,
+                         std::vector< const Block * > &, const BlockForest & /*forest*/ )
+{
+   for( auto it = minTargetLevels.begin(); it != minTargetLevels.end(); ++it )
+   {
+      const auto numberOfParticles = (*(it->first->getData< Storage >( storageID_ )))[0].size();
+      //WALBERLA_LOG_DEVEL("storage size: " << localBodyStorage.size());
+
+      it->second = it->first->getLevel(); //keep everything as it is
+      if (numberOfParticles < minParticles_)
+      {
+         WALBERLA_LOG_DEVEL(it->first->getLevel() << " -> " << it->first->getLevel() - uint_t(1) << " (" << numberOfParticles << ")" );
+         if (it->first->getLevel() > 0)
+            it->second = it->first->getLevel() - uint_t(1);
+      } else if (numberOfParticles > maxParticles_)
+      {
+         it->second = it->first->getLevel() + uint_t(1);
+         WALBERLA_LOG_DEVEL(it->first->getLevel() << " -> " << it->first->getLevel() + uint_t(1) << " (" << numberOfParticles << ")" );
+      }
+   }
+}
+
+int main( int argc, char** argv )
+{
+   walberla::debug::enterTestMode();
+   walberla::MPIManager::instance()->initializeMPI( &argc, &argv );
+
+   shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
+
+   // create blocks
+   shared_ptr< StructuredBlockForest > forest = blockforest::createUniformBlockGrid(
+            math::AABB(0,0,0,20,20,20),
+            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)
+            false,                              // max blocks per process
+            false, false, false,                // full periodicity
+            false);
+
+   SetBodyTypeIDs<BodyTuple>::execute();
+
+   auto storageID           = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
+   forest->addBlockData(ccd::createHashGridsDataHandling( globalBodyStorage, storageID ), "HCCD");
+   forest->addBlockData(fcd::createGenericFCDDataHandling<BodyTuple, fcd::AnalyticCollideFunctor>(), "FCD");
+
+   auto & blockforest = forest->getBlockForest();
+   blockforest.recalculateBlockLevelsInRefresh( true );
+   blockforest.alwaysRebalanceInRefresh( false );
+   blockforest.reevaluateMinTargetLevelsAfterForcedRefinement( false );
+   blockforest.allowRefreshChangingDepth( true );
+
+   blockforest.allowMultipleRefreshCycles( false );
+   blockforest.checkForEarlyOutInRefresh( true );
+   blockforest.checkForLateOutInRefresh( true );
+
+   ReGrid regrid( storageID, 20, 20 );
+
+   blockforest.setRefreshMinTargetLevelDeterminationFunction( regrid );
+
+   blockforest.setRefreshPhantomBlockMigrationPreparationFunction(
+            blockforest::DynamicLevelwiseCurveBalance< blockforest::NoPhantomData >( true, true ) );
+
+   real_t spacing(2.5);
+   for (auto blkIt = forest->begin(); blkIt != forest->end(); ++blkIt)
+   {
+      IBlock & currentBlock = *blkIt;
+      for (auto it = grid_generator::SCIterator(currentBlock.getAABB(), Vector3<real_t>(spacing) * real_t(0.5), spacing); it != grid_generator::SCIterator(); ++it)
+      {
+         createSphere( *globalBodyStorage, forest->getBlockStorage(), storageID, 0, *it, 1 );
+      }
+   }
+   syncNextNeighbors<BodyTuple>(forest->getBlockForest(), storageID);
+   syncNextNeighbors<BodyTuple>(forest->getBlockForest(), storageID);
+
+   clearSynchronization( forest->getBlockForest(), storageID );
+   forest->refresh();
+   syncNextNeighbors<BodyTuple>(forest->getBlockForest(), storageID);
+
+   WALBERLA_ASSERT_EQUAL( forest->size(), 8 );
+   for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
+   {
+//      IBlock & currentBlock = *blockIt;
+//      Storage * storage = currentBlock.getData< Storage >( storageID );
+//      BodyStorage& localStorage = (*storage)[0];
+//      BodyStorage& shadowStorage = (*storage)[1];
+
+      for (auto bodyIt = LocalBodyIterator::begin(*blockIt, storageID); bodyIt != LocalBodyIterator::end(); ++bodyIt)
+      {
+         WALBERLA_ASSERT( blockIt->getAABB().contains(bodyIt->getPosition()) );
+
+//         WALBERLA_LOG_DEVEL( blockIt->getAABB() );
+//         WALBERLA_LOG_DEVEL(*bodyIt );
+      }
+   }
+
+   WALBERLA_LOG_DEVEL("========================================================");
+
+   clearSynchronization( forest->getBlockForest(), storageID );
+   forest->refresh();
+   syncNextNeighbors<BodyTuple>(forest->getBlockForest(), storageID);
+
+   WALBERLA_ASSERT_EQUAL( forest->size(), 64 );
+   for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
+   {
+//      IBlock & currentBlock = *blockIt;
+//      Storage * storage = currentBlock.getData< Storage >( storageID );
+//      BodyStorage& localStorage = (*storage)[0];
+//      BodyStorage& shadowStorage = (*storage)[1];
+
+      for (auto bodyIt = LocalBodyIterator::begin(*blockIt, storageID); bodyIt != LocalBodyIterator::end(); ++bodyIt)
+      {
+         WALBERLA_ASSERT( blockIt->getAABB().contains(bodyIt->getPosition()) );
+
+//         WALBERLA_LOG_DEVEL( blockIt->getAABB() );
+//         WALBERLA_LOG_DEVEL(*bodyIt );
+      }
+   }
+
+   WALBERLA_LOG_DEVEL("========================================================");
+
+   clearSynchronization( forest->getBlockForest(), storageID );
+   forest->refresh();
+   syncNextNeighbors<BodyTuple>(forest->getBlockForest(), storageID);
+
+   WALBERLA_ASSERT_EQUAL( forest->size(), 8 );
+   for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
+   {
+//      IBlock & currentBlock = *blockIt;
+//      Storage * storage = currentBlock.getData< Storage >( storageID );
+//      BodyStorage& localStorage = (*storage)[0];
+//      BodyStorage& shadowStorage = (*storage)[1];
+
+      for (auto bodyIt = LocalBodyIterator::begin(*blockIt, storageID); bodyIt != LocalBodyIterator::end(); ++bodyIt)
+      {
+         WALBERLA_ASSERT( blockIt->getAABB().contains(bodyIt->getPosition()) );
+
+//         WALBERLA_LOG_DEVEL( blockIt->getAABB() );
+//         WALBERLA_LOG_DEVEL(*bodyIt );
+      }
+   }
+
+   return EXIT_SUCCESS;
+}
diff --git a/tests/pe/MinMaxRefinement.cpp b/tests/pe/MinMaxRefinement.cpp
new file mode 100644
index 000000000..458052c0e
--- /dev/null
+++ b/tests/pe/MinMaxRefinement.cpp
@@ -0,0 +1,203 @@
+//======================================================================================================================
+//
+//  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 Refinement.cpp
+//! \author Sebastian Eibl <sebastian.eibl@fau.de>
+//
+//======================================================================================================================
+
+
+#include "blockforest/all.h"
+#include <blockforest/loadbalancing/PODPhantomData.h>
+#include "core/all.h"
+#include "domain_decomposition/all.h"
+#include "timeloop/SweepTimeloop.h"
+#include "vtk/VTKOutput.h"
+
+
+#include "pe/basic.h"
+#include "pe/amr/InfoCollection.h"
+#include "pe/amr/regrid/RegridMinMax.h"
+#include "pe/amr/weight_assignment/WeightAssignmentFunctor.h"
+#include "pe/ccd/SimpleCCDDataHandling.h"
+#include "pe/synchronization/SyncNextNeighbors.h"
+#include "pe/synchronization/ClearSynchronization.h"
+#include "pe/vtk/BodyVtkOutput.h"
+#include "pe/vtk/SphereVtkOutput.h"
+
+#include "CheckVitalParameters.h"
+
+#include "core/debug/TestSubsystem.h"
+
+#include <boost/tuple/tuple.hpp>
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+using namespace walberla;
+using namespace walberla::pe;
+
+typedef boost::tuple<Sphere, Plane> BodyTuple ;
+
+int main( int argc, char ** argv )
+{
+   using namespace walberla::pe;
+
+   debug::enterTestMode();
+
+   walberla::MPIManager::instance()->initializeMPI( &argc, &argv );
+
+   //      logging::Logging::instance()->setStreamLogLevel( logging::Logging::DETAIL );
+   //   logging::Logging::instance()->setFileLogLevel( logging::Logging::DETAIL );
+   //   logging::Logging::instance()->includeLoggingToFile("SyncLog");
+
+   shared_ptr<BodyStorage> globalStorage = make_shared<BodyStorage>();
+
+   // create forest
+   shared_ptr< blockforest::StructuredBlockForest > forest = blockforest::createUniformBlockGrid(
+            math::AABB(0,0,0,4,4,4),
+            1,1,1,                                                 // number of blocks in x,y,z direction
+            1,1,1,                                                  // how many cells per block (x,y,z)
+            0,                                                      // max blocks per process
+            false, false,                                           // include metis / force metis
+            false, false, false );                                    // full periodicity
+
+   SetBodyTypeIDs<BodyTuple>::execute();
+
+   auto storageID           = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
+   auto ccdID               = forest->addBlockData(ccd::createHashGridsDataHandling( globalStorage, storageID ), "CCD");
+   auto fcdID               = forest->addBlockData(fcd::createGenericFCDDataHandling<BodyTuple, fcd::AnalyticCollideFunctor>(), "FCD");
+   WALBERLA_UNUSED(fcdID);
+
+   auto & blockforest = forest->getBlockForest();
+
+   //***** SETUP LOADBALACING & REFINEMENT
+   blockforest.recalculateBlockLevelsInRefresh( true );
+   blockforest.alwaysRebalanceInRefresh( true );
+   blockforest.reevaluateMinTargetLevelsAfterForcedRefinement( false );
+   blockforest.allowRefreshChangingDepth( true );
+
+   blockforest.allowMultipleRefreshCycles( false );
+   blockforest.checkForEarlyOutInRefresh( true );
+   blockforest.checkForLateOutInRefresh( true );
+
+   auto infoCollection = make_shared<InfoCollection>();
+
+   amr::ReGridMinMax regrid(infoCollection, 2, 5);
+   blockforest.setRefreshMinTargetLevelDeterminationFunction( regrid );
+
+   blockforest.setRefreshPhantomBlockDataAssignmentFunction( amr::WeightAssignmentFunctor( infoCollection ) );
+   blockforest.setRefreshPhantomBlockDataPackFunction( amr::WeightAssignmentFunctor::PhantomBlockWeightPackUnpackFunctor() );
+   blockforest.setRefreshPhantomBlockDataUnpackFunction( amr::WeightAssignmentFunctor::PhantomBlockWeightPackUnpackFunctor() );
+
+   blockforest.setRefreshPhantomBlockMigrationPreparationFunction(
+            blockforest::DynamicLevelwiseCurveBalance< amr::WeightAssignmentFunctor::PhantomBlockWeight >( false, true, false ) );
+
+   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(1,1,1), 1);
+   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(1,1,3), 1);
+   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(1,3,1), 1);
+   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(1,3,3), 1);
+   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(3,1,1), 1);
+   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(3,1,3), 1);
+   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(3,3,1), 1);
+   createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(3,3,3), 1);
+
+   WALBERLA_MPI_BARRIER();
+   WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 1" );
+   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   clearSynchronization( blockforest, storageID);
+   forest->refresh();
+   syncNextNeighbors<BodyTuple>(blockforest, storageID);
+
+   for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
+   {
+      ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID );
+      ccd->reloadBodies();
+   }
+
+   WALBERLA_CHECK_EQUAL( blockforest.size(), 1);
+
+   WALBERLA_MPI_BARRIER();
+   WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 2" );
+   blockforest.setRefreshMinTargetLevelDeterminationFunction( amr::ReGridMinMax(infoCollection, 9, 20) );
+   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   clearSynchronization( blockforest, storageID);
+   forest->refresh();
+   syncNextNeighbors<BodyTuple>(blockforest, storageID);
+
+   for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
+   {
+      ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID );
+      ccd->reloadBodies();
+   }
+
+   WALBERLA_CHECK_EQUAL( blockforest.size(), mpi::MPIManager::instance()->worldRank() == 6 ? 1 : 0);
+   WALBERLA_LOG_DEVEL( infoCollection->size() );
+
+   for (unsigned int i = 0; i < 30; ++i)
+   {
+      createSphere(*globalStorage.get(), forest->getBlockStorage(), storageID, 0, Vec3(real_t(2.1), real_t(2.1), real_t(2.1)), 1);
+   }
+
+   WALBERLA_MPI_BARRIER();
+   WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 3" );
+   blockforest.setRefreshMinTargetLevelDeterminationFunction( amr::ReGridMinMax(infoCollection, 2, 3) );
+   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   clearSynchronization( blockforest, storageID);
+   forest->refresh();
+   syncNextNeighbors<BodyTuple>(blockforest, storageID);
+
+   for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
+   {
+      ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID );
+      ccd->reloadBodies();
+   }
+
+   WALBERLA_LOG_DEVEL( infoCollection->size() );
+
+   WALBERLA_MPI_BARRIER();
+   WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 4" );
+   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   clearSynchronization( blockforest, storageID);
+   forest->refresh();
+   syncNextNeighbors<BodyTuple>(blockforest, storageID);
+
+   for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
+   {
+      ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID );
+      ccd->reloadBodies();
+   }
+
+   WALBERLA_LOG_DEVEL( infoCollection->size() );
+
+   WALBERLA_MPI_BARRIER();
+   WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 5" );
+   WALBERLA_LOG_DEVEL( "SIZE: " << blockforest.size() );
+   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   clearSynchronization( blockforest, storageID);
+   forest->refresh();
+   syncNextNeighbors<BodyTuple>(blockforest, storageID);
+
+   for (auto blockIt = forest->begin(); blockIt != forest->end(); ++blockIt)
+   {
+      ccd::ICCD* ccd = blockIt->getData< ccd::ICCD >( ccdID );
+      ccd->reloadBodies();
+   }
+
+   WALBERLA_LOG_DEVEL( infoCollection->size() );
+
+   return EXIT_SUCCESS;
+}
-- 
GitLab