diff --git a/apps/benchmarks/AdaptiveMeshRefinementFluidParticleCoupling/AMRSedimentSettling.cpp b/apps/benchmarks/AdaptiveMeshRefinementFluidParticleCoupling/AMRSedimentSettling.cpp
index 3bb791552152d802519ea2f321309a14c696f147..8012ac89d0558c02cee7e8224c2eadd5d7f6c820 100644
--- a/apps/benchmarks/AdaptiveMeshRefinementFluidParticleCoupling/AMRSedimentSettling.cpp
+++ b/apps/benchmarks/AdaptiveMeshRefinementFluidParticleCoupling/AMRSedimentSettling.cpp
@@ -820,7 +820,7 @@ real_t weightEvaluation(BlockForest & forest,
       }else if(loadEvaluationStrategy == "PE")
       {
          auto infoIt = peInfoCollection->find( blockID );
-         weight += real_c(infoIt->second.numberOfLocalBodies) + peBlockBaseWeight;
+         weight += real_c(infoIt->second.computationalWeight) + peBlockBaseWeight;
       }else if(loadEvaluationStrategy == "Fit" || loadEvaluationStrategy == "FitMulti")
       {
          auto infoIt = couplingInfoCollection->find( blockID );
@@ -2077,7 +2077,7 @@ int main( int argc, char **argv )
             auto &forest = blocks->getBlockForest();
             pe_coupling::createWithNeighborhood<BoundaryHandling_T>(forest, boundaryHandlingID, bodyStorageID, ccdID,
                                                                     fcdID, numPeSubCycles, *couplingInfoCollection);
-            pe::createWithNeighborhood(forest, bodyStorageID, *peInfoCollection);
+            pe::createWithNeighborhoodLocalShadow(forest, bodyStorageID, *peInfoCollection);
 
             // for the fluid property based check:
             if (useVorticityCriterion || useGradientCriterion) {
diff --git a/src/pe/amr/BlockInfo.h b/src/pe/amr/BlockInfo.h
index fccc9656bc50865de3e38dadb8454af468935370..e1f3446f30c80e2479f56dc2bf61151514b04796 100644
--- a/src/pe/amr/BlockInfo.h
+++ b/src/pe/amr/BlockInfo.h
@@ -30,23 +30,23 @@ namespace pe {
 
 struct BlockInfo
 {
-   uint_t numberOfLocalBodies;
-   uint_t numberOfShadowBodies;
+   uint_t computationalWeight;
+   uint_t communicationWeight;
 
    BlockInfo()
-      : numberOfLocalBodies(0)
-      , numberOfShadowBodies(0)
+      : computationalWeight(0)
+      , communicationWeight(0)
    {}
 
-   BlockInfo(const uint_t particles, const uint_t sparticles)
-      : numberOfLocalBodies(particles)
-      , numberOfShadowBodies(sparticles)
+   BlockInfo(const uint_t compWeight, const uint_t commWeight)
+      : computationalWeight(compWeight)
+      , communicationWeight(commWeight)
    {}
 
    BlockInfo&      operator+=( const BlockInfo& rhs )
    {
-      numberOfLocalBodies  += rhs.numberOfLocalBodies;
-      numberOfShadowBodies += rhs.numberOfShadowBodies;
+      computationalWeight += rhs.computationalWeight;
+      communicationWeight += rhs.communicationWeight;
       return *this;
    }
 };
@@ -62,7 +62,7 @@ BlockInfo operator+ ( const BlockInfo& lhs, const BlockInfo& rhs )
 inline
 std::ostream& operator<<( std::ostream& os, const BlockInfo& bi )
 {
-   os << bi.numberOfLocalBodies << " / " << bi.numberOfShadowBodies;
+   os << bi.computationalWeight << " / " << bi.communicationWeight;
    return os;
 }
 
@@ -71,7 +71,7 @@ template< typename T,    // Element type of SendBuffer
 mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, const BlockInfo& info )
 {
    buf.addDebugMarker( "pa" );
-   buf << info.numberOfLocalBodies << info.numberOfShadowBodies;
+   buf << info.computationalWeight << info.communicationWeight;
    return buf;
 }
 
@@ -79,7 +79,7 @@ template< typename T>    // Element type of SendBuffer
 mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, BlockInfo& info )
 {
    buf.readDebugMarker( "pa" );
-   buf >> info.numberOfLocalBodies >> info.numberOfShadowBodies;
+   buf >> info.computationalWeight >> info.communicationWeight;
    return buf;
 }
 
diff --git a/src/pe/amr/InfoCollection.cpp b/src/pe/amr/InfoCollection.cpp
index 4a725d32da757211f4716ee2cf7ab5690942d628..dced160b3575993176f8c802491955a2f6cec142 100644
--- a/src/pe/amr/InfoCollection.cpp
+++ b/src/pe/amr/InfoCollection.cpp
@@ -20,6 +20,7 @@
 
 #include "InfoCollection.h"
 
+#include "pe/fcd/IFCD.h"
 #include "pe/rigidbody/BodyStorage.h"
 
 #include "blockforest/BlockID.h"
@@ -28,7 +29,7 @@
 namespace walberla {
 namespace pe {
 
-void createWithNeighborhood(const BlockForest& bf, const BlockDataID storageID, InfoCollection& ic )
+void createWithNeighborhoodLocalShadow(const BlockForest& bf, const BlockDataID storageID, InfoCollection& ic )
 {
    ic.clear();
 
@@ -86,5 +87,64 @@ void createWithNeighborhood(const BlockForest& bf, const BlockDataID storageID,
    }
 }
 
+void createWithNeighborhoodContacts(BlockForest& bf, const BlockDataID storageID, const BlockDataID fcdID, InfoCollection& ic )
+{
+   ic.clear();
+
+   mpi::BufferSystem bs( MPIManager::instance()->comm(), 756 );
+
+   for (auto blockIt = bf.begin(); blockIt != bf.end(); ++blockIt)
+   {
+      blockforest::Block* block   = static_cast<blockforest::Block*> (&(*blockIt));
+      Storage const *     storage       = block->getData< Storage >( storageID );
+      BodyStorage const & shadowStorage = (*storage)[StorageType::SHADOW];
+      fcd::IFCD *     fcd         = block->getData< fcd::IFCD >( fcdID );
+      ic.insert( InfoCollection::value_type(block->getId(), BlockInfo(fcd->getContacts().size(), shadowStorage.size())) );
+      for( uint_t nb = uint_t(0); nb < block->getNeighborhoodSize(); ++nb )
+      {
+         bs.sendBuffer( block->getNeighborProcess(nb) ) << InfoCollection::value_type(block->getId(), BlockInfo(fcd->getContacts().size(), shadowStorage.size()));
+      }
+
+      for (uint_t branchID = 0; branchID < 8; ++branchID)
+      {
+         const auto childID   = BlockID(block->getId(), branchID);
+         const auto childAABB = bf.getAABBFromBlockId(childID);
+         uint_t localContacts  = 0;
+         auto& contacts = fcd->getContacts();
+         for (auto cIt = contacts.begin(); cIt != contacts.end(); ++cIt)
+         {
+            if (childAABB.contains(cIt->getPosition()))
+               ++localContacts;
+         }
+         uint_t shadow  = 0;
+         for (auto bodyIt = shadowStorage.begin(); bodyIt != shadowStorage.end(); ++bodyIt)
+         {
+            if (childAABB.contains(bodyIt->getPosition()))
+               ++shadow;
+         }
+         ic.insert( InfoCollection::value_type(childID, BlockInfo(localContacts, shadow)) );
+
+         for( uint_t nb = uint_t(0); nb < block->getNeighborhoodSize(); ++nb )
+         {
+            bs.sendBuffer( block->getNeighborProcess(nb) ) << InfoCollection::value_type(childID, BlockInfo(localContacts, shadow));
+         }
+      }
+   }
+
+   // size of buffer is unknown and changes with each send
+   bs.setReceiverInfoFromSendBufferState(false, true);
+   bs.sendAll();
+
+   for( auto recvIt = bs.begin(); recvIt != bs.end(); ++recvIt )
+   {
+      while( !recvIt.buffer().isEmpty() )
+      {
+         InfoCollectionPair val;
+         recvIt.buffer() >> val;
+         ic.insert(val);
+      }
+   }
+}
+
 }
 }
diff --git a/src/pe/amr/InfoCollection.h b/src/pe/amr/InfoCollection.h
index 3acdc2f27b01ffa2f3f5d752325d8ffed336845a..4830ba5430f5aa1a50e4f173f9ccd51742517f25 100644
--- a/src/pe/amr/InfoCollection.h
+++ b/src/pe/amr/InfoCollection.h
@@ -32,7 +32,23 @@ namespace pe {
 typedef std::map<blockforest::BlockID, BlockInfo>  InfoCollection;
 typedef std::pair<blockforest::BlockID, BlockInfo> InfoCollectionPair;
 
-void createWithNeighborhood(const BlockForest& bf, const BlockDataID storageID, InfoCollection& ic );
+/**
+ * @brief Fills \a InfoCollection with up to date information.
+ *
+ * The number of local particles is used as the computational weight.
+ * The number of shadow particles is used as the communication weight.
+ *
+ */
+void createWithNeighborhoodLocalShadow(const BlockForest& bf, const BlockDataID storageID, InfoCollection& ic );
+
+/**
+ * @brief Fills \a InfoCollection with up to date information.
+ *
+ * The number of contacts is used as the computational weight.
+ * The number of shadow particles is used as the communication weight.
+ *
+ */
+void createWithNeighborhoodContactsShadow(const BlockForest& bf, const BlockDataID storageID, const BlockDataID fcdID, InfoCollection& ic );
 
 }
 }
