From 1b218e7320fadddee18b32f0af3c2dd02e8de357 Mon Sep 17 00:00:00 2001 From: Sebastian Eibl <sebastian.eibl@fau.de> Date: Wed, 28 Feb 2018 17:03:26 +0100 Subject: [PATCH] [BUGFIX] fixed uninitialized vertex coordinates (parmetis) --- .../loadbalancing/DynamicParMetis.cpp | 4 +- .../loadbalancing/DynamicParMetis.h | 6 +- tests/pe/CMakeLists.txt | 5 + tests/pe/ParMetis.cpp | 142 ++++++++++++++++++ 4 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 tests/pe/ParMetis.cpp diff --git a/src/blockforest/loadbalancing/DynamicParMetis.cpp b/src/blockforest/loadbalancing/DynamicParMetis.cpp index 9989aca6b..ec2b38ff3 100644 --- a/src/blockforest/loadbalancing/DynamicParMetis.cpp +++ b/src/blockforest/loadbalancing/DynamicParMetis.cpp @@ -124,7 +124,7 @@ bool DynamicParMetis::operator()( std::vector< std::pair< const PhantomBlock *, globalTimer.start(); //create new communicator which excludes processes which do not have blocks - MPI_Comm subComm; + MPI_Comm subComm = MPIManager::instance()->comm(); MPI_Group allGroup, subGroup; MPI_Comm_group( MPIManager::instance()->comm(), &allGroup ); std::vector<int> ranks; @@ -142,7 +142,7 @@ bool DynamicParMetis::operator()( std::vector< std::pair< const PhantomBlock *, if (subComm != MPI_COMM_NULL) { const std::pair<uint_t, uint_t> blockSequenceRange = getBlockSequenceRange( phantomForest, subComm ); - const std::map< blockforest::BlockID, uint_t > mapping = getBlockIdToSequenceMapping( phantomForest, blockSequenceRange, subComm ); + const std::map< blockforest::BlockID, uint_t > mapping = getBlockIdToSequenceMapping( phantomForest, blockSequenceRange, subComm ); //blockid to vertex id std::vector<int64_t> vtxdist = mpi::allGather( int64_c( blockSequenceRange.second ), subComm ); vtxdist.insert( vtxdist.begin(), uint_t( 0 ) ); diff --git a/src/blockforest/loadbalancing/DynamicParMetis.h b/src/blockforest/loadbalancing/DynamicParMetis.h index a17a2e974..266b572d4 100644 --- a/src/blockforest/loadbalancing/DynamicParMetis.h +++ b/src/blockforest/loadbalancing/DynamicParMetis.h @@ -23,10 +23,12 @@ #include "blockforest/PhantomBlockForest.h" +#include "core/debug/Debug.h" #include "core/DataTypes.h" #include "core/math/Vector3.h" #include "core/mpi/MPIWrapper.h" +#include <cmath> #include <map> namespace walberla { @@ -100,7 +102,7 @@ public: vsize_t getVertexSize() const { return vertexSize_; } void setVertexSize( const vsize_t size ) { vertexSize_ = size; } - const Vector3<double> & getVertexCoords() const { return vertexCoords_; } + const Vector3<double> & getVertexCoords() const { WALBERLA_ASSERT( !std::isnan(vertexCoords_[0]) && !std::isnan(vertexCoords_[1]) && !std::isnan(vertexCoords_[2]) ); return vertexCoords_; } void setVertexCoords( const Vector3<double> & p ) { vertexCoords_ = p; } void setEdgeWeight( const blockforest::BlockID & blockId, const weight_t edgeWeight ) { edgeWeights_[blockId] = edgeWeight; } @@ -117,7 +119,7 @@ private: weight_t vertexWeight_; /// Defines the weight of a block vsize_t vertexSize_; /// Defines the cost of rebalancing a block - Vector3<double> vertexCoords_; /// Defines where the block is located in space. Needed by some ParMetis algorithms + Vector3<double> vertexCoords_ = Vector3<double>(std::numeric_limits<double>::signaling_NaN()); /// Defines where the block is located in space. Needed by some ParMetis algorithms std::map< blockforest::BlockID, weight_t > edgeWeights_; /// Defines the cost of communication with other blocks }; diff --git a/tests/pe/CMakeLists.txt b/tests/pe/CMakeLists.txt index 64a077d08..ce10e244c 100644 --- a/tests/pe/CMakeLists.txt +++ b/tests/pe/CMakeLists.txt @@ -69,6 +69,11 @@ waLBerla_execute_test( NAME PE_OVERLAP ) waLBerla_compile_test( NAME PE_PARALLELEQUIVALENCE FILES ParallelEquivalence.cpp DEPENDS core blockforest ) waLBerla_execute_test( NAME PE_PARALLELEQUIVALENCE PROCESSES 4 ) +if( WALBERLA_BUILD_WITH_PARMETIS ) + waLBerla_compile_test( NAME PE_PARMETIS FILES ParMetis.cpp DEPENDS core blockforest ) + waLBerla_execute_test( NAME PE_PARMETIS PROCESSES 64 ) +endif() + waLBerla_compile_test( NAME PE_PARSEMESSAGE FILES ParseMessage.cpp DEPENDS core ) waLBerla_execute_test( NAME PE_PARSEMESSAGE ) diff --git a/tests/pe/ParMetis.cpp b/tests/pe/ParMetis.cpp new file mode 100644 index 000000000..7196efa30 --- /dev/null +++ b/tests/pe/ParMetis.cpp @@ -0,0 +1,142 @@ +//====================================================================================================================== +// +// 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 ParMetis.cpp +//! \author Sebastian Eibl <sebastian.eibl@fau.de> +// +//====================================================================================================================== + +#include "pe/utility/CreateWorld.h" + +#include <blockforest/loadbalancing/DynamicParMetis.h> +#include <core/Environment.h> +#include <core/logging/Logging.h> +#include <core/math/Sample.h> + +using namespace walberla; +using namespace walberla::pe; + +class ReGrid +{ +public: + void operator()( std::vector< std::pair< const Block *, uint_t > > & minTargetLevels, + std::vector< const Block * > &, const BlockForest & /*forest*/ ) + { + std::for_each( minTargetLevels.begin(), + minTargetLevels.end(), + [](auto& pair){pair.second = 1;} ); + } + +}; + +class MetisAssignmentFunctor +{ +public: + + typedef blockforest::DynamicParMetisBlockInfo PhantomBlockWeight; + typedef blockforest::DynamicParMetisBlockInfoPackUnpack PhantomBlockWeightPackUnpackFunctor; + + void operator()( std::vector< std::pair< const PhantomBlock *, walberla::any > > & blockData, const PhantomBlockForest & ) + { + for( auto it = blockData.begin(); it != blockData.end(); ++it ) + { + const auto& corner = it->first->getAABB().maxCorner(); + const int weight = int_c( corner[0] + corner[1] + corner[2] ); + blockforest::DynamicParMetisBlockInfo info(0); + info.setVertexWeight( weight ); + info.setVertexSize( weight ); + info.setVertexCoords( it->first->getAABB().center() ); + for( uint_t nb = uint_t(0); nb < it->first->getNeighborhoodSize(); ++nb ) + { + info.setEdgeWeight(it->first->getNeighborId(nb), int64_c(10) ); + } + it->second = info; + } + } +}; + +int parmetisTest(const std::string& algorithm, + const std::string& weightsToUse, + const std::string& edgeSource) +{ + walberla::MPIManager::instance()->resetMPI(); + + WALBERLA_LOG_INFO_ON_ROOT("****** " << algorithm << " | " << weightsToUse << " | " << edgeSource); + + // create forest + shared_ptr< BlockForest > forest = createBlockForest( math::AABB(0,0,0,40,40,40), + Vector3<uint_t>(4, 4, 4), + Vector3<bool>(false, false, false), + 64, + 0); + if (!forest) + { + WALBERLA_LOG_INFO_ON_ROOT( "No BlockForest created ... exiting!"); + return EXIT_SUCCESS; + } + + forest->setRefreshMinTargetLevelDeterminationFunction( ReGrid() ); + + auto assFunc = MetisAssignmentFunctor(); + forest->setRefreshPhantomBlockDataAssignmentFunction( assFunc ); + forest->setRefreshPhantomBlockDataPackFunction( MetisAssignmentFunctor::PhantomBlockWeightPackUnpackFunctor() ); + forest->setRefreshPhantomBlockDataUnpackFunction( MetisAssignmentFunctor::PhantomBlockWeightPackUnpackFunctor() ); + + auto alg = blockforest::DynamicParMetis::stringToAlgorithm( algorithm ); + auto vWeight = blockforest::DynamicParMetis::stringToWeightsToUse( weightsToUse ); + auto eWeight = blockforest::DynamicParMetis::stringToEdgeSource( edgeSource ); + + auto prepFunc = blockforest::DynamicParMetis( alg, vWeight, eWeight ); + forest->setRefreshPhantomBlockMigrationPreparationFunction( prepFunc ); + + forest->refresh(); + + math::Sample numBlocks; + numBlocks.castToRealAndInsert( forest->size() ); + numBlocks.mpiGatherRoot(); + WALBERLA_LOG_INFO_ON_ROOT("#blocks: " << numBlocks.format() ); + + int weight = 0; + for (const auto& block : *forest) + { + const auto& corner = block.getAABB().maxCorner(); + weight += int_c( corner[0] + corner[1] + corner[2] ); + } + math::Sample weightSample; + weightSample.castToRealAndInsert( weight ); + weightSample.mpiGatherRoot(); + WALBERLA_LOG_INFO_ON_ROOT("#weights: " << weightSample.format() ); + + return EXIT_SUCCESS; +} + +int main( int argc, char ** argv ) +{ + walberla::debug::enterTestMode(); + walberla::MPIManager::instance()->initializeMPI( &argc, &argv ); + + std::vector<std::string> algs = {"PART_GEOM_KWAY", "PART_KWAY", "PART_ADAPTIVE_REPART", "REFINE_KWAY"}; + std::vector<std::string> wtu = {"NO_WEIGHTS", "EDGE_WEIGHTS", "VERTEX_WEIGHTS", "BOTH_WEIGHTS"}; + std::vector<std::string> es = {"EDGES_FROM_FOREST", "EDGES_FROM_EDGE_WEIGHTS"}; + + for (const auto& a : algs) + for (const auto& w : wtu) + for (const auto& e : es) + { + parmetisTest(a,w,e); + } + + return EXIT_SUCCESS; +} -- GitLab