Skip to content
Snippets Groups Projects
Commit a282e79c authored by Christian Godenschwager's avatar Christian Godenschwager
Browse files

Added support for ParMetis library

Also added wrapper for Metis & ParMetis to prevent it from polluting the global name space
parent 98827cd5
No related merge requests found
...@@ -70,6 +70,7 @@ option ( WALBERLA_BUILD_TUTORIALS "Build Tutorials" ...@@ -70,6 +70,7 @@ option ( WALBERLA_BUILD_TUTORIALS "Build Tutorials"
option ( WALBERLA_BUILD_WITH_MPI "Build with MPI" ON ) option ( WALBERLA_BUILD_WITH_MPI "Build with MPI" ON )
option ( WALBERLA_BUILD_WITH_METIS "Build with metis graph partitioner" OFF ) option ( WALBERLA_BUILD_WITH_METIS "Build with metis graph partitioner" OFF )
option ( WALBERLA_BUILD_WITH_PARMETIS "Build with ParMetis graph partitioner" OFF )
option ( WALBERLA_BUILD_WITH_GPROF "Enables gprof" ) option ( WALBERLA_BUILD_WITH_GPROF "Enables gprof" )
option ( WALBERLA_BUILD_WITH_GCOV "Enables gcov" ) option ( WALBERLA_BUILD_WITH_GCOV "Enables gcov" )
...@@ -853,6 +854,28 @@ else() ...@@ -853,6 +854,28 @@ else()
set ( METIS_FOUND OFF CACHE BOOL "Metis found" FORCE ) set ( METIS_FOUND OFF CACHE BOOL "Metis found" FORCE )
endif() endif()
if ( WALBERLA_BUILD_WITH_PARMETIS )
find_path(PARMETIS_INCLUDE_DIR parmetis.h
/usr/local/include
/usr/include
${PARMETIS_ROOT}/include
$ENV{PARMETIS_ROOT}/include
)
find_library(PARMETIS_LIBRARY parmetis
/usr/local/lib
/usr/lib
${PARMETIS_ROOT}/lib
$ENV{PARMETIS_ROOT}/lib
)
if( PARMETIS_INCLUDE_DIR AND PARMETIS_LIBRARY AND METIS_LIBRARY )
include_directories( ${PARMETIS_INCLUDE_DIR} )
list ( APPEND SERVICE_LIBS ${PARMETIS_LIBRARY} ${METIS_LIBRARY} )
endif()
endif()
############################################################################################################################ ############################################################################################################################
......
...@@ -24,12 +24,12 @@ ...@@ -24,12 +24,12 @@
#include "waLBerlaDefinitions.h" // for macro WALBERLA_BUILD_WITH_METIS #include "waLBerlaDefinitions.h" // for macro WALBERLA_BUILD_WITH_METIS
#include "BlockID.h" #include "BlockID.h"
#include "MetisWrapper.h"
#include "Types.h" #include "Types.h"
#include "core/Abort.h" #include "core/Abort.h"
#include "core/debug/Debug.h" #include "core/debug/Debug.h"
#include "core/logging/Logging.h" #include "core/logging/Logging.h"
#include "core/load_balancing/MetisWrapper.h"
#include "core/math/KahanSummation.h" #include "core/math/KahanSummation.h"
#include <boost/function.hpp> #include <boost/function.hpp>
...@@ -144,10 +144,10 @@ public: ...@@ -144,10 +144,10 @@ public:
static void metis2( const std::vector< BLOCK* >& blocks, const uint_t numberOfProcesses, const CommFunction & commFunction ); static void metis2( const std::vector< BLOCK* >& blocks, const uint_t numberOfProcesses, const CommFunction & commFunction );
private: private:
static inline uint_t metisAdaptPartVector( std::vector< idx_t >& part, const uint_t numberOfProcesses ); static inline uint_t metisAdaptPartVector( std::vector< int64_t >& part, const uint_t numberOfProcesses );
template< typename BLOCK > template< typename BLOCK >
static memory_t metisMaxMemory( const std::vector< BLOCK* >& blocks, const uint_t numberOfProcesses, const std::vector< idx_t >& part ); static memory_t metisMaxMemory( const std::vector< BLOCK* >& blocks, const uint_t numberOfProcesses, const std::vector< int64_t >& part );
static inline std::ostream & metisErrorCodeToStream( int errorCode, std::ostream & oss ); static inline std::ostream & metisErrorCodeToStream( int errorCode, std::ostream & oss );
static inline std::string metisErrorCodeToString( int errorCode ); static inline std::string metisErrorCodeToString( int errorCode );
...@@ -781,51 +781,51 @@ uint_t GlobalLoadBalancing::metis( const std::vector< BLOCK* >& blocks, const me ...@@ -781,51 +781,51 @@ uint_t GlobalLoadBalancing::metis( const std::vector< BLOCK* >& blocks, const me
// translate block forest to metis graph structure // translate block forest to metis graph structure
idx_t nvtxs = numeric_cast<idx_t>( blocks.size() ); // number of vertices in the graph int64_t nvtxs = numeric_cast<int64_t>( blocks.size() ); // number of vertices in the graph
idx_t ncon = 2; // number of balancing constraints int64_t ncon = 2; // number of balancing constraints
for( uint_t i = 0; i != blocks.size(); ++i ) for( uint_t i = 0; i != blocks.size(); ++i )
blocks[i]->setIndex(i); blocks[i]->setIndex(i);
std::vector< idx_t > xadj; // adjacency structure ... std::vector< int64_t > xadj; // adjacency structure ...
std::vector< idx_t > adjncy; // ... of the graph std::vector< int64_t > adjncy; // ... of the graph
std::vector< idx_t > vwgt( uint_c(ncon * nvtxs) ); // weights of the vertices std::vector< int64_t > vwgt( uint_c(ncon * nvtxs) ); // weights of the vertices
std::vector< idx_t > adjwgt; // weights of the edges std::vector< int64_t > adjwgt; // weights of the edges
xadj.push_back(0); xadj.push_back(0);
for( uint_t i = 0; i != blocks.size(); ++i ) { for( uint_t i = 0; i != blocks.size(); ++i ) {
const BLOCK* block = blocks[i]; const BLOCK* block = blocks[i];
idx_t next = xadj.back() + numeric_cast< idx_t >( block->getNeighborhoodSize() ); int64_t next = xadj.back() + numeric_cast< int64_t >( block->getNeighborhoodSize() );
xadj.push_back( next ); xadj.push_back( next );
for( uint_t j = 0; j != block->getNeighborhoodSize(); ++j ) { for( uint_t j = 0; j != block->getNeighborhoodSize(); ++j ) {
adjncy.push_back( numeric_cast<idx_t>( block->getNeighbor(j)->getIndex() ) ); adjncy.push_back( numeric_cast<int64_t>( block->getNeighbor(j)->getIndex() ) );
adjwgt.push_back( metisConfig.communicationFunction().empty() ? 1 : adjwgt.push_back( metisConfig.communicationFunction().empty() ? 1 :
( numeric_cast<idx_t>( static_cast< memory_t >(0.5) + metisConfig.communicationFunction()( block, block->getNeighbor(j) ) ) ) ); ( numeric_cast<int64_t>( static_cast< memory_t >(0.5) + metisConfig.communicationFunction()( block, block->getNeighbor(j) ) ) ) );
} }
vwgt[ i * 2 ] = numeric_cast< idx_t >( static_cast< workload_t >(0.5) + blocks[i]->getWorkload() ); vwgt[ i * 2 ] = numeric_cast< int64_t >( static_cast< workload_t >(0.5) + blocks[i]->getWorkload() );
vwgt[ i * 2 + 1 ] = numeric_cast< idx_t >( static_cast< memory_t >(0.5) + blocks[i]->getMemory() ); vwgt[ i * 2 + 1 ] = numeric_cast< int64_t >( static_cast< memory_t >(0.5) + blocks[i]->getMemory() );
} }
idx_t nparts = numeric_cast< idx_t >( numberOfProcesses ); // number of parts to partition the graph int64_t nparts = numeric_cast< int64_t >( numberOfProcesses ); // number of parts to partition the graph
idx_t objval; int64_t objval;
std::vector< idx_t > part( uint_c(nvtxs) ); std::vector< int64_t > part( uint_c(nvtxs) );
real_t maxUbvec = metisConfig.maxUbvec(); real_t maxUbvec = metisConfig.maxUbvec();
real_t ubvec[] = { real_c(1.01), maxUbvec }; real_t ubvec[] = { real_c(1.01), maxUbvec };
// first call to METIS: always try to balance the workload as good as possible, but allow large imbalances concerning the memory (-> ubvec[1]) // first call to METIS: always try to balance the workload as good as possible, but allow large imbalances concerning the memory (-> ubvec[1])
int ret = METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), NULL, &(adjwgt[0]), &nparts, NULL, int ret = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), NULL, &(adjwgt[0]), &nparts, NULL,
&(ubvec[0]), NULL /*idx t *options*/, &objval, &(part[0]) ); &(ubvec[0]), NULL /*idx t *options*/, &objval, &(part[0]) );
// if METIS was successful AND the memory limit of each process is not violated (which is highly unlikely due to a large value for ubvec[1]) // if METIS was successful AND the memory limit of each process is not violated (which is highly unlikely due to a large value for ubvec[1])
// then the algorithm is finished // then the algorithm is finished
if( ret == METIS_OK && metisMaxMemory( blocks, numberOfProcesses, part ) <= memoryLimit ) { if( ret == core::METIS_OK && metisMaxMemory( blocks, numberOfProcesses, part ) <= memoryLimit ) {
nProcesses = metisAdaptPartVector( part, numberOfProcesses ); nProcesses = metisAdaptPartVector( part, numberOfProcesses );
...@@ -844,16 +844,16 @@ uint_t GlobalLoadBalancing::metis( const std::vector< BLOCK* >& blocks, const me ...@@ -844,16 +844,16 @@ uint_t GlobalLoadBalancing::metis( const std::vector< BLOCK* >& blocks, const me
real_t minUbvec = real_t(1); real_t minUbvec = real_t(1);
ubvec[1] = minUbvec; ubvec[1] = minUbvec;
ret = METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), NULL, &(adjwgt[0]), &nparts, NULL, ret = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), NULL, &(adjwgt[0]), &nparts, NULL,
&(ubvec[0]), NULL /*idx t *options*/, &objval, &(part[0]) ); &(ubvec[0]), NULL /*idx t *options*/, &objval, &(part[0]) );
// ... if this doesn't work OR if the memory limit is still violated then METIS is unable to find a valid partitioning // ... if this doesn't work OR if the memory limit is still violated then METIS is unable to find a valid partitioning
if( ret != METIS_OK ) { if( ret != core::METIS_OK ) {
std::string error( "METIS_ERROR" ); std::string error( "METIS_ERROR" );
if( ret == METIS_ERROR_INPUT ) error.assign( "METIS_ERROR_INPUT" ); if( ret == core::METIS_ERROR_INPUT ) error.assign( "METIS_ERROR_INPUT" );
else if( ret == METIS_ERROR_MEMORY ) error.assign( "METIS_ERROR_MEMORY" ); else if( ret == core::METIS_ERROR_MEMORY ) error.assign( "METIS_ERROR_MEMORY" );
// DEBUG_LOGGING_SECTION { std::cout << "ERROR: static load balancing with METIS failed (" << error << ")" << std::endl; } // DEBUG_LOGGING_SECTION { std::cout << "ERROR: static load balancing with METIS failed (" << error << ")" << std::endl; }
return 0; return 0;
...@@ -881,10 +881,10 @@ uint_t GlobalLoadBalancing::metis( const std::vector< BLOCK* >& blocks, const me ...@@ -881,10 +881,10 @@ uint_t GlobalLoadBalancing::metis( const std::vector< BLOCK* >& blocks, const me
ubvec[1] = ( maxUbvec + minUbvec ) / real_c(2); ubvec[1] = ( maxUbvec + minUbvec ) / real_c(2);
ret = METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), NULL, &(adjwgt[0]), &nparts, NULL, ret = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj[0]), &(adjncy[0]), &(vwgt[0]), NULL, &(adjwgt[0]), &nparts, NULL,
&(ubvec[0]), NULL /*idx t *options*/, &objval, &(part[0]) ); &(ubvec[0]), NULL /*idx t *options*/, &objval, &(part[0]) );
if( ret == METIS_OK && metisMaxMemory( blocks, numberOfProcesses, part ) <= memoryLimit ) { if( ret == core::METIS_OK && metisMaxMemory( blocks, numberOfProcesses, part ) <= memoryLimit ) {
nProcesses = metisAdaptPartVector( part, numberOfProcesses ); nProcesses = metisAdaptPartVector( part, numberOfProcesses );
...@@ -913,8 +913,8 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin ...@@ -913,8 +913,8 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin
if( blocks.empty() ) if( blocks.empty() )
return; return;
idx_t nvtxs = 0; // number of vertices in the graph int64_t nvtxs = 0; // number of vertices in the graph
idx_t ncon = 1; // number of balancing constraints int64_t ncon = 1; // number of balancing constraints
uint_t j = 0; uint_t j = 0;
for( uint_t i = 0; i != blocks.size(); ++i ) for( uint_t i = 0; i != blocks.size(); ++i )
...@@ -947,10 +947,10 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin ...@@ -947,10 +947,10 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin
commFunction( blockPairs, communicationWeights ); commFunction( blockPairs, communicationWeights );
std::vector< idx_t > xadj; // adjacency structure ... std::vector< int64_t > xadj; // adjacency structure ...
std::vector< idx_t > adjncy; // ... of the graph std::vector< int64_t > adjncy; // ... of the graph
std::vector< idx_t > vwgt; // weights of the vertices std::vector< int64_t > vwgt; // weights of the vertices
std::vector< idx_t > adjwgt; // weights of the edges std::vector< int64_t > adjwgt; // weights of the edges
xadj.push_back( 0 ); xadj.push_back( 0 );
uint_t commIdx = 0; uint_t commIdx = 0;
...@@ -963,7 +963,7 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin ...@@ -963,7 +963,7 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin
++nvtxs; ++nvtxs;
xadj.push_back( xadj.back() ); xadj.push_back( xadj.back() );
vwgt.push_back( numeric_cast<idx_t>( blocks[ i ]->getWorkload() ) ); vwgt.push_back( numeric_cast<int64_t>( blocks[ i ]->getWorkload() ) );
for( uint_t k = 0; k != block->getNeighborhoodSize(); ++k ) for( uint_t k = 0; k != block->getNeighborhoodSize(); ++k )
{ {
...@@ -971,10 +971,10 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin ...@@ -971,10 +971,10 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin
{ {
if( communicationWeights[ commIdx ] > real_t(0) ) if( communicationWeights[ commIdx ] > real_t(0) )
{ {
adjncy.push_back( numeric_cast<idx_t>( block->getNeighbor( k )->getIndex() ) ); adjncy.push_back( numeric_cast<int64_t>( block->getNeighbor( k )->getIndex() ) );
WALBERLA_ASSERT_LESS( commIdx, communicationWeights.size() ); WALBERLA_ASSERT_LESS( commIdx, communicationWeights.size() );
WALBERLA_ASSERT_GREATER( numeric_cast<idx_t>( communicationWeights[ commIdx ] ), idx_t(0) ); WALBERLA_ASSERT_GREATER( numeric_cast<int64_t>( communicationWeights[ commIdx ] ), int64_t(0) );
adjwgt.push_back( numeric_cast<idx_t>( communicationWeights[ commIdx ] ) ); adjwgt.push_back( numeric_cast<int64_t>( communicationWeights[ commIdx ] ) );
xadj.back() += 1; xadj.back() += 1;
} }
++commIdx; ++commIdx;
...@@ -987,21 +987,21 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin ...@@ -987,21 +987,21 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin
WALBERLA_ASSERT_EQUAL( adjncy.size(), adjwgt.size() ); WALBERLA_ASSERT_EQUAL( adjncy.size(), adjwgt.size() );
WALBERLA_ASSERT_EQUAL( adjncy.size(), communicationWeights.size() ); WALBERLA_ASSERT_EQUAL( adjncy.size(), communicationWeights.size() );
idx_t nparts = numeric_cast<idx_t>( numberOfProcesses ); // number of parts to partition the graph int64_t nparts = numeric_cast<int64_t>( numberOfProcesses ); // number of parts to partition the graph
idx_t objval; int64_t objval;
std::vector< idx_t > part( uint_c(nvtxs) ); std::vector< int64_t > part( uint_c(nvtxs) );
idx_t options[ METIS_NOPTIONS ]; int64_t options[ METIS_NOPTIONS ];
METIS_SetDefaultOptions( options ); core::METIS_SetDefaultOptions( options );
options[ METIS_OPTION_NITER ] = 1000; options[ core::METIS_OPTION_NITER ] = 1000;
options[ METIS_OPTION_NSEPS ] = 100; options[ core::METIS_OPTION_NSEPS ] = 100;
options[ METIS_OPTION_NCUTS ] = 100; options[ core::METIS_OPTION_NCUTS ] = 100;
int ret = METIS_PartGraphKway( &nvtxs, &ncon, &( xadj[ 0 ] ), &( adjncy[ 0 ] ), &( vwgt[ 0 ] ), NULL, &( adjwgt[0] ), int ret = core::METIS_PartGraphKway( &nvtxs, &ncon, &( xadj[ 0 ] ), &( adjncy[ 0 ] ), &( vwgt[ 0 ] ), NULL, &( adjwgt[0] ),
&nparts, NULL, NULL, options, &objval, &( part[ 0 ] ) ); &nparts, NULL, NULL, options, &objval, &( part[ 0 ] ) );
if( ret != METIS_OK ) if( ret != core::METIS_OK )
{ {
WALBERLA_ABORT( "METIS partitioning failed! Error: " << metisErrorCodeToString( ret ) ); WALBERLA_ABORT( "METIS partitioning failed! Error: " << metisErrorCodeToString( ret ) );
} }
...@@ -1028,24 +1028,16 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin ...@@ -1028,24 +1028,16 @@ void GlobalLoadBalancing::metis2( const std::vector< BLOCK* >& blocks, const uin
std::ostream & GlobalLoadBalancing::metisErrorCodeToStream( int errorCode, std::ostream & oss ) std::ostream & GlobalLoadBalancing::metisErrorCodeToStream( int errorCode, std::ostream & oss )
{ {
switch( errorCode ) if( errorCode == core::METIS_OK)
{
case METIS_OK:
oss << "OK, no METIS error"; oss << "OK, no METIS error";
break; else if( errorCode == core::METIS_ERROR_INPUT )
case METIS_ERROR_INPUT:
oss << "Error in METIS input"; oss << "Error in METIS input";
break; else if (errorCode == core::METIS_ERROR_MEMORY )
case METIS_ERROR_MEMORY:
oss << "METIS could not allocate enough memory"; oss << "METIS could not allocate enough memory";
break; else if (errorCode == core::METIS_ERROR )
case METIS_ERROR:
oss << "Unknown type of error"; oss << "Unknown type of error";
break; else
default:
oss << "Unknown error code"; oss << "Unknown error code";
break;
}
return oss; return oss;
} }
...@@ -1060,7 +1052,7 @@ std::string GlobalLoadBalancing::metisErrorCodeToString( int errorCode ) ...@@ -1060,7 +1052,7 @@ std::string GlobalLoadBalancing::metisErrorCodeToString( int errorCode )
uint_t GlobalLoadBalancing::metisAdaptPartVector( std::vector< idx_t >& part, const uint_t numberOfProcesses ) uint_t GlobalLoadBalancing::metisAdaptPartVector( std::vector< int64_t >& part, const uint_t numberOfProcesses )
{ {
std::vector<bool> hasBlock( numberOfProcesses, false ); std::vector<bool> hasBlock( numberOfProcesses, false );
for( uint_t i = 0; i != part.size(); ++i ) for( uint_t i = 0; i != part.size(); ++i )
...@@ -1090,7 +1082,7 @@ uint_t GlobalLoadBalancing::metisAdaptPartVector( std::vector< idx_t >& part, co ...@@ -1090,7 +1082,7 @@ uint_t GlobalLoadBalancing::metisAdaptPartVector( std::vector< idx_t >& part, co
template< typename BLOCK > template< typename BLOCK >
memory_t GlobalLoadBalancing::metisMaxMemory( const std::vector< BLOCK* >& blocks, const uint_t numberOfProcesses, memory_t GlobalLoadBalancing::metisMaxMemory( const std::vector< BLOCK* >& blocks, const uint_t numberOfProcesses,
const std::vector< idx_t >& part ) { const std::vector< int64_t >& part ) {
WALBERLA_ASSERT_EQUAL( blocks.size(), part.size() ); WALBERLA_ASSERT_EQUAL( blocks.size(), part.size() );
......
//======================================================================================================================
//
// 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 MetisWrapper.cpp
//! \ingroup blockforest
//! \author Christian Godenschwager <christian.godenschwager@fau.de>
//
//======================================================================================================================
#include "MetisWrapper.h"
#define WALBERLA_METIS_NOPTIONS METIS_NOPTIONS
#undef METIS_NOPTIONS
#include "waLBerlaDefinitions.h"
#include "core/Abort.h"
#include <boost/type_traits/is_same.hpp>
#ifdef WALBERLA_BUILD_WITH_METIS
#ifdef _MSC_VER
# pragma push_macro( "INT32_MIN" )
# pragma push_macro( "INT32_MAX" )
# pragma push_macro( "INT64_MIN" )
# pragma push_macro( "INT64_MAX" )
# ifdef INT32_MIN
# undef INT32_MIN
# endif
# ifdef INT32_MAX
# undef INT32_MAX
# endif
# ifdef INT64_MIN
# undef INT64_MIN
# endif
# ifdef INT64_MAX
# undef INT64_MAX
# endif
#endif
#ifdef WALBERLA_BUILD_WITH_METIS
# include "metis.h"
#endif
#ifdef _MSC_VER
# pragma pop_macro( "INT64_MAX" )
# pragma pop_macro( "INT64_MIN" )
# pragma pop_macro( "INT32_MAX" )
# pragma pop_macro( "INT32_MIN" )
#endif
static_assert(WALBERLA_METIS_NOPTIONS == METIS_NOPTIONS, "The macro METIS_NOPTIONS defined in blockforest/loadbalancing/MetisWRapper.h does not match the value in metis.h!");
#endif // WALBERLA_BUILD_WITH_METIS
namespace walberla {
namespace core {
#ifdef WALBERLA_BUILD_WITH_METIS
int METIS_PartGraphKway( ::walberla::int64_t *nvtxs, ::walberla::int64_t *ncon, ::walberla::int64_t *xadj, ::walberla::int64_t *adjncy,
::walberla::int64_t *vwgt, ::walberla::int64_t *vsize, ::walberla::int64_t *adjwgt, ::walberla::int64_t *nparts,
double *tpwgts, double *ubvec, ::walberla::int64_t *options, ::walberla::int64_t *edgecut, ::walberla::int64_t *part)
{
static_assert(boost::is_same< ::walberla::int64_t, ::idx_t >::value, "You have to compile the metis library with 64-bit wide integer type support!");
static_assert(boost::is_same< double, ::real_t >::value, "You have to compile the metis library with 64-bit wide floating-point type support!");
return ::METIS_PartGraphKway( nvtxs, ncon, xadj, adjncy, vwgt, vsize, adjwgt, nparts, tpwgts, ubvec, options, edgecut, part );
}
int METIS_PartGraphRecursive( ::walberla::int64_t *nvtxs, ::walberla::int64_t *ncon, ::walberla::int64_t *xadj, ::walberla::int64_t *adjncy,
::walberla::int64_t *vwgt, ::walberla::int64_t *vsize, ::walberla::int64_t *adjwgt, ::walberla::int64_t *nparts,
double *tpwgts, double *ubvec, ::walberla::int64_t *options, ::walberla::int64_t *edgecut, ::walberla::int64_t *part)
{
static_assert(boost::is_same< ::walberla::int64_t, ::idx_t >::value, "You have to compile the metis library with 64-bit wide integer type support!");
static_assert(boost::is_same< double, ::real_t >::value, "You have to compile the metis library with 64-bit wide floating-point type support!");
return ::METIS_PartGraphRecursive( nvtxs, ncon, xadj, adjncy, vwgt, vsize, adjwgt, nparts, tpwgts, ubvec, options, edgecut, part );
}
int METIS_SetDefaultOptions( ::walberla::int64_t *options )
{
static_assert(boost::is_same< ::walberla::int64_t, ::idx_t >::value, "You have to compile the metis library with 64-bit wide integer type support!");
return ::METIS_SetDefaultOptions( options );
}
const int METIS_OK = ::METIS_OK;
const int METIS_ERROR = ::METIS_ERROR;
const int METIS_ERROR_INPUT = ::METIS_ERROR_INPUT;
const int METIS_ERROR_MEMORY = ::METIS_ERROR_MEMORY;
const int METIS_OPTION_PTYPE = ::METIS_OPTION_PTYPE;
const int METIS_OPTION_OBJTYPE = ::METIS_OPTION_OBJTYPE;
const int METIS_OPTION_CTYPE = ::METIS_OPTION_CTYPE;
const int METIS_OPTION_IPTYPE = ::METIS_OPTION_IPTYPE;
const int METIS_OPTION_RTYPE = ::METIS_OPTION_RTYPE;
const int METIS_OPTION_DBGLVL = ::METIS_OPTION_DBGLVL;
const int METIS_OPTION_NITER = ::METIS_OPTION_NITER;
const int METIS_OPTION_NCUTS = ::METIS_OPTION_NCUTS;
const int METIS_OPTION_SEED = ::METIS_OPTION_SEED;
const int METIS_OPTION_NO2HOP = ::METIS_OPTION_NO2HOP;
const int METIS_OPTION_MINCONN = ::METIS_OPTION_MINCONN;
const int METIS_OPTION_CONTIG = ::METIS_OPTION_CONTIG;
const int METIS_OPTION_COMPRESS = ::METIS_OPTION_COMPRESS;
const int METIS_OPTION_CCORDER = ::METIS_OPTION_CCORDER;
const int METIS_OPTION_PFACTOR = ::METIS_OPTION_PFACTOR;
const int METIS_OPTION_NSEPS = ::METIS_OPTION_NSEPS;
const int METIS_OPTION_UFACTOR = ::METIS_OPTION_UFACTOR;
const int METIS_OPTION_NUMBERING = ::METIS_OPTION_NUMBERING;
const int METIS_OPTION_HELP = ::METIS_OPTION_HELP;
const int METIS_OPTION_TPWGTS = ::METIS_OPTION_TPWGTS;
const int METIS_OPTION_NCOMMON = ::METIS_OPTION_NCOMMON;
const int METIS_OPTION_NOOUTPUT = ::METIS_OPTION_NOOUTPUT;
const int METIS_OPTION_BALANCE = ::METIS_OPTION_BALANCE;
const int METIS_OPTION_GTYPE = ::METIS_OPTION_GTYPE;
const int METIS_OPTION_UBVEC = ::METIS_OPTION_UBVEC;
#else // build without Metis
int METIS_PartGraphKway( ::walberla::int64_t * /*nvtxs*/, ::walberla::int64_t * /*ncon*/, ::walberla::int64_t * /*xadj*/, ::walberla::int64_t * /*adjncy*/,
::walberla::int64_t * /*vwgt*/, ::walberla::int64_t * /*vsize*/, ::walberla::int64_t * /*adjwgt*/, ::walberla::int64_t * /*nparts*/,
double * /*tpwgts*/, double * /*ubvec*/, ::walberla::int64_t * /*options*/, ::walberla::int64_t * /*edgecut*/, ::walberla::int64_t * /*part*/)
{
WALBERLA_ABORT( "You are trying to use Metis functionality but waLBerla is not configured to use it. Set 'WALBERLA_BUILD_WITH_METIS' to 'ON' in your CMake cache to build against an installed version of Metis!" );
}
int METIS_SetDefaultOptions( ::walberla::int64_t * /*options*/ )
{
WALBERLA_ABORT("You are trying to use Metis functionality but waLBerla is not configured to use it. Set 'WALBERLA_BUILD_WITH_METIS' to 'ON' in your CMake cache to build against an installed version of Metis!");
}
const int METIS_OK = 0;
const int METIS_ERROR = 0;
const int METIS_ERROR_INPUT = 0;
const int METIS_ERROR_MEMORY = 0;
const int METIS_OPTION_PTYPE = 0;
const int METIS_OPTION_OBJTYPE = 0;
const int METIS_OPTION_CTYPE = 0;
const int METIS_OPTION_IPTYPE = 0;
const int METIS_OPTION_RTYPE = 0;
const int METIS_OPTION_DBGLVL = 0;
const int METIS_OPTION_NITER = 0;
const int METIS_OPTION_NCUTS = 0;
const int METIS_OPTION_SEED = 0;
const int METIS_OPTION_NO2HOP = 0;
const int METIS_OPTION_MINCONN = 0;
const int METIS_OPTION_CONTIG = 0;
const int METIS_OPTION_COMPRESS = 0;
const int METIS_OPTION_CCORDER = 0;
const int METIS_OPTION_PFACTOR = 0;
const int METIS_OPTION_NSEPS = 0;
const int METIS_OPTION_UFACTOR = 0;
const int METIS_OPTION_NUMBERING = 0;
const int METIS_OPTION_HELP = 0;
const int METIS_OPTION_TPWGTS = 0;
const int METIS_OPTION_NCOMMON = 0;
const int METIS_OPTION_NOOUTPUT = 0;
const int METIS_OPTION_BALANCE = 0;
const int METIS_OPTION_GTYPE = 0;
const int METIS_OPTION_UBVEC = 0;
#endif
} // namespace core
} // namespace walberla
\ No newline at end of file
//======================================================================================================================
//
// 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 MetisWrapper.h
//! \ingroup blockforest
//! \author Christian Godenschwager <christian.godenschwager@fau.de>
//
//======================================================================================================================
#include "core/DataTypes.h"
#include "core/mpi/MPIWrapper.h"
namespace walberla {
namespace core {
int METIS_PartGraphKway( int64_t *nvtxs, int64_t *ncon, int64_t *xadj, int64_t *adjncy, int64_t *vwgt, int64_t *vsize, int64_t *adjwgt,
int64_t *nparts, double *tpwgts, double *ubvec, int64_t *options, int64_t *edgecut, int64_t *part );
int METIS_PartGraphRecursive( int64_t *nvtxs, int64_t *ncon, int64_t *xadj, int64_t *adjncy, int64_t *vwgt, int64_t *vsize, int64_t *adjwgt,
int64_t *nparts, double *tpwgts, double *ubvec, int64_t *options, int64_t *edgecut, int64_t *part );
int METIS_SetDefaultOptions(int64_t *options );
#ifndef METIS_NOPTIONS
# define METIS_NOPTIONS 40
#endif
extern const int METIS_OK;
extern const int METIS_ERROR;
extern const int METIS_ERROR_INPUT;
extern const int METIS_ERROR_MEMORY;
extern const int METIS_OPTION_PTYPE;
extern const int METIS_OPTION_OBJTYPE;
extern const int METIS_OPTION_CTYPE;
extern const int METIS_OPTION_IPTYPE;
extern const int METIS_OPTION_RTYPE;
extern const int METIS_OPTION_DBGLVL;
extern const int METIS_OPTION_NITER;
extern const int METIS_OPTION_NCUTS;
extern const int METIS_OPTION_SEED;
extern const int METIS_OPTION_NO2HOP;
extern const int METIS_OPTION_MINCONN;
extern const int METIS_OPTION_CONTIG;
extern const int METIS_OPTION_COMPRESS;
extern const int METIS_OPTION_CCORDER;
extern const int METIS_OPTION_PFACTOR;
extern const int METIS_OPTION_NSEPS;
extern const int METIS_OPTION_UFACTOR;
extern const int METIS_OPTION_NUMBERING;
extern const int METIS_OPTION_HELP;
extern const int METIS_OPTION_TPWGTS;
extern const int METIS_OPTION_NCOMMON;
extern const int METIS_OPTION_NOOUTPUT;
extern const int METIS_OPTION_BALANCE;
extern const int METIS_OPTION_GTYPE;
extern const int METIS_OPTION_UBVEC;
} // namespace core
} // namespace walberla
\ No newline at end of file
//======================================================================================================================
//
// 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 ParMetisWrapper.cpp
//! \ingroup blockforest
//! \author Christian Godenschwager <christian.godenschwager@fau.de>
//
//======================================================================================================================
#include "waLBerlaDefinitions.h"
#ifdef WALBERLA_BUILD_WITH_PARMETIS
#ifdef _MSC_VER
# pragma push_macro( "INT32_MIN" )
# pragma push_macro( "INT32_MAX" )
# pragma push_macro( "INT64_MIN" )
# pragma push_macro( "INT64_MAX" )
# ifdef INT32_MIN
# undef INT32_MIN
# endif
# ifdef INT32_MAX
# undef INT32_MAX
# endif
# ifdef INT64_MIN
# undef INT64_MIN
# endif
# ifdef INT64_MAX
# undef INT64_MAX
# endif
#endif
#ifdef WALBERLA_BUILD_WITH_METIS
# include "metis.h"
#endif
#ifdef _MSC_VER
# pragma pop_macro( "INT64_MAX" )
# pragma pop_macro( "INT64_MIN" )
# pragma pop_macro( "INT32_MAX" )
# pragma pop_macro( "INT32_MIN" )
#endif
#include <parmetis.h>
#endif
#include "ParMetisWrapper.h"
#include "core/Abort.h"
#include <boost/type_traits/is_same.hpp>
namespace walberla {
namespace core {
#ifdef WALBERLA_BUILD_WITH_PARMETIS
int ParMETIS_V3_AdaptiveRepart(
::walberla::int64_t *vtxdist, ::walberla::int64_t *xadj, ::walberla::int64_t *adjncy, ::walberla::int64_t *vwgt,
::walberla::int64_t *vsize, ::walberla::int64_t *adjwgt, ::walberla::int64_t *wgtflag, ::walberla::int64_t *numflag, int64_t *ncon,
::walberla::int64_t *nparts, double *tpwgts, double *ubvec, double *ipc2redist,
::walberla::int64_t *options, ::walberla::int64_t *edgecut, ::walberla::int64_t *part, MPI_Comm *comm )
{
static_assert( boost::is_same< ::walberla::int64_t, ::idx_t >::value, "You have to compile the metis library with 64-bit wide integer type support!" );
static_assert( boost::is_same< double, ::real_t >::value, "You have to compile the metis library with 64-bit wide floating-point type support!" );
return ::ParMETIS_V3_AdaptiveRepart( vtxdist, xadj, adjncy, vwgt,
vsize, adjwgt, wgtflag, numflag, ncon,
nparts, tpwgts, ubvec, ipc2redist,
options, edgecut, part, comm );
}
int ParMETIS_V3_PartKway(
::walberla::int64_t *vtxdist, ::walberla::int64_t *xadj, ::walberla::int64_t *adjncy, ::walberla::int64_t *vwgt,
::walberla::int64_t *adjwgt, ::walberla::int64_t *wgtflag, ::walberla::int64_t *numflag, ::walberla::int64_t *ncon, ::walberla::int64_t *nparts,
double *tpwgts, double *ubvec, ::walberla::int64_t *options, ::walberla::int64_t *edgecut, ::walberla::int64_t *part,
MPI_Comm *comm )
{
static_assert( boost::is_same< ::walberla::int64_t, ::idx_t >::value, "You have to compile the metis library with 64-bit wide integer type support!" );
static_assert( boost::is_same< double, ::real_t >::value, "You have to compile the metis library with 64-bit wide floating-point type support!" );
return ::ParMETIS_V3_PartKway( vtxdist, xadj, adjncy, vwgt,
adjwgt, wgtflag, numflag, ncon, nparts,
tpwgts, ubvec, options, edgecut, part, comm );
}
int ParMETIS_V3_PartGeomKway(
::walberla::int64_t *vtxdist, ::walberla::int64_t *xadj, ::walberla::int64_t *adjncy, ::walberla::int64_t *vwgt,
::walberla::int64_t *adjwgt, ::walberla::int64_t *wgtflag, ::walberla::int64_t *numflag, ::walberla::int64_t *ndims, double *xyz,
::walberla::int64_t *ncon, ::walberla::int64_t *nparts, double *tpwgts, double *ubvec, ::walberla::int64_t *options,
::walberla::int64_t *edgecut, ::walberla::int64_t *part, MPI_Comm *comm )
{
static_assert( boost::is_same< ::walberla::int64_t, ::idx_t >::value, "You have to compile the metis library with 64-bit wide integer type support!" );
static_assert( boost::is_same< double, ::real_t >::value, "You have to compile the metis library with 64-bit wide floating-point type support!" );
return ::ParMETIS_V3_PartGeomKway( vtxdist, xadj, adjncy, vwgt,
adjwgt, wgtflag, numflag, ndims, xyz,
ncon, nparts, tpwgts, ubvec, options,
edgecut, part, comm );
}
int ParMETIS_V3_RefineKway(
::walberla::int64_t *vtxdist, ::walberla::int64_t *xadj, ::walberla::int64_t *adjncy, ::walberla::int64_t *vwgt,
::walberla::int64_t *adjwgt, ::walberla::int64_t *wgtflag, ::walberla::int64_t *numflag, ::walberla::int64_t *ncon, ::walberla::int64_t *nparts,
double *tpwgts, double *ubvec, ::walberla::int64_t *options, ::walberla::int64_t *edgecut,
::walberla::int64_t *part, MPI_Comm *comm )
{
static_assert( boost::is_same< ::walberla::int64_t, ::idx_t >::value, "You have to compile the metis library with 64-bit wide integer type support!" );
static_assert( boost::is_same< double, ::real_t >::value, "You have to compile the metis library with 64-bit wide floating-point type support!" );
return ::ParMETIS_V3_RefineKway( vtxdist, xadj, adjncy, vwgt,
adjwgt, wgtflag, numflag, ncon, nparts,
tpwgts, ubvec, options, edgecut,
part, comm );
}
#else // build without ParMetis
int ParMETIS_V3_AdaptiveRepart(
::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *,
::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, int64_t *,
::walberla::int64_t *, double *, double *, double *,
::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, MPI_Comm * )
{
WALBERLA_ABORT( "You are trying to use ParMetis functionality but waLBerla is not configured to use it. Set 'WALBERLA_BUILD_WITH_PARMETIS' to 'ON' in your CMake cache to build against an installed version of ParMetis!" );
}
int ParMETIS_V3_PartKway(
::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *,
::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *,
double *, double *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *,
MPI_Comm * )
{
WALBERLA_ABORT( "You are trying to use ParMetis functionality but waLBerla is not configured to use it. Set 'WALBERLA_BUILD_WITH_PARMETIS' to 'ON' in your CMake cache to build against an installed version of ParMetis!" );
}
int ParMETIS_V3_PartGeomKway(
::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *,
::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, double *,
::walberla::int64_t *, ::walberla::int64_t *, double *, double *, ::walberla::int64_t *,
::walberla::int64_t *, ::walberla::int64_t *, MPI_Comm * )
{
WALBERLA_ABORT( "You are trying to use ParMetis functionality but waLBerla is not configured to use it. Set 'WALBERLA_BUILD_WITH_PARMETIS' to 'ON' in your CMake cache to build against an installed version of ParMetis!" );
}
int ParMETIS_V3_RefineKway(
::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *,
::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *, ::walberla::int64_t *,
double *, double *, ::walberla::int64_t *, ::walberla::int64_t *,
::walberla::int64_t *, MPI_Comm * )
{
WALBERLA_ABORT( "You are trying to use ParMetis functionality but waLBerla is not configured to use it. Set 'WALBERLA_BUILD_WITH_PARMETIS' to 'ON' in your CMake cache to build against an installed version of ParMetis!" );
}
#endif
} // namespace core
} // namespace walberla
\ No newline at end of file
//====================================================================================================================== //======================================================================================================================
// //
// This file is part of waLBerla. waLBerla is free software: you can // 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 // 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 // License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version. // the License, or (at your option) any later version.
// //
// waLBerla is distributed in the hope that it will be useful, but WITHOUT // waLBerla is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details. // for more details.
// //
// You should have received a copy of the GNU General Public License along // 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/>. // with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
// //
//! \file MetisWrapper.h //! \file ParMetisWrapper.h
//! \ingroup blockforest //! \ingroup blockforest
//! \author Christian Godenschwager <christian.godenschwager@fau.de> //! \author Christian Godenschwager <christian.godenschwager@fau.de>
// //
//====================================================================================================================== //======================================================================================================================
#pragma once #include "MetisWrapper.h"
#include "waLBerlaDefinitions.h" // for macro WALBERLA_BUILD_WITH_METIS
#ifdef _MSC_VER
#pragma push_macro( "INT32_MIN" )
#pragma push_macro( "INT32_MAX" )
#pragma push_macro( "INT64_MIN" )
#pragma push_macro( "INT64_MAX" )
#ifdef INT32_MIN
#undef INT32_MIN
#endif
#ifdef INT32_MAX #include "core/DataTypes.h"
#undef INT32_MAX #include "core/mpi/MPIWrapper.h"
#endif
#ifdef INT64_MIN namespace walberla {
#undef INT64_MIN namespace core {
#endif
#ifdef INT64_MAX int ParMETIS_V3_AdaptiveRepart(
#undef INT64_MAX int64_t *vtxdist, int64_t *xadj, int64_t *adjncy, int64_t *vwgt,
#endif int64_t *vsize, int64_t *adjwgt, int64_t *wgtflag, int64_t *numflag, int64_t *ncon,
#endif int64_t *nparts, double *tpwgts, double *ubvec, double *ipc2redist,
int64_t *options, int64_t *edgecut, int64_t *part, MPI_Comm *comm );
#ifdef WALBERLA_BUILD_WITH_METIS int ParMETIS_V3_PartKway(
// external software includes int64_t *vtxdist, int64_t *xadj, int64_t *adjncy, int64_t *vwgt,
#include "metis.h" int64_t *adjwgt, int64_t *wgtflag, int64_t *numflag, int64_t *ncon, int64_t *nparts,
double *tpwgts, double *ubvec, int64_t *options, int64_t *edgecut, int64_t *part,
MPI_Comm *comm );
#include <boost/type_traits/is_same.hpp> int ParMETIS_V3_PartGeomKway(
int64_t *vtxdist, int64_t *xadj, int64_t *adjncy, int64_t *vwgt,
int64_t *adjwgt, int64_t *wgtflag, int64_t *numflag, int64_t *ndims, double *xyz,
int64_t *ncon, int64_t *nparts, double *tpwgts, double *ubvec, int64_t *options,
int64_t *edgecut, int64_t *part, MPI_Comm *comm );
static_assert( boost::is_same< ::real_t, ::walberla::real_t >::value , "The width of waLBerla's real_t data type does not match the width of METIS' real_t data type. " \ int ParMETIS_V3_RefineKway(
"Please adapt either waLBerla's CMake option WALBERLA_DOUBLE_ACCURACY or change REALTYPEWIDTH in metis.h." ); int64_t *vtxdist, int64_t *xadj, int64_t *adjncy, int64_t *vwgt,
#endif int64_t *adjwgt, int64_t *wgtflag, int64_t *numflag, int64_t *ncon, int64_t *nparts,
double *tpwgts, double *ubvec, int64_t *options, int64_t *edgecut,
int64_t *part, MPI_Comm *comm );
#ifdef _MSC_VER } // namespace core
#pragma pop_macro( "INT64_MAX" ) } // namespace walberla
#pragma pop_macro( "INT64_MIN" ) \ No newline at end of file
#pragma pop_macro( "INT32_MAX" )
#pragma pop_macro( "INT32_MIN" )
#endif
\ No newline at end of file
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
// External libraries // External libraries
#cmakedefine WALBERLA_BUILD_WITH_MPI #cmakedefine WALBERLA_BUILD_WITH_MPI
#cmakedefine WALBERLA_BUILD_WITH_METIS #cmakedefine WALBERLA_BUILD_WITH_METIS
#cmakedefine WALBERLA_BUILD_WITH_PARMETIS
#cmakedefine WALBERLA_BUILD_WITH_BOOST_THREAD #cmakedefine WALBERLA_BUILD_WITH_BOOST_THREAD
#cmakedefine WALBERLA_BUILD_WITH_PYTHON #cmakedefine WALBERLA_BUILD_WITH_PYTHON
......
...@@ -200,3 +200,19 @@ waLBerla_execute_test( NAME UNIQUEID PROCESSES 4) ...@@ -200,3 +200,19 @@ waLBerla_execute_test( NAME UNIQUEID PROCESSES 4)
waLBerla_compile_test( FILES VersionTest.cpp ) waLBerla_compile_test( FILES VersionTest.cpp )
waLBerla_execute_test( NAME VersionTest ) waLBerla_execute_test( NAME VersionTest )
##################
# load_balancing #
##################
if( WALBERLA_BUILD_WITH_METIS )
waLBerla_compile_test( NAME MetisTest FILES load_balancing/MetisTest.cpp DEPENDS field )
waLBerla_execute_test( NAME MetisTest COMMAND $<TARGET_FILE:MetisTest> 64 64 4 --no-vtk )
endif()
if( WALBERLA_BUILD_WITH_PARMETIS )
waLBerla_compile_test( NAME ParMetisTest FILES load_balancing/ParMetisTest.cpp DEPENDS blockforest field stencil vtk )
waLBerla_execute_test( NAME ParMetisTest1 COMMAND $<TARGET_FILE:ParMetisTest> 64 64 4 --no-vtk )
waLBerla_execute_test( NAME ParMetisTest2 COMMAND $<TARGET_FILE:ParMetisTest> 64 64 8 --no-vtk PROCESSES 2 )
waLBerla_execute_test( NAME ParMetisTest4 COMMAND $<TARGET_FILE:ParMetisTest> 64 64 16 --no-vtk PROCESSES 4 )
endif()
\ No newline at end of file
//======================================================================================================================
//
// 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 MetisTest.cpp
//! \ingroup core
//! \author Christian Godenschwager <christian.godenschwager@fau.de>
//! \brief Test for MetisWrapper
//
//======================================================================================================================
#include "blockforest/Initialization.h"
#include "blockforest/communication/UniformBufferedScheme.h"
#include "core/Environment.h"
#include "core/debug/TestSubsystem.h"
#include "core/load_balancing/MetisWrapper.h"
#include "core/math/Vector2.h"
#include "core/logging/Logging.h"
#include "field/AddToStorage.h"
#include "field/GhostLayerField.h"
#include "field/vtk/VTKWriter.h"
#include "field/communication/PackInfo.h"
#include "stencil/D2Q9.h"
#include "vtk/VTKOutput.h"
#include "vtk/BlockCellDataWriter.h"
#include <boost/lexical_cast.hpp>
#include <boost/random.hpp>
int main( int argc, char * argv[] )
{
using namespace walberla;
mpi::Environment env( argc, argv );
debug::enterTestMode();
std::vector< std::string > args( argv, argv + argc );
Vector2<uint_t> fieldSize;
uint_t partitions;
bool vtk = true;
auto argIt = std::find( args.begin(), args.end(), "--no-vtk" );
if(argIt != args.end())
{
vtk = false;
args.erase( argIt );
}
try {
fieldSize.set( boost::lexical_cast< uint_t >( args.at(1) ), boost::lexical_cast< uint_t >( args.at(2) ) );
partitions = boost::lexical_cast< uint_t >( args.at(3) );
}
catch( std::exception & e )
{
WALBERLA_ABORT( "USAGE: " << args[0] << " SizeX SizeY #Partitions\n\n" << e.what() );
}
auto blocks = blockforest::createUniformBlockGrid( uint_t(1), uint_t(1), uint_t(1),
fieldSize[0], fieldSize[1], uint_t(1),
real_t(1),
uint_t(1), uint_t(1), uint_t(1),
true, true, false );
typedef field::GhostLayerField< int64_t, 1 > FieldType;
auto domainId = field::addToStorage< FieldType >( blocks, "domain", int64_t(-1), field::zyxf, uint_t(1) );
auto partFieldId = field::addToStorage< FieldType >( blocks, "partitions", int64_t(-1), field::zyxf, uint_t(1) );
auto & domain = *( blocks->begin()->getData< FieldType >( domainId ) );
auto & partField = *( blocks->begin()->getData< FieldType >( partFieldId ) );
int64_t ctr = 0;
for(auto it = domain.begin(); it != domain.end(); ++it)
{
*it = ctr++;
}
WALBERLA_CHECK_GREATER( ctr, 0 );
blockforest::communication::UniformBufferedScheme< stencil::D2Q9 > scheme( blocks );
scheme.addPackInfo( make_shared< field::communication::PackInfo< FieldType > >( domainId ) );
scheme();
int64_t nvtxs = ctr;
int64_t ncon = int64_t(1);
std::vector< int64_t > xadj, adjncy;
xadj.push_back( int64_t(0) );
Cell c( cell_idx_t(0), cell_idx_t(0), cell_idx_t(0) );
for( c[0] = 0; c[0] < cell_idx_c( domain.xSize() ); ++c[0] )
for( c[1] = 0; c[1] < cell_idx_c( domain.ySize() ); ++c[1] )
{
for( auto dirIt = stencil::D2Q9::beginNoCenter(); dirIt != stencil::D2Q9::end(); ++dirIt )
adjncy.push_back( domain.get( c + *dirIt ) );
xadj.push_back( int64_c( adjncy.size() ) );
}
WALBERLA_CHECK_EQUAL( xadj.size(), numeric_cast<size_t>( nvtxs ) + size_t(1) );
int64_t nparts = int64_c( partitions );
int64_t edgecut;
std::vector< int64_t > part( numeric_cast<size_t>( nvtxs ) );
int result = core::METIS_PartGraphRecursive( &nvtxs, &ncon, &(xadj.front()), &(adjncy.front()), NULL, NULL, NULL,
&nparts, NULL, NULL, NULL, &edgecut, &(part.front()) );
WALBERLA_CHECK_EQUAL( result, core::METIS_OK );
c = Cell( cell_idx_t(0), cell_idx_t(0), cell_idx_t(0) );
auto it = part.begin();
for( c[0] = 0; c[0] < cell_idx_c( domain.xSize() ); ++c[0] )
for( c[1] = 0; c[1] < cell_idx_c( domain.ySize() ); ++c[1] )
{
if( domain.get( c ) == int64_t( -1 ) )
continue;
WALBERLA_CHECK_UNEQUAL( it, part.end() );
partField.get( c ) = *it++;
}
WALBERLA_CHECK_EQUAL( it, part.end() );
if( vtk )
{
auto vtkOutput = vtk::createVTKOutput_BlockData( blocks, "Metis", 1, 0 );
vtkOutput->addCellDataWriter( make_shared< field::VTKWriter< FieldType, int64_t > >( domainId, "domain" ) );
vtkOutput->addCellDataWriter( make_shared< field::VTKWriter< FieldType, int64_t > >( partFieldId, "partitions" ) );
vtk::writeFiles( vtkOutput )();
}
return EXIT_SUCCESS;
}
//======================================================================================================================
//
// 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 ParMetisTest.cpp
//! \ingroup core
//! \author Christian Godenschwager <christian.godenschwager@fau.de>
//! \brief Test for MetisWrapper
//
//======================================================================================================================
#include "blockforest/Initialization.h"
#include "blockforest/communication/UniformBufferedScheme.h"
#include "core/Environment.h"
#include "core/debug/TestSubsystem.h"
#include "core/load_balancing/ParMetisWrapper.h"
#include "core/math/Vector2.h"
#include "core/math/IntegerFactorization.h"
#include "core/logging/Logging.h"
#include "field/AddToStorage.h"
#include "field/GhostLayerField.h"
#include "field/vtk/VTKWriter.h"
#include "field/communication/PackInfo.h"
#include "stencil/D2Q9.h"
#include "stencil/D3Q27.h"
#include "vtk/VTKOutput.h"
#include "vtk/BlockCellDataWriter.h"
#include <boost/lexical_cast.hpp>
#include <boost/random.hpp>
int main( int argc, char * argv[] )
{
using namespace walberla;
mpi::Environment env( argc, argv );
debug::enterTestMode();
std::vector< std::string > args( argv, argv + argc );
Vector2<uint_t> fieldSize;
uint_t partitions;
bool vtk = true;
try {
fieldSize.set( boost::lexical_cast< uint_t >( args.at(1) ), boost::lexical_cast< uint_t >( args.at(2) ) );
partitions = boost::lexical_cast< uint_t >( args.at(3) );
auto it = std::find( args.begin(), args.end(), "--no-vtk" );
if(it != args.end())
{
vtk = false;
args.erase( it );
}
}
catch( std::exception & e )
{
WALBERLA_ABORT( "USAGE: " << args[0] << " SizeX SizeY #Partitions\n\n" << e.what() );
}
int numProcesses = MPIManager::instance()->numProcesses();
auto gridSize = math::getFactors( uint_c( numProcesses ), uint_t(2) );
auto blocks = blockforest::createUniformBlockGrid( gridSize[0], gridSize[1], uint_t(1),
fieldSize[0], fieldSize[1], uint_t(1),
real_t(1),
true,
true, true, false );
typedef field::GhostLayerField< int64_t, 1 > FieldType;
auto domainId = field::addToStorage< FieldType >( blocks, "domain", int64_t(-1), field::zyxf, uint_t(1) );
auto partFieldId = field::addToStorage< FieldType >( blocks, "partitions", int64_t(-1), field::zyxf, uint_t(1) );
auto & domain = *( blocks->begin()->getData< FieldType >( domainId ) );
auto & partField = *( blocks->begin()->getData< FieldType >( partFieldId ) );
WALBERLA_CHECK_EQUAL( std::distance( blocks->begin(), blocks->end() ), 1 );
int64_t ctr = int64_c( fieldSize[0] * fieldSize[1] ) * int64_c( MPIManager::instance()->rank() );
Cell c( cell_idx_t(0), cell_idx_t(0), cell_idx_t(0) );
for( c[0] = 0; c[0] < cell_idx_c( domain.xSize() ); ++c[0] )
for( c[1] = 0; c[1] < cell_idx_c( domain.ySize() ); ++c[1] )
{
domain.get( c ) = ctr++;
}
blockforest::communication::UniformBufferedScheme< stencil::D2Q9 > scheme( blocks );
scheme.addPackInfo( make_shared< field::communication::PackInfo< FieldType > >( domainId ) );
scheme();
std::vector< int64_t > vtxdist;
for( int i = 0; i < MPIManager::instance()->numProcesses() + 1; ++i )
{
vtxdist.push_back( int64_c(i) * int64_c( fieldSize[0] * fieldSize[1] ) );
}
int64_t ncon = int64_t(1);
std::vector< int64_t > xadj, adjncy;
xadj.push_back( int64_t(0) );
c = Cell( cell_idx_t(0), cell_idx_t(0), cell_idx_t(0) );
for( c[0] = 0; c[0] < cell_idx_c( domain.xSize() ); ++c[0] )
for( c[1] = 0; c[1] < cell_idx_c( domain.ySize() ); ++c[1] )
{
for( auto dirIt = stencil::D2Q9::beginNoCenter(); dirIt != stencil::D2Q9::end(); ++dirIt )
adjncy.push_back( domain.get( c + *dirIt ) );
xadj.push_back( int64_c( adjncy.size() ) );
}
WALBERLA_CHECK_EQUAL( xadj.size(), fieldSize[0] * fieldSize[1] + uint_t(1) );
WALBERLA_CHECK_EQUAL( adjncy.size(), fieldSize[0] * fieldSize[1] * uint_t(8) );
int64_t wgtflag = 0;
int64_t numflag = 0;
int64_t nparts = int64_c( partitions );
std::vector< double > tpwgts( partitions, 1.0 / numeric_cast<double>( partitions ) );
std::vector< double > ubvec( ncon, 1.05 );
int64_t options[] = {0,0,0};
int64_t edgecut;
std::vector< int64_t > part( fieldSize[0] * fieldSize[1] );
MPI_Comm comm = MPIManager::instance()->comm();
int result = core::ParMETIS_V3_PartKway( &(vtxdist.front()), &(xadj.front()), &(adjncy.front()), NULL, NULL, &wgtflag, &numflag, &ncon, &nparts,
&(tpwgts.front()), &(ubvec.front()), options, &edgecut, &(part.front()), &comm );
WALBERLA_CHECK_EQUAL( result, core::METIS_OK );
c = Cell( cell_idx_t(0), cell_idx_t(0), cell_idx_t(0) );
auto it = part.begin();
for( c[0] = 0; c[0] < cell_idx_c( domain.xSize() ); ++c[0] )
for( c[1] = 0; c[1] < cell_idx_c( domain.ySize() ); ++c[1] )
{
if( domain.get( c ) == int64_t( -1 ) )
continue;
WALBERLA_CHECK_UNEQUAL( it, part.end() );
partField.get( c ) = *it++;
}
WALBERLA_CHECK_EQUAL( it, part.end() );
if( vtk )
{
auto vtkOutput = vtk::createVTKOutput_BlockData( blocks, "Metis", 1, 0 );
vtkOutput->addCellDataWriter( make_shared< field::VTKWriter< FieldType, int64_t > >( domainId, "domain" ) );
vtkOutput->addCellDataWriter( make_shared< field::VTKWriter< FieldType, int64_t > >( partFieldId, "partitions" ) );
vtk::writeFiles( vtkOutput )();
}
return EXIT_SUCCESS;
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment