Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
ReadParallel.cpp
Go to the documentation of this file.
1 #include "ReadParallel.hpp"
2 #include "moab/Core.hpp"
3 #include "moab/ProcConfig.hpp"
4 #include "moab/FileOptions.hpp"
5 #include "moab/Error.hpp"
7 #include "moab/ReadUtilIface.hpp"
8 #include "moab/ParallelComm.hpp"
10 
11 #include <iostream>
12 #include <iomanip>
13 #include <iterator>
14 #include <sstream>
15 #include <algorithm>
16 #include <cassert>
17 
18 namespace moab
19 {
20 
21 const bool debug = false;
22 
23 const char* ReadParallel::ParallelActionsNames[] = { "PARALLEL READ",
24  "PARALLEL READ PART",
25  "PARALLEL BROADCAST",
26  "PARALLEL DELETE NONLOCAL",
27  "PARALLEL CHECK_GIDS_SERIAL",
28  "PARALLEL GET_FILESET_ENTS",
29  "PARALLEL RESOLVE_SHARED_ENTS",
30  "PARALLEL EXCHANGE_GHOSTS",
31  "PARALLEL RESOLVE_SHARED_SETS",
32  "PARALLEL_AUGMENT_SETS_WITH_GHOSTS",
33  "PARALLEL PRINT_PARALLEL",
34  "PARALLEL_CREATE_TRIVIAL_PARTITION",
35  "PARALLEL_CORRECT_THIN_GHOST_LAYERS" };
36 
37 const char* ReadParallel::parallelOptsNames[] = { "NONE", "BCAST", "BCAST_DELETE", "READ_DELETE", "READ_PART", "", 0 };
38 
40  : mbImpl( impl ), myPcomm( pc ), myDebug( "ReadPara", std::cerr )
41 {
42  if( !myPcomm )
43  {
45  if( NULL == myPcomm ) myPcomm = new ParallelComm( mbImpl, MPI_COMM_WORLD );
46  }
48  if( debug ) // For backwards compatibility, enable all debug output if constant is true
49  myDebug.set_verbosity( 10 );
50 
51  impl->query_interface( mError );
52 }
53 
54 ErrorCode ReadParallel::load_file( const char** file_names,
55  const int num_files,
56  const EntityHandle* file_set,
57  const FileOptions& opts,
58  const ReaderIface::SubsetList* subset_list,
59  const Tag* file_id_tag )
60 {
61  int tmpval;
62  if( MB_SUCCESS == opts.get_int_option( "DEBUG_PIO", 1, tmpval ) )
63  {
64  myDebug.set_verbosity( tmpval );
65  myPcomm->set_debug_verbosity( tmpval );
66  }
67  myDebug.tprint( 1, "Setting up...\n" );
68 
69  // Get parallel settings
70  int parallel_mode;
71  ErrorCode result = opts.match_option( "PARALLEL", parallelOptsNames, parallel_mode );
72  if( MB_FAILURE == result )
73  {
74  MB_SET_ERR( MB_FAILURE, "Unexpected value for 'PARALLEL' option" );
75  }
76  else if( MB_ENTITY_NOT_FOUND == result )
77  {
78  parallel_mode = 0;
79  }
80 
81  // Get partition setting
82  bool distrib;
83  std::string partition_tag_name;
84  result = opts.get_option( "PARTITION", partition_tag_name );
85  if( MB_ENTITY_NOT_FOUND == result )
86  {
87  distrib = false;
88  partition_tag_name = "";
89  }
90  else
91  {
92  distrib = true;
93  if( partition_tag_name.empty() ) partition_tag_name = PARALLEL_PARTITION_TAG_NAME;
94 
95  // Also get deprecated PARTITION_DISTRIBUTE option
96  // so that higher-level code doesn't return an error
97  // due to an unrecognized option
98  opts.get_null_option( "PARTITION_DISTRIBUTE" );
99  }
100 
101  // Get partition tag value(s), if any, and whether they're to be
102  // distributed or assigned
103  std::vector< int > partition_tag_vals;
104  opts.get_ints_option( "PARTITION_VAL", partition_tag_vals );
105 
106  // see if partition tag name is "TRIVIAL", if the tag exists
107  bool create_trivial_partition = false;
108  if( partition_tag_name == std::string( "TRIVIAL" ) )
109  {
110  Tag ttag; // see if the trivial tag exists
111  result = mbImpl->tag_get_handle( partition_tag_name.c_str(), ttag );
112  if( MB_TAG_NOT_FOUND == result ) create_trivial_partition = true;
113  }
114  // See if we need to report times
115  bool cputime = false;
116  result = opts.get_null_option( "CPUTIME" );
117  if( MB_SUCCESS == result ) cputime = true;
118 
119  // See if we need to report times
120  bool print_parallel = false;
121  result = opts.get_null_option( "PRINT_PARALLEL" );
122  if( MB_SUCCESS == result ) print_parallel = true;
123 
124  // Get ghosting options
125  std::string ghost_str;
126  int bridge_dim, ghost_dim = -1, num_layers, addl_ents = 0;
127  result = opts.get_str_option( "PARALLEL_GHOSTS", ghost_str );
128  if( MB_TYPE_OUT_OF_RANGE == result )
129  {
130  ghost_dim = 3;
131  bridge_dim = 0;
132  num_layers = 1;
133  }
134  else if( MB_SUCCESS == result )
135  {
136  int num_fields = sscanf( ghost_str.c_str(), "%d.%d.%d.%d", &ghost_dim, &bridge_dim, &num_layers, &addl_ents );
137  if( 3 > num_fields )
138  {
139  MB_SET_ERR( MB_FAILURE, "Didn't read 3 fields from PARALLEL_GHOSTS string" );
140  }
141  }
142 
143  // Get resolve_shared_ents option
144  std::string shared_str;
145  int resolve_dim = -2, shared_dim = -1;
146  result = opts.get_str_option( "PARALLEL_RESOLVE_SHARED_ENTS", shared_str );
147  if( MB_TYPE_OUT_OF_RANGE == result )
148  {
149  resolve_dim = -1;
150  shared_dim = -1;
151  }
152  else if( MB_SUCCESS == result )
153  {
154  int num_fields = sscanf( shared_str.c_str(), "%d.%d", &resolve_dim, &shared_dim );
155  if( 2 != num_fields )
156  {
157  MB_SET_ERR( MB_FAILURE, "Didn't read 2 fields from PARALLEL_RESOLVE_SHARED_ENTS string" );
158  }
159  }
160 
161  // Get skip augmenting with ghosts option
162  bool skip_augment = false;
163  result = opts.get_null_option( "SKIP_AUGMENT_WITH_GHOSTS" );
164  if( MB_SUCCESS == result ) skip_augment = true;
165 
166  bool correct_thin_ghosts = false;
167  result = opts.get_null_option( "PARALLEL_THIN_GHOST_LAYER" );
168  if( MB_SUCCESS == result ) correct_thin_ghosts = true;
169 
170  // Get MPI IO processor rank
171  int reader_rank;
172  result = opts.get_int_option( "MPI_IO_RANK", reader_rank );
173  if( MB_ENTITY_NOT_FOUND == result )
174  reader_rank = 0;
175  else if( MB_SUCCESS != result )
176  {
177  MB_SET_ERR( MB_FAILURE, "Unexpected value for 'MPI_IO_RANK' option" );
178  }
179 
180  // Now that we've parsed all the parallel options, make an instruction queue
181  std::vector< int > pa_vec;
182  bool is_reader = ( reader_rank == (int)myPcomm->proc_config().proc_rank() );
183 
184  bool partition_by_rank = false;
185  if( MB_SUCCESS == opts.get_null_option( "PARTITION_BY_RANK" ) )
186  {
187  partition_by_rank = true;
188  if( !partition_tag_vals.empty() )
189  {
190  MB_SET_ERR( MB_FAILURE, "Cannot specify both PARTITION_VALS and PARTITION_BY_RANK" );
191  }
192  }
193 
194  double factor_seq;
195  if( MB_SUCCESS == opts.get_real_option( "PARALLEL_SEQUENCE_FACTOR", factor_seq ) )
196  {
197  if( factor_seq < 1. ) MB_SET_ERR( MB_FAILURE, "cannot have sequence factor less than 1." );
198  mbImpl->set_sequence_multiplier( factor_seq );
199  }
200  switch( parallel_mode )
201  {
202  case POPT_BCAST:
203  myDebug.print( 1, "Read mode is BCAST\n" );
204  if( is_reader )
205  {
206  pa_vec.push_back( PA_READ );
207  pa_vec.push_back( PA_CHECK_GIDS_SERIAL );
208  pa_vec.push_back( PA_GET_FILESET_ENTS );
209  }
210  pa_vec.push_back( PA_BROADCAST );
211  if( !is_reader ) pa_vec.push_back( PA_GET_FILESET_ENTS );
212  break;
213 
214  case POPT_BCAST_DELETE:
215  myDebug.print( 1, "Read mode is BCAST_DELETE\n" );
216  if( is_reader )
217  {
218  pa_vec.push_back( PA_READ );
219  pa_vec.push_back( PA_CHECK_GIDS_SERIAL );
220  pa_vec.push_back( PA_GET_FILESET_ENTS );
221  if( create_trivial_partition ) pa_vec.push_back( PA_CREATE_TRIVIAL_PARTITION );
222  }
223  pa_vec.push_back( PA_BROADCAST );
224  if( !is_reader ) pa_vec.push_back( PA_GET_FILESET_ENTS );
225  pa_vec.push_back( PA_DELETE_NONLOCAL );
226  break;
227 
228  case POPT_DEFAULT:
229  case POPT_READ_DELETE:
230  myDebug.print( 1, "Read mode is READ_DELETE\n" );
231  pa_vec.push_back( PA_READ );
232  pa_vec.push_back( PA_CHECK_GIDS_SERIAL );
233  pa_vec.push_back( PA_GET_FILESET_ENTS );
234  pa_vec.push_back( PA_DELETE_NONLOCAL );
235  break;
236 
237  case POPT_READ_PART:
238  myDebug.print( 1, "Read mode is READ_PART\n" );
239  pa_vec.push_back( PA_READ_PART );
240  break;
241 
242  default:
243  MB_SET_ERR( MB_FAILURE, "Unexpected parallel read mode" );
244  }
245 
246  if( -2 != resolve_dim ) pa_vec.push_back( PA_RESOLVE_SHARED_ENTS );
247 
248  if( -1 != ghost_dim ) pa_vec.push_back( PA_EXCHANGE_GHOSTS );
249 
250  if( -2 != resolve_dim )
251  {
252  pa_vec.push_back( PA_RESOLVE_SHARED_SETS );
253  if( -1 != ghost_dim && !skip_augment ) pa_vec.push_back( PA_AUGMENT_SETS_WITH_GHOSTS );
254  if( -1 != ghost_dim && correct_thin_ghosts ) pa_vec.push_back( PA_CORRECT_THIN_GHOSTS );
255  }
256 
257  if( print_parallel ) pa_vec.push_back( PA_PRINT_PARALLEL );
258 
259  result = load_file( file_names, num_files, file_set, parallel_mode, partition_tag_name, partition_tag_vals, distrib,
260  partition_by_rank, pa_vec, opts, subset_list, file_id_tag, reader_rank, cputime, resolve_dim,
261  shared_dim, ghost_dim, bridge_dim, num_layers, addl_ents );
262  MB_CHK_ERR( result );
263 
264  if( parallel_mode == POPT_BCAST_DELETE && !is_reader ) opts.mark_all_seen();
265 
266  return MB_SUCCESS;
267 }
268 
269 ErrorCode ReadParallel::load_file( const char** file_names,
270  const int num_files,
271  const EntityHandle* file_set_ptr,
272  int /*parallel_mode*/,
273  std::string& partition_tag_name,
274  std::vector< int >& partition_tag_vals,
275  bool distrib,
276  bool partition_by_rank,
277  std::vector< int >& pa_vec,
278  const FileOptions& opts,
279  const ReaderIface::SubsetList* subset_list,
280  const Tag* file_id_tag,
281  const int reader_rank,
282  const bool cputime,
283  const int resolve_dim,
284  const int shared_dim,
285  const int ghost_dim,
286  const int bridge_dim,
287  const int num_layers,
288  const int addl_ents )
289 {
290  ErrorCode result = MB_SUCCESS;
291  if( myPcomm == NULL ) myPcomm = new ParallelComm( mbImpl, MPI_COMM_WORLD );
292 
293  Range entities;
294  Tag file_set_tag = 0;
295  int other_sets = 0;
297  Range other_file_sets, file_sets;
298  Core* impl = dynamic_cast< Core* >( mbImpl );
299 
300  std::vector< double > act_times( pa_vec.size() + 1 );
301  std::vector< int >::iterator vit;
302  int i, j;
303  act_times[0] = MPI_Wtime();
304 
305  // Make a new set for the parallel read
306  EntityHandle file_set;
307  if( !file_set_ptr || !( *file_set_ptr ) )
308  {
309  result = mbImpl->create_meshset( MESHSET_SET, file_set );
310  MB_CHK_SET_ERR( result, "Trouble creating file set" );
311  }
312  else
313  file_set = *file_set_ptr;
314 
315  bool i_read = false;
316  Tag id_tag = 0;
317  bool use_id_tag = false;
318  Range ents;
319 
320  for( i = 1, vit = pa_vec.begin(); vit != pa_vec.end(); ++vit, i++ )
321  {
322  ErrorCode tmp_result = MB_SUCCESS;
323  switch( *vit )
324  {
325  //==================
326  case PA_READ:
327  i_read = true;
328 
329  for( j = 0; j < num_files; j++ )
330  {
331  myDebug.tprintf( 1, "Reading file: \"%s\"\n", file_names[j] );
332 
333  EntityHandle new_file_set;
334  result = mbImpl->create_meshset( MESHSET_SET, new_file_set );
335  MB_CHK_SET_ERR( result, "Trouble creating file set" );
336  tmp_result = impl->serial_load_file( file_names[j], &new_file_set, opts, subset_list, file_id_tag );
337  if( MB_SUCCESS != tmp_result ) break;
338 
339  // Put the contents of each file set for the reader into the
340  // file set for the parallel read
341  assert( 0 != new_file_set );
342  Range all_ents;
343  tmp_result = mbImpl->get_entities_by_handle( new_file_set, all_ents );
344  if( MB_SUCCESS != tmp_result ) break;
345  all_ents.insert( new_file_set );
346  tmp_result = mbImpl->add_entities( file_set, all_ents );
347  if( MB_SUCCESS != tmp_result ) break;
348  }
349  if( MB_SUCCESS != tmp_result ) break;
350 
351  // Mark the file set for this parallel reader
352  tmp_result = mbImpl->tag_get_handle( "__file_set", 1, MB_TYPE_INTEGER, file_set_tag,
354  if( MB_SUCCESS != tmp_result ) break;
355 
356  tmp_result = mbImpl->tag_set_data( file_set_tag, &file_set, 1, &other_sets );
357  break;
358 
359  //==================
360  case PA_READ_PART: {
361  myDebug.tprintf( 1, "Reading file: \"%s\"\n", file_names[0] );
362 
363  i_read = true;
364  if( num_files != 1 )
365  {
366  MB_SET_ERR( MB_NOT_IMPLEMENTED, "Multiple file read not supported for READ_PART" );
367  }
368 
369  // If we're going to resolve shared entities, then we need
370  // to ask the file reader to populate a tag with unique ids
371  // (typically file ids/indices/whatever.)
372  if( std::find( pa_vec.begin(), pa_vec.end(), PA_RESOLVE_SHARED_ENTS ) != pa_vec.end() )
373  {
374  use_id_tag = true;
375  if( !file_id_tag )
376  {
377  // This tag is really used for resolving shared entities with crystal router
378  // In the end, this is an identifier that gets converted to long
379  // In hdf5 file reader, we also convert from hdf5 file id type to long
380  tmp_result = mbImpl->tag_get_handle( "", sizeof( long ), MB_TYPE_OPAQUE, id_tag,
382  if( MB_SUCCESS != tmp_result ) break;
383  file_id_tag = &id_tag;
384  }
385  }
386 
387  ReaderIface::IDTag parts = { partition_tag_name.c_str(), 0, 0 };
389  sl.num_parts = 0;
390  int rank = myPcomm->rank();
391  if( partition_by_rank )
392  {
393  assert( partition_tag_vals.empty() );
394  parts.tag_values = &rank;
395  parts.num_tag_values = 1;
396  }
397  else
398  {
399  sl.num_parts = myPcomm->size();
400  sl.part_number = myPcomm->rank();
401  if( !partition_tag_vals.empty() )
402  {
403  parts.tag_values = partition_tag_vals.data();
404  parts.num_tag_values = partition_tag_vals.size();
405  }
406  }
407  std::vector< ReaderIface::IDTag > subset;
408  if( subset_list )
409  {
410  std::vector< ReaderIface::IDTag > tmplist( subset_list->tag_list,
411  subset_list->tag_list + subset_list->tag_list_length );
412  tmplist.push_back( parts );
413  subset.swap( tmplist );
414  sl.tag_list = subset.data();
415  sl.tag_list_length = subset.size();
416  }
417  else
418  {
419  sl.tag_list = &parts;
420  sl.tag_list_length = 1;
421  }
422  tmp_result = impl->serial_load_file( *file_names, &file_set, opts, &sl, file_id_tag );
423  if( MB_SUCCESS != tmp_result ) break;
424 
425  if( !partition_tag_name.empty() )
426  {
427  Tag part_tag;
428  tmp_result = impl->tag_get_handle( partition_tag_name.c_str(), 1, MB_TYPE_INTEGER, part_tag );
429  if( MB_SUCCESS != tmp_result ) break;
430 
431  tmp_result = impl->get_entities_by_type_and_tag( file_set, MBENTITYSET, &part_tag, 0, 1,
432  myPcomm->partition_sets() );
433  }
434  }
435  break;
436 
437  //==================
438  case PA_GET_FILESET_ENTS:
439  myDebug.tprint( 1, "Getting fileset entities.\n" );
440 
441  // Get entities in the file set, and add actual file set to it;
442  // mark the file set to make sure any receiving procs know which it is
443  tmp_result = mbImpl->get_entities_by_handle( file_set, entities );
444  if( MB_SUCCESS != tmp_result )
445  {
446  entities.clear();
447  break;
448  }
449 
450  // Add actual file set to entities too
451  entities.insert( file_set );
452  break;
453  //==================
455  myDebug.tprint( 1, "create trivial partition, for higher dim entities.\n" );
456  // get high dim entities (2 or 3)
457  Range hi_dim_ents = entities.subset_by_dimension( 3 );
458  if( hi_dim_ents.empty() ) hi_dim_ents = entities.subset_by_dimension( 2 );
459  if( hi_dim_ents.empty() ) hi_dim_ents = entities.subset_by_dimension( 1 );
460  if( hi_dim_ents.empty() ) MB_SET_ERR( MB_FAILURE, "there are no elements of dim 1-3" );
461 
462  size_t num_hi_ents = hi_dim_ents.size();
463  unsigned int num_parts = myPcomm->size();
464 
465  // create first the trivial partition tag
466  int dum_id = -1;
467  Tag ttag; // trivial tag
468  tmp_result = mbImpl->tag_get_handle( partition_tag_name.c_str(), 1, MB_TYPE_INTEGER, ttag,
469  MB_TAG_CREAT | MB_TAG_SPARSE, &dum_id );
470  MB_CHK_SET_ERR( tmp_result, "Can't create trivial partition tag" );
471 
472  // Compute the number of high dim entities on each part
473  size_t nPartEnts = num_hi_ents / num_parts;
474 
475  // Number of extra entities after equal split over parts
476  int iextra = num_hi_ents % num_parts;
477  Range::iterator itr = hi_dim_ents.begin();
478  for( int k = 0; k < (int)num_parts; k++ )
479  {
480  // create a mesh set, insert a subrange of entities
481  EntityHandle part_set;
482  tmp_result = mbImpl->create_meshset( MESHSET_SET, part_set );
483  MB_CHK_SET_ERR( tmp_result, "Can't create part set" );
484  entities.insert( part_set );
485 
486  tmp_result = mbImpl->tag_set_data( ttag, &part_set, 1, &k );
487  MB_CHK_SET_ERR( tmp_result, "Can't set trivial partition tag" );
488  Range subrange;
489  size_t num_ents_in_part = nPartEnts;
490  if( i < iextra ) num_ents_in_part++;
491  for( size_t i1 = 0; i1 < num_ents_in_part; i1++, itr++ )
492  subrange.insert( *itr );
493  tmp_result = mbImpl->add_entities( part_set, subrange );
494  MB_CHK_SET_ERR( tmp_result, "Can't add entities to trivial part " << k );
495  myDebug.tprintf( 1, "create trivial part %d with %lu entities \n", k, num_ents_in_part );
496  tmp_result = mbImpl->add_entities( file_set, &part_set, 1 );
497  MB_CHK_SET_ERR( tmp_result, "Can't add trivial part to file set " << k );
498  }
499  }
500 
501  break;
502  //==================
503  case PA_BROADCAST:
504  // Do the actual broadcast; if single-processor, ignore error
505  myDebug.tprint( 1, "Broadcasting mesh.\n" );
506 
507  if( myPcomm->proc_config().proc_size() > 1 )
508  {
509  tmp_result = myPcomm->broadcast_entities( reader_rank, entities );
510  if( MB_SUCCESS != tmp_result ) break;
511  }
512 
513  if( debug )
514  {
515  std::cerr << "Bcast done; entities:" << std::endl;
516  mbImpl->list_entities( 0, 0 );
517  }
518 
519  // Add the received entities to this fileset if I wasn't the reader
520  if( !i_read && MB_SUCCESS == tmp_result ) tmp_result = mbImpl->add_entities( file_set, entities );
521 
522  break;
523 
524  //==================
525  case PA_DELETE_NONLOCAL:
526  myDebug.tprint( 1, "Deleting nonlocal entities.\n" );
527 
528  tmp_result = delete_nonlocal_entities( partition_tag_name, partition_tag_vals, distrib, file_set );
529  if( debug )
530  {
531  std::cerr << "Delete nonlocal done; entities:" << std::endl;
532  mbImpl->list_entities( 0, 0 );
533  }
534 
535  if( MB_SUCCESS == tmp_result ) tmp_result = create_partition_sets( partition_tag_name, file_set );
536 
537  break;
538 
539  //==================
541  myDebug.tprint( 1, "Checking global IDs.\n" );
542 
543  tmp_result = myPcomm->check_global_ids( file_set, 0, 1, true, false );
544  break;
545 
546  //==================
548  myDebug.tprint( 1, "Resolving shared entities.\n" );
549 
550  if( 1 == myPcomm->size() )
551  tmp_result = MB_SUCCESS;
552  else
553  tmp_result =
554  myPcomm->resolve_shared_ents( file_set, resolve_dim, shared_dim, use_id_tag ? file_id_tag : 0 );
555  if( MB_SUCCESS != tmp_result ) break;
556 
557 #ifndef NDEBUG
558  // check number of owned vertices through pcomm's public interface
559  tmp_result = mbImpl->get_entities_by_type( 0, MBVERTEX, ents );
560  if( MB_SUCCESS == tmp_result )
561  tmp_result = myPcomm->filter_pstatus( ents, PSTATUS_NOT_OWNED, PSTATUS_NOT );
562  if( MB_SUCCESS == tmp_result )
563  myDebug.tprintf( 1, "Proc %u reports %lu owned vertices.\n", myPcomm->proc_config().proc_rank(),
564  ents.size() );
565 #endif
566  break;
567 
568  //==================
569  case PA_EXCHANGE_GHOSTS:
570  myDebug.tprint( 1, "Exchanging ghost entities.\n" );
571 
572  tmp_result = myPcomm->exchange_ghost_cells( ghost_dim, bridge_dim, num_layers, addl_ents, true, true,
573  &file_set );
574  break;
575 
576  //==================
578  myDebug.tprint( 1, "Resolving shared sets.\n" );
579 
580  if( 1 == myPcomm->size() )
581  tmp_result = MB_SUCCESS;
582  else
583  tmp_result = myPcomm->resolve_shared_sets( file_set, use_id_tag ? file_id_tag : 0 );
584  break;
585 
586  //==================
588  myDebug.tprint( 1, "Augmenting sets with ghost entities.\n" );
589 
590  if( 1 == myPcomm->size() )
591  tmp_result = MB_SUCCESS;
592  else
593  tmp_result = myPcomm->augment_default_sets_with_ghosts( file_set );
594  break;
595  //==================
597  myDebug.tprint( 1, "correcting thin ghost layers.\n" );
598  if( 2 >= myPcomm->size() ) // it is a problem only for multi-shared entities
599  tmp_result = MB_SUCCESS;
600  else
601  tmp_result = myPcomm->correct_thin_ghost_layers();
602  break;
603  case PA_PRINT_PARALLEL:
604  myDebug.tprint( 1, "Printing parallel information.\n" );
605 
606  tmp_result = myPcomm->list_entities( 0, -1 );
607  break;
608 
609  //==================
610  default:
611  MB_SET_ERR( MB_FAILURE, "Unexpected parallel action" );
612  } // switch (*vit)
613 
614  if( MB_SUCCESS != tmp_result )
615  {
616  MB_SET_ERR( MB_FAILURE, "Failed in step " << ParallelActionsNames[*vit] );
617  }
618 
619  if( cputime ) act_times[i] = MPI_Wtime();
620  } // for (i = 1, vit = pa_vec.begin(); vit != pa_vec.end(); ++vit, i++)
621 
622  if( use_id_tag )
623  {
624  result = mbImpl->tag_delete( id_tag );
625  MB_CHK_SET_ERR( result, "Trouble deleting id tag" );
626  }
627 
628  if( cputime )
629  {
630  for( i = pa_vec.size(); i > 0; i-- )
631  act_times[i] -= act_times[i - 1];
632 
633  // Replace initial time with overall time
634  act_times[0] = MPI_Wtime() - act_times[0];
635  // Get the maximum over all procs
636  if( 0 != myPcomm->proc_config().proc_rank() )
637  {
638  MPI_Reduce( act_times.data(), 0, pa_vec.size() + 1, MPI_DOUBLE, MPI_MAX, 0,
640  }
641  else
642  {
643 #if ( MPI_VERSION >= 2 )
644  MPI_Reduce( MPI_IN_PLACE, act_times.data(), pa_vec.size() + 1, MPI_DOUBLE, MPI_MAX, 0,
646 #else
647  // Note, extra comm-size allocation is required
648  std::vector< double > act_times_tmp( pa_vec.size() + 1 );
649  MPI_Reduce( act_times.data(), act_times_tmp.data(), pa_vec.size() + 1, MPI_DOUBLE, MPI_MAX, 0,
651  act_times = act_times_tmp; // extra copy here too
652 #endif
653  std::cout << "Parallel Read times: " << std::endl;
654  for( i = 1, vit = pa_vec.begin(); vit != pa_vec.end(); ++vit, i++ )
655  std::cout << " " << act_times[i] << " " << ParallelActionsNames[*vit] << std::endl;
656  std::cout << " " << act_times[0] << " PARALLEL TOTAL" << std::endl;
657  }
658  }
659 
660  return MB_SUCCESS;
661 }
662 
664  std::vector< int >& ptag_vals,
665  bool distribute,
666  EntityHandle file_set )
667 {
668  Range partition_sets;
669 
670  Tag ptag;
671  ErrorCode result = mbImpl->tag_get_handle( ptag_name.c_str(), 1, MB_TYPE_INTEGER, ptag );
672  MB_CHK_SET_ERR( result, "Failed getting tag handle in delete_nonlocal_entities" );
673 
674  result = mbImpl->get_entities_by_type_and_tag( file_set, MBENTITYSET, &ptag, NULL, 1, myPcomm->partition_sets() );
675  MB_CHK_SET_ERR( result, "Failed to get sets with partition-type tag" );
676 
677  int proc_sz = myPcomm->proc_config().proc_size();
678  int proc_rk = myPcomm->proc_config().proc_rank();
679 
680  if( !ptag_vals.empty() )
681  {
682  // Values input, get sets with those values
683  Range tmp_sets;
684  std::vector< int > tag_vals( myPcomm->partition_sets().size() );
685  result = mbImpl->tag_get_data( ptag, myPcomm->partition_sets(), tag_vals.data() );
686  MB_CHK_SET_ERR( result, "Failed to get tag data for partition vals tag" );
687  for( std::vector< int >::iterator pit = tag_vals.begin(); pit != tag_vals.end(); ++pit )
688  {
689  std::vector< int >::iterator pit2 = std::find( ptag_vals.begin(), ptag_vals.end(), *pit );
690  if( pit2 != ptag_vals.end() ) tmp_sets.insert( myPcomm->partition_sets()[pit - tag_vals.begin()] );
691  }
692 
693  myPcomm->partition_sets().swap( tmp_sets );
694  }
695 
696  if( distribute )
697  {
698  // For now, require that number of partition sets be greater
699  // than number of procs
700  if( myPcomm->partition_sets().size() < (unsigned int)proc_sz )
701  {
702  MB_SET_ERR( MB_FAILURE, "Too few parts; P = " << proc_rk << ", tag = " << ptag
703  << ", # sets = " << myPcomm->partition_sets().size() );
704  }
705 
706  Range tmp_sets;
707  // Distribute the partition sets
708  unsigned int num_sets = myPcomm->partition_sets().size() / proc_sz;
709  unsigned int num_leftover = myPcomm->partition_sets().size() % proc_sz;
710  int begin_set = 0;
711  if( proc_rk < (int)num_leftover )
712  {
713  num_sets++;
714  begin_set = num_sets * proc_rk;
715  }
716  else
717  begin_set = proc_rk * num_sets + num_leftover;
718 
719  for( unsigned int i = 0; i < num_sets; i++ )
720  tmp_sets.insert( myPcomm->partition_sets()[begin_set + i] );
721 
722  myPcomm->partition_sets().swap( tmp_sets );
723  }
724 
725  myDebug.print( 1, "My partition sets: ", myPcomm->partition_sets() );
726 
727  result = delete_nonlocal_entities( file_set );
728  MB_CHK_ERR( result );
729 
730  return MB_SUCCESS;
731 }
732 
733 ErrorCode ReadParallel::create_partition_sets( std::string& ptag_name, EntityHandle file_set )
734 {
735  int proc_rk = myPcomm->proc_config().proc_rank();
736  ErrorCode result = MB_SUCCESS;
737 
738  Tag ptag;
739 
740  // Tag the partition sets with a standard tag name
741  if( ptag_name.empty() ) ptag_name = PARALLEL_PARTITION_TAG_NAME;
742  bool tag_created = false;
743  result = mbImpl->tag_get_handle( ptag_name.c_str(), 1, MB_TYPE_INTEGER, ptag, MB_TAG_SPARSE | MB_TAG_CREAT, 0,
744  &tag_created );
745  MB_CHK_SET_ERR( result, "Trouble getting PARALLEL_PARTITION tag" );
746 
747  if( !tag_created )
748  {
749  // This tag already exists; better check to see that tagged sets
750  // agree with this partition
751  Range tagged_sets;
752  int* proc_rk_ptr = &proc_rk;
753  result = mbImpl->get_entities_by_type_and_tag( file_set, MBENTITYSET, &ptag, (const void* const*)&proc_rk_ptr,
754  1, tagged_sets );
755  MB_CHK_SET_ERR( result, "Trouble getting tagged sets" );
756  if( !tagged_sets.empty() && tagged_sets != myPcomm->partition_sets() )
757  {
758  result = mbImpl->tag_delete_data( ptag, tagged_sets );
759  MB_CHK_SET_ERR( result, "Trouble deleting data of PARALLEL_PARTITION tag" );
760  }
761  else if( tagged_sets == myPcomm->partition_sets() )
762  return MB_SUCCESS;
763  }
764 
765  // If we get here, we need to assign the tag
766  std::vector< int > values( myPcomm->partition_sets().size() );
767  for( unsigned int i = 0; i < myPcomm->partition_sets().size(); i++ )
768  values[i] = proc_rk;
769  result = mbImpl->tag_set_data( ptag, myPcomm->partition_sets(), values.data() );
770  MB_CHK_SET_ERR( result, "Trouble setting data to PARALLEL_PARTITION tag" );
771 
772  return MB_SUCCESS;
773 }
774 
776 {
777  // Get partition entities and ents related to/used by those
778  // get ents in the partition
779  ReadUtilIface* read_iface;
780  mbImpl->query_interface( read_iface );
781  Range partition_ents, all_sets;
782 
783  myDebug.tprint( 2, "Gathering related entities.\n" );
784 
785  ErrorCode result = read_iface->gather_related_ents( myPcomm->partition_sets(), partition_ents, &file_set );
786  MB_CHK_SET_ERR( result, "Failure gathering related entities" );
787 
788  // Get pre-existing entities
789  Range file_ents;
790  result = mbImpl->get_entities_by_handle( file_set, file_ents );
791  MB_CHK_SET_ERR( result, "Couldn't get pre-existing entities" );
792 
793  if( 0 == myPcomm->proc_config().proc_rank() )
794  {
795  myDebug.print( 2, "File entities: ", file_ents );
796  }
797 
798  // Get deletable entities by subtracting partition ents from file ents
799  Range deletable_ents = subtract( file_ents, partition_ents );
800 
801  // Cache deletable vs. keepable sets
802  Range deletable_sets = deletable_ents.subset_by_type( MBENTITYSET );
803  Range keepable_sets = subtract( file_ents.subset_by_type( MBENTITYSET ), deletable_sets );
804 
805  myDebug.tprint( 2, "Removing deletable entities from keepable sets.\n" );
806 
807  // Remove deletable ents from all keepable sets
808  for( Range::iterator rit = keepable_sets.begin(); rit != keepable_sets.end(); ++rit )
809  {
810  result = mbImpl->remove_entities( *rit, deletable_ents );
811  MB_CHK_SET_ERR( result, "Failure removing deletable entities" );
812  }
813  result = mbImpl->remove_entities( file_set, deletable_ents );
814  MB_CHK_SET_ERR( result, "Failure removing deletable entities" );
815 
816  myDebug.tprint( 2, "Deleting deletable entities.\n" );
817 
818  if( 0 == myPcomm->proc_config().proc_rank() )
819  {
820  myDebug.print( 2, "Deletable sets: ", deletable_sets );
821  }
822 
823  // Delete sets, then ents
824  if( !deletable_sets.empty() )
825  {
826  result = mbImpl->delete_entities( deletable_sets );
827  MB_CHK_SET_ERR( result, "Failure deleting sets in delete_nonlocal_entities" );
828  }
829 
830  deletable_ents -= deletable_sets;
831 
832  if( 0 == myPcomm->proc_config().proc_rank() )
833  {
834  myDebug.print( 2, "Deletable entities: ", deletable_ents );
835  }
836 
837  if( !deletable_ents.empty() )
838  {
839  result = mbImpl->delete_entities( deletable_ents );
840  MB_CHK_SET_ERR( result, "Failure deleting entities in delete_nonlocal_entities" );
841  }
842 
843  return MB_SUCCESS;
844 }
845 
846 } // namespace moab