Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
HelloParMOAB.cpp File Reference
#include "moab/Core.hpp"
#include "moab/Range.hpp"
#include "MBParallelConventions.h"
#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <cstdlib>
+ Include dependency graph for HelloParMOAB.cpp:

Go to the source code of this file.

Namespaces

 anonymous_namespace{HelloParMOAB.cpp}
 

Functions

void anonymous_namespace{HelloParMOAB.cpp}::print_usage (const char *program_name)
 
void anonymous_namespace{HelloParMOAB.cpp}::print_entity_stats (const std::vector< int > &counts, int nprocs, const std::string &title="")
 
int main (int argc, char **argv)
 

Variables

const char *const anonymous_namespace{HelloParMOAB.cpp}::DEFAULT_MESH_FILE = "/64bricks_512hex_256part.h5m"
 
const char *const anonymous_namespace{HelloParMOAB.cpp}::DEFAULT_READ_OPTS = "PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;PARALLEL_RESOLVE_SHARED_ENTS"
 

Function Documentation

◆ main()

int main ( int  argc,
char **  argv 
)
Examples
HelloParMOAB.cpp.

Definition at line 83 of file HelloParMOAB.cpp.

84 {
85  // Initialize MPI
86  int mpi_initialized = 0;
87  MPI_Initialized( &mpi_initialized );
88  if( !mpi_initialized )
89  {
90  MPI_Init( &argc, &argv );
91  }
92 
93  int global_rank = 0, global_size = 1;
94  MPI_Comm_rank( MPI_COMM_WORLD, &global_rank );
95  MPI_Comm_size( MPI_COMM_WORLD, &global_size );
96 
97  try
98  {
99  // Parse command line arguments
100  std::string mesh_file = std::string( MESH_DIR ) + DEFAULT_MESH_FILE;
101  int num_comms = 1;
102 
103  if( argc > 1 && ( std::string( argv[1] ) == "-h" || std::string( argv[1] ) == "--help" ) )
104  {
105  if( global_rank == 0 ) print_usage( argv[0] );
106  MPI_Finalize();
107  return 0;
108  }
109 
110  if( argc > 1 )
111  {
112  mesh_file = argv[1];
113  }
114 
115  if( argc > 2 )
116  {
117  num_comms = std::atoi( argv[2] );
118  if( num_comms < 1 )
119  {
120  if( global_rank == 0 )
121  {
122  std::cerr << "Error: Number of communicators must be at least 1\n";
123  print_usage( argv[0] );
124  }
125  MPI_Finalize();
126  return 1;
127  }
128  }
129 
130  // Create MOAB instance with smart pointer for automatic cleanup
131  auto moab = std::make_unique< Core >();
132  if( !moab )
133  {
134  std::cerr << "Error: Failed to create MOAB instance\n";
135  MPI_Abort( MPI_COMM_WORLD, 1 );
136  }
137 
138  // Split the communicator if requested
139  MPI_Comm comm;
140  int color = global_rank % num_comms; // Determine color based on requested number of communicators
141 
142  if( num_comms > 1 )
143  {
144  // Split the communicator into the specified number of groups
145  MPI_Comm_split( MPI_COMM_WORLD, color, global_rank, &comm );
146  }
147  else
148  {
149  // Use the default communicator
150  comm = MPI_COMM_WORLD;
151  }
152 
153  // Get the local communicator information
154  int local_rank = 0, local_size = 1;
155  MPI_Comm_rank( comm, &local_rank );
156  MPI_Comm_size( comm, &local_size );
157 
158  // Print process information
159  if( global_rank == 0 )
160  {
161  std::cout << "\n=== MOAB Parallel Hello World ===\n"
162  << "Global processes: " << global_size << "\n"
163  << "Number of communicator groups: " << num_comms << "\n"
164  << "Processes per group: ~" << ( global_size + num_comms - 1 ) / num_comms << "\n"
165  << "Reading file: " << mesh_file << "\n"
166  << "Read options: " << DEFAULT_READ_OPTS << "\n\n";
167  }
168 
169  // Read the mesh file in parallel
170  if( global_rank == 0 )
171  {
172  std::cout << "Loading mesh file..." << std::endl;
173  }
174 
175  // Create root sets for each mesh. Then pass these
176  // to the load_file functions to be populated.
177  moab::EntityHandle rootset, partnset;
178  MB_CHK_SET_ERR( moab->create_meshset( moab::MESHSET_SET, rootset ), "Creating root set failed" );
179  MB_CHK_SET_ERR( moab->create_meshset( moab::MESHSET_SET, partnset ), "Creating partition set failed" );
180 
181  // Create the parallel communicator object with the partition handle associated with MOAB
182  auto pcomm = std::auto_ptr< moab::ParallelComm >( ParallelComm::get_pcomm( moab.get(), partnset, &comm ) );
183 
184  MB_CHK_SET_ERR( moab->load_file( mesh_file.c_str(), &rootset, DEFAULT_READ_OPTS ),
185  "Failed to load mesh file: " << mesh_file );
186 
187  // Create parallel communication interface
188  // auto pcomm = std::make_unique<ParallelComm>(moab.get(), comm);
189  // auto pcomm = std::make_unique<ParallelComm>(moab.get(), comm);
190 
191  // Get shared entities and report statistics
192  Range shared_sets, shared_ents, owned_entities;
193 
194  // Range src_elems;
195  // MB_CHK_ERR( pcomm->get_part_entities( src_elems, 3 ) );
196  // src_elems.print("Source elements: ");
197 
198  // Get sets shared with all other processors
199  MB_CHK_SET_ERR( pcomm->get_shared_sets( shared_sets ), "Failed to get shared sets" );
200 
201  shared_sets.print( "Shared sets: " );
202 
203  // Get entities shared with all other processors
204  for( int dim = 0; dim < 4; ++dim )
205  {
206  MB_CHK_SET_ERR( pcomm->get_part_entities( shared_ents, dim ), "Failed to get shared entities" );
207  shared_ents.print( "Shared entities: " );
208  }
209 
210  // MB_CHK_SET_ERR(
211  // pcomm->get_shared_entities(-1, shared_ents),
212  // "Failed to get shared entities"
213  // );
214 
215  // Filter to get only locally owned shared entities
216  MB_CHK_SET_ERR( pcomm->filter_pstatus( shared_ents, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1, &owned_entities ),
217  "Failed to filter owned entities" );
218 
219  shared_ents.print( "Owned entities: " );
220 
221  // Count owned entities by dimension
222  unsigned int entity_counts[4] = { 0 };
223  for( int dim = 0; dim < 4; ++dim )
224  {
225  entity_counts[dim] = static_cast< unsigned int >( owned_entities.num_of_dimension( dim ) );
226  }
227 
228  // Gather statistics on process 0 of each communicator
229  std::vector< int > recv_buffer( local_size * 4, 0 );
230  MPI_Gather( entity_counts, 4, MPI_INT, recv_buffer.data(), 4, MPI_INT, 0, comm );
231 
232  // Print initial statistics
233  if( local_rank == 0 )
234  {
235  std::cout << "\n=== Initial Shared Entity Statistics (Group " << color << ") ===\n";
236  print_entity_stats( std::vector< int >( entity_counts, entity_counts + 4 ), local_size );
237  print_entity_stats( recv_buffer, local_size );
238  }
239 
240  // Exchange ghost elements (1 layer, using vertices as bridge)
241  if( global_rank == 0 ) std::cout << "\nExchanging ghost elements..." << std::endl;
243  pcomm->exchange_ghost_cells( 3, // ghost_dim: exchange 3D elements (hexahedra)
244  0, // bridge_dim: use vertices as bridge
245  1, // num_layers: exchange 1 layer of ghost elements
246  0, // addl_ents: no additional entities
247  true // store_remote_handles: store remote handles for ghost entities
248  ),
249  "Failed to exchange ghost cells" );
250 
251  // Update shared entity information after ghost exchange
252  shared_ents.clear();
253  owned_entities.clear();
254 
255  MB_CHK_SET_ERR( pcomm->get_shared_entities( -1, shared_ents ),
256  "Failed to get shared entities after ghost exchange" );
257 
258  MB_CHK_SET_ERR( pcomm->filter_pstatus( shared_ents, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1, &owned_entities ),
259  "Failed to filter owned entities after ghost exchange" );
260 
261  // Recalculate entity counts
262  for( int dim = 0; dim < 4; ++dim )
263  {
264  entity_counts[dim] = static_cast< unsigned int >( owned_entities.num_of_dimension( dim ) );
265  }
266 
267  // Gather updated statistics
268  MPI_Gather( entity_counts, 4, MPI_INT, recv_buffer.data(), 4, MPI_INT, 0, comm );
269 
270  // Print final statistics
271  if( local_rank == 0 )
272  {
273  std::cout << "\n=== Final Shared Entity Statistics After Ghost Exchange (Group " << color << ") ===\n";
274  print_entity_stats( recv_buffer, local_size );
275  std::cout << "\n=== Parallel Example Completed Successfully ===\n\n";
276  }
277 
278  // Clean up MPI communicator if we created it
279  if( num_comms > 1 )
280  {
281  MPI_Comm_free( &comm );
282  }
283 
284  // Clean up MOAB and MPI
285  pcomm.reset();
286  moab.reset();
287 
288  // Only finalize MPI if we initialized it
289  if( !mpi_initialized )
290  {
291  MPI_Finalize();
292  }
293 
294  return 0;
295  }
296  catch( const std::exception& e )
297  {
298  std::cerr << "Error on rank " << global_rank << ": " << e.what() << std::endl;
299  MPI_Abort( MPI_COMM_WORLD, 1 );
300  return 1;
301  }
302  catch( ... )
303  {
304  std::cerr << "Unknown error occurred on rank " << global_rank << std::endl;
305  MPI_Abort( MPI_COMM_WORLD, 1 );
306  return 1;
307  }
308 }

References moab::Range::clear(), anonymous_namespace{HelloParMOAB.cpp}::DEFAULT_MESH_FILE, anonymous_namespace{HelloParMOAB.cpp}::DEFAULT_READ_OPTS, MB_CHK_SET_ERR, MESH_DIR, MESHSET_SET, moab::Range::num_of_dimension(), moab::Range::print(), anonymous_namespace{HelloParMOAB.cpp}::print_entity_stats(), anonymous_namespace{HelloParMOAB.cpp}::print_usage(), PSTATUS_NOT, and PSTATUS_NOT_OWNED.