Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
TempestRemapper.cpp
Go to the documentation of this file.
1 /*
2  * =====================================================================================
3  *
4  * Filename: TempestRemapper.hpp
5  *
6  * Description: Interface to the TempestRemap library to enable intersection and
7  * high-order conservative remapping of climate solution from
8  * arbitrary resolution of source and target grids on the sphere.
9  *
10  * Author: Vijay S. Mahadevan (vijaysm), [email protected]
11  *
12  * =====================================================================================
13  */
14 
15 #include <string>
16 #include <iostream>
17 #include <cassert>
18 #include <numeric> // std::iota
19 #include <algorithm> // std::sort, std::stable_sort
20 
21 #include "DebugOutput.hpp"
23 #include "moab/ReadUtilIface.hpp"
24 #include "moab/MeshTopoUtil.hpp"
25 #include "AEntityFactory.hpp"
26 
27 // Intersection includes
30 
31 #include "moab/AdaptiveKDTree.hpp"
32 #include "moab/SpatialLocator.hpp"
33 
34 // skinner for augmenting overlap mesh to complete coverage
35 #include "moab/Skinner.hpp"
36 #include "MBParallelConventions.h"
37 
38 #ifdef MOAB_HAVE_TEMPESTREMAP
39 #include "GaussLobattoQuadrature.h"
40 #endif
41 
42 // #define VERBOSE
43 
44 namespace moab
45 {
46 
47 ///////////////////////////////////////////////////////////////////////////////////
48 
49 ErrorCode TempestRemapper::initialize( bool initialize_fsets )
50 {
51  ErrorCode rval;
52  if( initialize_fsets )
53  {
54  rval = m_interface->create_meshset( moab::MESHSET_SET, m_source_set );MB_CHK_SET_ERR( rval, "Can't create new set" );
55  rval = m_interface->create_meshset( moab::MESHSET_SET, m_target_set );MB_CHK_SET_ERR( rval, "Can't create new set" );
56  rval = m_interface->create_meshset( moab::MESHSET_SET, m_overlap_set );MB_CHK_SET_ERR( rval, "Can't create new set" );
57  }
58  else
59  {
60  m_source_set = 0;
61  m_target_set = 0;
62  m_overlap_set = 0;
63  }
64 
65  is_parallel = false;
66  is_root = true;
67  rank = 0;
68  size = 1;
69 #ifdef MOAB_HAVE_MPI
70  int flagInit;
71  MPI_Initialized( &flagInit );
72  if( flagInit )
73  {
74  assert( m_pcomm != nullptr );
75  rank = m_pcomm->rank();
76  size = m_pcomm->size();
77  is_root = ( rank == 0 );
78  is_parallel = ( size > 1 );
79  // is_parallel = true;
80  }
81 #endif
82 
83  m_source = nullptr;
84  m_target = nullptr;
85  m_overlap = nullptr;
86  m_covering_source = nullptr;
87 
88  point_cloud_source = false;
89  point_cloud_target = false;
90 
91  return MB_SUCCESS;
92 }
93 
94 ///////////////////////////////////////////////////////////////////////////////////
95 
97 {
98  this->clear();
99 }
100 
102 {
103  // destroy all meshes
104  if( m_source )
105  {
106  delete m_source;
107  m_source = nullptr;
108  }
109  if( m_target )
110  {
111  delete m_target;
112  m_target = nullptr;
113  }
114  if( m_overlap )
115  {
116  delete m_overlap;
117  m_overlap = nullptr;
118  }
119  if( m_covering_source && size > 1 )
120  {
121  delete m_covering_source;
122  m_covering_source = nullptr;
123  }
124 
125  point_cloud_source = false;
126  point_cloud_target = false;
127 
135  gid_to_lid_src.clear();
136  gid_to_lid_tgt.clear();
137  gid_to_lid_covsrc.clear();
138  lid_to_gid_src.clear();
139  lid_to_gid_tgt.clear();
140  lid_to_gid_covsrc.clear();
141 
142  return MB_SUCCESS;
143 }
144 
145 ///////////////////////////////////////////////////////////////////////////////////
146 
148  std::string inputFilename,
149  TempestMeshType type )
150 {
151  if( ctx == Remapper::SourceMesh )
152  {
153  m_source_type = type;
154  return load_tempest_mesh_private( inputFilename, &m_source );
155  }
156  else if( ctx == Remapper::TargetMesh )
157  {
158  m_target_type = type;
159  return load_tempest_mesh_private( inputFilename, &m_target );
160  }
161  else if( ctx != Remapper::DEFAULT )
162  {
163  m_overlap_type = type;
164  return load_tempest_mesh_private( inputFilename, &m_overlap );
165  }
166  else
167  {
168  MB_CHK_SET_ERR( MB_FAILURE, "Invalid IntersectionContext context provided" );
169  }
170 }
171 
172 ErrorCode TempestRemapper::load_tempest_mesh_private( std::string inputFilename, Mesh** tempest_mesh )
173 {
174  const bool outputEnabled = ( TempestRemapper::verbose && is_root );
175  if( outputEnabled ) std::cout << "\nLoading TempestRemap Mesh object from file = " << inputFilename << " ...\n";
176 
177  {
178  NcError error( NcError::silent_nonfatal );
179 
180  try
181  {
182  // Load input mesh
183  if( outputEnabled ) std::cout << "Loading mesh ...\n";
184  Mesh* mesh = new Mesh( inputFilename );
185  mesh->RemoveZeroEdges();
186  if( outputEnabled ) std::cout << "----------------\n";
187 
188  // Validate mesh
189  if( meshValidate )
190  {
191  if( outputEnabled ) std::cout << "Validating mesh ...\n";
192  mesh->Validate();
193  if( outputEnabled ) std::cout << "-------------------\n";
194  }
195 
196  // Construct the edge map on the mesh
197  if( constructEdgeMap )
198  {
199  if( outputEnabled ) std::cout << "Constructing edge map on mesh ...\n";
200  mesh->ConstructEdgeMap( false );
201  if( outputEnabled ) std::cout << "---------------------------------\n";
202  }
203 
204  if( tempest_mesh ) *tempest_mesh = mesh;
205  }
206  catch( Exception& e )
207  {
208  std::cout << "TempestRemap ERROR: " << e.ToString() << "\n";
209  return MB_FAILURE;
210  }
211  catch( ... )
212  {
213  return MB_FAILURE;
214  }
215  }
216  return MB_SUCCESS;
217 }
218 
219 ///////////////////////////////////////////////////////////////////////////////////
220 
222 {
223  const bool outputEnabled = ( TempestRemapper::verbose && is_root );
224  if( ctx == Remapper::SourceMesh )
225  {
226  if( outputEnabled ) std::cout << "Converting (source) TempestRemap Mesh object to MOAB representation ...\n";
229  }
230  else if( ctx == Remapper::TargetMesh )
231  {
232  if( outputEnabled ) std::cout << "Converting (target) TempestRemap Mesh object to MOAB representation ...\n";
235  }
236  else if( ctx != Remapper::DEFAULT )
237  {
238  if( outputEnabled ) std::cout << "Converting (overlap) TempestRemap Mesh object to MOAB representation ...\n";
240  }
241  else
242  {
243  MB_CHK_SET_ERR( MB_FAILURE, "Invalid IntersectionContext context provided" );
244  }
245 }
246 
247 #define NEW_CONVERT_LOGIC
248 
249 #ifdef NEW_CONVERT_LOGIC
251  Mesh* mesh,
252  EntityHandle& mesh_set,
253  Range& entities,
254  Range* vertices )
255 {
256  ErrorCode rval;
257 
258  const bool outputEnabled = ( TempestRemapper::verbose && is_root );
259  const NodeVector& nodes = mesh->nodes;
260  const FaceVector& faces = mesh->faces;
261 
262  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
263  dbgprint.set_prefix( "[TempestToMOAB]: " );
264 
266  rval = m_interface->query_interface( iface );MB_CHK_SET_ERR( rval, "Can't get reader interface" );
267 
268  Tag gidTag = m_interface->globalId_tag();
269 
270  // Set the data for the vertices
271  std::vector< double* > arrays;
272  std::vector< int > gidsv( nodes.size() );
273  EntityHandle startv;
274  rval = iface->get_node_coords( 3, nodes.size(), 0, startv, arrays );MB_CHK_SET_ERR( rval, "Can't get node coords" );
275  for( unsigned iverts = 0; iverts < nodes.size(); ++iverts )
276  {
277  const Node& node = nodes[iverts];
278  arrays[0][iverts] = node.x;
279  arrays[1][iverts] = node.y;
280  arrays[2][iverts] = node.z;
281  gidsv[iverts] = iverts + 1;
282  }
283  Range mbverts( startv, startv + nodes.size() - 1 );
284  rval = m_interface->add_entities( mesh_set, mbverts );MB_CHK_SET_ERR( rval, "Can't add entities" );
285  rval = m_interface->tag_set_data( gidTag, mbverts, &gidsv[0] );MB_CHK_SET_ERR( rval, "Can't set global_id tag" );
286 
287  gidsv.clear();
288  entities.clear();
289 
290  Tag srcParentTag, tgtParentTag;
291  std::vector< int > srcParent( faces.size(), -1 ), tgtParent( faces.size(), -1 );
292  std::vector< int > gidse( faces.size(), -1 );
293  bool storeParentInfo = ( mesh->vecSourceFaceIx.size() > 0 );
294 
295  if( storeParentInfo )
296  {
297  int defaultInt = -1;
298  rval = m_interface->tag_get_handle( "TargetParent", 1, MB_TYPE_INTEGER, tgtParentTag,
299  MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );MB_CHK_SET_ERR( rval, "can't create positive tag" );
300 
301  rval = m_interface->tag_get_handle( "SourceParent", 1, MB_TYPE_INTEGER, srcParentTag,
302  MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );MB_CHK_SET_ERR( rval, "can't create negative tag" );
303  }
304 
305  // Let us first perform a full pass assuming arbitrary polygons. This is especially true for
306  // overlap meshes.
307  // 1. We do a first pass over faces, decipher edge size and group into categories based on
308  // element type
309  // 2. Next we loop over type, and add blocks of elements into MOAB
310  // 3. For each block within the loop, also update the connectivity of elements.
311  {
312  if( outputEnabled )
313  dbgprint.printf( 0, "..Mesh size: Nodes [%zu] Elements [%zu].\n", nodes.size(), faces.size() );
314  std::vector< EntityHandle > mbcells( faces.size() );
315  unsigned ntris = 0, nquads = 0, npolys = 0;
316  std::vector< EntityHandle > conn( 16 );
317 
318  for( unsigned ifaces = 0; ifaces < faces.size(); ++ifaces )
319  {
320  const Face& face = faces[ifaces];
321  const unsigned num_v_per_elem = face.edges.size();
322 
323  for( unsigned iedges = 0; iedges < num_v_per_elem; ++iedges )
324  {
325  conn[iedges] = startv + face.edges[iedges].node[0];
326  }
327 
328  switch( num_v_per_elem )
329  {
330  case 3:
331  // if( outputEnabled )
332  // dbgprint.printf( 0, "....Block %d: Triangular Elements [%u].\n", iBlock++, nPolys[iType] );
333  rval = m_interface->create_element( MBTRI, &conn[0], num_v_per_elem, mbcells[ifaces] );MB_CHK_SET_ERR( rval, "Can't get element connectivity" );
334  ntris++;
335  break;
336  case 4:
337  // if( outputEnabled )
338  // dbgprint.printf( 0, "....Block %d: Quadrilateral Elements [%u].\n", iBlock++, nPolys[iType] );
339  rval = m_interface->create_element( MBQUAD, &conn[0], num_v_per_elem, mbcells[ifaces] );MB_CHK_SET_ERR( rval, "Can't get element connectivity" );
340  nquads++;
341  break;
342  default:
343  // if( outputEnabled )
344  // dbgprint.printf( 0, "....Block %d: Polygonal [%u] Elements [%u].\n", iBlock++, iType,
345  // nPolys[iType] );
346  rval = m_interface->create_element( MBPOLYGON, &conn[0], num_v_per_elem, mbcells[ifaces] );MB_CHK_SET_ERR( rval, "Can't get element connectivity" );
347  npolys++;
348  break;
349  }
350 
351  gidse[ifaces] = ifaces + 1;
352 
353  if( storeParentInfo )
354  {
355  srcParent[ifaces] = mesh->vecSourceFaceIx[ifaces] + 1;
356  tgtParent[ifaces] = mesh->vecTargetFaceIx[ifaces] + 1;
357  }
358  }
359 
360  if( ntris ) dbgprint.printf( 0, "....Triangular Elements [%u].\n", ntris );
361  if( nquads ) dbgprint.printf( 0, "....Quadrangular Elements [%u].\n", nquads );
362  if( npolys ) dbgprint.printf( 0, "....Polygonal Elements [%u].\n", npolys );
363 
364  rval = m_interface->add_entities( mesh_set, &mbcells[0], mbcells.size() );MB_CHK_SET_ERR( rval, "Could not add entities" );
365 
366  rval = m_interface->tag_set_data( gidTag, &mbcells[0], mbcells.size(), &gidse[0] );MB_CHK_SET_ERR( rval, "Can't set global_id tag" );
367  if( storeParentInfo )
368  {
369  rval = m_interface->tag_set_data( srcParentTag, &mbcells[0], mbcells.size(), &srcParent[0] );MB_CHK_SET_ERR( rval, "Can't set tag data" );
370  rval = m_interface->tag_set_data( tgtParentTag, &mbcells[0], mbcells.size(), &tgtParent[0] );MB_CHK_SET_ERR( rval, "Can't set tag data" );
371  }
372 
373  // insert from mbcells to entities to preserve ordering
374  std::copy( mbcells.begin(), mbcells.end(), range_inserter( entities ) );
375  }
376 
377  if( vertices ) *vertices = mbverts;
378 
379  return MB_SUCCESS;
380 }
381 
382 #else
384  Mesh* mesh,
385  EntityHandle& mesh_set,
386  Range& entities,
387  Range* vertices )
388 {
389  ErrorCode rval;
390 
391  const bool outputEnabled = ( TempestRemapper::verbose && is_root );
392  const NodeVector& nodes = mesh->nodes;
393  const FaceVector& faces = mesh->faces;
394 
395  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
396  dbgprint.set_prefix( "[TempestToMOAB]: " );
397 
399  rval = m_interface->query_interface( iface );MB_CHK_SET_ERR( rval, "Can't get reader interface" );
400 
401  Tag gidTag = m_interface->globalId_tag();
402 
403  // Set the data for the vertices
404  std::vector< double* > arrays;
405  std::vector< int > gidsv( nodes.size() );
406  EntityHandle startv;
407  rval = iface->get_node_coords( 3, nodes.size(), 0, startv, arrays );MB_CHK_SET_ERR( rval, "Can't get node coords" );
408  for( unsigned iverts = 0; iverts < nodes.size(); ++iverts )
409  {
410  const Node& node = nodes[iverts];
411  arrays[0][iverts] = node.x;
412  arrays[1][iverts] = node.y;
413  arrays[2][iverts] = node.z;
414  gidsv[iverts] = iverts + 1;
415  }
416  Range mbverts( startv, startv + nodes.size() - 1 );
417  rval = m_interface->add_entities( mesh_set, mbverts );MB_CHK_SET_ERR( rval, "Can't add entities" );
418  rval = m_interface->tag_set_data( gidTag, mbverts, &gidsv[0] );MB_CHK_SET_ERR( rval, "Can't set global_id tag" );
419 
420  gidsv.clear();
421  entities.clear();
422 
423  Tag srcParentTag, tgtParentTag;
424  std::vector< int > srcParent, tgtParent;
425  bool storeParentInfo = ( mesh->vecSourceFaceIx.size() > 0 );
426 
427  if( storeParentInfo )
428  {
429  int defaultInt = -1;
430  rval = m_interface->tag_get_handle( "TargetParent", 1, MB_TYPE_INTEGER, tgtParentTag,
431  MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );MB_CHK_SET_ERR( rval, "can't create positive tag" );
432 
433  rval = m_interface->tag_get_handle( "SourceParent", 1, MB_TYPE_INTEGER, srcParentTag,
434  MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );MB_CHK_SET_ERR( rval, "can't create negative tag" );
435  }
436 
437  // Let us first perform a full pass assuming arbitrary polygons. This is especially true for
438  // overlap meshes.
439  // 1. We do a first pass over faces, decipher edge size and group into categories based on
440  // element type
441  // 2. Next we loop over type, and add blocks of elements into MOAB
442  // 3. For each block within the loop, also update the connectivity of elements.
443  {
444  if( outputEnabled )
445  dbgprint.printf( 0, "..Mesh size: Nodes [%zu] Elements [%zu].\n", nodes.size(), faces.size() );
446  const int NMAXPOLYEDGES = 15;
447  std::vector< unsigned > nPolys( NMAXPOLYEDGES, 0 );
448  std::vector< std::vector< int > > typeNSeqs( NMAXPOLYEDGES );
449  for( unsigned ifaces = 0; ifaces < faces.size(); ++ifaces )
450  {
451  const int iType = faces[ifaces].edges.size();
452  nPolys[iType]++;
453  typeNSeqs[iType].push_back( ifaces );
454  }
455  int iBlock = 0;
456  for( unsigned iType = 0; iType < NMAXPOLYEDGES; ++iType )
457  {
458  if( !nPolys[iType] ) continue; // Nothing to do
459 
460  const unsigned num_v_per_elem = iType;
461  EntityHandle starte; // Connectivity
462  EntityHandle* conn;
463 
464  // Allocate the connectivity array, depending on the element type
465  switch( num_v_per_elem )
466  {
467  case 3:
468  if( outputEnabled )
469  dbgprint.printf( 0, "....Block %d: Triangular Elements [%u].\n", iBlock++, nPolys[iType] );
470  rval = iface->get_element_connect( nPolys[iType], num_v_per_elem, MBTRI, 0, starte, conn );MB_CHK_SET_ERR( rval, "Can't get element connectivity" );
471  break;
472  case 4:
473  if( outputEnabled )
474  dbgprint.printf( 0, "....Block %d: Quadrilateral Elements [%u].\n", iBlock++, nPolys[iType] );
475  rval = iface->get_element_connect( nPolys[iType], num_v_per_elem, MBQUAD, 0, starte, conn );MB_CHK_SET_ERR( rval, "Can't get element connectivity" );
476  break;
477  default:
478  if( outputEnabled )
479  dbgprint.printf( 0, "....Block %d: Polygonal [%u] Elements [%u].\n", iBlock++, iType,
480  nPolys[iType] );
481  rval = iface->get_element_connect( nPolys[iType], num_v_per_elem, MBPOLYGON, 0, starte, conn );MB_CHK_SET_ERR( rval, "Can't get element connectivity" );
482  break;
483  }
484 
485  Range mbcells( starte, starte + nPolys[iType] - 1 );
486  m_interface->add_entities( mesh_set, mbcells );
487 
488  if( storeParentInfo )
489  {
490  srcParent.resize( mbcells.size(), -1 );
491  tgtParent.resize( mbcells.size(), -1 );
492  }
493 
494  std::vector< int > gids( typeNSeqs[iType].size() );
495  for( unsigned ifaces = 0, offset = 0; ifaces < typeNSeqs[iType].size(); ++ifaces )
496  {
497  const int fIndex = typeNSeqs[iType][ifaces];
498  const Face& face = faces[fIndex];
499  // conn[offset++] = startv + face.edges[0].node[0];
500  for( unsigned iedges = 0; iedges < face.edges.size(); ++iedges )
501  {
502  conn[offset++] = startv + face.edges[iedges].node[0];
503  }
504 
505  if( storeParentInfo )
506  {
507  srcParent[ifaces] = mesh->vecSourceFaceIx[fIndex] + 1;
508  tgtParent[ifaces] = mesh->vecTargetFaceIx[fIndex] + 1;
509  }
510 
511  gids[ifaces] = typeNSeqs[iType][ifaces] + 1;
512  }
513  rval = m_interface->tag_set_data( gidTag, mbcells, &gids[0] );MB_CHK_SET_ERR( rval, "Can't set global_id tag" );
514 
515  if( meshType == OVERLAP_FILES )
516  {
517  // Now let us update the adjacency data, because some elements are new
518  rval = iface->update_adjacencies( starte, nPolys[iType], num_v_per_elem, conn );MB_CHK_SET_ERR( rval, "Can't update adjacencies" );
519  // Generate all adj entities dimension 1 and 2 (edges and faces/ tri or qua)
520  Range edges;
521  rval = m_interface->get_adjacencies( mbcells, 1, true, edges, Interface::UNION );MB_CHK_SET_ERR( rval, "Can't get edges" );
522  }
523 
524  if( storeParentInfo )
525  {
526  rval = m_interface->tag_set_data( srcParentTag, mbcells, &srcParent[0] );MB_CHK_SET_ERR( rval, "Can't set tag data" );
527  rval = m_interface->tag_set_data( tgtParentTag, mbcells, &tgtParent[0] );MB_CHK_SET_ERR( rval, "Can't set tag data" );
528  }
529  entities.merge( mbcells );
530  }
531  }
532 
533  if( vertices ) *vertices = mbverts;
534 
535  return MB_SUCCESS;
536 }
537 #endif
538 
539 ///////////////////////////////////////////////////////////////////////////////////
540 
542 {
543  ErrorCode rval;
544  const bool outputEnabled = ( TempestRemapper::verbose && is_root );
545 
546  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
547  dbgprint.set_prefix( "[MOABToTempest]: " );
548 
549  if( ctx == Remapper::SourceMesh )
550  {
551  if( !m_source ) m_source = new Mesh();
552  if( outputEnabled ) dbgprint.printf( 0, "Converting (source) MOAB to TempestRemap Mesh representation ...\n" );
553  rval = convert_mesh_to_tempest_private( m_source, m_source_set, m_source_entities, &m_source_vertices );MB_CHK_SET_ERR( rval, "Can't convert source mesh to Tempest" );
554  if( m_source_entities.size() == 0 && m_source_vertices.size() != 0 )
555  {
556  this->point_cloud_source = true;
557  }
558  }
559  else if( ctx == Remapper::TargetMesh )
560  {
561  if( !m_target ) m_target = new Mesh();
562  if( outputEnabled ) dbgprint.printf( 0, "Converting (target) MOAB to TempestRemap Mesh representation ...\n" );
563  rval = convert_mesh_to_tempest_private( m_target, m_target_set, m_target_entities, &m_target_vertices );MB_CHK_SET_ERR( rval, "Can't convert target mesh to Tempest" );
564  if( m_target_entities.size() == 0 && m_target_vertices.size() != 0 ) this->point_cloud_target = true;
565  }
566  else if( ctx == Remapper::OverlapMesh ) // Overlap mesh
567  {
568  if( !m_overlap ) m_overlap = new Mesh();
569  if( outputEnabled ) dbgprint.printf( 0, "Converting (overlap) MOAB to TempestRemap Mesh representation ...\n" );
570  rval = convert_overlap_mesh_sorted_by_source();MB_CHK_SET_ERR( rval, "Can't convert overlap mesh to Tempest" );
571  }
572  else
573  {
574  MB_CHK_SET_ERR( MB_FAILURE, "Invalid IntersectionContext context provided" );
575  }
576 
577  return rval;
578 }
579 
581  EntityHandle mesh_set,
582  moab::Range& elems,
583  moab::Range* pverts )
584 {
585  ErrorCode rval;
586  Range verts;
587 
588  NodeVector& nodes = mesh->nodes;
589  FaceVector& faces = mesh->faces;
590 
591  elems.clear();
592  rval = m_interface->get_entities_by_dimension( mesh_set, 2, elems );MB_CHK_ERR( rval );
593 
594  const size_t nelems = elems.size();
595 
596  // resize the number of elements in Tempest mesh
597  faces.resize( nelems );
598 
599  // let us now get the vertices from all the elements
600  rval = m_interface->get_connectivity( elems, verts );MB_CHK_ERR( rval );
601  if( verts.size() == 0 )
602  {
603  rval = m_interface->get_entities_by_dimension( mesh_set, 0, verts );MB_CHK_ERR( rval );
604  }
605  // assert(verts.size() > 0); // If not, this may be an invalid mesh ! possible for unbalanced loads
606 
607  std::map< EntityHandle, int > indxMap;
608  bool useRange = true;
609  if( verts.compactness() > 0.01 )
610  {
611  int j = 0;
612  for( Range::iterator it = verts.begin(); it != verts.end(); it++ )
613  indxMap[*it] = j++;
614  useRange = false;
615  }
616 
617  std::vector< int > globIds( nelems );
618 
620  rval = m_interface->tag_get_data( gid, elems, &globIds[0] );MB_CHK_ERR( rval );
621  // initialize original index locations
622  std::vector< size_t > sortedIdx( nelems );
623  std::iota( sortedIdx.begin(), sortedIdx.end(), 0 );
624  // sort indexes based on comparing values in v, using std::stable_sort instead of std::sort
625  // to avoid unnecessary index re-orderings when v contains elements of equal values
626  std::sort( sortedIdx.begin(), sortedIdx.end(),
627  [&globIds]( size_t i1, size_t i2 ) { return globIds[i1] < globIds[i2]; } );
628 
629  for( unsigned iface = 0; iface < nelems; ++iface )
630  {
631  Face& face = faces[iface];
632  EntityHandle ehandle = ( offlineWorkflow ? elems[sortedIdx[iface]] : elems[iface] );
633 
634  // get the connectivity for each edge
635  const EntityHandle* connectface;
636  int nnodesf;
637  rval = m_interface->get_connectivity( ehandle, connectface, nnodesf );MB_CHK_ERR( rval );
638  // account for padded polygons
639  while( connectface[nnodesf - 2] == connectface[nnodesf - 1] && nnodesf > 3 )
640  nnodesf--;
641 
642  face.edges.resize( nnodesf );
643  for( int iverts = 0; iverts < nnodesf; ++iverts )
644  {
645  int indx = ( useRange ? verts.index( connectface[iverts] ) : indxMap[connectface[iverts]] );
646  assert( indx >= 0 );
647  face.SetNode( iverts, indx );
648  }
649  }
650 
651  unsigned nnodes = verts.size();
652  nodes.resize( nnodes );
653 
654  // Set the data for the vertices
655  std::vector< double > coordx( nnodes ), coordy( nnodes ), coordz( nnodes );
656  rval = m_interface->get_coords( verts, &coordx[0], &coordy[0], &coordz[0] );MB_CHK_ERR( rval );
657  for( unsigned inode = 0; inode < nnodes; ++inode )
658  {
659  Node& node = nodes[inode];
660  node.x = coordx[inode];
661  node.y = coordy[inode];
662  node.z = coordz[inode];
663  }
664  coordx.clear();
665  coordy.clear();
666  coordz.clear();
667 
668  mesh->RemoveZeroEdges();
669  mesh->RemoveCoincidentNodes();
670 
671  // Generate reverse node array and edge map
672  if( constructEdgeMap ) mesh->ConstructEdgeMap( false );
673  // mesh->ConstructReverseNodeArray();
674 
675  // mesh->Validate();
676 
677  if( pverts )
678  {
679  pverts->clear();
680  *pverts = verts;
681  }
682  verts.clear();
683 
684  return MB_SUCCESS;
685 }
686 
687 ///////////////////////////////////////////////////////////////////////////////////
688 
689 bool IntPairComparator( const std::pair< int, int >& a, const std::pair< int, int >& b )
690 {
691  if( a.first == b.first )
692  return a.second < b.second;
693  else
694  return a.first < b.first;
695 }
696 
698 {
699  sharedGhostEntities.clear();
700 #ifdef MOAB_HAVE_MPI
701  moab::ErrorCode rval;
702 
703  // Remove entities in the intersection mesh that are part of the ghosted overlap
704  if( is_parallel && size > 1 )
705  {
706  moab::Range allents;
707  rval = m_interface->get_entities_by_dimension( m_overlap_set, 2, allents );MB_CHK_SET_ERR( rval, "Getting entities dim 2 failed" );
708 
709  moab::Range sharedents;
710  moab::Tag ghostTag;
711  std::vector< int > ghFlags( allents.size() );
712  rval = m_interface->tag_get_handle( "ORIG_PROC", ghostTag );MB_CHK_ERR( rval );
713  rval = m_interface->tag_get_data( ghostTag, allents, &ghFlags[0] );MB_CHK_ERR( rval );
714  for( unsigned i = 0; i < allents.size(); ++i )
715  if( ghFlags[i] >= 0 ) // it means it is a ghost overlap element
716  sharedents.insert( allents[i] ); // this should not participate in smat!
717 
718  allents = subtract( allents, sharedents );
719 
720  // Get connectivity from all ghosted elements and filter out
721  // the vertices that are not owned
722  moab::Range ownedverts, sharedverts;
723  rval = m_interface->get_connectivity( allents, ownedverts );MB_CHK_SET_ERR( rval, "Deleting entities dim 0 failed" );
724  rval = m_interface->get_connectivity( sharedents, sharedverts );MB_CHK_SET_ERR( rval, "Deleting entities dim 0 failed" );
725  sharedverts = subtract( sharedverts, ownedverts );
726  // rval = m_interface->remove_entities(m_overlap_set, sharedents);MB_CHK_SET_ERR(rval,
727  // "Deleting entities dim 2 failed"); rval = m_interface->remove_entities(m_overlap_set,
728  // sharedverts);MB_CHK_SET_ERR(rval, "Deleting entities dim 0 failed");
729 
730  sharedGhostEntities.merge( sharedents );
731  // sharedGhostEntities.merge(sharedverts);
732  }
733 #endif
734  return moab::MB_SUCCESS;
735 }
736 
738 {
739  ErrorCode rval;
740 
743 
744  // Allocate for the overlap mesh
745  if( !m_overlap ) m_overlap = new Mesh();
746 
747  size_t n_overlap_entitites = m_overlap_entities.size();
748 
749  std::vector< std::pair< int, int > > sorted_overlap_order( n_overlap_entitites );
750  {
751  Tag srcParentTag, tgtParentTag;
752  rval = m_interface->tag_get_handle( "SourceParent", srcParentTag );MB_CHK_ERR( rval );
753  rval = m_interface->tag_get_handle( "TargetParent", tgtParentTag );MB_CHK_ERR( rval );
754  // Overlap mesh: resize the source and target connection arrays
755  m_overlap->vecTargetFaceIx.resize( n_overlap_entitites );
756  m_overlap->vecSourceFaceIx.resize( n_overlap_entitites );
757 
758  // Overlap mesh: resize the source and target connection arrays
759  std::vector< int > rbids_src( n_overlap_entitites ), rbids_tgt( n_overlap_entitites );
760  rval = m_interface->tag_get_data( srcParentTag, m_overlap_entities, &rbids_src[0] );MB_CHK_ERR( rval );
761  rval = m_interface->tag_get_data( tgtParentTag, m_overlap_entities, &rbids_tgt[0] );MB_CHK_ERR( rval );
762  for( size_t ix = 0; ix < n_overlap_entitites; ++ix )
763  {
764  sorted_overlap_order[ix].first =
765  ( gid_to_lid_covsrc.size() ? gid_to_lid_covsrc[rbids_src[ix]] : rbids_src[ix] );
766  sorted_overlap_order[ix].second = ix;
767  }
768  std::sort( sorted_overlap_order.begin(), sorted_overlap_order.end(), IntPairComparator );
769  // sorted_overlap_order[ie].second , ie=0,nOverlap-1 is the order such that overlap elems
770  // are ordered by source parent
771 
772  std::vector< int > ghFlags;
773  if( is_parallel && size > 1 )
774  {
775  Tag ghostTag;
776  ghFlags.resize( n_overlap_entitites );
777  rval = m_interface->tag_get_handle( "ORIG_PROC", ghostTag );MB_CHK_ERR( rval );
778  rval = m_interface->tag_get_data( ghostTag, m_overlap_entities, &ghFlags[0] );MB_CHK_ERR( rval );
779  }
780  for( unsigned ie = 0; ie < n_overlap_entitites; ++ie )
781  {
782  int ix = sorted_overlap_order[ie].second; // original index of the element
783  m_overlap->vecSourceFaceIx[ie] =
784  ( gid_to_lid_covsrc.size() ? gid_to_lid_covsrc[rbids_src[ix]] : rbids_src[ix] - 1 );
785  if( is_parallel && size > 1 && ghFlags[ix] >= 0 ) // it means it is a ghost overlap element
786  m_overlap->vecTargetFaceIx[ie] = -1; // this should not participate in smat!
787  else
788  m_overlap->vecTargetFaceIx[ie] =
789  ( gid_to_lid_tgt.size() ? gid_to_lid_tgt[rbids_tgt[ix]] : rbids_tgt[ix] - 1 );
790  }
791  }
792 
793  FaceVector& faces = m_overlap->faces;
794  faces.resize( n_overlap_entitites );
795 
796  Range verts;
797  // let us now get the vertices from all the elements
798  rval = m_interface->get_connectivity( m_overlap_entities, verts );MB_CHK_ERR( rval );
799  // std::cout << "Vertices size = " << verts.size() << " , psize = " << verts.psize() << ",
800  // compactness = " << verts.compactness() << std::endl;
801 
802  std::map< EntityHandle, int > indxMap;
803  bool useRange = true;
804  if( verts.compactness() > 0.01 )
805  {
806  int j = 0;
807  for( Range::iterator it = verts.begin(); it != verts.end(); ++it )
808  indxMap[*it] = j++;
809  useRange = false;
810  }
811 
812  for( unsigned ifac = 0; ifac < m_overlap_entities.size(); ++ifac )
813  {
814  const unsigned iface = sorted_overlap_order[ifac].second;
815  Face& face = faces[ifac];
817 
818  // get the connectivity for each edge
819  const EntityHandle* connectface;
820  int nnodesf;
821  rval = m_interface->get_connectivity( ehandle, connectface, nnodesf );MB_CHK_ERR( rval );
822 
823  face.edges.resize( nnodesf );
824  for( int iverts = 0; iverts < nnodesf; ++iverts )
825  {
826  int indx = ( useRange ? verts.index( connectface[iverts] ) : indxMap[connectface[iverts]] );
827  assert( indx >= 0 );
828  face.SetNode( iverts, indx );
829  }
830  }
831 
832  unsigned nnodes = verts.size();
833  NodeVector& nodes = m_overlap->nodes;
834  nodes.resize( nnodes );
835 
836  // Set the data for the vertices
837  std::vector< double > coordx( nnodes ), coordy( nnodes ), coordz( nnodes );
838  rval = m_interface->get_coords( verts, &coordx[0], &coordy[0], &coordz[0] );MB_CHK_ERR( rval );
839  for( unsigned inode = 0; inode < nnodes; ++inode )
840  {
841  Node& node = nodes[inode];
842  node.x = coordx[inode];
843  node.y = coordy[inode];
844  node.z = coordz[inode];
845  }
846  coordx.clear();
847  coordy.clear();
848  coordz.clear();
849  verts.clear();
850 
851  m_overlap->RemoveZeroEdges();
852  m_overlap->RemoveCoincidentNodes( false );
853 
854  // Generate reverse node array and edge map
855  // if ( constructEdgeMap ) m_overlap->ConstructEdgeMap(false);
856  // m_overlap->ConstructReverseNodeArray();
857 
858  // m_overlap->Validate();
859  return MB_SUCCESS;
860 }
861 
862 // Should be ordered as Source, Target, Overlap
864 {
865  ErrorCode rval;
866 
867  if( 0 == m_covering_source )
868  {
869  m_covering_source = new Mesh();
871  &m_covering_source_vertices );MB_CHK_SET_ERR( rval, "Can't convert source Tempest mesh" );
872 
873  // std::cout << "ComputeGlobalLocalMaps: " << rank << ", "
874  // << " covering entities = [" << m_covering_source_vertices.size() << ", "
875  // << m_covering_source_entities.size() << "]\n";
876  }
877 #ifdef VERBOSE
878  m_covering_source->Write( std::string( "coverage_TR_p" + std::to_string( rank ) + ".g" ) );
879  m_target->Write( std::string( "target_TR_p" + std::to_string( rank ) + ".g" ) );
880 #endif
881  gid_to_lid_src.clear();
882  lid_to_gid_src.clear();
883  gid_to_lid_covsrc.clear();
884  lid_to_gid_covsrc.clear();
885  gid_to_lid_tgt.clear();
886  lid_to_gid_tgt.clear();
887  {
888  Tag gidtag = m_interface->globalId_tag();
889 
890  std::vector< int > gids;
891  if( point_cloud_source )
892  {
893  gids.resize( m_covering_source_vertices.size(), -1 );
894  rval = m_interface->tag_get_data( gidtag, m_covering_source_vertices, &gids[0] );MB_CHK_ERR( rval );
895  }
896  else
897  {
898  gids.resize( m_covering_source_entities.size(), -1 );
899  rval = m_interface->tag_get_data( gidtag, m_covering_source_entities, &gids[0] );MB_CHK_ERR( rval );
900  }
901  for( unsigned ie = 0; ie < gids.size(); ++ie )
902  {
903  gid_to_lid_covsrc[gids[ie]] = ie;
904  lid_to_gid_covsrc[ie] = gids[ie];
905  }
906 
907  if( point_cloud_source )
908  {
909  gids.resize( m_source_vertices.size(), -1 );
910  rval = m_interface->tag_get_data( gidtag, m_source_vertices, &gids[0] );MB_CHK_ERR( rval );
911  }
912  else
913  {
914  gids.resize( m_source_entities.size(), -1 );
915  rval = m_interface->tag_get_data( gidtag, m_source_entities, &gids[0] );MB_CHK_ERR( rval );
916  }
917  for( unsigned ie = 0; ie < gids.size(); ++ie )
918  {
919  gid_to_lid_src[gids[ie]] = ie;
920  lid_to_gid_src[ie] = gids[ie];
921  }
922 
923  if( point_cloud_target )
924  {
925  gids.resize( m_target_vertices.size(), -1 );
926  rval = m_interface->tag_get_data( gidtag, m_target_vertices, &gids[0] );MB_CHK_ERR( rval );
927  }
928  else
929  {
930  gids.resize( m_target_entities.size(), -1 );
931  rval = m_interface->tag_get_data( gidtag, m_target_entities, &gids[0] );MB_CHK_ERR( rval );
932  }
933  for( unsigned ie = 0; ie < gids.size(); ++ie )
934  {
935  gid_to_lid_tgt[gids[ie]] = ie;
936  lid_to_gid_tgt[ie] = gids[ie];
937  }
938  }
939 
940  return MB_SUCCESS;
941 }
942 
943 ///////////////////////////////////////////////////////////////////////////////////
944 
946  const bool fAllParallel,
947  const bool fInputConcave,
948  const bool fOutputConcave )
949 {
950  // Let us alos write out the TempestRemap equivalent so that we can do some verification checks
951  if( fAllParallel )
952  {
953  if( is_root && size == 1 )
954  {
955  this->m_source->CalculateFaceAreas( fInputConcave );
956  this->m_target->CalculateFaceAreas( fOutputConcave );
957  this->m_overlap->Write( strOutputFileName.c_str(), NcFile::Netcdf4 );
958  }
959  else
960  {
961  // Perform reduction and write from root processor
962  // if ( is_root )
963  // std::cout << "--- PARALLEL IMPLEMENTATION is NOT AVAILABLE yet ---\n";
964 
965  this->m_source->CalculateFaceAreas( fInputConcave );
966  this->m_covering_source->CalculateFaceAreas( fInputConcave );
967  this->m_target->CalculateFaceAreas( fOutputConcave );
968  this->m_overlap->Write( strOutputFileName.c_str(), NcFile::Netcdf4 );
969  }
970  }
971  else
972  {
973  this->m_source->CalculateFaceAreas( fInputConcave );
974  this->m_target->CalculateFaceAreas( fOutputConcave );
975  this->m_overlap->Write( strOutputFileName.c_str(), NcFile::Netcdf4 );
976  }
977 
978  return moab::MB_SUCCESS;
979 }
980 void TempestRemapper::SetMeshSet( Remapper::IntersectionContext ctx /* Remapper::CoveringMesh*/,
981  moab::EntityHandle mset,
983 {
984 
985  if( ctx == Remapper::SourceMesh ) // should not be used
986  {
988  m_source_set = mset;
989  }
990  else if( ctx == Remapper::TargetMesh )
991  {
993  m_target_set = mset;
994  }
995  else if( ctx == Remapper::CoveringMesh )
996  {
998  m_covering_source_set = mset;
999  }
1000  else
1001  {
1002  // some error
1003  }
1004  return;
1005 }
1006 ///////////////////////////////////////////////////////////////////////////////////
1007 
1008 #ifndef MOAB_HAVE_MPI
1010  EntityHandle this_set,
1011  const int dimension,
1012  const int start_id )
1013 {
1014  assert( idtag );
1015 
1016  ErrorCode rval;
1017  Range entities;
1018  rval = m_interface->get_entities_by_dimension( this_set, dimension, entities );MB_CHK_SET_ERR( rval, "Failed to get entities" );
1019 
1020  if( entities.size() == 0 ) return moab::MB_SUCCESS;
1021 
1022  int idoffset = start_id;
1023  std::vector< int > gid( entities.size() );
1024  for( unsigned i = 0; i < entities.size(); ++i )
1025  gid[i] = idoffset++;
1026 
1027  rval = m_interface->tag_set_data( idtag, entities, &gid[0] );MB_CHK_ERR( rval );
1028 
1029  return moab::MB_SUCCESS;
1030 }
1031 #endif
1032 
1033 ///////////////////////////////////////////////////////////////////////////////
1034 
1035 // Create a custom comparator for Nodes
1036 bool operator<( Node const& lhs, Node const& rhs )
1037 {
1038  return std::pow( lhs.x - rhs.x, 2.0 ) + std::pow( lhs.y - rhs.y, 2.0 ) + std::pow( lhs.z - rhs.z, 2.0 );
1039 }
1040 
1042  moab::Range& ents,
1043  moab::Range* secondary_ents,
1044  const std::string& dofTagName,
1045  int nP )
1046 {
1047  Mesh csMesh;
1048  int err;
1049  moab::ErrorCode rval;
1050 
1051  const int res = std::sqrt( ntot_elements / 6 );
1052 
1053  // create a temporary CS mesh
1054  // NOTE: This will not work for RRM grids. Need to run HOMME for that case anyway
1055  err = GenerateCSMesh( csMesh, res, "", "NetCDF4" );
1056  if( err )
1057  {
1058  MB_CHK_SET_ERR( MB_FAILURE, "Failed to generate CS mesh through TempestRemap" );
1059  ;
1060  }
1061 
1062  rval = this->GenerateMeshMetadata( csMesh, ntot_elements, ents, secondary_ents, dofTagName, nP );MB_CHK_SET_ERR( rval, "Failed in call to GenerateMeshMetadata" );
1063 
1064  return moab::MB_SUCCESS;
1065 }
1066 
1068  const int ntot_elements,
1069  moab::Range& ents,
1070  moab::Range* secondary_ents,
1071  const std::string dofTagName,
1072  int nP )
1073 {
1074  moab::ErrorCode rval;
1075 
1076  Tag dofTag;
1077  bool created = false;
1078  rval = m_interface->tag_get_handle( dofTagName.c_str(), nP * nP, MB_TYPE_INTEGER, dofTag,
1079  MB_TAG_DENSE | MB_TAG_CREAT, 0, &created );MB_CHK_SET_ERR( rval, "Failed creating DoF tag" );
1080 
1081  // Number of Faces
1082  int nElements = static_cast< int >( csMesh.faces.size() );
1083 
1084  if( nElements != ntot_elements ) return MB_INVALID_SIZE;
1085 
1086  // Initialize data structures
1087  DataArray3D< int > dataGLLnodes;
1088  dataGLLnodes.Allocate( nP, nP, nElements );
1089 
1090  std::map< Node, int > mapNodes;
1091  std::map< Node, moab::EntityHandle > mapLocalMBNodes;
1092 
1093  // GLL Quadrature nodes
1094  DataArray1D< double > dG;
1095  DataArray1D< double > dW;
1096  GaussLobattoQuadrature::GetPoints( nP, 0.0, 1.0, dG, dW );
1097 
1098  moab::Range entities( ents );
1099  if( secondary_ents ) entities.insert( secondary_ents->begin(), secondary_ents->end() );
1100  double elcoords[3];
1101  for( unsigned iel = 0; iel < entities.size(); ++iel )
1102  {
1103  EntityHandle eh = entities[iel];
1104  rval = m_interface->get_coords( &eh, 1, elcoords );
1105  Node elCentroid( elcoords[0], elcoords[1], elcoords[2] );
1106  mapLocalMBNodes.insert( std::pair< Node, moab::EntityHandle >( elCentroid, eh ) );
1107  }
1108 
1109  // Build a Kd-tree for local mesh (nearest neighbor searches)
1110  // Loop over all elements in CS-Mesh
1111  // Then find if current centroid is in an element
1112  // If yes - then let us compute the DoF numbering and set to tag data
1113  // If no - then compute DoF numbering BUT DO NOT SET to tag data
1114  // continue
1115  int* dofIDs = new int[nP * nP];
1116 
1117  // Write metadata
1118  for( int k = 0; k < nElements; k++ )
1119  {
1120  const Face& face = csMesh.faces[k];
1121  const NodeVector& nodes = csMesh.nodes;
1122 
1123  if( face.edges.size() != 4 )
1124  {
1125  _EXCEPTIONT( "Mesh must only contain quadrilateral elements" );
1126  }
1127 
1128  Node centroid;
1129  centroid.x = centroid.y = centroid.z = 0.0;
1130  for( unsigned l = 0; l < face.edges.size(); ++l )
1131  {
1132  centroid.x += nodes[face[l]].x;
1133  centroid.y += nodes[face[l]].y;
1134  centroid.z += nodes[face[l]].z;
1135  }
1136  const double factor = 1.0 / face.edges.size();
1137  centroid.x *= factor;
1138  centroid.y *= factor;
1139  centroid.z *= factor;
1140 
1141  bool locElem = false;
1142  EntityHandle current_eh;
1143  if( mapLocalMBNodes.find( centroid ) != mapLocalMBNodes.end() )
1144  {
1145  locElem = true;
1146  current_eh = mapLocalMBNodes[centroid];
1147  }
1148 
1149  for( int j = 0; j < nP; j++ )
1150  {
1151  for( int i = 0; i < nP; i++ )
1152  {
1153  // Get local map vectors
1154  Node nodeGLL;
1155  Node dDx1G;
1156  Node dDx2G;
1157 
1158  // ApplyLocalMap(
1159  // face,
1160  // nodevec,
1161  // dG[i],
1162  // dG[j],
1163  // nodeGLL,
1164  // dDx1G,
1165  // dDx2G);
1166  const double& dAlpha = dG[i];
1167  const double& dBeta = dG[j];
1168 
1169  // Calculate nodal locations on the plane
1170  double dXc = nodes[face[0]].x * ( 1.0 - dAlpha ) * ( 1.0 - dBeta ) +
1171  nodes[face[1]].x * dAlpha * ( 1.0 - dBeta ) + nodes[face[2]].x * dAlpha * dBeta +
1172  nodes[face[3]].x * ( 1.0 - dAlpha ) * dBeta;
1173 
1174  double dYc = nodes[face[0]].y * ( 1.0 - dAlpha ) * ( 1.0 - dBeta ) +
1175  nodes[face[1]].y * dAlpha * ( 1.0 - dBeta ) + nodes[face[2]].y * dAlpha * dBeta +
1176  nodes[face[3]].y * ( 1.0 - dAlpha ) * dBeta;
1177 
1178  double dZc = nodes[face[0]].z * ( 1.0 - dAlpha ) * ( 1.0 - dBeta ) +
1179  nodes[face[1]].z * dAlpha * ( 1.0 - dBeta ) + nodes[face[2]].z * dAlpha * dBeta +
1180  nodes[face[3]].z * ( 1.0 - dAlpha ) * dBeta;
1181 
1182  double dR = sqrt( dXc * dXc + dYc * dYc + dZc * dZc );
1183 
1184  // Mapped node location
1185  nodeGLL.x = dXc / dR;
1186  nodeGLL.y = dYc / dR;
1187  nodeGLL.z = dZc / dR;
1188 
1189  // Determine if this is a unique Node
1190  std::map< Node, int >::const_iterator iter = mapNodes.find( nodeGLL );
1191  if( iter == mapNodes.end() )
1192  {
1193  // Insert new unique node into map
1194  int ixNode = static_cast< int >( mapNodes.size() );
1195  mapNodes.insert( std::pair< Node, int >( nodeGLL, ixNode ) );
1196  dataGLLnodes[j][i][k] = ixNode + 1;
1197  }
1198  else
1199  {
1200  dataGLLnodes[j][i][k] = iter->second + 1;
1201  }
1202 
1203  dofIDs[j * nP + i] = dataGLLnodes[j][i][k];
1204  }
1205  }
1206 
1207  if( locElem )
1208  {
1209  rval = m_interface->tag_set_data( dofTag, &current_eh, 1, dofIDs );MB_CHK_SET_ERR( rval, "Failed to tag_set_data for DoFs" );
1210  }
1211  }
1212 
1213  // clear memory
1214  delete[] dofIDs;
1215  mapLocalMBNodes.clear();
1216  mapNodes.clear();
1217 
1218  return moab::MB_SUCCESS;
1219 }
1220 
1221 ///////////////////////////////////////////////////////////////////////////////////
1222 
1224  double radius_src,
1225  double radius_tgt,
1226  double boxeps,
1227  bool regional_mesh,
1228  bool gnomonic )
1229 {
1230  ErrorCode rval;
1231 
1232  rrmgrids = regional_mesh;
1233  moab::Range local_verts;
1234 
1235  // Initialize intersection context
1237 
1239  mbintx->set_radius_source_mesh( radius_src );
1240  mbintx->set_radius_destination_mesh( radius_tgt );
1241  mbintx->set_box_error( boxeps );
1242 #ifdef MOAB_HAVE_MPI
1243  mbintx->set_parallel_comm( m_pcomm );
1244 #endif
1245 
1246  // compute the maxiumum edges in elements comprising source and target mesh
1248 
1251 
1252  // Note: lots of communication possible, if mesh is distributed very differently
1253 #ifdef MOAB_HAVE_MPI
1254  if( is_parallel )
1255  {
1256  rval = mbintx->build_processor_euler_boxes( m_target_set, local_verts, gnomonic );MB_CHK_ERR( rval );
1257 
1258  rval = m_interface->create_meshset( moab::MESHSET_SET, m_covering_source_set );MB_CHK_SET_ERR( rval, "Can't create new set" );
1259 
1260  rval = mbintx->construct_covering_set( m_source_set, m_covering_source_set, gnomonic );MB_CHK_ERR( rval );
1261  }
1262  else
1263  {
1264 #endif
1265  if( rrmgrids )
1266  {
1267  rval = m_interface->create_meshset( moab::MESHSET_SET, m_covering_source_set );MB_CHK_SET_ERR( rval, "Can't create new set" );
1268 
1269  double tolerance = 1e-6, btolerance = 1e-3;
1271  moab::Range targetVerts;
1272 
1273  rval = m_interface->get_connectivity( m_target_entities, targetVerts, true );MB_CHK_ERR( rval );
1274 
1275  rval = tree.build_tree( m_source_entities, &m_source_set );MB_CHK_ERR( rval );
1276 
1277  for( unsigned ie = 0; ie < targetVerts.size(); ++ie )
1278  {
1279  EntityHandle el = targetVerts[ie], leaf;
1280  double point[3];
1281 
1282  // Get the element centroid to be queried
1283  rval = m_interface->get_coords( &el, 1, point );MB_CHK_ERR( rval );
1284 
1285  // Search for the closest source element in the master mesh corresponding
1286  // to the target element centroid in the slave mesh
1287  rval = tree.point_search( point, leaf, tolerance, btolerance );MB_CHK_ERR( rval );
1288 
1289  if( leaf == 0 )
1290  {
1291  leaf = m_source_set; // no hint
1292  }
1293 
1294  std::vector< moab::EntityHandle > leaf_elems;
1295  // We only care about the dimension that the user specified.
1296  // MOAB partitions are ordered by elements anyway.
1297  rval = m_interface->get_entities_by_dimension( leaf, 2, leaf_elems );MB_CHK_ERR( rval );
1298 
1299  if( !leaf_elems.size() )
1300  {
1301  // std::cout << ie << ": " << " No leaf elements found." << std::endl;
1302  continue;
1303  }
1304 
1305  // Now get the master element centroids so that we can compute
1306  // the minimum distance to the target point
1307  std::vector< double > centroids( leaf_elems.size() * 3 );
1308  rval = m_interface->get_coords( &leaf_elems[0], leaf_elems.size(), &centroids[0] );MB_CHK_ERR( rval );
1309 
1310  double dist = 1e5;
1311  int pinelem = -1;
1312  for( size_t il = 0; il < leaf_elems.size(); ++il )
1313  {
1314  const double* centroid = &centroids[il * 3];
1315  const double locdist = std::pow( point[0] - centroid[0], 2 ) +
1316  std::pow( point[1] - centroid[1], 2 ) +
1317  std::pow( point[2] - centroid[2], 2 );
1318 
1319  if( locdist < dist )
1320  {
1321  dist = locdist;
1322  pinelem = il;
1323  m_covering_source_entities.insert( leaf_elems[il] );
1324  }
1325  }
1326 
1327  if( pinelem < 0 )
1328  {
1329  std::cout << ie
1330  << ": [Error] - Could not find a minimum distance within the leaf "
1331  "nodes. Dist = "
1332  << dist << std::endl;
1333  }
1334  }
1335  // rval = tree.reset_tree();MB_CHK_ERR(rval);
1336  std::cout << "[INFO] - Total covering source entities = " << m_covering_source_entities.size() << std::endl;
1338  }
1339  else
1340  {
1343  m_covering_source_entities = m_source_entities; // this is a tempest mesh object; careful about
1344  // incrementing the reference?
1345  m_covering_source_vertices = m_source_vertices; // this is a tempest mesh object; careful about
1346  // incrementing the reference?
1347  }
1348 #ifdef MOAB_HAVE_MPI
1349  }
1350 #endif
1351 
1352  return rval;
1353 }
1354 
1355 ErrorCode TempestRemapper::ComputeOverlapMesh( bool kdtree_search, bool use_tempest )
1356 {
1357  ErrorCode rval;
1358  const bool outputEnabled = ( this->rank == 0 );
1359  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
1360  dbgprint.set_prefix( "[ComputeOverlapMesh]: " );
1361 
1362  // const double radius = 1.0 /*2.0*acos(-1.0)*/;
1363  // const double boxeps = 0.1;
1364  // Create the intersection on the sphere object and set up necessary parameters
1365 
1366  // First, split based on whether to use Tempest or MOAB
1367  // If Tempest
1368  // 1) Check for valid Mesh and pointers to objects for source/target
1369  // 2) Invoke GenerateOverlapWithMeshes routine from Tempest library
1370  // If MOAB
1371  // 1) Check for valid source and target meshsets (and entities)
1372  // 2) Build processor bounding boxes and construct a covering set
1373  // 3) Perform intersection between the source (covering) and target entities
1374  if( use_tempest )
1375  {
1376  // Now let us construct the overlap mesh, by calling TempestRemap interface directly
1377  // For the overlap method, choose between: "fuzzy", "exact" or "mixed"
1378  assert( m_source != nullptr );
1379  assert( m_target != nullptr );
1380  if( m_overlap != nullptr ) delete m_overlap;
1381  m_overlap = new Mesh();
1382  bool concaveMeshA = false, concaveMeshB = false;
1383  int err = GenerateOverlapWithMeshes( *m_covering_source, *m_target, *m_overlap, "" /*outFilename*/, "Netcdf4",
1384  "exact", concaveMeshA, concaveMeshB, false );
1385  if( err )
1386  {
1387  MB_CHK_SET_ERR( MB_FAILURE, "TempestRemap: Can't compute the intersection of meshes on the sphere" );
1388  }
1389  }
1390  else
1391  {
1392  Tag gidtag = m_interface->globalId_tag();
1393  moab::EntityHandle subrange[2];
1394  int gid[2];
1395  if( m_source_entities.size() > 1 )
1396  { // Let us do some sanity checking to fix ID if they have are setup incorrectly
1397  subrange[0] = m_source_entities[0];
1398  subrange[1] = m_source_entities[1];
1399  rval = m_interface->tag_get_data( gidtag, subrange, 2, gid );MB_CHK_ERR( rval );
1400 
1401  // Check if we need to impose Global ID numbering for vertices and elements. This may be
1402  // needed if we load the meshes from exodus or some other formats that may not have a
1403  // numbering forced.
1404  if( gid[0] + gid[1] == 0 ) // this implies first two elements have GID = 0
1405  {
1406 #ifdef MOAB_HAVE_MPI
1407  rval = m_pcomm->assign_global_ids( m_source_set, 2, 1, false, true, false );MB_CHK_ERR( rval );
1408 #else
1409  rval = this->assign_vertex_element_IDs( gidtag, m_source_set, 2, 1 );MB_CHK_ERR( rval );
1410 #endif
1411  }
1412  }
1413  if( m_target_entities.size() > 1 )
1414  {
1415  subrange[0] = m_target_entities[0];
1416  subrange[1] = m_target_entities[1];
1417  rval = m_interface->tag_get_data( gidtag, subrange, 2, gid );MB_CHK_ERR( rval );
1418 
1419  // Check if we need to impose Global ID numbering for vertices and elements. This may be
1420  // needed if we load the meshes from exodus or some other formats that may not have a
1421  // numbering forced.
1422  if( gid[0] + gid[1] == 0 ) // this implies first two elements have GID = 0
1423  {
1424 #ifdef MOAB_HAVE_MPI
1425  rval = m_pcomm->assign_global_ids( m_target_set, 2, 1, false, true, false );MB_CHK_ERR( rval );
1426 #else
1427  rval = this->assign_vertex_element_IDs( gidtag, m_target_set, 2, 1 );MB_CHK_ERR( rval );
1428 #endif
1429  }
1430  }
1431 
1432  // Now perform the actual parallel intersection between the source and the target meshes
1433  if( kdtree_search )
1434  {
1435  if( outputEnabled ) dbgprint.printf( 0, "Computing intersection mesh with the Kd-tree search algorithm" );
1436  rval = mbintx->intersect_meshes_kdtree( m_covering_source_set, m_target_set, m_overlap_set );MB_CHK_SET_ERR( rval, "Can't compute the intersection of meshes on the sphere with brute-force" );
1437  }
1438  else
1439  {
1440  if( outputEnabled )
1441  dbgprint.printf( 0, "Computing intersection mesh with the advancing-front propagation algorithm" );
1442  rval = mbintx->intersect_meshes( m_covering_source_set, m_target_set, m_overlap_set );MB_CHK_SET_ERR( rval, "Can't compute the intersection of meshes on the sphere" );
1443  }
1444 
1445 #ifdef MOAB_HAVE_MPI
1446  if( is_parallel || rrmgrids )
1447  {
1448 #ifdef VERBOSE
1449  std::stringstream ffc, fft, ffo;
1450  ffc << "cover_" << rank << ".h5m";
1451  fft << "target_" << rank << ".h5m";
1452  ffo << "intx_" << rank << ".h5m";
1453  rval = m_interface->write_mesh( ffc.str().c_str(), &m_covering_source_set, 1 );MB_CHK_ERR( rval );
1454  rval = m_interface->write_mesh( fft.str().c_str(), &m_target_set, 1 );MB_CHK_ERR( rval );
1455  rval = m_interface->write_mesh( ffo.str().c_str(), &m_overlap_set, 1 );MB_CHK_ERR( rval );
1456 #endif
1457  // because we do not want to work with elements in coverage set that do not participate
1458  // in intersection, remove them from the coverage set we will not delete them yet, just
1459  // remove from the set !
1460  if( !point_cloud_target )
1461  {
1462  Range covEnts;
1464  Tag gidtag = m_interface->globalId_tag();
1465 
1466  std::map< int, int > loc_gid_to_lid_covsrc;
1467  std::vector< int > gids( covEnts.size(), -1 );
1468  rval = m_interface->tag_get_data( gidtag, covEnts, &gids[0] );MB_CHK_ERR( rval );
1469  for( unsigned ie = 0; ie < gids.size(); ++ie )
1470  {
1471  loc_gid_to_lid_covsrc[gids[ie]] = ie;
1472  }
1473 
1474  Range intxCov, intxCells;
1475  Tag srcParentTag;
1476  rval = m_interface->tag_get_handle( "SourceParent", srcParentTag );MB_CHK_ERR( rval );
1477  rval = m_interface->get_entities_by_dimension( m_overlap_set, 2, intxCells );MB_CHK_ERR( rval );
1478  for( Range::iterator it = intxCells.begin(); it != intxCells.end(); it++ )
1479  {
1480  EntityHandle intxCell = *it;
1481  int srcParent = -1;
1482  rval = m_interface->tag_get_data( srcParentTag, &intxCell, 1, &srcParent );MB_CHK_ERR( rval );
1483  // if (is_root) std::cout << "Found intersecting element: " << srcParent << ",
1484  // " << gid_to_lid_covsrc[srcParent] << "\n";
1485  assert( srcParent >= 0 );
1486  intxCov.insert( covEnts[loc_gid_to_lid_covsrc[srcParent]] );
1487  }
1488 
1489  Range notNeededCovCells = moab::subtract( covEnts, intxCov );
1490 
1491  // now let us get only the covering entities that participate in intersection mesh
1492  covEnts = moab::subtract( covEnts, notNeededCovCells );
1493 
1494  // in order for getting 1-ring neighborhood, we need to be sure that the adjacencies are updated (created)
1495  if( false )
1496  {
1497  // update all adjacency list
1498  Core* mb = dynamic_cast< Core* >( m_interface );
1499  AEntityFactory* adj_fact = mb->a_entity_factory();
1500  if( !adj_fact->vert_elem_adjacencies() )
1501  adj_fact->create_vert_elem_adjacencies();
1502  else
1503  {
1504  for( Range::iterator it = covEnts.begin(); it != covEnts.end(); ++it )
1505  {
1506  EntityHandle eh = *it;
1507  const EntityHandle* conn = nullptr;
1508  int num_nodes = 0;
1509  rval = mb->get_connectivity( eh, conn, num_nodes );MB_CHK_ERR( rval );
1510  adj_fact->notify_create_entity( eh, conn, num_nodes );
1511  }
1512  }
1513 
1514  // next, for elements on the edge of the partition, get one ring adjacencies
1515  Skinner skinner( mb );
1516  Range skin;
1517  rval = skinner.find_skin( m_covering_source_set, covEnts, false, skin );MB_CHK_SET_ERR( rval, "Unable to find skin" );
1518  for( Range::iterator it = skin.begin(); it != skin.end(); ++it )
1519  {
1520  const EntityHandle* conn = nullptr;
1521  int len = 0;
1522  rval = mb->get_connectivity( *it, conn, len, false );MB_CHK_ERR( rval );
1523  for( int ie = 0; ie < len; ++ie )
1524  {
1525  std::vector< EntityHandle > adjacent_entities;
1526  rval = adj_fact->get_adjacencies( conn[ie], 2, false, adjacent_entities );MB_CHK_ERR( rval );
1527  for( auto ent : adjacent_entities )
1528  notNeededCovCells.erase( ent ); // ent is part of the 1-ring neighborhood
1529  }
1530  }
1531 
1532  rval = m_interface->write_mesh(
1533  std::string( "sourcecoveragemesh_p" + std::to_string( rank ) + ".h5m" ).c_str(),
1534  &m_covering_source_set, 1 );MB_CHK_ERR( rval );
1535  }
1536 
1537  // remove now from coverage set the cells that are not needed
1538  // rval = m_interface->remove_entities( m_covering_source_set, notNeededCovCells );MB_CHK_ERR( rval );
1539 
1540  // Need to loop over covEnts now and ensure at least N-rings are available dependign on whether bilinear (1) or
1541  // high order FV (p) methods are being used for map generation. For bilinear/FV(1): need 1 ring, and for FV(p)
1542  // need p=ring neighborhood to recover exact conservation and consistency wrt serial/parallel.
1543 #ifdef VERBOSE
1544  std::cout << " total participating elements in the covering set: " << intxCov.size() << "\n";
1545  std::cout << " remove from coverage set elements that are not intersected: " << notNeededCovCells.size()
1546  << "\n";
1547 #endif
1548  if( size > 1 )
1549  {
1550  // some source elements cover multiple target partitions; the conservation logic
1551  // requires to know all overlap elements for a source element; they need to be
1552  // communicated from the other target partitions
1553  //
1554  // so first we have to identify source (coverage) elements that cover multiple
1555  // target partitions
1556 
1557  // we will then mark the source, we will need to migrate the overlap elements
1558  // that cover this to the original source for the source element; then
1559  // distribute the overlap elements to all processors that have the coverage mesh
1560  // used
1561 
1562  rval = augment_overlap_set();MB_CHK_ERR( rval );
1563  }
1564  }
1565  }
1566 #endif
1567 
1568  // Fix any inconsistencies in the overlap mesh
1569  {
1570  IntxAreaUtils areaAdaptor;
1572  rval = areaAdaptor.positive_orientation( m_interface, m_overlap_set, 1.0 /*radius*/ );MB_CHK_ERR( rval );
1573  }
1574 
1575  // Now let us re-convert the MOAB mesh back to Tempest representation
1576  rval = this->ComputeGlobalLocalMaps();MB_CHK_ERR( rval );
1577 
1578  rval = this->convert_overlap_mesh_sorted_by_source();MB_CHK_ERR( rval );
1579 
1580  // free the memory
1581  delete mbintx;
1582  }
1583 
1584  return MB_SUCCESS;
1585 }
1586 
1587 #ifdef MOAB_HAVE_MPI
1588 // this function is called only in parallel
1589 ///////////////////////////////////////////////////////////////////////////////////
1591 {
1592  /*
1593  * overall strategy:
1594  *
1595  * 1) collect all boundary target cells on the current task, affected by the partition boundary;
1596  * note: not only partition boundary, we need all boundary (all coastal lines) and partition
1597  * boundary targetBoundaryIds is the set of target boundary cell IDs
1598  *
1599  * 2) collect all source cells that are intersecting boundary cells (call them
1600  * affectedSourceCellsIds)
1601  *
1602  * 3) collect overlap, that is accumulate all overlap cells that have source target in
1603  * affectedSourceCellsIds
1604  */
1605  // first, get all edges on the partition boundary, on the target mesh, then all the target
1606  // elements that border the partition boundary
1607  ErrorCode rval;
1608  Skinner skinner( m_interface );
1609  Range targetCells, boundaryEdges;
1610  rval = m_interface->get_entities_by_dimension( m_target_set, 2, targetCells );MB_CHK_ERR( rval );
1611  /// find all boundary edges
1612  rval = skinner.find_skin( 0, targetCells, false, boundaryEdges );MB_CHK_ERR( rval );
1613  // filter boundary edges that are on partition boundary, not on boundary
1614  // find all cells adjacent to these boundary edges, from target set
1615  Range boundaryCells; // these will be filtered from target_set
1616  rval = m_interface->get_adjacencies( boundaryEdges, 2, false, boundaryCells, Interface::UNION );MB_CHK_ERR( rval );
1617  boundaryCells = intersect( boundaryCells, targetCells );
1618 #ifdef VERBOSE
1619  EntityHandle tmpSet;
1620  rval = m_interface->create_meshset( MESHSET_SET, tmpSet );MB_CHK_SET_ERR( rval, "Can't create temporary set" );
1621  // add the boundary set and edges, and save it to a file
1622  rval = m_interface->add_entities( tmpSet, boundaryCells );MB_CHK_SET_ERR( rval, "Can't add entities" );
1623  rval = m_interface->add_entities( tmpSet, boundaryEdges );MB_CHK_SET_ERR( rval, "Can't add edges" );
1624  std::stringstream ffs;
1625  ffs << "boundaryCells_0" << rank << ".h5m";
1626  rval = m_interface->write_mesh( ffs.str().c_str(), &tmpSet, 1 );MB_CHK_ERR( rval );
1627 #endif
1628 
1629  // now that we have the boundary cells, see which overlap polys have have these as parents;
1630  // find the ids of the boundary cells;
1631  Tag gid = m_interface->globalId_tag();
1632  std::set< int > targetBoundaryIds;
1633  for( Range::iterator it = boundaryCells.begin(); it != boundaryCells.end(); it++ )
1634  {
1635  int tid;
1636  EntityHandle targetCell = *it;
1637  rval = m_interface->tag_get_data( gid, &targetCell, 1, &tid );MB_CHK_SET_ERR( rval, "Can't get global id tag on target cell" );
1638  if( tid < 0 ) std::cout << " incorrect id for a target cell\n";
1639  targetBoundaryIds.insert( tid );
1640  }
1641 
1642  Range overlapCells;
1643  rval = m_interface->get_entities_by_dimension( m_overlap_set, 2, overlapCells );MB_CHK_ERR( rval );
1644 
1645  std::set< int > affectedSourceCellsIds;
1646  Tag targetParentTag, sourceParentTag; // do not use blue/red, as it is more confusing
1647  rval = m_interface->tag_get_handle( "TargetParent", targetParentTag );MB_CHK_ERR( rval );
1648  rval = m_interface->tag_get_handle( "SourceParent", sourceParentTag );MB_CHK_ERR( rval );
1649  for( Range::iterator it = overlapCells.begin(); it != overlapCells.end(); it++ )
1650  {
1651  EntityHandle intxCell = *it;
1652  int targetParentID, sourceParentID;
1653  rval = m_interface->tag_get_data( targetParentTag, &intxCell, 1, &targetParentID );MB_CHK_ERR( rval );
1654  if( targetBoundaryIds.find( targetParentID ) != targetBoundaryIds.end() )
1655  {
1656  // this means that the source element is affected
1657  rval = m_interface->tag_get_data( sourceParentTag, &intxCell, 1, &sourceParentID );MB_CHK_ERR( rval );
1658  affectedSourceCellsIds.insert( sourceParentID );
1659  }
1660  }
1661 
1662  // now find all source cells affected, based on their id;
1663  // (we do not have yet the mapping gid_to_lid_covsrc)
1664  std::map< int, EntityHandle > affectedCovCellFromID; // map from source cell id to the eh; it is needed to find out
1665  // the original processor
1666  // this one came from , so to know where to send the overlap elements
1667 
1668  // use std::set<EntityHandle> instead of moab::Range for collecting cells, either on coverage or
1669  // target or intx cells
1670  std::set< EntityHandle > affectedCovCells; // their overlap cells will be sent to their
1671  // original task, then distributed to all
1672  // other processes that might need them to compute conservation
1673 
1674  Range covCells;
1676  // loop thru all cov cells, to find the ones with global ids in affectedSourceCellsIds
1677  for( Range::iterator it = covCells.begin(); it != covCells.end(); it++ )
1678  {
1679  EntityHandle covCell = *it; //
1680  int covID;
1681  rval = m_interface->tag_get_data( gid, &covCell, 1, &covID );
1682  if( affectedSourceCellsIds.find( covID ) != affectedSourceCellsIds.end() )
1683  {
1684  // this source cell is affected;
1685  affectedCovCellFromID[covID] = covCell;
1686  affectedCovCells.insert( covCell );
1687  }
1688  }
1689 
1690  // now loop again over all overlap cells, to see if their source parent is "affected"
1691  // store in ranges the overlap cells that need to be sent to original task of the source cell
1692  // from there, they will be redistributed to the tasks that need that coverage cell
1693  Tag sendProcTag;
1694  rval = m_interface->tag_get_handle( "sending_processor", 1, MB_TYPE_INTEGER, sendProcTag );
1695 
1696  // basically a map from original processor task to the set of overlap cells to be sent there
1697  std::map< int, std::set< EntityHandle > > overlapCellsForTask;
1698  // this set will contain all intx cells that will need to be sent ( a union of above sets ,
1699  // that are organized per task on the above map )
1700  std::set< EntityHandle > overlapCellsToSend;
1701 
1702  for( Range::iterator it = overlapCells.begin(); it != overlapCells.end(); it++ )
1703  {
1704  EntityHandle intxCell = *it;
1705  int sourceParentID;
1706  rval = m_interface->tag_get_data( sourceParentTag, &intxCell, 1, &sourceParentID );MB_CHK_ERR( rval );
1707  if( affectedSourceCellsIds.find( sourceParentID ) != affectedSourceCellsIds.end() )
1708  {
1709  EntityHandle covCell = affectedCovCellFromID[sourceParentID];
1710  int orgTask;
1711  rval = m_interface->tag_get_data( sendProcTag, &covCell, 1, &orgTask );MB_CHK_ERR( rval );
1712  overlapCellsForTask[orgTask].insert(
1713  intxCell ); // put the overlap cell in corresponding range (set<EntityHandle>)
1714  overlapCellsToSend.insert( intxCell ); // also put it in this range, for debugging mostly
1715  }
1716  }
1717 
1718  // now prepare to send; will use crystal router, as the buffers in ParComm are prepared only
1719  // for neighbors; coverage mesh was also migrated with crystal router, so here we go again :(
1720 
1721  // find out the maximum number of edges of the polygons needed to be sent
1722  // we could we conservative and use a big number, or the number from intx, if we store it then?
1723  int maxEdges = 0;
1724  for( std::set< EntityHandle >::iterator it = overlapCellsToSend.begin(); it != overlapCellsToSend.end(); it++ )
1725  {
1726  EntityHandle intxCell = *it;
1727  int nnodes;
1728  const EntityHandle* conn;
1729  rval = m_interface->get_connectivity( intxCell, conn, nnodes );MB_CHK_ERR( rval );
1730  if( maxEdges < nnodes ) maxEdges = nnodes;
1731  }
1732 
1733  // find the maximum among processes in intersection
1734  int globalMaxEdges;
1735  if( m_pcomm )
1736  MPI_Allreduce( &maxEdges, &globalMaxEdges, 1, MPI_INT, MPI_MAX, m_pcomm->comm() );
1737  else
1738  globalMaxEdges = maxEdges;
1739 
1740 #ifdef VERBOSE
1741  if( is_root ) std::cout << "maximum number of edges for polygons to send is " << globalMaxEdges << "\n";
1742 #endif
1743 
1744 #ifdef VERBOSE
1745  EntityHandle tmpSet2;
1746  rval = m_interface->create_meshset( MESHSET_SET, tmpSet2 );MB_CHK_SET_ERR( rval, "Can't create temporary set2" );
1747  // add the affected source and overlap elements
1748  for( std::set< EntityHandle >::iterator it = overlapCellsToSend.begin(); it != overlapCellsToSend.end(); it++ )
1749  {
1750  EntityHandle intxCell = *it;
1751  rval = m_interface->add_entities( tmpSet2, &intxCell, 1 );MB_CHK_SET_ERR( rval, "Can't add entities" );
1752  }
1753  for( std::set< EntityHandle >::iterator it = affectedCovCells.begin(); it != affectedCovCells.end(); it++ )
1754  {
1755  EntityHandle covCell = *it;
1756  rval = m_interface->add_entities( tmpSet2, &covCell, 1 );MB_CHK_SET_ERR( rval, "Can't add entities" );
1757  }
1758  std::stringstream ffs2;
1759  // these will contain coverage cells and intx cells on the boundary
1760  ffs2 << "affectedCells_" << m_pcomm->rank() << ".h5m";
1761  rval = m_interface->write_mesh( ffs2.str().c_str(), &tmpSet2, 1 );MB_CHK_ERR( rval );
1762 #endif
1763  // form tuple lists to send vertices and cells;
1764  // the problem is that the lists of vertices will need to have other information, like the
1765  // processor it comes from, and its index in that list; we may have to duplicate vertices, but
1766  // we do not care much; we will not duplicate overlap elements, just the vertices, as they may
1767  // come from different cells and different processes each vertex will have a local index and a
1768  // processor task it is coming from
1769 
1770  // look through the std::set's to be sent to other processes, and form the vertex tuples and
1771  // cell tuples
1772  //
1773  std::map< int, std::set< EntityHandle > > verticesOverlapForTask;
1774  // Range allVerticesToSend;
1775  std::set< EntityHandle > allVerticesToSend;
1776  std::map< EntityHandle, int > allVerticesToSendMap;
1777  int numVerts = 0;
1778  int numOverlapCells = 0;
1779  for( std::map< int, std::set< EntityHandle > >::iterator it = overlapCellsForTask.begin();
1780  it != overlapCellsForTask.end(); it++ )
1781  {
1782  int sendToProc = it->first;
1783  std::set< EntityHandle >& overlapCellsToSend2 = it->second; // organize vertices in std::set per processor
1784  // Range vertices;
1785  std::set< EntityHandle > vertices; // collect all vertices connected to overlapCellsToSend2
1786  for( std::set< EntityHandle >::iterator set_it = overlapCellsToSend2.begin();
1787  set_it != overlapCellsToSend2.end(); ++set_it )
1788  {
1789  int nnodes_local = 0;
1790  const EntityHandle* conn1 = nullptr;
1791  rval = m_interface->get_connectivity( *set_it, conn1, nnodes_local );MB_CHK_ERR( rval );
1792  for( int k = 0; k < nnodes_local; k++ )
1793  vertices.insert( conn1[k] );
1794  }
1795  verticesOverlapForTask[sendToProc] = vertices;
1796  numVerts += (int)vertices.size();
1797  numOverlapCells += (int)overlapCellsToSend2.size();
1798  allVerticesToSend.insert( vertices.begin(), vertices.end() );
1799  }
1800  // build the index map, from entity handle to index in all vert set
1801  int j = 0;
1802  for( std::set< EntityHandle >::iterator vert_it = allVerticesToSend.begin(); vert_it != allVerticesToSend.end();
1803  vert_it++, j++ )
1804  {
1805  EntityHandle vert = *vert_it;
1806  allVerticesToSendMap[vert] = j;
1807  }
1808 
1809  // first send vertices in a tuple list, then send overlap cells, according to requests
1810  // overlap cells need to send info about the blue and red parent tags, too
1811  TupleList TLv; //
1812  TLv.initialize( 2, 0, 0, 3, numVerts ); // to proc, index in all range, DP points
1813  TLv.enableWriteAccess();
1814 
1815  for( std::map< int, std::set< EntityHandle > >::iterator it = verticesOverlapForTask.begin();
1816  it != verticesOverlapForTask.end(); it++ )
1817  {
1818  int sendToProc = it->first;
1819  std::set< EntityHandle >& vertices = it->second;
1820  int i = 0;
1821  for( std::set< EntityHandle >::iterator it2 = vertices.begin(); it2 != vertices.end(); it2++, i++ )
1822  {
1823  int n = TLv.get_n();
1824  TLv.vi_wr[2 * n] = sendToProc; // send to processor
1825  EntityHandle v = *it2;
1826  int indexInAllVert = allVerticesToSendMap[v];
1827  TLv.vi_wr[2 * n + 1] = indexInAllVert; // will be orgProc, to differentiate indices
1828  // of vertices sent to "sentToProc"
1829  double coords[3];
1830  rval = m_interface->get_coords( &v, 1, coords );MB_CHK_ERR( rval );
1831  TLv.vr_wr[3 * n] = coords[0]; // departure position, of the node local_verts[i]
1832  TLv.vr_wr[3 * n + 1] = coords[1];
1833  TLv.vr_wr[3 * n + 2] = coords[2];
1834  TLv.inc_n();
1835  }
1836  }
1837 
1838  TupleList TLc;
1839  int sizeTuple = 4 + globalMaxEdges;
1840  // total number of overlap cells to send
1841  TLc.initialize( sizeTuple, 0, 0, 0,
1842  numOverlapCells ); // to proc, blue parent ID, red parent ID, nvert,
1843  // connectivity[globalMaxEdges] (global ID v), local eh)
1844  TLc.enableWriteAccess();
1845 
1846  for( std::map< int, std::set< EntityHandle > >::iterator it = overlapCellsForTask.begin();
1847  it != overlapCellsForTask.end(); it++ )
1848  {
1849  int sendToProc = it->first;
1850  std::set< EntityHandle >& overlapCellsToSend2 = it->second;
1851  // send also the target and source parents for these overlap cells
1852  for( std::set< EntityHandle >::iterator it2 = overlapCellsToSend2.begin(); it2 != overlapCellsToSend2.end();
1853  it2++ )
1854  {
1855  EntityHandle intxCell = *it2;
1856  int sourceParentID, targetParentID;
1857  rval = m_interface->tag_get_data( targetParentTag, &intxCell, 1, &targetParentID );MB_CHK_ERR( rval );
1858  rval = m_interface->tag_get_data( sourceParentTag, &intxCell, 1, &sourceParentID );MB_CHK_ERR( rval );
1859  int n = TLc.get_n();
1860  TLc.vi_wr[sizeTuple * n] = sendToProc;
1861  TLc.vi_wr[sizeTuple * n + 1] = sourceParentID;
1862  TLc.vi_wr[sizeTuple * n + 2] = targetParentID;
1863  int nnodes;
1864  const EntityHandle* conn = nullptr;
1865  rval = m_interface->get_connectivity( intxCell, conn, nnodes );MB_CHK_ERR( rval );
1866  TLc.vi_wr[sizeTuple * n + 3] = nnodes;
1867  for( int i = 0; i < nnodes; i++ )
1868  {
1869  int indexVertex = allVerticesToSendMap[conn[i]];
1870  ; // the vertex index will be now unique per original proc
1871  if( -1 == indexVertex ) MB_CHK_SET_ERR( MB_FAILURE, "Can't find vertex in range of vertices to send" );
1872  TLc.vi_wr[sizeTuple * n + 4 + i] = indexVertex;
1873  }
1874  // fill the rest with 0, just because we do not like uninitialized data
1875  for( int i = nnodes; i < globalMaxEdges; i++ )
1876  TLc.vi_wr[sizeTuple * n + 4 + i] = 0;
1877 
1878  TLc.inc_n();
1879  }
1880  }
1881 
1882  // send first the vertices and overlap cells to original task for coverage cells
1883  // now we are done populating the tuples; route them to the appropriate processors
1884 #ifdef VERBOSE
1885  std::stringstream ff1;
1886  ff1 << "TLc_" << rank << ".txt";
1887  TLc.print_to_file( ff1.str().c_str() );
1888  std::stringstream ffv;
1889  ffv << "TLv_" << rank << ".txt";
1890  TLv.print_to_file( ffv.str().c_str() );
1891 #endif
1892  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, TLv, 0 );
1893  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, TLc, 0 );
1894 
1895 #ifdef VERBOSE
1896  TLc.print_to_file( ff1.str().c_str() ); // will append to existing file
1897  TLv.print_to_file( ffv.str().c_str() );
1898 #endif
1899  // first phase of transfer complete
1900  // now look at TLc, and sort by the source parent (index 1)
1901 
1903  buffer.buffer_init( sizeTuple * TLc.get_n() * 2 ); // allocate memory for sorting !! double
1904  TLc.sort( 1, &buffer );
1905 #ifdef VERBOSE
1906  TLc.print_to_file( ff1.str().c_str() );
1907 #endif
1908 
1909  // will keep a map with vertices per processor that will need to be used in TLv2;
1910  // so, availVertexIndicesPerProcessor[proc] is a map from vertex indices that are available from
1911  // this processor to the index in the local TLv; the used vertices will have to be sent to the
1912  // tasks that need them
1913 
1914  // connectivity of a cell is given by sending proc and index in original list of vertices from
1915  // that proc
1916 
1917  std::map< int, std::map< int, int > > availVertexIndicesPerProcessor;
1918  int nv = TLv.get_n();
1919  for( int i = 0; i < nv; i++ )
1920  {
1921  // int proc=TLv.vi_rd[3*i]; // it is coming from this processor
1922  int orgProc = TLv.vi_rd[2 * i]; // this is the original processor, for index vertex consideration
1923  int indexVert = TLv.vi_rd[2 * i + 1];
1924  availVertexIndicesPerProcessor[orgProc][indexVert] = i;
1925  }
1926 
1927  // now we have sorted the incoming overlap elements by the source element;
1928  // if we have overlap elements for one source coming from 2 or more processes, we need to send
1929  // back to the processes that do not have that overlap cell;
1930 
1931  // form new TLc2, TLv2, that will be distributed to necessary processes
1932  // first count source elements that are "spread" over multiple processes
1933  // TLc is ordered now by source ID; loop over them
1934  int n = TLc.get_n(); // total number of overlap elements received on current task;
1935  std::map< int, int > currentProcsCount;
1936  // form a map from proc to sets of vertex indices that will be sent using TLv2
1937  // will form a map between a source cell ID and tasks/targets that are partially overlapped by
1938  // these sources
1939  std::map< int, std::set< int > > sourcesForTasks;
1940  int sizeOfTLc2 = 0; // only increase when we will have to send data
1941  if( n > 0 )
1942  {
1943  int currentSourceID = TLc.vi_rd[sizeTuple * 0 + 1]; // we have written sizeTuple*0 for "clarity"
1944  int proc0 = TLc.vi_rd[sizeTuple * 0];
1945  currentProcsCount[proc0] = 1; //
1946 
1947  for( int i = 1; i < n; i++ )
1948  {
1949  int proc = TLc.vi_rd[sizeTuple * i];
1950  int sourceID = TLc.vi_rd[sizeTuple * i + 1];
1951  if( sourceID == currentSourceID )
1952  {
1953  if( currentProcsCount.find( proc ) == currentProcsCount.end() )
1954  {
1955  currentProcsCount[proc] = 1;
1956  }
1957  else
1958  currentProcsCount[proc]++;
1959  }
1960  if( sourceID != currentSourceID || ( ( n - 1 ) == i ) ) // we study the current source if we reach the last
1961  {
1962  // we have found a new source id, need to reset the proc counts, and establish if we
1963  // need to send data
1964  if( currentProcsCount.size() > 1 )
1965  {
1966 #ifdef VERBOSE
1967  std::cout << " source element " << currentSourceID << " intersects with "
1968  << currentProcsCount.size() << " target partitions\n";
1969  for( std::map< int, int >::iterator it = currentProcsCount.begin(); it != currentProcsCount.end();
1970  it++ )
1971  {
1972  int procID = it->first;
1973  int numOverCells = it->second;
1974  std::cout << " task:" << procID << " " << numOverCells << " cells\n";
1975  }
1976 
1977 #endif
1978  // estimate what we need to send
1979  for( std::map< int, int >::iterator it1 = currentProcsCount.begin(); it1 != currentProcsCount.end();
1980  it1++ )
1981  {
1982  int proc1 = it1->first;
1983  sourcesForTasks[currentSourceID].insert( proc1 );
1984  for( std::map< int, int >::iterator it2 = currentProcsCount.begin();
1985  it2 != currentProcsCount.end(); it2++ )
1986  {
1987  int proc2 = it2->first;
1988  if( proc1 != proc2 ) sizeOfTLc2 += it2->second;
1989  }
1990  }
1991  // mark vertices in TLv tuple that need to be sent
1992  }
1993  if( sourceID != currentSourceID ) // maybe we are not at the end, so continue on
1994  {
1995  currentSourceID = sourceID;
1996  currentProcsCount.clear();
1997  currentProcsCount[proc] = 1;
1998  }
1999  }
2000  }
2001  }
2002  // begin a loop to send the needed cells to the processes; also mark the vertices that need to
2003  // be sent, put them in a set
2004 
2005 #ifdef VERBOSE
2006  std::cout << " need to initialize TLc2 with " << sizeOfTLc2 << " cells\n ";
2007 #endif
2008 
2009  TupleList TLc2;
2010  int sizeTuple2 = 5 + globalMaxEdges; // send to, original proc for intx cell, source parent id,
2011  // target parent id,
2012  // number of vertices, then connectivity in terms of indices in vertex lists from original proc
2013  TLc2.initialize( sizeTuple2, 0, 0, 0, sizeOfTLc2 );
2014  TLc2.enableWriteAccess();
2015  // loop again through TLc, and select intx cells that have the problem sources;
2016 
2017  std::map< int, std::set< int > > verticesToSendForProc; // will look at indices in the TLv list
2018  // will form for each processor, the index list from TLv
2019  for( int i = 0; i < n; i++ )
2020  {
2021  int sourceID = TLc.vi_rd[sizeTuple * i + 1];
2022  if( sourcesForTasks.find( sourceID ) != sourcesForTasks.end() )
2023  {
2024  // it means this intx cell needs to be sent to any proc that is not "original" to it
2025  std::set< int > procs = sourcesForTasks[sourceID]; // set of processors involved with this source
2026  if( procs.size() < 2 ) MB_CHK_SET_ERR( MB_FAILURE, " not enough processes involved with a sourceID cell" );
2027 
2028  int orgProc = TLc.vi_rd[sizeTuple * i]; // this intx cell was sent from this orgProc, originally
2029  // will need to be sent to all other procs from above set; also, need to mark the vertex
2030  // indices for that proc, and check that they are available to populate TLv2
2031  std::map< int, int >& availableVerticesFromThisProc = availVertexIndicesPerProcessor[orgProc];
2032  for( std::set< int >::iterator setIt = procs.begin(); setIt != procs.end(); setIt++ )
2033  {
2034  int procID = *setIt;
2035  // send this cell to the other processors, not to orgProc this cell is coming from
2036 
2037  if( procID != orgProc )
2038  {
2039  // send the cell to this processor;
2040  int n2 = TLc2.get_n();
2041  if( n2 >= sizeOfTLc2 ) MB_CHK_SET_ERR( MB_FAILURE, " memory overflow" );
2042  //
2043  std::set< int >& indexVerticesInTLv = verticesToSendForProc[procID];
2044  TLc2.vi_wr[n2 * sizeTuple2] = procID; // send to
2045  TLc2.vi_wr[n2 * sizeTuple2 + 1] = orgProc; // this cell is coming from here
2046  TLc2.vi_wr[n2 * sizeTuple2 + 2] = sourceID; // source parent of the intx cell
2047  TLc2.vi_wr[n2 * sizeTuple2 + 3] = TLc.vi_rd[sizeTuple * i + 2]; // target parent of the intx cell
2048  // number of vertices of the intx cell
2049  int nvert = TLc.vi_rd[sizeTuple * i + 3];
2050  TLc2.vi_wr[n2 * sizeTuple2 + 4] = nvert;
2051  // now loop through the connectivity, and make sure the vertices are available;
2052  // mark them, to populate later the TLv2 tuple list
2053 
2054  // just copy the vertices, including 0 ones
2055  for( int j = 0; j < nvert; j++ )
2056  {
2057  int vertexIndex = TLc.vi_rd[i * sizeTuple + 4 + j];
2058  // is this vertex available from org proc?
2059  if( availableVerticesFromThisProc.find( vertexIndex ) == availableVerticesFromThisProc.end() )
2060  {
2061  MB_CHK_SET_ERR( MB_FAILURE, " vertex index not available from processor" );
2062  }
2063  TLc2.vi_wr[n2 * sizeTuple2 + 5 + j] = vertexIndex;
2064  int indexInTLv = availVertexIndicesPerProcessor[orgProc][vertexIndex];
2065  indexVerticesInTLv.insert( indexInTLv );
2066  }
2067 
2068  for( int j = nvert; j < globalMaxEdges; j++ )
2069  {
2070  TLc2.vi_wr[n2 * sizeTuple2 + 5 + j] = 0; // or mark them 0
2071  }
2072  TLc2.inc_n();
2073  }
2074  }
2075  }
2076  }
2077 
2078  // now we have to populate TLv2, with original source proc, index of vertex, and coordinates
2079  // from TLv use the verticesToSendForProc sets from above, and the map from index in proc to the
2080  // index in TLv
2081  TupleList TLv2;
2082  int numVerts2 = 0;
2083  // how many vertices to send?
2084  for( std::map< int, std::set< int > >::iterator it = verticesToSendForProc.begin();
2085  it != verticesToSendForProc.end(); it++ )
2086  {
2087  std::set< int >& indexInTLvSet = it->second;
2088  numVerts2 += (int)indexInTLvSet.size();
2089  }
2090  TLv2.initialize( 3, 0, 0, 3,
2091  numVerts2 ); // send to, original proc, index in original proc, and 3 coords
2092  TLv2.enableWriteAccess();
2093  for( std::map< int, std::set< int > >::iterator it = verticesToSendForProc.begin();
2094  it != verticesToSendForProc.end(); it++ )
2095  {
2096  int sendToProc = it->first;
2097  std::set< int >& indexInTLvSet = it->second;
2098  // now, look at indices in TLv, to find out the original proc, and the index in that list
2099  for( std::set< int >::iterator itSet = indexInTLvSet.begin(); itSet != indexInTLvSet.end(); itSet++ )
2100  {
2101  int indexInTLv = *itSet;
2102  int orgProc = TLv.vi_rd[2 * indexInTLv];
2103  int indexVertexInOrgProc = TLv.vi_rd[2 * indexInTLv + 1];
2104  int nv2 = TLv2.get_n();
2105  TLv2.vi_wr[3 * nv2] = sendToProc;
2106  TLv2.vi_wr[3 * nv2 + 1] = orgProc;
2107  TLv2.vi_wr[3 * nv2 + 2] = indexVertexInOrgProc;
2108  for( int j = 0; j < 3; j++ )
2109  TLv2.vr_wr[3 * nv2 + j] =
2110  TLv.vr_rd[3 * indexInTLv + j]; // departure position, of the node local_verts[i]
2111  TLv2.inc_n();
2112  }
2113  }
2114  // now, finally, transfer the vertices and the intx cells;
2115  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, TLv2, 0 );
2116  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, TLc2, 0 );
2117  // now, look at vertices from TLv2, and create them
2118  // we should have in TLv2 only vertices with orgProc different from current task
2119 #ifdef VERBOSE
2120  std::stringstream ff2;
2121  ff2 << "TLc2_" << rank << ".txt";
2122  TLc2.print_to_file( ff2.str().c_str() );
2123  std::stringstream ffv2;
2124  ffv2 << "TLv2_" << rank << ".txt";
2125  TLv2.print_to_file( ffv2.str().c_str() );
2126 #endif
2127  // first create vertices, and make a map from origin processor, and index, to entity handle
2128  // (index in TLv2 )
2129  Tag ghostTag;
2130  int orig_proc = -1;
2131  rval = m_interface->tag_get_handle( "ORIG_PROC", 1, MB_TYPE_INTEGER, ghostTag, MB_TAG_DENSE | MB_TAG_CREAT,
2132  &orig_proc );MB_CHK_ERR( rval );
2133 
2134  int nvNew = TLv2.get_n();
2135  // if number of vertices to be created is 0, it means there is no need of ghost intx cells,
2136  // because everything matched perfectly (it can happen in manufactured cases)
2137  if( 0 == nvNew ) return MB_SUCCESS;
2138  // create a vertex h for each coordinate
2139  Range newVerts;
2140  rval = m_interface->create_vertices( &( TLv2.vr_rd[0] ), nvNew, newVerts );MB_CHK_ERR( rval );
2141  // now create a map from index , org proc, to actual entity handle corresponding to it
2142  std::map< int, std::map< int, EntityHandle > > vertexPerProcAndIndex;
2143  for( int i = 0; i < nvNew; i++ )
2144  {
2145  int orgProc = TLv2.vi_rd[3 * i + 1];
2146  int indexInVert = TLv2.vi_rd[3 * i + 2];
2147  vertexPerProcAndIndex[orgProc][indexInVert] = newVerts[i];
2148  }
2149 
2150  // new polygons will receive a dense tag, with default value -1, with the processor task they
2151  // originally belonged to
2152 
2153  // now form the needed cells, in order
2154  Range newPolygons;
2155  int ne = TLc2.get_n();
2156  for( int i = 0; i < ne; i++ )
2157  {
2158  int orgProc = TLc2.vi_rd[i * sizeTuple2 + 1]; // this cell is coming from here, originally
2159  int sourceID = TLc2.vi_rd[i * sizeTuple2 + 2]; // source parent of the intx cell
2160  int targetID = TLc2.vi_wr[i * sizeTuple2 + 3]; // target parent of intx cell
2161  int nve = TLc2.vi_wr[i * sizeTuple2 + 4]; // number of vertices for the polygon
2162  std::vector< EntityHandle > conn;
2163  conn.resize( nve );
2164  for( int j = 0; j < nve; j++ )
2165  {
2166  int indexV = TLc2.vi_wr[i * sizeTuple2 + 5 + j];
2167  EntityHandle vh = vertexPerProcAndIndex[orgProc][indexV];
2168  conn[j] = vh;
2169  }
2170  EntityHandle polyNew;
2171  rval = m_interface->create_element( MBPOLYGON, &conn[0], nve, polyNew );MB_CHK_ERR( rval );
2172  newPolygons.insert( polyNew );
2173  rval = m_interface->tag_set_data( targetParentTag, &polyNew, 1, &targetID );MB_CHK_ERR( rval );
2174  rval = m_interface->tag_set_data( sourceParentTag, &polyNew, 1, &sourceID );MB_CHK_ERR( rval );
2175  rval = m_interface->tag_set_data( ghostTag, &polyNew, 1, &orgProc );MB_CHK_ERR( rval );
2176  }
2177 
2178 #ifdef VERBOSE
2179  EntityHandle tmpSet3;
2180  rval = m_interface->create_meshset( MESHSET_SET, tmpSet3 );MB_CHK_SET_ERR( rval, "Can't create temporary set3" );
2181  // add the boundary set and edges, and save it to a file
2182  rval = m_interface->add_entities( tmpSet3, newPolygons );MB_CHK_SET_ERR( rval, "Can't add entities" );
2183 
2184  std::stringstream ffs4;
2185  ffs4 << "extraIntxCells" << rank << ".h5m";
2186  rval = m_interface->write_mesh( ffs4.str().c_str(), &tmpSet3, 1 );MB_CHK_ERR( rval );
2187 #endif
2188 
2189  // add the new polygons to the overlap set
2190  // these will be ghosted, so will participate in conservation only
2191  rval = m_interface->add_entities( m_overlap_set, newPolygons );MB_CHK_ERR( rval );
2192  return MB_SUCCESS;
2193 }
2194 
2195 #endif
2196 
2198 {
2199  Tag maskTag;
2200  // it should have been created already, if not, we might have a problem
2201  int def_val = 1;
2202  ErrorCode rval =
2203  m_interface->tag_get_handle( "GRID_IMASK", 1, MB_TYPE_INTEGER, maskTag, MB_TAG_DENSE | MB_TAG_CREAT, &def_val );MB_CHK_SET_ERR( rval, "Trouble creating GRID_IMASK tag" );
2204 
2205  switch( ctx )
2206  {
2207  case Remapper::SourceMesh: {
2208  if( point_cloud_source )
2209  {
2210  masks.resize( m_source_vertices.size() );
2211  rval = m_interface->tag_get_data( maskTag, m_source_vertices, &masks[0] );MB_CHK_SET_ERR( rval, "Trouble getting GRID_IMASK tag" );
2212  }
2213  else
2214  {
2215  masks.resize( m_source_entities.size() );
2216  rval = m_interface->tag_get_data( maskTag, m_source_entities, &masks[0] );MB_CHK_SET_ERR( rval, "Trouble getting GRID_IMASK tag" );
2217  }
2218  return MB_SUCCESS;
2219  }
2220  case Remapper::TargetMesh: {
2221  if( point_cloud_target )
2222  {
2223  masks.resize( m_target_vertices.size() );
2224  rval = m_interface->tag_get_data( maskTag, m_target_vertices, &masks[0] );MB_CHK_SET_ERR( rval, "Trouble getting GRID_IMASK tag" );
2225  }
2226  else
2227  {
2228  masks.resize( m_target_entities.size() );
2229  rval = m_interface->tag_get_data( maskTag, m_target_entities, &masks[0] );MB_CHK_SET_ERR( rval, "Trouble getting GRID_IMASK tag" );
2230  }
2231  return MB_SUCCESS;
2232  }
2234  case Remapper::OverlapMesh:
2235  default:
2236  return MB_SUCCESS;
2237  }
2238 }
2239 
2240 } // namespace moab