Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
ExchangeHalos.cpp File Reference
#include "moab/Core.hpp"
#include "moab/CpuTimer.hpp"
#include "moab/ProgOptions.hpp"
#include "moab/ParallelComm.hpp"
#include "MBParallelConventions.h"
#include <iostream>
#include <string>
+ Include dependency graph for ExchangeHalos.cpp:

Go to the source code of this file.

Classes

struct  RuntimeContext
 The RunttimeContext is an example specific class to store the run specific input data, MOAB datastructures used during the run and provides other utility functions to profile operations etc. More...
 

Macros

#define dbgprint(MSG)
 
#define runchk(CODE, MSG)
 
#define runchk_cont(CODE, MSG)
 

Functions

int main (int argc, char **argv)
 

Macro Definition Documentation

◆ dbgprint

#define dbgprint (   MSG)
Value:
do \
{ \
if( context.proc_id == 0 ) std::cout << MSG << std::endl; \
} while( false )

Definition at line 51 of file ExchangeHalos.cpp.

◆ runchk

#define runchk (   CODE,
  MSG 
)
Value:
do \
{ \
moab::ErrorCode err = CODE; \
MB_CHK_SET_ERR( err, MSG ); \
} while( false )

Definition at line 57 of file ExchangeHalos.cpp.

◆ runchk_cont

#define runchk_cont (   CODE,
  MSG 
)
Value:
do \
{ \
moab::ErrorCode err = CODE; \
MB_CHK_ERR_CONT( err ); \
if( err ) std::cout << "Error:: " << MSG << std::endl; \
} while( false )

Definition at line 64 of file ExchangeHalos.cpp.

Function Documentation

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 167 of file ExchangeHalos.cpp.