diff --git a/src/pe/amr/regrid/RegridMinMax.cpp b/src/pe/amr/level_determination/MinMaxLevelDetermination.cpp
similarity index 79%
rename from src/pe/amr/regrid/RegridMinMax.cpp
rename to src/pe/amr/level_determination/MinMaxLevelDetermination.cpp
index 62e9d06f410276eec3194f76de63d862cf3a06d4..bb1de0695648a5f9a3ce32d4a0bf8aaeba8e8ce7 100644
--- a/src/pe/amr/regrid/RegridMinMax.cpp
+++ b/src/pe/amr/level_determination/MinMaxLevelDetermination.cpp
@@ -13,19 +13,19 @@
 //  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 RegridMinMax.cpp
+//! \file MinMaxLevelDetermination.cpp
 //! \author Sebastian Eibl <sebastian.eibl@fau.de>
 //
 //======================================================================================================================
 
-#include "RegridMinMax.h"
+#include "MinMaxLevelDetermination.h"
 
 namespace walberla {
 namespace pe {
 namespace amr {
 
-void ReGridMinMax::operator()( std::vector< std::pair< const Block *, uint_t > > & minTargetLevels,
-                               std::vector< const Block * > &, const BlockForest & /*forest*/ )
+void MinMaxLevelDetermination::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 )
    {
@@ -35,16 +35,16 @@ void ReGridMinMax::operator()( std::vector< std::pair< const Block *, uint_t > >
       it->second = it->first->getLevel(); //keep everything as it is
 
       //check for refinement
-      if (infoIt->second.numberOfLocalBodies > maxBodies_)
+      if (infoIt->second.computationalWeight > maxBodies_)
       {
          it->second = it->first->getLevel() + uint_t(1);
          continue;
       }
 
       //check for coarsening
-      if ((it->first->getLevel() > 0) && (infoIt->second.numberOfLocalBodies < minBodies_))
+      if ((it->first->getLevel() > 0) && (infoIt->second.computationalWeight < minBodies_))
       {
-         if (getOrCreateCoarseInfo(it->first->getId())->second.numberOfLocalBodies < maxBodies_)
+         if (getOrCreateCoarseInfo(it->first->getId())->second.computationalWeight < maxBodies_)
          {
             it->second = it->first->getLevel() - uint_t(1);
          }
@@ -53,7 +53,7 @@ void ReGridMinMax::operator()( std::vector< std::pair< const Block *, uint_t > >
    }
 }
 
-InfoCollection::const_iterator ReGridMinMax::getOrCreateCoarseInfo( const blockforest::BlockID& id )
+InfoCollection::const_iterator MinMaxLevelDetermination::getOrCreateCoarseInfo( const blockforest::BlockID& id )
 {
    auto fatherId = id.getFatherId();
    auto infoIt   = ic_->find( fatherId );
diff --git a/src/pe/amr/regrid/RegridMinMax.h b/src/pe/amr/level_determination/MinMaxLevelDetermination.h
similarity index 90%
rename from src/pe/amr/regrid/RegridMinMax.h
rename to src/pe/amr/level_determination/MinMaxLevelDetermination.h
index 47d24349ea07922a90c88e7e2ae5febfb1e4fb22..6f5433822d457ba7b5705063b41864b45c42d966 100644
--- a/src/pe/amr/regrid/RegridMinMax.h
+++ b/src/pe/amr/level_determination/MinMaxLevelDetermination.h
@@ -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 RegridMinMax.h
+//! \file MinMaxLevelDetermination.h
 //! \author Sebastian Eibl <sebastian.eibl@fau.de>
 //
 //======================================================================================================================
@@ -32,11 +32,11 @@ namespace walberla {
 namespace pe {
 namespace amr {
 
-class ReGridMinMax
+class MinMaxLevelDetermination
 {
 public:
 
-   ReGridMinMax( const shared_ptr<InfoCollection>& ic, const size_t minBodies, const size_t maxBodies) :
+   MinMaxLevelDetermination( const shared_ptr<InfoCollection>& ic, const size_t minBodies, const size_t maxBodies) :
       ic_( ic ), minBodies_(minBodies), maxBodies_(maxBodies)
    {}
 
diff --git a/src/pe/amr/weight_assignment/MetisAssignmentFunctor.h b/src/pe/amr/weight_assignment/MetisAssignmentFunctor.h
index dd1fdac59c24ae7d751fc9014236109ccaedfca3..d7777a8da8c8676e20212e3ebdec1d465d655843 100644
--- a/src/pe/amr/weight_assignment/MetisAssignmentFunctor.h
+++ b/src/pe/amr/weight_assignment/MetisAssignmentFunctor.h
@@ -29,11 +29,18 @@ namespace walberla {
 namespace pe {
 namespace amr {
 
+/**
+ * Assignment functor for ParMetis based load balancing.
+ *
+ * Uses BlockInfo::computationalWeight as vertex weight.
+ * Uses the overlap between neighboring domains as edge weight.
+ */
 class MetisAssignmentFunctor
 {
 public:
-
+   ///Convenience typedef to be used as PhantomBlock weight in conjunction with this weight assignment functor.
    typedef blockforest::DynamicParMetisBlockInfo           PhantomBlockWeight;
+   ///Convenience typdef for pack and unpack functions to be used in conjunction with PhantomBlockWeight.
    typedef blockforest::DynamicParMetisBlockInfoPackUnpack PhantomBlockWeightPackUnpackFunctor;
 
    MetisAssignmentFunctor( shared_ptr<InfoCollection>& ic, const real_t baseWeight = real_t(10.0) ) : ic_(ic), baseWeight_(baseWeight) {}
@@ -54,7 +61,7 @@ public:
          //all information is provided by info collection
          auto infoIt         = ic_->find( block->getId() );
          WALBERLA_CHECK_UNEQUAL( infoIt, ic_->end() );
-         const double weight = double_c( infoIt->second.numberOfLocalBodies ) + baseWeight_;
+         const double weight = double_c( infoIt->second.computationalWeight ) + baseWeight_;
          blockforest::DynamicParMetisBlockInfo info( 0 );
          info.setVertexWeight( int64_c(weight) );
          info.setVertexSize( int64_c( weight ) );
diff --git a/src/pe/amr/weight_assignment/WeightAssignmentFunctor.h b/src/pe/amr/weight_assignment/WeightAssignmentFunctor.h
index 7c7b381786967bd739b31f6c49ed673230ebd4fb..b18b9b0fdcb762414af23b1cf275f58840550b96 100644
--- a/src/pe/amr/weight_assignment/WeightAssignmentFunctor.h
+++ b/src/pe/amr/weight_assignment/WeightAssignmentFunctor.h
@@ -29,10 +29,17 @@ namespace walberla {
 namespace pe {
 namespace amr {
 
+/**
+ * General assignment functor for load balancing.
+ *
+ * Uses BlockInfo::computationalWeight as PhantomBlockWeight
+ */
 class WeightAssignmentFunctor
 {
 public:
+   ///Convenience typedef to be used as PhantomBlock weight in conjunction with this weight assignment functor.
    typedef walberla::blockforest::PODPhantomWeight<double>           PhantomBlockWeight;
+   ///Convenience typdef for pack and unpack functions to be used in conjunction with PhantomBlockWeight.
    typedef walberla::blockforest::PODPhantomWeightPackUnpack<double> PhantomBlockWeightPackUnpackFunctor;
 
    WeightAssignmentFunctor( shared_ptr<InfoCollection>& ic, const real_t baseWeight = real_t(10.0) ) : ic_(ic), baseWeight_(baseWeight) {}
@@ -47,7 +54,7 @@ public:
 
          auto infoIt = ic_->find( block->getId()/*.getFatherId()*/ );
          WALBERLA_CHECK_UNEQUAL( infoIt, ic_->end() );
-         it->second = PhantomBlockWeight( double_c(infoIt->second.numberOfLocalBodies) + baseWeight_ );
+         it->second = PhantomBlockWeight( double_c(infoIt->second.computationalWeight) + baseWeight_ );
       }
    }
 
diff --git a/tests/pe/MinMaxRefinement.cpp b/tests/pe/MinMaxRefinement.cpp
index 34cde5d21c9f9c5ef4b2e84cb2246b9cc5c722df..3640056459becd13079590470f6b16291c96918e 100644
--- a/tests/pe/MinMaxRefinement.cpp
+++ b/tests/pe/MinMaxRefinement.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 Refinement.cpp
+//! \file MinMaxRefinement.cpp
 //! \author Sebastian Eibl <sebastian.eibl@fau.de>
 //
 //======================================================================================================================
@@ -29,7 +29,7 @@
 
 #include "pe/basic.h"
 #include "pe/amr/InfoCollection.h"
-#include "pe/amr/regrid/RegridMinMax.h"
+#include "pe/amr/level_determination/MinMaxLevelDetermination.h"
 #include "pe/amr/weight_assignment/WeightAssignmentFunctor.h"
 #include "pe/ccd/SimpleCCDDataHandling.h"
 #include "pe/synchronization/SyncNextNeighbors.h"
@@ -40,6 +40,7 @@
 #include "CheckVitalParameters.h"
 
 #include "core/debug/TestSubsystem.h"
+#include "core/logging/Logging.h"
 
 #include <boost/tuple/tuple.hpp>
 
@@ -96,15 +97,15 @@ int main( int argc, char ** argv )
 
    auto infoCollection = make_shared<InfoCollection>();
 
-   amr::ReGridMinMax regrid(infoCollection, 2, 5);
-   blockforest.setRefreshMinTargetLevelDeterminationFunction( regrid );
+   amr::MinMaxLevelDetermination levelDetermination(infoCollection, 2, 5);
+   blockforest.setRefreshMinTargetLevelDeterminationFunction( levelDetermination );
 
    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 ) );
+            blockforest::DynamicCurveBalance< 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);
@@ -117,7 +118,7 @@ int main( int argc, char ** argv )
 
    WALBERLA_MPI_BARRIER();
    WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 1" );
-   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   createWithNeighborhoodLocalShadow(blockforest, storageID, *infoCollection);
    clearSynchronization( blockforest, storageID);
    forest->refresh();
    syncNextNeighbors<BodyTuple>(blockforest, storageID);
@@ -132,8 +133,8 @@ int main( int argc, char ** argv )
 
    WALBERLA_MPI_BARRIER();
    WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 2" );
-   blockforest.setRefreshMinTargetLevelDeterminationFunction( amr::ReGridMinMax(infoCollection, 9, 20) );
-   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   blockforest.setRefreshMinTargetLevelDeterminationFunction( amr::MinMaxLevelDetermination(infoCollection, 9, 20) );
+   createWithNeighborhoodLocalShadow(blockforest, storageID, *infoCollection);
    clearSynchronization( blockforest, storageID);
    forest->refresh();
    syncNextNeighbors<BodyTuple>(blockforest, storageID);
@@ -154,8 +155,8 @@ int main( int argc, char ** argv )
 
    WALBERLA_MPI_BARRIER();
    WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 3" );
-   blockforest.setRefreshMinTargetLevelDeterminationFunction( amr::ReGridMinMax(infoCollection, 2, 3) );
-   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   blockforest.setRefreshMinTargetLevelDeterminationFunction( amr::MinMaxLevelDetermination(infoCollection, 2, 3) );
+   createWithNeighborhoodLocalShadow(blockforest, storageID, *infoCollection);
    clearSynchronization( blockforest, storageID);
    forest->refresh();
    syncNextNeighbors<BodyTuple>(blockforest, storageID);
@@ -170,7 +171,7 @@ int main( int argc, char ** argv )
 
    WALBERLA_MPI_BARRIER();
    WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 4" );
-   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   createWithNeighborhoodLocalShadow(blockforest, storageID, *infoCollection);
    clearSynchronization( blockforest, storageID);
    forest->refresh();
    syncNextNeighbors<BodyTuple>(blockforest, storageID);
@@ -186,7 +187,7 @@ int main( int argc, char ** argv )
    WALBERLA_MPI_BARRIER();
    WALBERLA_LOG_DEVEL_ON_ROOT( "Refinement 5" );
    WALBERLA_LOG_DEVEL( "SIZE: " << blockforest.size() );
-   createWithNeighborhood(blockforest, storageID, *infoCollection);
+   createWithNeighborhoodLocalShadow(blockforest, storageID, *infoCollection);
    clearSynchronization( blockforest, storageID);
    forest->refresh();
    syncNextNeighbors<BodyTuple>(blockforest, storageID);
@@ -206,4 +207,4 @@ int main( int argc, char ** argv )
 int main( int argc, char* argv[] )
 {
   return walberla::main( argc, argv );
-}
\ No newline at end of file
+}