Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
ScdInterface.cpp
Go to the documentation of this file.
1 #include "moab/ScdInterface.hpp"
2 #include "moab/Core.hpp"
3 #include "SequenceManager.hpp"
4 #include "EntitySequence.hpp"
6 #include "VertexSequence.hpp"
7 #include "ScdVertexData.hpp"
8 #include "MBTagConventions.hpp"
9 #ifdef MOAB_HAVE_MPI
10 #include "moab/ParallelComm.hpp"
11 #include "moab/TupleList.hpp"
12 #include "moab/gs.hpp"
13 #endif
14 #include <cassert>
15 #include <iostream>
16 #include <functional>
17 
18 #define ERRORR( rval, str ) \
19  { \
20  if( MB_SUCCESS != ( rval ) ) \
21  { \
22  std::cerr << ( str ); \
23  return rval; \
24  } \
25  }
26 
27 namespace moab
28 {
29 
30 const char* ScdParData::PartitionMethodNames[] = { "alljorkori", "alljkbal", "sqij", "sqjk",
31  "sqijk", "trivial", "rcbzoltan", "nopart" };
32 
34  : mbImpl( imp ), searchedBoxes( false ), boxPeriodicTag( 0 ), boxDimsTag( 0 ), globalBoxDimsTag( 0 ),
35  partMethodTag( 0 ), boxSetTag( 0 )
36 {
37  if( boxes ) find_boxes( scdBoxes );
38 }
39 
40 // Destructor
42 {
43  std::vector< ScdBox* > tmp_boxes;
44  tmp_boxes.swap( scdBoxes );
45 
46  for( std::vector< ScdBox* >::iterator rit = tmp_boxes.begin(); rit != tmp_boxes.end(); ++rit )
47  delete *rit;
48 
49  if( box_set_tag( false ) ) mbImpl->tag_delete( box_set_tag() );
50 }
51 
53 {
54  return mbImpl;
55 }
56 
57 ErrorCode ScdInterface::find_boxes( std::vector< ScdBox* >& scd_boxes )
58 {
59  Range tmp_boxes;
60  ErrorCode rval = find_boxes( tmp_boxes );
61  if( MB_SUCCESS != rval ) return rval;
62 
63  for( Range::iterator rit = tmp_boxes.begin(); rit != tmp_boxes.end(); ++rit )
64  {
65  ScdBox* tmp_box = get_scd_box( *rit );
66  if( tmp_box )
67  scd_boxes.push_back( tmp_box );
68  else
69  rval = MB_FAILURE;
70  }
71 
72  return rval;
73 }
74 
76 {
77  box_dims_tag();
78  Range boxes;
79  if( !searchedBoxes )
80  {
82  "failed to get entitities by type and tag" );
83  searchedBoxes = true;
84  if( !boxes.empty() )
85  {
86  scdBoxes.resize( boxes.size() );
87  MB_CHK_SET_ERR( mbImpl->tag_get_data( boxSetTag, boxes, &scdBoxes[0] ), "failed to get tag data" );
88  ScdBox* dum = nullptr;
89  scdBoxes.erase(
90  std::remove_if(
91  scdBoxes.begin(),
92  scdBoxes.end(),
93  [dum](ScdBox* ptr) { return ptr == dum; }
94  ),
95  scdBoxes.end()
96  );
97  }
98  }
99 
100  for( std::vector< ScdBox* >::iterator vit = scdBoxes.begin(); vit != scdBoxes.end(); ++vit )
101  scd_boxes.insert( ( *vit )->box_set() );
102 
103  return MB_SUCCESS;
104 }
105 
107 {
108  ScdBox* scd_box = NULL;
109  if( !box_set_tag( false ) ) return scd_box;
110 
111  mbImpl->tag_get_data( box_set_tag(), &eh, 1, &scd_box );
112  return scd_box;
113 }
114 
116  HomCoord high,
117  const double* const coords,
118  unsigned int num_coords,
119  ScdBox*& new_box,
120  int* const lperiodic,
121  ScdParData* par_data,
122  bool assign_gids,
123  int tag_shared_ents )
124 {
125  // create a rectangular structured mesh block
126  ErrorCode rval;
127 
128  int tmp_lper[3] = { 0, 0, 0 };
129  if( lperiodic ) std::copy( lperiodic, lperiodic + 3, tmp_lper );
130 
131 #ifndef MOAB_HAVE_MPI
132  if( -1 != tag_shared_ents ) ERRORR( MB_FAILURE, "Parallel capability requested but MOAB not compiled parallel." );
133  if( -1 == tag_shared_ents && !assign_gids ) assign_gids = true; // need to assign gids in order to tag shared verts
134 #else
135  if( par_data && low == high && ScdParData::NOPART != par_data->partMethod )
136  {
137  // requesting creation of parallel mesh, so need to compute partition
138  if( !par_data->pComm )
139  {
140  // this is a really boneheaded way to have to create a PC
141  par_data->pComm = ParallelComm::get_pcomm( mbImpl, 0 );
142  if( NULL == par_data->pComm ) par_data->pComm = new ParallelComm( mbImpl, MPI_COMM_WORLD );
143  }
144  int ldims[6];
145  rval = compute_partition( par_data->pComm->size(), par_data->pComm->rank(), *par_data, ldims, tmp_lper,
146  par_data->pDims );ERRORR( rval, "Error returned from compute_partition." );
147  low.set( ldims[0], ldims[1], ldims[2] );
148  high.set( ldims[3], ldims[4], ldims[5] );
149  if( par_data->pComm->get_debug_verbosity() > 0 )
150  {
151  std::cout << "Proc " << par_data->pComm->rank() << ": " << *par_data;
152  std::cout << "Proc " << par_data->pComm->rank() << " local dims: " << low << "-" << high << std::endl;
153  }
154  }
155 #endif
156 
157  HomCoord tmp_size = high - low + HomCoord( 1, 1, 1, 0 );
158  if( ( tmp_size[1] && num_coords && (int)num_coords < tmp_size[0] ) ||
159  ( tmp_size[2] && num_coords && (int)num_coords < tmp_size[0] * tmp_size[1] ) )
160  return MB_FAILURE;
161 
162  rval = create_scd_sequence( low, high, MBVERTEX, 0, new_box );ERRORR( rval, "Trouble creating scd vertex sequence." );
163 
164  // set the vertex coordinates
165  double *xc, *yc, *zc;
166  rval = new_box->get_coordinate_arrays( xc, yc, zc );ERRORR( rval, "Couldn't get vertex coordinate arrays." );
167 
168  if( coords && num_coords )
169  {
170  unsigned int i = 0;
171  for( int kl = low[2]; kl <= high[2]; kl++ )
172  {
173  for( int jl = low[1]; jl <= high[1]; jl++ )
174  {
175  for( int il = low[0]; il <= high[0]; il++ )
176  {
177  xc[i] = coords[3 * i];
178  if( new_box->box_size()[1] ) yc[i] = coords[3 * i + 1];
179  if( new_box->box_size()[2] ) zc[i] = coords[3 * i + 2];
180  i++;
181  }
182  }
183  }
184  }
185  else
186  {
187  unsigned int i = 0;
188  for( int kl = low[2]; kl <= high[2]; kl++ )
189  {
190  for( int jl = low[1]; jl <= high[1]; jl++ )
191  {
192  for( int il = low[0]; il <= high[0]; il++ )
193  {
194  xc[i] = (double)il;
195  if( new_box->box_size()[1] )
196  yc[i] = (double)jl;
197  else
198  yc[i] = 0.0;
199  if( new_box->box_size()[2] )
200  zc[i] = (double)kl;
201  else
202  zc[i] = 0.0;
203  i++;
204  }
205  }
206  }
207  }
208 
209  // create element sequence
210  Core* mbcore = dynamic_cast< Core* >( mbImpl );
211  SequenceManager* seq_mgr = mbcore->sequence_manager();
212 
213  EntitySequence* tmp_seq;
214  EntityHandle start_ent;
215 
216  // construct the sequence
217  EntityType this_tp = MBHEX;
218  if( 1 >= tmp_size[2] ) this_tp = MBQUAD;
219  if( 1 >= tmp_size[2] && 1 >= tmp_size[1] ) this_tp = MBEDGE;
220  rval = seq_mgr->create_scd_sequence( low, high, this_tp, 0, start_ent, tmp_seq, tmp_lper );ERRORR( rval, "Trouble creating scd element sequence." );
221 
222  new_box->elem_seq( tmp_seq );
223  new_box->start_element( start_ent );
224 
225  // add vertex seq to element seq, forward orientation, unity transform
226  rval = new_box->add_vbox( new_box,
227  // p1: imin,jmin
228  low, low,
229  // p2: imax,jmin
230  low + HomCoord( 1, 0, 0 ), low + HomCoord( 1, 0, 0 ),
231  // p3: imin,jmax
232  low + HomCoord( 0, 1, 0 ), low + HomCoord( 0, 1, 0 ) );ERRORR( rval, "Error constructing structured element sequence." );
233 
234  // add the new hexes to the scd box set; vertices were added in call to create_scd_sequence
235  Range tmp_range( new_box->start_element(), new_box->start_element() + new_box->num_elements() - 1 );
236  rval = mbImpl->add_entities( new_box->box_set(), tmp_range );ERRORR( rval, "Couldn't add new hexes to box set." );
237 
238  if( par_data ) new_box->par_data( *par_data );
239 
240  if( assign_gids )
241  {
242  rval = assign_global_ids( new_box );ERRORR( rval, "Trouble assigning global ids" );
243  }
244 
245 #ifdef MOAB_HAVE_MPI
246  if( par_data && -1 != tag_shared_ents )
247  {
248  rval = tag_shared_vertices( par_data->pComm, new_box );
249  }
250 #endif
251 
252  return MB_SUCCESS;
253 }
254 
256 {
257  // Get a ptr to global id memory
258  void* data;
259  int count = 0;
260  Tag gid_tag = mbImpl->globalId_tag();
261  Range tmp_range( box->start_vertex(), box->start_vertex() + box->num_vertices() );
262  ErrorCode rval = mbImpl->tag_iterate( gid_tag, tmp_range.begin(), tmp_range.end(), count, data );ERRORR( rval, "Failed to get tag iterator." );
263  assert( count == box->num_vertices() );
264  int* gid_data = (int*)data;
265  int di = box->par_data().gDims[3] - box->par_data().gDims[0] + 1;
266  int dj = box->par_data().gDims[4] - box->par_data().gDims[1] + 1;
267 
268  for( int kl = box->box_dims()[2]; kl <= box->box_dims()[5]; kl++ )
269  {
270  for( int jl = box->box_dims()[1]; jl <= box->box_dims()[4]; jl++ )
271  {
272  for( int il = box->box_dims()[0]; il <= box->box_dims()[3]; il++ )
273  {
274  int itmp =
275  ( !box->locally_periodic()[0] && box->par_data().gPeriodic[0] && il == box->par_data().gDims[3]
276  ? box->par_data().gDims[0]
277  : il );
278  *gid_data = ( -1 != kl ? kl * di * dj : 0 ) + jl * di + itmp + 1;
279  gid_data++;
280  }
281  }
282  }
283 
284  return MB_SUCCESS;
285 }
286 
288  const HomCoord& high,
289  EntityType tp,
290  int starting_id,
291  ScdBox*& new_box,
292  int* is_periodic )
293 {
294  HomCoord tmp_size = high - low + HomCoord( 1, 1, 1, 0 );
295  if( ( tp == MBHEX && 1 >= tmp_size[2] ) || ( tp == MBQUAD && 1 >= tmp_size[1] ) ||
296  ( tp == MBEDGE && 1 >= tmp_size[0] ) )
297  return MB_TYPE_OUT_OF_RANGE;
298 
299  Core* mbcore = dynamic_cast< Core* >( mbImpl );
300  assert( mbcore != NULL );
301  SequenceManager* seq_mgr = mbcore->sequence_manager();
302 
303  EntitySequence* tmp_seq;
304  EntityHandle start_ent, scd_set;
305 
306  // construct the sequence
307  ErrorCode rval = seq_mgr->create_scd_sequence( low, high, tp, starting_id, start_ent, tmp_seq, is_periodic );
308  if( MB_SUCCESS != rval ) return rval;
309 
310  // create the set for this rectangle
311  rval = create_box_set( low, high, scd_set );
312  if( MB_SUCCESS != rval ) return rval;
313 
314  // make the ScdBox
315  new_box = new ScdBox( this, scd_set, tmp_seq );
316  if( !new_box ) return MB_FAILURE;
317 
318  // set the start vertex/element
319  Range new_range;
320  if( MBVERTEX == tp )
321  {
322  new_range.insert( start_ent, start_ent + new_box->num_vertices() - 1 );
323  }
324  else
325  {
326  new_range.insert( start_ent, start_ent + new_box->num_elements() - 1 );
327  }
328 
329  // put the entities in the box set
330  rval = mbImpl->add_entities( scd_set, new_range );
331  if( MB_SUCCESS != rval ) return rval;
332 
333  // tag the set with the box
334  rval = mbImpl->tag_set_data( box_set_tag(), &scd_set, 1, &new_box );
335  if( MB_SUCCESS != rval ) return rval;
336 
337  return MB_SUCCESS;
338 }
339 
341  const HomCoord& high,
342  EntityHandle& scd_set,
343  int* is_periodic )
344 {
345  // create the set and put the entities in it
346  ErrorCode rval = mbImpl->create_meshset( MESHSET_SET, scd_set );
347  if( MB_SUCCESS != rval ) return rval;
348 
349  // tag the set with parameter extents
350  int boxdims[6];
351  for( int i = 0; i < 3; i++ )
352  boxdims[i] = low[i];
353  for( int i = 0; i < 3; i++ )
354  boxdims[3 + i] = high[i];
355  rval = mbImpl->tag_set_data( box_dims_tag(), &scd_set, 1, boxdims );
356  if( MB_SUCCESS != rval ) return rval;
357 
358  if( is_periodic )
359  {
360  rval = mbImpl->tag_set_data( box_periodic_tag(), &scd_set, 1, is_periodic );
361  if( MB_SUCCESS != rval ) return rval;
362  }
363 
364  return rval;
365 }
366 
367 Tag ScdInterface::box_periodic_tag( bool create_if_missing )
368 {
369  // Reset boxPeriodicTag in case it has been deleted (e.g. by Core::clean_up_failed_read)
370  if( boxPeriodicTag )
371  {
372  std::string tag_name;
373  if( MB_TAG_NOT_FOUND == mbImpl->tag_get_name( boxPeriodicTag, tag_name ) ) boxPeriodicTag = NULL;
374  }
375 
376  if( boxPeriodicTag || !create_if_missing ) return boxPeriodicTag;
377 
378  ErrorCode rval =
380  if( MB_SUCCESS != rval ) return 0;
381  return boxPeriodicTag;
382 }
383 
384 Tag ScdInterface::box_dims_tag( bool create_if_missing )
385 {
386  // Reset boxDimsTag in case it has been deleted (e.g. by clean_up_failed_read)
387  if( boxDimsTag )
388  {
389  std::string tag_name;
390  if( MB_TAG_NOT_FOUND == mbImpl->tag_get_name( boxDimsTag, tag_name ) ) boxDimsTag = NULL;
391  }
392 
393  if( boxDimsTag || !create_if_missing ) return boxDimsTag;
394 
396  if( MB_SUCCESS != rval ) return 0;
397  return boxDimsTag;
398 }
399 
400 Tag ScdInterface::global_box_dims_tag( bool create_if_missing )
401 {
402  // Reset globalBoxDimsTag in case it has been deleted (e.g. by Core::clean_up_failed_read)
403  if( globalBoxDimsTag )
404  {
405  std::string tag_name;
407  }
408 
409  if( globalBoxDimsTag || !create_if_missing ) return globalBoxDimsTag;
410 
411  ErrorCode rval =
413  if( MB_SUCCESS != rval ) return 0;
414  return globalBoxDimsTag;
415 }
416 
417 Tag ScdInterface::part_method_tag( bool create_if_missing )
418 {
419  // Reset partMethodTag in case it has been deleted (e.g. by Core::clean_up_failed_read)
420  if( partMethodTag )
421  {
422  std::string tag_name;
423  if( MB_TAG_NOT_FOUND == mbImpl->tag_get_name( partMethodTag, tag_name ) ) partMethodTag = NULL;
424  }
425 
426  if( partMethodTag || !create_if_missing ) return partMethodTag;
427 
428  ErrorCode rval =
430  if( MB_SUCCESS != rval ) return 0;
431  return partMethodTag;
432 }
433 
434 Tag ScdInterface::box_set_tag( bool create_if_missing )
435 {
436  // Reset boxSetTag in case it has been deleted (e.g. by Core::clean_up_failed_read)
437  if( boxSetTag )
438  {
439  std::string tag_name;
440  if( MB_TAG_NOT_FOUND == mbImpl->tag_get_name( boxSetTag, tag_name ) ) boxSetTag = NULL;
441  }
442 
443  if( boxSetTag || !create_if_missing ) return boxSetTag;
444 
445  ErrorCode rval = mbImpl->tag_get_handle( "__BOX_SET", sizeof( ScdBox* ), MB_TYPE_OPAQUE, boxSetTag,
447  if( MB_SUCCESS != rval ) return 0;
448  return boxSetTag;
449 }
450 
451 //! Remove the box from the list on ScdInterface
453 {
454  std::vector< ScdBox* >::iterator vit = std::find( scdBoxes.begin(), scdBoxes.end(), box );
455  if( vit != scdBoxes.end() )
456  {
457  scdBoxes.erase( vit );
458  return MB_SUCCESS;
459  }
460  else
461  return MB_FAILURE;
462 }
463 
464 //! Add the box to the list on ScdInterface
466 {
467  scdBoxes.push_back( box );
468  return MB_SUCCESS;
469 }
470 
471 ErrorCode ScdInterface::get_boxes( std::vector< ScdBox* >& boxes )
472 {
473  std::copy( scdBoxes.begin(), scdBoxes.end(), std::back_inserter( boxes ) );
474  return MB_SUCCESS;
475 }
476 
478  : scImpl( impl ), boxSet( bset ), vertDat( NULL ), elemSeq( NULL ), startVertex( 0 ), startElem( 0 )
479 {
480  for( int i = 0; i < 6; i++ )
481  boxDims[i] = 0;
482  for( int i = 0; i < 3; i++ )
483  locallyPeriodic[i] = false;
484  VertexSequence* vseq = dynamic_cast< VertexSequence* >( seq1 );
485  if( vseq ) vertDat = dynamic_cast< ScdVertexData* >( vseq->data() );
486  if( vertDat )
487  {
488  // retrieve the parametric space
489  for( int i = 0; i < 3; i++ )
490  {
491  boxDims[i] = vertDat->min_params()[i];
492  boxDims[3 + i] = vertDat->max_params()[i];
493  }
495  }
496  else if( impl->boxDimsTag )
497  {
498  // look for parametric space info on set
499  ErrorCode rval = impl->mbImpl->tag_get_data( impl->boxDimsTag, &bset, 1, boxDims );
500  if( MB_SUCCESS == rval )
501  {
502  Range verts;
503  impl->mbImpl->get_entities_by_dimension( bset, 0, verts );
504  if( !verts.empty() ) startVertex = *verts.begin();
505  }
506  }
507 
508  elemSeq = dynamic_cast< StructuredElementSeq* >( seq2 );
509  if( !elemSeq ) elemSeq = dynamic_cast< StructuredElementSeq* >( seq1 );
510 
511  if( elemSeq )
512  {
513  if( vertDat )
514  {
515  // check the parametric space to make sure it's consistent
516  assert( elemSeq->sdata()->min_params() == HomCoord( boxDims, 3 ) &&
517  ( elemSeq->sdata()->max_params() + HomCoord( 1, 1, 1 ) ) == HomCoord( boxDims, 3 ) );
518  }
519  else
520  {
521  // get the parametric space from the element sequence
522  for( int i = 0; i < 3; i++ )
523  {
524  boxDims[i] = elemSeq->sdata()->min_params()[i];
525  boxDims[3 + i] = elemSeq->sdata()->max_params()[i];
526  }
527  }
528 
530  }
531  else
532  {
533  Range elems;
535  bset, ( boxDims[2] == boxDims[5] ? ( boxDims[1] == boxDims[4] ? 1 : 2 ) : 3 ), elems );
536  if( !elems.empty() ) startElem = *elems.begin();
537  // call the following w/o looking at return value, since it doesn't really need to be there
538  if( impl->boxPeriodicTag ) impl->mbImpl->tag_get_data( impl->boxPeriodicTag, &bset, 1, locallyPeriodic );
539  }
540 
541  assert( vertDat || elemSeq || boxDims[0] != boxDims[3] || boxDims[1] != boxDims[4] || boxDims[2] != boxDims[5] );
542 
543  boxSize = HomCoord( boxDims + 3, 3 ) - HomCoord( boxDims, 3 ) + HomCoord( 1, 1, 1 );
544  boxSizeIJ = ( boxSize[1] ? boxSize[1] : 1 ) * boxSize[0];
545  boxSizeIM1 = boxSize[0] - ( locallyPeriodic[0] ? 0 : 1 );
546  boxSizeIJM1 = ( boxSize[1] ? ( boxSize[1] - ( locallyPeriodic[1] ? 0 : 1 ) ) : 1 ) * boxSizeIM1;
547 
548  scImpl->add_box( this );
549 }
550 
552 {
553  // Reset the tag on the set
554  if( boxSet )
555  {
556  // It is possible that the box set entity has been deleted (e.g. by
557  // Core::clean_up_failed_read)
558  Core* mbcore = dynamic_cast< Core* >( scImpl->mbImpl );
559  assert( mbcore != NULL );
560  if( mbcore->is_valid( boxSet ) )
561  {
562  ScdBox* tmp_ptr = NULL;
563  scImpl->mbImpl->tag_set_data( scImpl->box_set_tag(), &boxSet, 1, &tmp_ptr );
564  }
565  else
566  boxSet = 0;
567  }
568 
569  scImpl->remove_box( this );
570 }
571 
572 EntityHandle ScdBox::get_vertex_from_seq( int i, int j, int k ) const
573 {
574  assert( elemSeq );
575  return elemSeq->get_vertex( i, j, k );
576 }
577 
579 {
580  return ( startElem ? scImpl->mbImpl->dimension_from_handle( startElem ) : -1 );
581 }
582 
584  HomCoord from1,
585  HomCoord to1,
586  HomCoord from2,
587  HomCoord to2,
588  HomCoord from3,
589  HomCoord to3,
590  bool bb_input,
591  const HomCoord& bb_min,
592  const HomCoord& bb_max )
593 {
594  if( !vbox->vertDat ) return MB_FAILURE;
595  ScdVertexData* dum_data = dynamic_cast< ScdVertexData* >( vbox->vertDat );
596  ErrorCode rval =
597  elemSeq->sdata()->add_vsequence( dum_data, from1, to1, from2, to2, from3, to3, bb_input, bb_min, bb_max );
598  return rval;
599 }
600 
602 {
603  return elemSeq->boundary_complete();
604 }
605 
606 ErrorCode ScdBox::get_coordinate_arrays( double*& xc, double*& yc, double*& zc )
607 {
608  if( !vertDat ) return MB_FAILURE;
609 
610  xc = reinterpret_cast< double* >( vertDat->get_sequence_data( 0 ) );
611  yc = reinterpret_cast< double* >( vertDat->get_sequence_data( 1 ) );
612  zc = reinterpret_cast< double* >( vertDat->get_sequence_data( 2 ) );
613  return MB_SUCCESS;
614 }
615 
616 ErrorCode ScdBox::get_coordinate_arrays( const double*& xc, const double*& yc, const double*& zc ) const
617 {
618  if( !vertDat ) return MB_FAILURE;
619  xc = reinterpret_cast< const double* >( vertDat->get_sequence_data( 0 ) );
620  yc = reinterpret_cast< const double* >( vertDat->get_sequence_data( 1 ) );
621  zc = reinterpret_cast< const double* >( vertDat->get_sequence_data( 2 ) );
622  return MB_SUCCESS;
623 }
624 
626 {
627  vertDat = vert_dt;
628  return MB_SUCCESS;
629 }
630 
632 {
633  elemSeq = dynamic_cast< StructuredElementSeq* >( elem_sq );
635 
636  if( locallyPeriodic[0] ) boxSizeIM1 = boxSize[0] - ( locallyPeriodic[0] ? 0 : 1 );
637  if( locallyPeriodic[0] || locallyPeriodic[1] )
638  boxSizeIJM1 = ( boxSize[1] ? ( boxSize[1] - ( locallyPeriodic[1] ? 0 : 1 ) ) : 1 ) * boxSizeIM1;
639 
640  return ( elemSeq ? MB_SUCCESS : MB_FAILURE );
641 }
642 
644 {
645  // check first whether this is an intermediate entity, so we know what to do
646  int dimension = box_dimension();
647  int this_dim = scImpl->impl()->dimension_from_handle( ent );
648 
649  if( ( 0 == this_dim && !vertDat ) || ( this_dim && this_dim == dimension ) )
650  {
651  assert( elemSeq );
652  return elemSeq->get_params( ent, ijkd[0], ijkd[1], ijkd[2] );
653  }
654 
655  else if( !this_dim && vertDat )
656  return vertDat->get_params( ent, ijkd[0], ijkd[1], ijkd[2] );
657 
658  else
659  return MB_NOT_IMPLEMENTED;
660 }
661 
662 //! Get the entity of specified dimension adjacent to parametric element
663 /**
664  * \param dim Dimension of adjacent entity being requested
665  * \param i Parametric coordinates of cell being evaluated
666  * \param j Parametric coordinates of cell being evaluated
667  * \param k Parametric coordinates of cell being evaluated
668  * \param dir Direction (0, 1, or 2), for getting adjacent edges (2d, 3d) or faces (3d)
669  * \param ent EntityHandle of adjacent entity
670  * \param create_if_missing If true, creates the entity if it doesn't already exist
671  */
673  int i,
674  int j,
675  int k,
676  int dir,
677  EntityHandle& ent,
678  bool create_if_missing ) const
679 {
680  // describe connectivity of sub-element in static array
681  // subconnect[dim-1][dir][numv][ijk] where dimensions are:
682  // [dim-1]: dim=1 or 2, so this is 0 or 1
683  // [dir]: one of 0..2, for ijk directions in a hex
684  // [numv]: number of vertices describing sub entity = 2*dim <= 4
685  // [ijk]: 3 values for i, j, k
686  int subconnect[2][3][4][3] = { { { { 0, 0, 0 }, { 1, 0, 0 }, { -1, -1, -1 }, { -1, -1, -1 } }, // i edge
687  { { 0, 0, 0 }, { 0, 1, 0 }, { -1, -1, -1 }, { -1, -1, -1 } }, // j edge
688  { { 0, 0, 0 }, { 0, 0, 1 }, { -1, -1, -1 }, { -1, -1, -1 } } }, // k edge
689 
690  { { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 1, 1 }, { 0, 0, 1 } }, // i face
691  { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 0, 1 }, { 0, 0, 1 } }, // j face
692  { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 } } } }; // k face
693 
694  // check proper input dimensions and lower bound
695  if( dim < 1 || dim > 2 || i < boxDims[0] || j < boxDims[1] || k < boxDims[2] ) return MB_FAILURE;
696 
697  // now check upper bound; parameters must be <= upper corner, since edges/faces
698  // follow element parameterization, not vertex parameterization
699  else if( ( boxDims[3] != boxDims[0] && i > ( locallyPeriodic[0] ? boxDims[3] + 1 : boxDims[3] ) ) ||
700  ( boxDims[4] != boxDims[1] && j > ( locallyPeriodic[1] ? boxDims[4] + 1 : boxDims[4] ) ) ||
701  ( boxDims[5] != boxDims[2] && k > boxDims[5] ) )
702  return MB_FAILURE;
703 
704  // get the vertices making up this entity
705  EntityHandle verts[4];
706  for( int ind = 0; ind < 2 * dim; ind++ )
707  {
708  int i1 = i + subconnect[dim - 1][dir][ind][0];
709  int j1 = j + subconnect[dim - 1][dir][ind][1];
710  // if periodic in i and i1 is boxDims[3]+1, wrap around
711  if( locallyPeriodic[0] && i1 == boxDims[3] + 1 ) i1 = boxDims[0];
712  // if periodic in j and j1 is boxDims[4]+1, wrap around
713  if( locallyPeriodic[1] && j1 == boxDims[4] + 1 ) j1 = boxDims[1];
714  verts[ind] = get_vertex( i1, j1, k + subconnect[dim - 1][dir][ind][2] );
715  if( !verts[ind] ) return MB_FAILURE;
716  }
717 
718  Range ents;
719  ErrorCode rval = scImpl->impl()->get_adjacencies( verts, 2 * dim, dim, false, ents );
720  if( MB_SUCCESS != rval ) return rval;
721 
722  if( ents.size() > 1 )
723  return MB_FAILURE;
724 
725  else if( ents.size() == 1 )
726  {
727  ent = *ents.begin();
728  }
729  else if( create_if_missing )
730  rval = scImpl->impl()->create_element( ( 1 == dim ? MBEDGE : MBQUAD ), verts, 2 * dim, ent );
731 
732  return rval;
733 }
734 
735 #ifndef MOAB_HAVE_MPI
737 {
738  return MB_FAILURE;
739 #else
741 {
742  EntityHandle seth = box->box_set();
743 
744  // check the # ents in the box against the num in the set, to make sure it's only 1 box;
745  // reuse tmp_range
746  Range tmp_range;
747  ErrorCode rval = mbImpl->get_entities_by_dimension( seth, box->box_dimension(), tmp_range );
748  if( MB_SUCCESS != rval ) return rval;
749  if( box->num_elements() != (int)tmp_range.size() ) return MB_FAILURE;
750 
751  const int* gdims = box->par_data().gDims;
752  if( ( gdims[0] == gdims[3] && gdims[1] == gdims[4] && gdims[2] == gdims[5] ) || -1 == box->par_data().partMethod )
753  return MB_FAILURE;
754 
755  // ok, we have a partitioned box; get the vertices shared with other processors
756  std::vector< int > procs, offsets, shared_indices;
757  rval = get_shared_vertices( pcomm, box, procs, offsets, shared_indices );
758  if( MB_SUCCESS != rval ) return rval;
759 
760  // post receives for start handles once we know how many to look for
761  std::vector< MPI_Request > recv_reqs( procs.size(), MPI_REQUEST_NULL ), send_reqs( procs.size(), MPI_REQUEST_NULL );
762  std::vector< EntityHandle > rhandles( 4 * procs.size() ), shandles( 4 );
763  for( unsigned int i = 0; i < procs.size(); i++ )
764  {
765  int success = MPI_Irecv( (void*)&rhandles[4 * i], 4 * sizeof( EntityHandle ), MPI_UNSIGNED_CHAR, procs[i], 1,
766  pcomm->proc_config().proc_comm(), &recv_reqs[i] );
767  if( success != MPI_SUCCESS ) return MB_FAILURE;
768  }
769 
770  // send our own start handles
771  shandles[0] = box->start_vertex();
772  shandles[1] = 0;
773  if( box->box_dimension() == 1 )
774  {
775  shandles[1] = box->start_element();
776  shandles[2] = 0;
777  shandles[3] = 0;
778  }
779  else if( box->box_dimension() == 2 )
780  {
781  shandles[2] = box->start_element();
782  shandles[3] = 0;
783  }
784  else
785  {
786  shandles[2] = 0;
787  shandles[3] = box->start_element();
788  }
789  for( unsigned int i = 0; i < procs.size(); i++ )
790  {
791  int success = MPI_Isend( (void*)&shandles[0], 4 * sizeof( EntityHandle ), MPI_UNSIGNED_CHAR, procs[i], 1,
792  pcomm->proc_config().proc_comm(), &send_reqs[i] );
793  if( success != MPI_SUCCESS ) return MB_FAILURE;
794  }
795 
796  // receive start handles and save info to a tuple list
797  int incoming = procs.size();
798  int p, j, k;
799  MPI_Status status;
800  TupleList shared_data;
801  shared_data.initialize( 1, 0, 2, 0, shared_indices.size() / 2 );
802  shared_data.enableWriteAccess();
803 
804  j = 0;
805  k = 0;
806  while( incoming )
807  {
808  int success = MPI_Waitany( procs.size(), &recv_reqs[0], &p, &status );
809  if( MPI_SUCCESS != success ) return MB_FAILURE;
810  unsigned int num_indices = ( offsets[p + 1] - offsets[p] ) / 2;
811  int *lh = &shared_indices[offsets[p]], *rh = lh + num_indices;
812  for( unsigned int i = 0; i < num_indices; i++ )
813  {
814  shared_data.vi_wr[j++] = procs[p];
815  shared_data.vul_wr[k++] = shandles[0] + lh[i];
816  shared_data.vul_wr[k++] = rhandles[4 * p] + rh[i];
817  shared_data.inc_n();
818  }
819  incoming--;
820  }
821 
822  // still need to wait for the send requests
823  std::vector< MPI_Status > mult_status( procs.size() );
824  int success = MPI_Waitall( procs.size(), &send_reqs[0], &mult_status[0] );
825  if( MPI_SUCCESS != success )
826  {
827  MB_SET_ERR( MB_FAILURE, "Failed in waitall in ScdInterface::tag_shared_vertices" );
828  }
829  // sort by local handle
830  TupleList::buffer sort_buffer;
831  sort_buffer.buffer_init( shared_indices.size() / 2 );
832  shared_data.sort( 1, &sort_buffer );
833  sort_buffer.reset();
834 
835  // process into sharing data
836  std::map< std::vector< int >, std::vector< EntityHandle > > proc_nvecs;
837  Range dum;
838  rval = pcomm->tag_shared_verts( shared_data, proc_nvecs, dum, 0 );
839  if( MB_SUCCESS != rval ) return rval;
840 
841  // create interface sets
842  rval = pcomm->create_interface_sets( proc_nvecs );
843  if( MB_SUCCESS != rval ) return rval;
844 
845  // add the box to the PComm's partitionSets
846  pcomm->partition_sets().insert( box->box_set() );
847 
848  // make sure buffers are allocated for communicating procs
849  for( std::vector< int >::iterator pit = procs.begin(); pit != procs.end(); ++pit )
850  pcomm->get_buffers( *pit );
851 
852  if( pcomm->get_debug_verbosity() > 1 ) pcomm->list_entities( NULL, 1 );
853 
854 #ifndef NDEBUG
855  rval = pcomm->check_all_shared_handles();
856  if( MB_SUCCESS != rval ) return rval;
857 #endif
858 
859  return MB_SUCCESS;
860 
861 #endif
862 }
863 
865  int pfrom,
866  const int* const gdims,
867  const int* const gperiodic,
868  const int* const dijk,
869  int& pto,
870  int* rdims,
871  int* facedims,
872  int* across_bdy )
873 {
874  if( dijk[0] != 0 )
875  {
876  pto = -1;
877  return MB_SUCCESS;
878  }
879 
880  pto = -1;
881  across_bdy[0] = across_bdy[1] = across_bdy[2] = 0;
882 
883  int ldims[6], pijk[3], lperiodic[3];
884  ErrorCode rval = compute_partition_alljkbal( np, pfrom, gdims, gperiodic, ldims, lperiodic, pijk );
885  if( MB_SUCCESS != rval ) return rval;
886  assert( pijk[1] * pijk[2] == np );
887  pto = -1;
888  bool bot_j = pfrom< pijk[2], top_j = pfrom > np - pijk[2];
889  if( ( 1 == pijk[2] && dijk[2] ) || // 1d in j means no neighbors with dk != 0
890  ( !( pfrom % pijk[2] ) && -1 == dijk[2] ) || // at -k bdy
891  ( pfrom % pijk[2] == pijk[2] - 1 && 1 == dijk[2] ) || // at +k bdy
892  ( pfrom < pijk[2] && -1 == dijk[1] && !gperiodic[1] ) || // down and not periodic
893  ( pfrom >= np - pijk[2] && 1 == dijk[1] && !gperiodic[1] ) ) // up and not periodic
894  return MB_SUCCESS;
895 
896  pto = pfrom;
897  std::copy( ldims, ldims + 6, rdims );
898  std::copy( ldims, ldims + 6, facedims );
899 
900  if( 0 != dijk[1] )
901  {
902  pto = ( pto + dijk[1] * pijk[2] + np ) % np;
903  assert( pto >= 0 && pto < np );
904  int dj = ( gdims[4] - gdims[1] ) / pijk[1], extra = ( gdims[4] - gdims[1] ) % pijk[1];
905  if( -1 == dijk[1] )
906  {
907  facedims[4] = facedims[1];
908  if( bot_j )
909  {
910  // going across periodic lower bdy in j
911  rdims[4] = gdims[4];
912  across_bdy[1] = -1;
913  }
914  else
915  {
916  rdims[4] = ldims[1];
917  }
918  rdims[1] = rdims[4] - dj;
919  if( pto < extra ) rdims[1]--;
920  }
921  else
922  {
923  if( pfrom > np - pijk[2] ) facedims[4] = gdims[1];
924  facedims[1] = facedims[4];
925  if( top_j )
926  {
927  // going across periodic upper bdy in j
928  rdims[1] = gdims[1];
929  across_bdy[1] = 1;
930  }
931  else
932  {
933  rdims[1] = ldims[4];
934  }
935  rdims[4] = rdims[1] + dj;
936  if( pto < extra ) rdims[4]++;
937  }
938  }
939  if( 0 != dijk[2] )
940  {
941  pto = ( pto + dijk[2] ) % np;
942  assert( pto >= 0 && pto < np );
943  facedims[2] = facedims[5] = ( -1 == dijk[2] ? facedims[2] : facedims[5] );
944  int dk = ( gdims[5] - gdims[2] ) / pijk[2];
945  if( -1 == dijk[2] )
946  {
947  facedims[5] = facedims[2];
948  rdims[5] = ldims[2];
949  rdims[2] = rdims[5] - dk; // never any kextra for alljkbal
950  }
951  else
952  {
953  facedims[2] = facedims[5];
954  rdims[2] = ldims[5];
955  rdims[5] = rdims[2] + dk; // never any kextra for alljkbal
956  }
957  }
958 
959  assert( -1 == pto || ( rdims[0] >= gdims[0] && rdims[3] <= gdims[3] ) );
960  assert( -1 == pto || ( rdims[1] >= gdims[1] && ( rdims[4] <= gdims[4] || ( across_bdy[1] && bot_j ) ) ) );
961  assert( -1 == pto || ( rdims[2] >= gdims[2] && rdims[5] <= gdims[5] ) );
962  assert( -1 == pto || ( ( facedims[0] >= rdims[0] ||
963  ( gperiodic[0] && rdims[3] == gdims[3] + 1 && facedims[0] == gdims[0] ) ) ) );
964  assert( -1 == pto || ( facedims[3] <= rdims[3] ) );
965  assert( -1 == pto || ( ( facedims[1] >= rdims[1] ||
966  ( gperiodic[1] && rdims[4] == gdims[4] + 1 && facedims[1] == gdims[1] ) ) ) );
967  assert( -1 == pto || ( facedims[4] <= rdims[4] ) );
968  assert( -1 == pto || ( facedims[2] >= rdims[2] ) );
969  assert( -1 == pto || ( facedims[5] <= rdims[5] ) );
970  assert( -1 == pto || ( facedims[0] >= ldims[0] ) );
971  assert( -1 == pto || ( facedims[3] <= ldims[3] ) );
972  assert( -1 == pto || ( facedims[1] >= ldims[1] ) );
973  assert( -1 == pto || ( facedims[4] <= ldims[4] ) );
974  assert( -1 == pto || ( facedims[2] >= ldims[2] ) );
975  assert( -1 == pto || ( facedims[5] <= ldims[5] ) );
976 
977  return MB_SUCCESS;
978 }
979 
981  int pfrom,
982  const int* const gdims,
983  const int* const gperiodic,
984  const int* const dijk,
985  int& pto,
986  int* rdims,
987  int* facedims,
988  int* across_bdy )
989 {
990  if( dijk[2] != 0 )
991  {
992  // for sqij, there is no k neighbor, ever
993  pto = -1;
994  return MB_SUCCESS;
995  }
996 
997  pto = -1;
998  across_bdy[0] = across_bdy[1] = across_bdy[2] = 0;
999  int lperiodic[3], pijk[3], ldims[6];
1000  ErrorCode rval = compute_partition_sqij( np, pfrom, gdims, gperiodic, ldims, lperiodic, pijk );
1001  if( MB_SUCCESS != rval ) return rval;
1002  assert( pijk[0] * pijk[1] == np );
1003  pto = -1;
1004  bool top_i = 0, top_j = 0, bot_i = 0, bot_j = 0;
1005  int ni = pfrom % pijk[0], nj = pfrom / pijk[0]; // row / column number of me
1006  if( ni == pijk[0] - 1 ) top_i = 1;
1007  if( nj == pijk[1] - 1 ) top_j = 1;
1008  if( !ni ) bot_i = 1;
1009  if( !nj ) bot_j = 1;
1010  if( ( !gperiodic[0] && bot_i && -1 == dijk[0] ) || // left and not periodic
1011  ( !gperiodic[0] && top_i && 1 == dijk[0] ) || // right and not periodic
1012  ( !gperiodic[1] && bot_j && -1 == dijk[1] ) || // bottom and not periodic
1013  ( !gperiodic[1] && top_j && 1 == dijk[1] ) ) // top and not periodic
1014  return MB_SUCCESS;
1015 
1016  std::copy( ldims, ldims + 6, facedims );
1017  std::copy( ldims, ldims + 6, rdims );
1018  pto = pfrom;
1019  int j = gdims[4] - gdims[1], dj = j / pijk[1], jextra = ( gdims[4] - gdims[1] ) % dj, i = gdims[3] - gdims[0],
1020  di = i / pijk[0], iextra = ( gdims[3] - gdims[0] ) % di;
1021 
1022  if( 0 != dijk[0] )
1023  {
1024  pto = ( ni + dijk[0] + pijk[0] ) % pijk[0]; // get pto's ni value
1025  pto = nj * pijk[0] + pto; // then convert to pto
1026  assert( pto >= 0 && pto < np );
1027  if( -1 == dijk[0] )
1028  {
1029  facedims[3] = facedims[0];
1030  if( bot_i )
1031  {
1032  // going across lower periodic bdy in i
1033  across_bdy[0] = -1;
1034  rdims[3] = gdims[3] + 1; // +1 because ldims[3] on remote proc is gdims[3]+1
1035  rdims[0] = rdims[3] - di - 1; // -1 to account for rdims[3] being one larger
1036  }
1037  else
1038  {
1039  rdims[3] = ldims[0];
1040  rdims[0] = rdims[3] - di;
1041  }
1042 
1043  if( pto % pijk[0] < iextra ) rdims[0]--;
1044  }
1045  else
1046  {
1047  if( top_i )
1048  {
1049  // going across lower periodic bdy in i
1050  facedims[3] = gdims[0];
1051  across_bdy[0] = 1;
1052  }
1053  facedims[0] = facedims[3];
1054  rdims[0] = ( top_i ? gdims[0] : ldims[3] );
1055  rdims[3] = rdims[0] + di;
1056  if( pto % pijk[0] < iextra ) rdims[3]++;
1057  if( gperiodic[0] && ni == pijk[0] - 2 ) rdims[3]++; // remote proc is top_i and periodic
1058  }
1059  }
1060  if( 0 != dijk[1] )
1061  {
1062  pto = ( pto + dijk[1] * pijk[0] + np ) % np;
1063  assert( pto >= 0 && pto < np );
1064  if( -1 == dijk[1] )
1065  {
1066  facedims[4] = facedims[1];
1067  if( bot_j )
1068  {
1069  // going across lower periodic bdy in j
1070  rdims[4] = gdims[4] + 1; // +1 because ldims[4] on remote proc is gdims[4]+1
1071  rdims[1] = rdims[4] - dj - 1; // -1 to account for gdims[4] being one larger
1072  across_bdy[1] = -1;
1073  }
1074  else
1075  {
1076  rdims[4] = ldims[1];
1077  rdims[1] = rdims[4] - dj;
1078  }
1079  if( pto / pijk[0] < jextra ) rdims[1]--;
1080  }
1081  else
1082  {
1083  if( top_j )
1084  {
1085  // going across lower periodic bdy in j
1086  facedims[4] = gdims[1];
1087  rdims[1] = gdims[1];
1088  across_bdy[1] = 1;
1089  }
1090  else
1091  {
1092  rdims[1] = ldims[4];
1093  }
1094  facedims[1] = facedims[4];
1095  rdims[4] = rdims[1] + dj;
1096  if( nj + 1 < jextra ) rdims[4]++;
1097  if( gperiodic[1] && nj == pijk[1] - 2 ) rdims[4]++; // remote proc is top_j and periodic
1098  }
1099  }
1100 
1101  // rdims within gdims
1102  assert( -1 == pto || ( rdims[0] >= gdims[0] &&
1103  ( rdims[3] <= gdims[3] + ( gperiodic[0] && pto % pijk[0] == pijk[0] - 1 ? 1 : 0 ) ) ) );
1104  assert( -1 == pto || ( rdims[1] >= gdims[1] &&
1105  ( rdims[4] <= gdims[4] + ( gperiodic[1] && pto / pijk[0] == pijk[1] - 1 ? 1 : 0 ) ) ) );
1106  assert( -1 == pto || ( rdims[2] >= gdims[2] && rdims[5] <= gdims[5] ) );
1107  // facedims within rdims
1108  assert( -1 == pto || ( ( facedims[0] >= rdims[0] ||
1109  ( gperiodic[0] && pto % pijk[0] == pijk[0] - 1 && facedims[0] == gdims[0] ) ) ) );
1110  assert( -1 == pto || ( facedims[3] <= rdims[3] ) );
1111  assert( -1 == pto || ( ( facedims[1] >= rdims[1] ||
1112  ( gperiodic[1] && pto / pijk[0] == pijk[1] - 1 && facedims[1] == gdims[1] ) ) ) );
1113  assert( -1 == pto || ( facedims[4] <= rdims[4] ) );
1114  assert( -1 == pto || ( facedims[2] >= rdims[2] && facedims[5] <= rdims[5] ) );
1115  // facedims within ldims
1116  assert( -1 == pto || ( ( facedims[0] >= ldims[0] || ( top_i && facedims[0] == gdims[0] ) ) ) );
1117  assert( -1 == pto || ( facedims[3] <= ldims[3] ) );
1118  assert( -1 == pto || ( ( facedims[1] >= ldims[1] || ( gperiodic[1] && top_j && facedims[1] == gdims[1] ) ) ) );
1119  assert( -1 == pto || ( facedims[4] <= ldims[4] ) );
1120  assert( -1 == pto || ( facedims[2] >= ldims[2] && facedims[5] <= ldims[5] ) );
1121 
1122  return MB_SUCCESS;
1123 }
1124 
1126  int pfrom,
1127  const int* const gdims,
1128  const int* const gperiodic,
1129  const int* const dijk,
1130  int& pto,
1131  int* rdims,
1132  int* facedims,
1133  int* across_bdy )
1134 {
1135  if( dijk[0] != 0 )
1136  {
1137  pto = -1;
1138  return MB_SUCCESS;
1139  }
1140 
1141  pto = -1;
1142  across_bdy[0] = across_bdy[1] = across_bdy[2] = 0;
1143  int pijk[3], lperiodic[3], ldims[6];
1144  ErrorCode rval = compute_partition_sqjk( np, pfrom, gdims, gperiodic, ldims, lperiodic, pijk );
1145  if( MB_SUCCESS != rval ) return rval;
1146  assert( pijk[1] * pijk[2] == np );
1147  pto = -1;
1148  bool top_j = 0, top_k = 0, bot_j = 0, bot_k = 0;
1149  int nj = pfrom % pijk[1], nk = pfrom / pijk[1];
1150  if( nj == pijk[1] - 1 ) top_j = 1;
1151  if( nk == pijk[2] - 1 ) top_k = 1;
1152  if( !nj ) bot_j = 1;
1153  if( !nk ) bot_k = 1;
1154  if( ( !gperiodic[1] && bot_j && -1 == dijk[1] ) || // down and not periodic
1155  ( !gperiodic[1] && top_j && 1 == dijk[1] ) || // up and not periodic
1156  ( bot_k && -1 == dijk[2] ) || // k- bdy
1157  ( top_k && 1 == dijk[2] ) ) // k+ bdy
1158  return MB_SUCCESS;
1159 
1160  std::copy( ldims, ldims + 6, facedims );
1161  std::copy( ldims, ldims + 6, rdims );
1162  pto = pfrom;
1163  int dj = ( gdims[4] - gdims[1] ) / pijk[1], jextra = ( gdims[4] - gdims[1] ) % dj,
1164  dk = ( gdims[5] == gdims[2] ? 0 : ( gdims[5] - gdims[2] ) / pijk[2] ),
1165  kextra = ( gdims[5] - gdims[2] ) - dk * pijk[2];
1166  assert( ( dj * pijk[1] + jextra == ( gdims[4] - gdims[1] ) ) &&
1167  ( dk * pijk[2] + kextra == ( gdims[5] - gdims[2] ) ) );
1168  if( 0 != dijk[1] )
1169  {
1170  pto = ( nj + dijk[1] + pijk[1] ) % pijk[1]; // get pto's ni value
1171  pto = nk * pijk[1] + pto; // then convert to pto
1172  assert( pto >= 0 && pto < np );
1173  if( -1 == dijk[1] )
1174  {
1175  facedims[4] = facedims[1];
1176  if( bot_j )
1177  {
1178  // going across lower periodic bdy in j
1179  rdims[4] = gdims[4] + 1; // +1 because ldims[4] on remote proc is gdims[4]+1
1180  across_bdy[1] = -1;
1181  }
1182  else
1183  {
1184  rdims[4] = ldims[1];
1185  }
1186  rdims[1] = rdims[4] - dj;
1187  if( nj < jextra ) rdims[1]--;
1188  }
1189  else
1190  {
1191  if( top_j )
1192  {
1193  // going across upper periodic bdy in j
1194  rdims[1] = gdims[1];
1195  facedims[4] = gdims[1];
1196  across_bdy[1] = 1;
1197  }
1198  else
1199  {
1200  rdims[1] = ldims[4];
1201  }
1202  facedims[1] = facedims[4];
1203  rdims[4] = rdims[1] + dj;
1204  if( nj < jextra ) rdims[4]++;
1205  if( gperiodic[1] && nj == dijk[1] - 2 ) rdims[4]++; // +1 because next proc is on periodic bdy
1206  }
1207  }
1208  if( 0 != dijk[2] )
1209  {
1210  pto = ( pto + dijk[2] * pijk[1] + np ) % np;
1211  assert( pto >= 0 && pto < np );
1212  if( -1 == dijk[2] )
1213  {
1214  facedims[5] = facedims[2];
1215  rdims[5] = ldims[2];
1216  rdims[2] -= dk;
1217  if( pto / pijk[1] < kextra ) rdims[2]--;
1218  }
1219  else
1220  {
1221  facedims[2] = facedims[5];
1222  rdims[2] = ldims[5];
1223  rdims[5] += dk;
1224  if( pto / pijk[1] < kextra ) rdims[5]++;
1225  }
1226  }
1227 
1228  assert( -1 == pto || ( rdims[0] >= gdims[0] && rdims[3] <= gdims[3] ) );
1229  assert( -1 == pto || ( rdims[1] >= gdims[1] && ( rdims[4] <= gdims[4] || ( across_bdy[1] && bot_j ) ) ) );
1230  assert( -1 == pto || ( rdims[2] >= gdims[2] && rdims[5] <= gdims[5] ) );
1231  assert( -1 == pto || ( facedims[0] >= rdims[0] && facedims[3] <= rdims[3] ) );
1232  assert( -1 == pto ||
1233  ( ( facedims[1] >= rdims[1] || ( gperiodic[1] && rdims[4] == gdims[4] && facedims[1] == gdims[1] ) ) ) );
1234  assert( -1 == pto || ( facedims[4] <= rdims[4] ) );
1235  assert( -1 == pto || ( facedims[2] >= rdims[2] && facedims[5] <= rdims[5] ) );
1236  assert( -1 == pto || ( facedims[0] >= ldims[0] && facedims[3] <= ldims[3] ) );
1237  assert( -1 == pto || ( facedims[1] >= ldims[1] && facedims[4] <= ldims[4] ) );
1238  assert( -1 == pto || ( facedims[2] >= ldims[2] && facedims[5] <= ldims[5] ) );
1239 
1240  return MB_SUCCESS;
1241 }
1242 
1244  int pfrom,
1245  const int* const gdims,
1246  const int* const gperiodic,
1247  const int* const dijk,
1248  int& pto,
1249  int* rdims,
1250  int* facedims,
1251  int* across_bdy )
1252 {
1253  if( gperiodic[0] || gperiodic[1] || gperiodic[2] ) return MB_FAILURE;
1254 
1255  pto = -1;
1256  across_bdy[0] = across_bdy[1] = across_bdy[2] = 0;
1257  int pijk[3], lperiodic[3], ldims[6];
1258  ErrorCode rval = compute_partition_sqijk( np, pfrom, gdims, gperiodic, ldims, lperiodic, pijk );
1259  if( MB_SUCCESS != rval ) return rval;
1260  assert( pijk[0] * pijk[1] * pijk[2] == np );
1261  pto = -1;
1262  bool top[3] = { false, false, false }, bot[3] = { false, false, false };
1263  // nijk: rank in i/j/k direction
1264  int nijk[3] = { pfrom % pijk[0], ( pfrom % ( pijk[0] * pijk[1] ) ) / pijk[0], pfrom / ( pijk[0] * pijk[1] ) };
1265 
1266  for( int i = 0; i < 3; i++ )
1267  {
1268  if( nijk[i] == pijk[i] - 1 ) top[i] = true;
1269  if( !nijk[i] ) bot[i] = true;
1270  if( ( !gperiodic[i] && bot[i] && -1 == dijk[i] ) || // downward && not periodic
1271  ( !gperiodic[i] && top[i] && 1 == dijk[i] ) ) // upward && not periodic
1272  return MB_SUCCESS;
1273  }
1274 
1275  std::copy( ldims, ldims + 6, facedims );
1276  std::copy( ldims, ldims + 6, rdims );
1277  pto = pfrom;
1278  int delijk[3], extra[3];
1279  // nijk_to: rank of pto in i/j/k direction
1280  int nijk_to[3];
1281  for( int i = 0; i < 3; i++ )
1282  {
1283  delijk[i] = ( gdims[i + 3] == gdims[i] ? 0 : ( gdims[i + 3] - gdims[i] ) / pijk[i] );
1284  extra[i] = ( gdims[i + 3] - gdims[i] ) % delijk[i];
1285  nijk_to[i] = ( nijk[i] + dijk[i] + pijk[i] ) % pijk[i];
1286  }
1287  pto = nijk_to[2] * pijk[0] * pijk[1] + nijk_to[1] * pijk[0] + nijk_to[0];
1288  assert( pto >= 0 && pto < np );
1289  for( int i = 0; i < 3; i++ )
1290  {
1291  if( 0 != dijk[i] )
1292  {
1293  if( -1 == dijk[i] )
1294  {
1295  facedims[i + 3] = facedims[i];
1296  if( bot[i] )
1297  {
1298  // going across lower periodic bdy in i
1299  rdims[i + 3] = gdims[i + 3] + 1; // +1 because ldims[4] on remote proc is gdims[4]+1
1300  across_bdy[i] = -1;
1301  }
1302  else
1303  {
1304  rdims[i + 3] = ldims[i];
1305  }
1306  rdims[i] = rdims[i + 3] - delijk[i];
1307  if( nijk[i] < extra[i] ) rdims[i]--;
1308  }
1309  else
1310  {
1311  if( top[i] )
1312  {
1313  // going across upper periodic bdy in i
1314  rdims[i] = gdims[i];
1315  facedims[i + 3] = gdims[i];
1316  across_bdy[i] = 1;
1317  }
1318  else
1319  {
1320  rdims[i] = ldims[i + 3];
1321  }
1322  facedims[i] = facedims[i + 3];
1323  rdims[i + 3] = rdims[i] + delijk[i];
1324  if( nijk[i] < extra[i] ) rdims[i + 3]++;
1325  if( gperiodic[i] && nijk[i] == dijk[i] - 2 ) rdims[i + 3]++; // +1 because next proc is on periodic bdy
1326  }
1327  }
1328  }
1329 
1330  assert( -1 != pto );
1331 #ifndef NDEBUG
1332  for( int i = 0; i < 3; i++ )
1333  {
1334  assert( ( rdims[i] >= gdims[i] && ( rdims[i + 3] <= gdims[i + 3] || ( across_bdy[i] && bot[i] ) ) ) );
1335  assert( ( ( facedims[i] >= rdims[i] ||
1336  ( gperiodic[i] && rdims[i + 3] == gdims[i + 3] && facedims[i] == gdims[i] ) ) ) );
1337  assert( ( facedims[i] >= ldims[i] && facedims[i + 3] <= ldims[i + 3] ) );
1338  }
1339 #endif
1340 
1341  return MB_SUCCESS;
1342 }
1343 
1345  int pfrom,
1346  const int* const gdims,
1347  const int* const gperiodic,
1348  const int* const dijk,
1349  int& pto,
1350  int* rdims,
1351  int* facedims,
1352  int* across_bdy )
1353 {
1354  ErrorCode rval = MB_SUCCESS;
1355  pto = -1;
1356  if( np == 1 ) return MB_SUCCESS;
1357 
1358  int pijk[3], lperiodic[3], ldims[6];
1359  rval = compute_partition_alljorkori( np, pfrom, gdims, gperiodic, ldims, lperiodic, pijk );
1360  if( MB_SUCCESS != rval ) return rval;
1361 
1362  int ind = -1;
1363  across_bdy[0] = across_bdy[1] = across_bdy[2] = 0;
1364 
1365  for( int i = 0; i < 3; i++ )
1366  {
1367  if( pijk[i] > 1 )
1368  {
1369  ind = i;
1370  break;
1371  }
1372  }
1373 
1374  assert( -1 < ind );
1375 
1376  if( !dijk[ind] )
1377  // no neighbor, pto is already -1, return
1378  return MB_SUCCESS;
1379 
1380  bool is_periodic = ( ( gperiodic[0] && ind == 0 ) || ( gperiodic[1] && ind == 1 ) );
1381  if( dijk[( ind + 1 ) % 3] || dijk[( ind + 2 ) % 3] || // stepping in either other two directions
1382  ( !is_periodic && ldims[ind] == gdims[ind] && dijk[ind] == -1 ) || // lower side and going lower
1383  ( !is_periodic && ldims[3 + ind] >= gdims[3 + ind] &&
1384  dijk[ind] == 1 ) ) // not >= because ldims is only > gdims when periodic;
1385  // higher side and going higher
1386  return MB_SUCCESS;
1387 
1388  std::copy( ldims, ldims + 6, facedims );
1389  std::copy( ldims, ldims + 6, rdims );
1390 
1391  int dind = ( gdims[ind + 3] - gdims[ind] ) / np;
1392  int extra = ( gdims[ind + 3] - gdims[ind] ) % np;
1393  if( -1 == dijk[ind] && pfrom )
1394  {
1395  // actual left neighbor
1396  pto = pfrom - 1; // no need for %np, because pfrom > 0
1397  facedims[ind + 3] = facedims[ind];
1398  rdims[ind + 3] = ldims[ind];
1399  rdims[ind] = rdims[ind + 3] - dind - ( pto < extra ? 1 : 0 );
1400  }
1401  else if( 1 == dijk[ind] && pfrom < np - 1 )
1402  {
1403  // actual right neighbor
1404  pto = pfrom + 1;
1405  facedims[ind] = facedims[ind + 3];
1406  rdims[ind] = ldims[ind + 3];
1407  rdims[ind + 3] = rdims[ind] + dind + ( pto < extra ? 1 : 0 );
1408  if( is_periodic && pfrom == np - 2 ) rdims[ind + 3]++; // neighbor is on periodic bdy
1409  }
1410  else if( -1 == dijk[ind] && !pfrom && gperiodic[ind] )
1411  {
1412  // downward across periodic bdy
1413  pto = np - 1;
1414  facedims[ind + 3] = facedims[ind] = gdims[ind]; // by convention, facedims is within gdims, so lower value
1415  rdims[ind + 3] =
1416  gdims[ind + 3] + 1; // by convention, local dims one greater than gdims to indicate global lower value
1417  rdims[ind] = rdims[ind + 3] - dind - 1;
1418  across_bdy[ind] = -1;
1419  }
1420  else if( 1 == dijk[ind] && pfrom == np - 1 && is_periodic )
1421  {
1422  // right across periodic bdy
1423  pto = 0;
1424  facedims[ind + 3] = facedims[ind] = gdims[ind]; // by convention, facedims is within gdims, so lowest value
1425  rdims[ind] = gdims[ind];
1426  rdims[ind + 3] = rdims[ind] + dind + ( pto < extra ? 1 : 0 );
1427  across_bdy[ind] = 1;
1428  }
1429 
1430  assert( -1 == pto || ( rdims[0] >= gdims[0] && ( rdims[3] <= gdims[3] || ( across_bdy[0] && !pfrom ) ) ) );
1431  assert( -1 == pto || ( rdims[1] >= gdims[1] && ( rdims[4] <= gdims[4] || ( across_bdy[1] && !pfrom ) ) ) );
1432  assert( -1 == pto || ( rdims[2] >= gdims[2] && rdims[5] <= gdims[5] ) );
1433  assert( -1 == pto || ( facedims[0] >= rdims[0] && facedims[3] <= rdims[3] ) );
1434  assert( -1 == pto || ( facedims[1] >= rdims[1] && facedims[4] <= rdims[4] ) );
1435  assert( -1 == pto || ( facedims[2] >= rdims[2] && facedims[5] <= rdims[5] ) );
1436  assert( -1 == pto || ( facedims[0] >= ldims[0] && facedims[3] <= ldims[3] ) );
1437  assert( -1 == pto || ( facedims[1] >= ldims[1] && facedims[4] <= ldims[4] ) );
1438  assert( -1 == pto || ( facedims[2] >= ldims[2] && facedims[5] <= ldims[5] ) );
1439 
1440  return rval;
1441 }
1442 
1443 //! get shared vertices for alljorkori partition scheme
1444 #ifndef MOAB_HAVE_MPI
1446  ScdBox*,
1447  std::vector< int >&,
1448  std::vector< int >&,
1449  std::vector< int >& )
1450 {
1451  return MB_FAILURE;
1452 #else
1454  ScdBox* box,
1455  std::vector< int >& procs,
1456  std::vector< int >& offsets,
1457  std::vector< int >& shared_indices )
1458 {
1459  // get index of partitioned dimension
1460  const int* ldims = box->box_dims();
1461  ErrorCode rval;
1462  int ijkrem[6], ijkface[6], across_bdy[3];
1463 
1464  for( int k = -1; k <= 1; k++ )
1465  {
1466  for( int j = -1; j <= 1; j++ )
1467  {
1468  for( int i = -1; i <= 1; i++ )
1469  {
1470  if( !i && !j && !k ) continue;
1471  int pto;
1472  int dijk[] = { i, j, k };
1473  rval = get_neighbor( pcomm->proc_config().proc_size(), pcomm->proc_config().proc_rank(),
1474  box->par_data(), dijk, pto, ijkrem, ijkface, across_bdy );
1475  if( MB_SUCCESS != rval ) return rval;
1476  if( -1 != pto )
1477  {
1478  if( procs.empty() || pto != *procs.rbegin() )
1479  {
1480  procs.push_back( pto );
1481  offsets.push_back( shared_indices.size() );
1482  }
1483  rval = get_indices( ldims, ijkrem, across_bdy, ijkface, shared_indices );
1484  if( MB_SUCCESS != rval ) return rval;
1485 
1486  // check indices against known #verts on local and remote
1487  // begin of this block is shared_indices[*offsets.rbegin()], end is
1488  // shared_indices.end(), halfway is
1489  // (shared_indices.size()-*offsets.rbegin())/2
1490 #ifndef NDEBUG
1491  int start_idx = *offsets.rbegin(), end_idx = shared_indices.size(),
1492  mid_idx = ( start_idx + end_idx ) / 2;
1493 
1494  int num_local_verts = ( ldims[3] - ldims[0] + 1 ) * ( ldims[4] - ldims[1] + 1 ) *
1495  ( -1 == ldims[2] && -1 == ldims[5] ? 1 : ( ldims[5] - ldims[2] + 1 ) ),
1496  num_remote_verts = ( ijkrem[3] - ijkrem[0] + 1 ) * ( ijkrem[4] - ijkrem[1] + 1 ) *
1497  ( -1 == ijkrem[2] && -1 == ijkrem[5] ? 1 : ( ijkrem[5] - ijkrem[2] + 1 ) );
1498 
1499  assert(
1500  *std::min_element( &shared_indices[start_idx], &shared_indices[mid_idx] ) >= 0 &&
1501  *std::max_element( &shared_indices[start_idx], &shared_indices[mid_idx] ) < num_local_verts &&
1502  *std::min_element( &shared_indices[mid_idx], &shared_indices[end_idx] ) >= 0 &&
1503  *std::max_element( &shared_indices[mid_idx], &shared_indices[end_idx] ) < num_remote_verts );
1504 #endif
1505  }
1506  }
1507  }
1508  }
1509 
1510  offsets.push_back( shared_indices.size() );
1511 
1512  return MB_SUCCESS;
1513 #endif
1514 }
1515 
1516 std::ostream& operator<<( std::ostream& str, const ScdParData& pd )
1517 {
1518  str << "Partition method = " << ScdParData::PartitionMethodNames[pd.partMethod] << ", gDims = (" << pd.gDims[0]
1519  << "," << pd.gDims[1] << "," << pd.gDims[2] << ")-(" << pd.gDims[3] << "," << pd.gDims[4] << "," << pd.gDims[5]
1520  << "), gPeriodic = (" << pd.gPeriodic[0] << "," << pd.gPeriodic[1] << "," << pd.gPeriodic[2] << "), pDims = ("
1521  << pd.pDims[0] << "," << pd.pDims[1] << "," << pd.pDims[2] << ")" << std::endl;
1522  return str;
1523 }
1524 
1525 } // namespace moab