168 {
169  // Initialize MPI first
170  MPI_Init( &argc, &argv );
171 
172  {
173  // Create our context for this example run
175  dbgprint( "********** Exchange halos example **********\n" );
176 
177  // Get the input options
178  context.ParseCLOptions( argc, argv );
179 
180  /////////////////////////////////////////////////////////////////////////
181  // Print out the input parameters in use
182  dbgprint( " -- Input Parameters -- " );
183  dbgprint( " Number of Processes = " << context.num_procs );
184  dbgprint( " Input mesh = " << context.input_filename );
185  dbgprint( " Ghost Layers = " << context.ghost_layers );
186  dbgprint( " Scalar Tag name = " << context.scalar_tagname );
187  dbgprint( " Vector Tag name = " << context.vector_tagname );
188  dbgprint( " Vector Tag length = " << context.vector_length << endl );
189  /////////////////////////////////////////////////////////////////////////
190 
191  // Timer storage for all phases
192  double elapsed_times[4];
193 
194  // Read the input file specified by user, in parallel, using appropriate options
195  // Supports reading partitioned h5m files and MPAS nc files directly with online Zoltan partitioning
196  context.timer_push( "Read input file" );
197  {
198  // Load the file from disk with given options
199  runchk( context.load_file( false ), "MOAB::load_file failed for filename: " << context.input_filename );
200  }
201  context.timer_pop();
202  elapsed_times[0] = context.last_elapsed();
203 
204  // Let the actual measurements begin...
205  dbgprint( "\n- Starting execution -\n" );
206 
207  // We need to set up the ghost layers requested by the user. First correct for thin layers and then
208  // call `exchange_ghost_cells` to prepare the mesh for use with halo regions
209  context.timer_push( "Setup ghost layers" );
210  {
211  // Loop over the number of ghost layers needed and ask MOAB for layers 1 at a time
212  for( int ighost = 0; ighost < context.ghost_layers; ++ighost )
213  {
214  // Exchange ghost cells
215  int ghost_dimension = context.dimension;
216  int bridge_dimension = context.dimension - 1;
217  // Let us now get all ghost layers from adjacent parts
218  runchk( context.parallel_communicator->exchange_ghost_cells(
219  ghost_dimension, bridge_dimension, ( ighost + 1 ), 0, true /* store_remote_handles */,
220  true /* wait_all */, &context.fileset ),
221  "Exchange ghost cells failed" ); // true to store remote handles
222 
223  // Ensure that all processes understand about multi-shared vertices and entities
224  // in case some adjacent parts are only m layers thick (where m < context.ghost_layers)
225  if( ighost < context.ghost_layers - 1 )
226  runchk( context.parallel_communicator->correct_thin_ghost_layers(),
227  "Thin layer correction failed" );
228  }
229  }
230  context.timer_pop();
231  elapsed_times[1] = context.last_elapsed();
232 
233  // Get the 2D MPAS elements and filter it so that we have only owned elements
234  Range dimEnts;
235  {
236  // Get all entities of dimension = dim
237  runchk( context.moab_interface.get_entities_by_dimension( context.fileset, context.dimension, dimEnts ),
238  "Getting 2D entities failed" );
239  // Get only owned entities! The ghosted/shared entities will get their data when we exchange
240  // So let us filter entities based on the status: NOT x NOT_OWNED = OWNED status :-)
241  runchk( context.parallel_communicator->filter_pstatus( dimEnts, PSTATUS_NOT_OWNED, PSTATUS_NOT ),
242  "Filtering pstatus failed" );
243 
244  // Aggregate the total number of elements in the mesh
245  auto numEntities = dimEnts.size();
246  int numTotalEntities = 0;
247  MPI_Reduce( &numEntities, &numTotalEntities, 1, MPI_INT, MPI_SUM, 0,
248  context.parallel_communicator->proc_config().proc_comm() );
249 
250  // We expect the total number of elements to be constant, immaterial of number of processes.
251  // If not, we have a bug!
252  dbgprint( "Total number of " << context.dimension << "D elements in the mesh = " << numTotalEntities );
253  }
254 
255  Tag tagScalar = nullptr;
256  Tag tagVector = nullptr;
257  // Create two tag handles: scalar_variable and vector_variable
258  // Set these tags with appropriate closed form functional data
259  // based on element centroid information
260  runchk( context.create_sv_tags( tagScalar, tagVector, dimEnts ), "Unable to create scalar and vector tags" );
261 
262  // let us write out the local mesh before tag_exchange is called
263  // we expect to see data only on the owned entities - and ghosted entities should have default values
264  if( context.debug_output && ( context.proc_id == 0 ) ) // only on root process, for debugging
265  {
266  dbgprint( "> Writing to file *before* ghost exchange " );
267  runchk( context.moab_interface.write_file( "exchangeHalos_output_rank0_pre.h5m", "H5M", "" ),
268  "Writing to disk failed" );
269  }
270 
271  // Perform exchange of tag data between neighboring tasks
272  dbgprint( "> Exchanging tags between processors " );
273  context.timer_push( "Exchange scalar tag data" );
274  for( auto irun = 0; irun < context.num_max_exchange; ++irun )
275  {
276  // Exchange scalar tags between processors
277  runchk( context.parallel_communicator->exchange_tags( tagScalar, dimEnts ),
278  "Exchanging scalar tag between processors failed" );
279  }
280  context.timer_pop( context.num_max_exchange );
281  elapsed_times[2] = context.last_elapsed();
282 
283  context.timer_push( "Exchange vector tag data" );
284  for( auto irun = 0; irun < context.num_max_exchange; ++irun )
285  {
286  // Exchange vector tags between processors
287  runchk( context.parallel_communicator->exchange_tags( tagVector, dimEnts ),
288  "Exchanging vector tag between processors failed" );
289  }
290  context.timer_pop( context.num_max_exchange );
291  elapsed_times[3] = context.last_elapsed();
292 
293  // let us write out the local mesh after tag_exchange is called
294  // we expect to see real data on both owned and ghost entities in halo regions (non-default values)
295  if( context.debug_output && ( context.proc_id == 0 ) ) // only on root process, for debugging
296  {
297  dbgprint( "> Writing to file *after* ghost exchange " );
298  runchk( context.moab_interface.write_file( "exchangeHalos_output_rank0_post.h5m", "H5M", "" ),
299  "Writing to disk failed" );
300  }
301 
302  // Write out the final mesh with the tag data and mesh -- just for verification
303  if( context.debug_output )
304  {
305  dbgprint( "> Writing out the final mesh and data in MOAB h5m format. File = " << context.output_filename );
306  string write_options = ( context.num_procs > 1 ? "PARALLEL=WRITE_PART;DEBUG_IO=0;" : "" );
307  // Write out to output file to visualize reduction/exchange of tag data
308  runchk( context.moab_interface.write_file( context.output_filename.c_str(), "H5M", write_options.c_str() ),
309  "File write failed" );
310  }
311 
312  // Consolidated timing results: the data is listed as follows
313  // [ntasks, nghosts, load_mesh(I/O), exchange_ghost_cells(setup), exchange_tags(scalar),
314  // exchange_tags(vector)]
315  dbgprint( "\n> Consolidated: [" << context.num_procs << ", " << context.ghost_layers << ", " << elapsed_times[0]
316  << ", " << elapsed_times[1] << ", " << elapsed_times[2] << ", "
317  << elapsed_times[3] << "]," );
318 
319  // execution finished
320  dbgprint( "\n********** ExchangeHalos Example DONE! **********" );
321  }
322  // Done, cleanup
323  MPI_Finalize();
324 
325  return 0;
326 }

References context, dbgprint, PSTATUS_NOT, PSTATUS_NOT_OWNED, runchk, and moab::Range::size().