Demonstrates parallel mesh operations with MOAB, including shared entity resolution and ghost exchange.This example shows how to:
This will load the mesh on 8 processes, split into 2 communicator groups (4 processes each).
#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <cstdlib>
#ifdef MOAB_HAVE_MPI
#include <mpi.h>
#endif
namespace
{
const char*
const DEFAULT_READ_OPTS =
"PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;PARALLEL_RESOLVE_SHARED_ENTS";
{
std::cout << "Usage: mpiexec -np <num_procs> " << program_name << " [meshfile] [num_communicators]\n"
<< "\nOptions:"
<< "\n num_communicators - Number of MPI communicator groups to create (default: 1)\n";
}
void print_entity_stats(
const std::vector< int >& counts,
int nprocs,
const std::string& title =
"" )
{
if( !title.empty() )
{
std::cout << "\n" << title << ":\n";
}
for( int i = 0; i < nprocs; ++i )
{
std::cout << " Shared, owned entities on proc " << i << ": " << counts[4 * i] << " verts, "
<< counts[4 * i + 1] << " edges, " << counts[4 * i + 2] << " faces, " << counts[4 * i + 3]
<< " elements\n";
}
}
}
int main(
int argc,
char** argv )
{
int mpi_initialized = 0;
MPI_Initialized( &mpi_initialized );
if( !mpi_initialized )
{
MPI_Init( &argc, &argv );
}
int global_rank = 0, global_size = 1;
MPI_Comm_rank( MPI_COMM_WORLD, &global_rank );
MPI_Comm_size( MPI_COMM_WORLD, &global_size );
try
{
int num_comms = 1;
if( argc > 1 && ( std::string( argv[1] ) == "-h" || std::string( argv[1] ) == "--help" ) )
{
MPI_Finalize();
return 0;
}
if( argc > 1 )
{
mesh_file = argv[1];
}
if( argc > 2 )
{
num_comms = std::atoi( argv[2] );
if( num_comms < 1 )
{
if( global_rank == 0 )
{
std::cerr << "Error: Number of communicators must be at least 1\n";
}
MPI_Finalize();
return 1;
}
}
auto moab = std::make_unique< Core >();
{
std::cerr << "Error: Failed to create MOAB instance\n";
MPI_Abort( MPI_COMM_WORLD, 1 );
}
MPI_Comm comm;
int color = global_rank % num_comms;
if( num_comms > 1 )
{
MPI_Comm_split( MPI_COMM_WORLD, color, global_rank, &comm );
}
else
{
comm = MPI_COMM_WORLD;
}
int local_rank = 0, local_size = 1;
MPI_Comm_rank( comm, &local_rank );
MPI_Comm_size( comm, &local_size );
if( global_rank == 0 )
{
std::cout << "\n=== MOAB Parallel Hello World ===\n"
<< "Global processes: " << global_size << "\n"
<< "Number of communicator groups: " << num_comms << "\n"
<< "Processes per group: ~" << ( global_size + num_comms - 1 ) / num_comms << "\n"
<< "Reading file: " << mesh_file << "\n"
}
if( global_rank == 0 )
{
std::cout << "Loading mesh file..." << std::endl;
}
auto pcomm = std::auto_ptr< moab::ParallelComm >( ParallelComm::get_pcomm(
moab.get(), partnset, &comm ) );
"Failed to load mesh file: " << mesh_file );
Range shared_sets, shared_ents, owned_entities;
MB_CHK_SET_ERR( pcomm->get_shared_sets( shared_sets ),
"Failed to get shared sets" );
shared_sets.print( "Shared sets: " );
for( int dim = 0; dim < 4; ++dim )
{
MB_CHK_SET_ERR( pcomm->get_part_entities( shared_ents, dim ),
"Failed to get shared entities" );
shared_ents.print( "Shared entities: " );
}
"Failed to filter owned entities" );
shared_ents.print( "Owned entities: " );
unsigned int entity_counts[4] = { 0 };
for( int dim = 0; dim < 4; ++dim )
{
entity_counts[dim] = static_cast< unsigned int >( owned_entities.num_of_dimension( dim ) );
}
std::vector< int > recv_buffer( local_size * 4, 0 );
MPI_Gather( entity_counts, 4, MPI_INT, recv_buffer.data(), 4, MPI_INT, 0, comm );
if( local_rank == 0 )
{
std::cout << "\n=== Initial Shared Entity Statistics (Group " << color << ") ===\n";
}
if( global_rank == 0 ) std::cout << "\nExchanging ghost elements..." << std::endl;
pcomm->exchange_ghost_cells( 3,
0,
1,
0,
true
),
"Failed to exchange ghost cells" );
shared_ents.clear();
owned_entities.clear();
"Failed to get shared entities after ghost exchange" );
"Failed to filter owned entities after ghost exchange" );
for( int dim = 0; dim < 4; ++dim )
{
entity_counts[dim] = static_cast< unsigned int >( owned_entities.num_of_dimension( dim ) );
}
MPI_Gather( entity_counts, 4, MPI_INT, recv_buffer.data(), 4, MPI_INT, 0, comm );
if( local_rank == 0 )
{
std::cout << "\n=== Final Shared Entity Statistics After Ghost Exchange (Group " << color << ") ===\n";
std::cout << "\n=== Parallel Example Completed Successfully ===\n\n";
}
if( num_comms > 1 )
{
MPI_Comm_free( &comm );
}
pcomm.reset();
if( !mpi_initialized )
{
MPI_Finalize();
}
return 0;
}
catch( const std::exception& e )
{
std::cerr << "Error on rank " << global_rank << ": " << e.what() << std::endl;
MPI_Abort( MPI_COMM_WORLD, 1 );
return 1;
}
catch( ... )
{
std::cerr << "Unknown error occurred on rank " << global_rank << std::endl;
MPI_Abort( MPI_COMM_WORLD, 1 );
return 1;
}
}