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