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 +}