Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
moab::Intx2Mesh Class Referenceabstract

#include <Intx2Mesh.hpp>

+ Inheritance diagram for moab::Intx2Mesh:
+ Collaboration diagram for moab::Intx2Mesh:

Public Member Functions

 Intx2Mesh (Interface *mbimpl)
 
virtual ~Intx2Mesh ()
 
ErrorCode intersect_meshes (EntityHandle mbs1, EntityHandle mbs2, EntityHandle &outputSet)
 
ErrorCode intersect_meshes_kdtree (EntityHandle mbset1, EntityHandle mbset2, EntityHandle &outputSet)
 
virtual ErrorCode computeIntersectionBetweenTgtAndSrc (EntityHandle tgt, EntityHandle src, double *P, int &nP, double &area, int markb[MAXEDGES], int markr[MAXEDGES], int &nsidesSrc, int &nsidesTgt, bool check_boxes_first=false)=0
 
virtual ErrorCode findNodes (EntityHandle tgt, int nsTgt, EntityHandle src, int nsSrc, double *iP, int nP)=0
 
virtual double setup_tgt_cell (EntityHandle tgt, int &nsTgt)=0
 
virtual ErrorCode FindMaxEdgesInSet (EntityHandle eset, int &max_edges)
 
virtual ErrorCode FindMaxEdges (EntityHandle set1, EntityHandle set2)
 
virtual ErrorCode createTags ()
 
virtual ErrorCode filterByMask (Range &cells)
 
ErrorCode DetermineOrderedNeighbors (EntityHandle inputSet, int max_edges, Tag &neighTag)
 
void set_error_tolerance (double eps)
 
void clean ()
 
void set_box_error (double berror)
 
ErrorCode create_departure_mesh_2nd_alg (EntityHandle &euler_set, EntityHandle &covering_lagr_set)
 
ErrorCode create_departure_mesh_3rd_alg (EntityHandle &lagr_set, EntityHandle &covering_set)
 
void correct_polygon (EntityHandle *foundIds, int &nP)
 

Protected Attributes

Interfacemb
 
EntityHandle mbs1
 
EntityHandle mbs2
 
Range rs1
 
Range rs2
 
EntityHandle outSet
 
Tag gid
 
Tag TgtFlagTag
 
Range TgtEdges
 
Tag tgtParentTag
 
Tag srcParentTag
 
Tag countTag
 
Tag srcNeighTag
 
Tag tgtNeighTag
 
Tag neighTgtEdgeTag
 
Tag orgSendProcTag
 
Tag imaskTag
 for coverage mesh, will store the original sender More...
 
const EntityHandletgtConn
 
const EntityHandlesrcConn
 
CartVect tgtCoords [MAXEDGES]
 
CartVect srcCoords [MAXEDGES]
 
double tgtCoords2D [MAXEDGES2]
 
double srcCoords2D [MAXEDGES2]
 
std::vector< std::vector< EntityHandle > * > extraNodesVec
 
double epsilon_1
 
double epsilon_area
 
std::vector< double > allBoxes
 
double box_error
 
EntityHandle localRoot
 
Range localEnts
 
unsigned int my_rank
 
int max_edges_1
 
int max_edges_2
 
int counting
 

Detailed Description

Definition at line 55 of file Intx2Mesh.hpp.

Constructor & Destructor Documentation

◆ Intx2Mesh()

moab::Intx2Mesh::Intx2Mesh ( Interface mbimpl)

Definition at line 42 of file Intx2Mesh.cpp.

43  : mb( mbimpl ), mbs1( 0 ), mbs2( 0 ), outSet( 0 ), gid( 0 ), TgtFlagTag( 0 ), tgtParentTag( 0 ), srcParentTag( 0 ),
44  countTag( 0 ), srcNeighTag( 0 ), tgtNeighTag( 0 ), neighTgtEdgeTag( 0 ), orgSendProcTag( 0 ), imaskTag( 0 ),
45  tgtConn( nullptr ), srcConn( nullptr ), epsilon_1( 0.0 ), epsilon_area( 0.0 ), box_error( 0.0 ), localRoot( 0 ),
46  my_rank( 0 )
47 #ifdef MOAB_HAVE_MPI
48  ,
49  parcomm( nullptr ), remote_cells( nullptr ), remote_cells_with_tracers( nullptr )
50 #endif
51  ,
52  max_edges_1( 0 ), max_edges_2( 0 ), counting( 0 )
53 {
54  gid = mbimpl->globalId_tag();
55 }

References gid, and moab::Interface::globalId_tag().

◆ ~Intx2Mesh()

moab::Intx2Mesh::~Intx2Mesh ( )
virtual

Definition at line 57 of file Intx2Mesh.cpp.

58 {
59  // TODO Auto-generated destructor stub
60 #ifdef MOAB_HAVE_MPI
61  if( remote_cells )
62  {
63  delete remote_cells;
64  remote_cells = nullptr;
65  }
66 #endif
67 }

Member Function Documentation

◆ clean()

void moab::Intx2Mesh::clean ( )

Definition at line 1004 of file Intx2Mesh.cpp.

1005 {
1006  //
1007  int indx = 0;
1008  for( Range::iterator eit = TgtEdges.begin(); eit != TgtEdges.end(); ++eit, indx++ )
1009  {
1010  delete extraNodesVec[indx];
1011  }
1012  // extraNodesMap.clear();
1013  extraNodesVec.clear();
1014  // also, delete some bit tags, used to mark processed tgts and srcs
1015  mb->tag_delete( TgtFlagTag );
1016  counting = 0; // reset counting to original value
1017 }

References moab::Range::begin(), counting, moab::Range::end(), extraNodesVec, mb, moab::Interface::tag_delete(), TgtEdges, and TgtFlagTag.

Referenced by intersect_meshes(), and intersect_meshes_kdtree().

◆ computeIntersectionBetweenTgtAndSrc()

virtual ErrorCode moab::Intx2Mesh::computeIntersectionBetweenTgtAndSrc ( EntityHandle  tgt,
EntityHandle  src,
double *  P,
int &  nP,
double &  area,
int  markb[MAXEDGES],
int  markr[MAXEDGES],
int &  nsidesSrc,
int &  nsidesTgt,
bool  check_boxes_first = false 
)
pure virtual

◆ correct_polygon()

void moab::Intx2Mesh::correct_polygon ( EntityHandle foundIds,
int &  nP 
)

Definition at line 1022 of file Intx2Mesh.cpp.

1023 {
1024  int i = 0;
1025  while( i < nP )
1026  {
1027  int nextIndex = ( i + 1 ) % nP;
1028  if( nodes[i] == nodes[nextIndex] )
1029  {
1030 #ifdef ENABLE_DEBUG
1031  // we need to reduce nP, and collapse nodes
1032  if( dbg_1 )
1033  {
1034  std::cout << " nodes duplicated in list: ";
1035  for( int j = 0; j < nP; j++ )
1036  std::cout << nodes[j] << " ";
1037  std::cout << "\n";
1038  std::cout << " node " << nodes[i] << " at index " << i << " is duplicated" << "\n";
1039  }
1040 #endif
1041  // this will work even if we start from 1 2 3 1; when i is 3, we find nextIndex is 0,
1042  // then next thing does nothing
1043  // (nP-1 is 3, so k is already >= nP-1); it will result in nodes -> 1, 2, 3
1044  for( int k = i; k < nP - 1; k++ )
1045  nodes[k] = nodes[k + 1];
1046  nP--; // decrease the number of nodes; also, decrease i, just if we may need to check
1047  // again
1048  i--;
1049  }
1050  i++;
1051  }
1052  return;
1053 }

Referenced by moab::Intx2MeshInPlane::findNodes(), moab::Intx2MeshOnSphere::findNodes(), and moab::IntxRllCssphere::findNodes().

◆ create_departure_mesh_2nd_alg()

ErrorCode moab::Intx2Mesh::create_departure_mesh_2nd_alg ( EntityHandle euler_set,
EntityHandle covering_lagr_set 
)

◆ create_departure_mesh_3rd_alg()

ErrorCode moab::Intx2Mesh::create_departure_mesh_3rd_alg ( EntityHandle lagr_set,
EntityHandle covering_set 
)

◆ createTags()

ErrorCode moab::Intx2Mesh::createTags ( )
virtual

Definition at line 107 of file Intx2Mesh.cpp.

108 {
111  if( countTag ) mb->tag_delete( countTag );
112 
113  unsigned char def_data_bit = 0; // unused by default
114  // maybe the tgt tag is better to be deleted every time, and recreated;
115  // or is it easy to set all values to something again? like 0?
116  MB_CHK_SET_ERR( mb->tag_get_handle( "tgtFlag", 1, MB_TYPE_BIT, TgtFlagTag, MB_TAG_CREAT, &def_data_bit ),
117  "can't get tgt flag tag" );
118  // create tgt edges if they do not exist yet; so when they are looked upon, they are found
119  // this is the only call that is potentially NlogN, in the whole method
120  MB_CHK_SET_ERR( mb->get_adjacencies( rs2, 1, true, TgtEdges, Interface::UNION ), "can't get adjacent tgt edges" );
121 
122  // now, create a map from each edge to a list of potential new nodes on a tgt edge
123  // this memory has to be cleaned up
124  // change it to a vector, and use the index in range of tgt edges
125  int indx = 0;
126  extraNodesVec.resize( TgtEdges.size() );
127  for( Range::iterator eit = TgtEdges.begin(); eit != TgtEdges.end(); ++eit, indx++ )
128  {
129  std::vector< EntityHandle >* nv = new std::vector< EntityHandle >;
130  extraNodesVec[indx] = nv;
131  }
132 
133  int defaultInt = -1;
134 
136  &defaultInt ),
137  "can't create TargetParent tag" );
138 
140  &defaultInt ),
141  "can't create SourceParent tag" );
142 
144  &defaultInt ),
145  "can't create Counting tag" );
146 
147  // for each cell in set 1, determine its neigh in set 1 (could be nullptr too)
148  // for each cell in set 2, determine its neigh in set 2 (if on boundary, could be 0)
150  "can't determine neighbors for set 1" );
152  "can't determine neighbors for set 2" );
153 
154  // for tgt cells, save a dense tag with the bordering edges, so we do not have to search for
155  // them each time edges were for sure created before (tgtEdges)
156  std::vector< EntityHandle > zeroh( max_edges_2, 0 );
157  // if we have a tag with this name, it could be of a different size, so delete it if it exists
158  if( mb->tag_get_handle( "__tgtEdgeNeighbors", neighTgtEdgeTag ) == MB_SUCCESS ) mb->tag_delete( neighTgtEdgeTag );
160  MB_TAG_DENSE | MB_TAG_CREAT, &zeroh[0] ),
161  "can't create target edge neighbors tag" );
162  for( Range::iterator rit = rs2.begin(); rit != rs2.end(); ++rit )
163  {
164  EntityHandle tgtCell = *rit;
165  int num_nodes = 0;
166  MB_CHK_SET_ERR( mb->get_connectivity( tgtCell, tgtConn, num_nodes ), "can't get target connectivity" );
167  // account for padded polygons
168  while( tgtConn[num_nodes - 2] == tgtConn[num_nodes - 1] && num_nodes > 3 )
169  num_nodes--;
170 
171  int i = 0;
172  for( i = 0; i < num_nodes; i++ )
173  {
174  EntityHandle v[2] = { tgtConn[i],
175  tgtConn[( i + 1 ) % num_nodes] }; // this is fine even for padded polygons
176  std::vector< EntityHandle > adj_entities;
177  MB_CHK_SET_ERR( mb->get_adjacencies( v, 2, 1, false, adj_entities, Interface::INTERSECT ),
178  "can't get adjacencies" );
179  if( !adj_entities.size() ) MB_CHK_SET_ERR( MB_FAILURE, "no adjacencies found" ); // get out , big error
180  zeroh[i] = adj_entities[0]; // should be only one edge between 2 nodes
181  // also, even if number of edges is less than max_edges_2, they will be ignored, even if
182  // the tag is dense
183  }
184  // zero out the rest
185  for( i = num_nodes; i < max_edges_2; i++ )
186  zeroh[i] = 0;
187  // now set the value of the tag
188  MB_CHK_SET_ERR( mb->tag_set_data( neighTgtEdgeTag, &tgtCell, 1, &( zeroh[0] ) ),
189  "can't set edge target edge neighbors tag" );
190  }
191  return MB_SUCCESS;
192 }

References moab::Range::begin(), countTag, DetermineOrderedNeighbors(), moab::Range::end(), extraNodesVec, moab::Interface::get_adjacencies(), moab::Interface::get_connectivity(), moab::Interface::INTERSECT, max_edges_1, max_edges_2, mb, MB_CHK_SET_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_BIT, MB_TYPE_HANDLE, MB_TYPE_INTEGER, mbs1, mbs2, neighTgtEdgeTag, rs2, moab::Range::size(), srcNeighTag, srcParentTag, moab::Interface::tag_delete(), moab::Interface::tag_get_handle(), moab::Interface::tag_set_data(), tgtConn, TgtEdges, TgtFlagTag, tgtNeighTag, tgtParentTag, and moab::Interface::UNION.

Referenced by intersect_meshes().

◆ DetermineOrderedNeighbors()

ErrorCode moab::Intx2Mesh::DetermineOrderedNeighbors ( EntityHandle  inputSet,
int  max_edges,
Tag neighTag 
)

Definition at line 194 of file Intx2Mesh.cpp.

195 {
196  Range cells;
197  MB_CHK_SET_ERR( mb->get_entities_by_dimension( inputSet, 2, cells ), "can't get cells in set" );
198 
199  std::vector< EntityHandle > neighbors( max_edges );
200  std::vector< EntityHandle > zeroh( max_edges, 0 );
201  // nameless tag, as the name is not important; we will have 2 related tags, but one on tgt mesh,
202  // one on src mesh
204  &zeroh[0] ),
205  "can't create neighbors tag" );
206 
207  for( Range::iterator cit = cells.begin(); cit != cells.end(); ++cit )
208  {
209  EntityHandle cell = *cit;
210  int nnodes = 3;
211  // will get the nnodes ordered neighbors;
212  // first cell is for nodes 0, 1, second to 1, 2, third to 2, 3, last to nnodes-1,
213  const EntityHandle* conn4;
214  MB_CHK_SET_ERR( mb->get_connectivity( cell, conn4, nnodes ), "can't get connectivity of a cell" );
215  int nsides = nnodes;
216  // account for possible padded polygons
217  while( conn4[nsides - 2] == conn4[nsides - 1] && nsides > 3 )
218  nsides--;
219 
220  for( int i = 0; i < nsides; i++ )
221  {
222  EntityHandle v[2];
223  v[0] = conn4[i];
224  v[1] = conn4[( i + 1 ) % nsides];
225  // get all cells adjacent to these 2 vertices on the edge
226  std::vector< EntityHandle > adjcells;
227  std::vector< EntityHandle > cellsInSet;
228  MB_CHK_SET_ERR( mb->get_adjacencies( v, 2, 2, false, adjcells, Interface::INTERSECT ),
229  "can't get adjacency to 2 verts" );
230  // now look for the cells contained in the input set;
231  // the input set should be a correct mesh, not overlapping cells, and manifold
232  size_t siz = adjcells.size();
233  for( size_t j = 0; j < siz; j++ )
234  if( mb->contains_entities( inputSet, &( adjcells[j] ), 1 ) ) cellsInSet.push_back( adjcells[j] );
235  siz = cellsInSet.size();
236 
237  if( siz > 2 )
238  {
239  std::cout << "non manifold mesh, error" << mb->list_entities( &( cellsInSet[0] ), cellsInSet.size() )
240  << std::endl;
241  MB_CHK_SET_ERR( MB_FAILURE, "non-manifold input mesh set" ); // non-manifold
242  }
243  if( siz == 1 )
244  {
245  // it must be the border of the input mesh;
246  neighbors[i] = 0; // we are guaranteed that ids are !=0; this is marking a border
247  // borders do not appear for a sphere in serial, but they do appear for
248  // parallel processing anyway
249  continue;
250  }
251  // here siz ==2, it is either the first or second
252  if( cell == cellsInSet[0] )
253  neighbors[i] = cellsInSet[1];
254  else
255  neighbors[i] = cellsInSet[0];
256  }
257  // fill the rest with 0
258  for( int i = nsides; i < max_edges; i++ )
259  neighbors[i] = 0;
260  // now simply set the neighbors tag; the last few positions will not be used, but for
261  // simplicity will keep them all (MAXEDGES)
262  MB_CHK_SET_ERR( mb->tag_set_data( neighTag, &cell, 1, &neighbors[0] ), "can't set neighbors tag" );
263  }
264  return MB_SUCCESS;
265 }

References moab::Range::begin(), moab::Interface::contains_entities(), moab::Range::end(), moab::Interface::get_adjacencies(), moab::Interface::get_connectivity(), moab::Interface::get_entities_by_dimension(), moab::Interface::INTERSECT, moab::Interface::list_entities(), mb, MB_CHK_SET_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_HANDLE, moab::Interface::tag_get_handle(), and moab::Interface::tag_set_data().

Referenced by createTags().

◆ filterByMask()

ErrorCode moab::Intx2Mesh::filterByMask ( Range cells)
virtual

Definition at line 985 of file Intx2Mesh.cpp.

986 {
987  if( !imaskTag ) return MB_SUCCESS; // nothing to do
988  size_t sz = cells.size();
989  std::vector< int > masks( sz );
990 
991  MB_CHK_SET_ERR( mb->tag_get_data( imaskTag, cells, &masks[0] ), "can't get mask tag" );
992  Range cellsToRemove;
993  size_t indx = 0;
994  for( Range::iterator eit = cells.begin(); eit != cells.end(); ++eit, ++indx )
995  {
996  if( masks[indx] ) continue;
997  cellsToRemove.insert( *eit );
998  }
999  cells = subtract( cells, cellsToRemove );
1000  return MB_SUCCESS;
1001 }

References moab::Range::begin(), moab::Range::end(), imaskTag, moab::Range::insert(), mb, MB_CHK_SET_ERR, MB_SUCCESS, moab::Range::size(), moab::subtract(), and moab::Interface::tag_get_data().

Referenced by intersect_meshes(), and intersect_meshes_kdtree().

◆ FindMaxEdges()

ErrorCode moab::Intx2Mesh::FindMaxEdges ( EntityHandle  set1,
EntityHandle  set2 
)
virtual

Definition at line 99 of file Intx2Mesh.cpp.

100 {
101  MB_CHK_SET_ERR( FindMaxEdgesInSet( set1, max_edges_1 ), "can't determine max_edges in set 1" );
102  MB_CHK_SET_ERR( FindMaxEdgesInSet( set2, max_edges_2 ), "can't determine max_edges in set 2" );
103 
104  return MB_SUCCESS;
105 }

References FindMaxEdgesInSet(), max_edges_1, max_edges_2, MB_CHK_SET_ERR, and MB_SUCCESS.

Referenced by moab::TempestRemapper::ConstructCoveringSet(), and main().

◆ FindMaxEdgesInSet()

ErrorCode moab::Intx2Mesh::FindMaxEdgesInSet ( EntityHandle  eset,
int &  max_edges 
)
virtual

Definition at line 69 of file Intx2Mesh.cpp.

70 {
71  Range cells;
72  MB_CHK_SET_ERR( mb->get_entities_by_dimension( eset, 2, cells ), "can't get entities by dimension" );
73 
74  max_edges = 0; // can be 0 for point clouds
75  for( Range::iterator cit = cells.begin(); cit != cells.end(); ++cit )
76  {
77  EntityHandle cell = *cit;
78  const EntityHandle* conn4;
79  int nnodes = 3;
80  MB_CHK_SET_ERR( mb->get_connectivity( cell, conn4, nnodes ), "can't get connectivity of a cell" );
81  if( nnodes > max_edges ) max_edges = nnodes;
82  }
83  // if in parallel, communicate the actual max_edges; it is not needed for tgt mesh (to be
84  // global) but it is better to be consistent
85 #ifdef MOAB_HAVE_MPI
86  if( parcomm )
87  {
88  int local_max_edges = max_edges;
89  // now reduce max_edges over all processors
90  int mpi_err =
91  MPI_Allreduce( &local_max_edges, &max_edges, 1, MPI_INT, MPI_MAX, parcomm->proc_config().proc_comm() );
92  if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
93  }
94 #endif
95 
96  return MB_SUCCESS;
97 }

References moab::Range::begin(), moab::Range::end(), moab::Interface::get_connectivity(), moab::Interface::get_entities_by_dimension(), mb, MB_CHK_SET_ERR, and MB_SUCCESS.

Referenced by FindMaxEdges().

◆ findNodes()

virtual ErrorCode moab::Intx2Mesh::findNodes ( EntityHandle  tgt,
int  nsTgt,
EntityHandle  src,
int  nsSrc,
double *  iP,
int  nP 
)
pure virtual

◆ intersect_meshes()

ErrorCode moab::Intx2Mesh::intersect_meshes ( EntityHandle  mbs1,
EntityHandle  mbs2,
EntityHandle outputSet 
)

Definition at line 559 of file Intx2Mesh.cpp.

560 {
561  mbs1 = mbset1; // set 1 is departure, and it is completely covering the euler set on proc
562  mbs2 = mbset2;
563  outSet = outputSet;
564 #ifdef VERBOSE
565  std::stringstream ffs, fft;
566  ffs << "source_rank0" << my_rank << ".vtk";
567  MB_CHK_SET_ERR( mb->write_mesh( ffs.str().c_str(), &mbset1, 1 ), "can't write source mesh" );
568  fft << "target_rank0" << my_rank << ".vtk";
569  MB_CHK_SET_ERR( mb->write_mesh( fft.str().c_str(), &mbset2, 1 ), "can't write target mesh" );
570 
571 #endif
572  // really, should be something from t1 and t2; src is 1 (lagrange), tgt is 2 (euler)
573 
574  EntityHandle startSrc = 0, startTgt = 0;
575 
576  MB_CHK_SET_ERR( mb->get_entities_by_dimension( mbs1, 2, rs1 ), "can't get source entities by dimension" );
577  MB_CHK_SET_ERR( mb->get_entities_by_dimension( mbs2, 2, rs2 ), "can't get target entities by dimension" );
578 
579  // filter rs1 and rs2 by mask; remove everything with 0 mask
580  // get the mask tag if it exists; if not, leave it uninitialized (nullptr)
581  ErrorCode rval = mb->tag_get_handle( "GRID_IMASK", imaskTag );
582  if( imaskTag != nullptr && rval != MB_SUCCESS ) MB_CHK_SET_ERR( rval, "can't get GRID_IMASK tag" );
583 
584  MB_CHK_SET_ERR( filterByMask( rs1 ), "can't filter source by mask" );
585  MB_CHK_SET_ERR( filterByMask( rs2 ), "can't filter target by mask" );
586 
587  createTags(); // will also determine max_edges_1, max_edges_2 (for src and tgt meshes)
588 
589  Range rs22 = rs2; // a copy of the initial range; we will remove from it elements as we
590  // advance ; rs2 is needed for marking the polygon to the tgt parent
591 
592  // create the local kdd tree with source elements; will use it to search
593  // more efficiently for the seeds in advancing front;
594  // some of the target cells will not be covered by source cells, and they need to be eliminated
595  // early from contention
596  FileOptions kdOpts( "PLANE_SET=1;SPLITS_PER_DIR=2;SPHERICAL;RADIUS=1.0;" );
597  AdaptiveKDTree kd( mb );
598  kd.parse_options( kdOpts );
599  EntityHandle tree_root = 0;
600 
601  // build a kd tree with the rs1 (source) cells
602  MB_CHK_SET_ERR( kd.build_tree( rs1, &tree_root ), "can't build kd tree on source cells" );
603 #if defined( ENABLE_DEBUG )
604  for( auto it = rs22.begin(); it != rs22.end(); ++it )
605  {
606  EntityHandle cell = *it;
607  const EntityHandle* conn = nullptr;
608  int nnodes = 0;
609  rval = mb->get_connectivity( cell, conn, nnodes );MB_CHK_ERR( rval );
610  std::cout << " cell: \t" << " ht:" << mb->id_from_handle( cell ) << " nodes: " << nnodes
611  << " gt:" << global_id_ent( mb, cell, gid ) << " stat: " << char_stat_ent( mb, cell, TgtFlagTag )
612  << "\n";
613  }
614 #endif
615 
616  while( !rs22.empty() )
617  {
618 #if defined( ENABLE_DEBUG ) || defined( VERBOSE )
619  if( rs22.size() < rs2.size() )
620  {
621  std::cout << " possible not connected arrival mesh; my_rank: " << my_rank << " counting: " << counting
622  << " rs22.size():" << rs22.size() << "\n";
623  std::stringstream ffo;
624  ffo << "file0" << counting << "rank0" << my_rank << ".h5m";
625  MB_CHK_SET_ERR( mb->write_mesh( ffo.str().c_str(), &outSet, 1 ), "can't write output mesh" );
626  for( auto it = rs22.begin(); it != rs22.end(); ++it )
627  {
628  EntityHandle cell = *it;
629  const EntityHandle* conn = nullptr;
630  int nnodes = 0;
631  rval = mb->get_connectivity( cell, conn, nnodes );MB_CHK_ERR( rval );
632  std::cout << " cell: \t" << " ht:" << mb->id_from_handle( cell ) << " nodes: " << nnodes
633  << " g:" << global_id_ent( mb, cell, gid )
634  << " stat: " << char_stat_ent( mb, cell, TgtFlagTag ) << "\n";
635  }
636  }
637 #endif
638  bool seedFound = false;
639  Range verified_seeds;
640  for( Range::reverse_iterator it = rs22.rbegin(); it != rs22.rend(); ++it )
641  {
642  startTgt = *it;
643  unsigned char status = 0;
644  rval = mb->tag_get_data( TgtFlagTag, &startTgt, 1, &status );MB_CHK_ERR( rval );
645  if( 1 == status )
646  {
647  verified_seeds.insert( startTgt );
648  continue;
649  }
650  int found = 0;
651  // find vertex positions
652  const EntityHandle* conn = nullptr;
653  int nnodes = 0;
654  MB_CHK_SET_ERR( mb->get_connectivity( startTgt, conn, nnodes ), "can't get target connectivity" );
655  // find leaves close to those positions
656  std::vector< double > positions;
657  positions.resize( nnodes * 3 );
658  MB_CHK_SET_ERR( mb->get_coords( conn, nnodes, &positions[0] ), "can't get target coordinates" );
659  // find leaves within a distance from each vertex of target
660  // in those leaves, collect all cells; we will try for an intx in there, instead of
661  // looping over all rs1 cells, as before
662  Range close_source_cells;
663  std::vector< EntityHandle > leaves;
664  for( int i = 0; i < nnodes; i++ )
665  {
666  leaves.clear();
667  MB_CHK_SET_ERR( kd.distance_search( &positions[3 * i], epsilon_1, leaves, epsilon_1, epsilon_1 ),
668  "can't search for leaves" );
669 
670  for( std::vector< EntityHandle >::iterator j = leaves.begin(); j != leaves.end(); ++j )
671  {
672  Range tmp;
673  MB_CHK_SET_ERR( mb->get_entities_by_dimension( *j, 2, tmp ), "can't get entities by dimension" );
674 
675  close_source_cells.merge( tmp.begin(), tmp.end() );
676  }
677  }
678 
679  for( Range::iterator it2 = close_source_cells.begin(); it2 != close_source_cells.end() && !found; ++it2 )
680  {
681  startSrc = *it2;
682  double area = 0;
683  // if area is > 0 , we have intersections
684  double P[10 * MAXEDGES]; // max 8 intx points + 8 more in the polygon
685  //
686  int nP = 0;
687  int nb[MAXEDGES], nr[MAXEDGES]; // sides 3 or 4? also, check boxes first
688  int nsTgt, nsSrc;
689  MB_CHK_SET_ERR( computeIntersectionBetweenTgtAndSrc( startTgt, startSrc, P, nP, area, nb, nr, nsSrc,
690  nsTgt, true ),
691  "can't compute intersection between target and source" );
692  if( area > 0 )
693  {
694  found = 1;
695  seedFound = true;
696  break; // found 2 elements that intersect; these will be the seeds
697  }
698  }
699  if( found )
700  break;
701  else
702  {
703 #ifdef ENABLE_DEBUG
704  std::cout << " on rank " << my_rank << " target cell " << " ht:" << mb->id_from_handle( startTgt )
705  << " g:" << global_id_ent( mb, startTgt, gid ) << " not intx with any source\n";
706 #endif
707  verified_seeds.insert( startTgt );
708  }
709  }
710  rs22 = subtract( rs22, verified_seeds );
711  if( !seedFound ) continue; // continue while(!rs22.empty())
712 
713  std::queue< EntityHandle > srcQueue; // these are corresponding to Ta,
714  srcQueue.push( startSrc );
715  std::queue< EntityHandle > tgtQueue;
716  tgtQueue.push( startTgt );
717 
718  unsigned char used = 1;
719  // mark the start tgt quad as used, so it will not come back again
720  MB_CHK_SET_ERR( mb->tag_set_data( TgtFlagTag, &startTgt, 1, &used ), "can't set target flag" );
721  while( !tgtQueue.empty() )
722  {
723  // flags for the side : 0 means a src cell not found on side
724  // a paired src not found yet for the neighbors of tgt
725  Range nextSrc[MAXEDGES]; // there are new ranges of possible next src cells for
726  // seeding the side j of tgt cell
727 
728  EntityHandle currentTgt = tgtQueue.front();
729  tgtQueue.pop();
730  int nsidesTgt; // will be initialized now
731  double areaTgtCell = setup_tgt_cell( currentTgt, nsidesTgt ); // this is the area in the gnomonic plane
732  double recoveredArea = 0;
733  // get the neighbors of tgt, and if they are solved already, do not bother with that
734  // side of tgt
735  EntityHandle tgtNeighbors[MAXEDGES] = { 0 };
736  MB_CHK_SET_ERR( mb->tag_get_data( tgtNeighTag, &currentTgt, 1, tgtNeighbors ),
737  "can't get target neighbors" );
738 #ifdef ENABLE_DEBUG
739  if( dbg_1 )
740  {
741  std::cout << "Next: neighbors for current tgt nsidesTgt: " << nsidesTgt << " ";
742  for( int kk = 0; kk < nsidesTgt; kk++ )
743  {
744  if( tgtNeighbors[kk] > 0 )
745  std::cout << " ht:" << mb->id_from_handle( tgtNeighbors[kk] ) << " ";
746  else
747  std::cout << 0 << " ";
748  }
749  std::cout << std::endl;
750  }
751 #endif
752  // now get the status of neighbors; if already solved, make them 0, so not to bother
753  // anymore on that side of tgt
754  for( int j = 0; j < nsidesTgt; j++ )
755  {
756  EntityHandle tgtNeigh = tgtNeighbors[j];
757  unsigned char status = 1;
758  if( tgtNeigh == 0 ) continue;
759  MB_CHK_SET_ERR( mb->tag_get_data( TgtFlagTag, &tgtNeigh, 1, &status ),
760  "can't get target flag" ); // status 0 is unused
761  if( 1 == status ) tgtNeighbors[j] = 0; // so will not look anymore on this side of tgt
762  }
763 
764  EntityHandle currentSrc = srcQueue.front();
765  // tgt and src queues are parallel; for clarity we should have kept in the queue pairs
766  // of entity handle std::pair<EntityHandle, EntityHandle>; so just one queue, with
767  // pairs;
768  // at every moment, the queue contains pairs of cells that intersect, and they form the
769  // "advancing front"
770  srcQueue.pop();
771 
772  Range localSrc;
773  Range localSrcAlreadyTested;
774  localSrc.insert( currentSrc );
775 #ifdef VERBOSE
776  int countingStart = counting;
777 #endif
778  // will advance-front search in the neighborhood of tgt cell, until we finish processing
779  // all
780  // possible src cells; localSrc set will contain all possible src cells that cover
781  // the current tgt cell
782  while( !localSrc.empty() )
783  {
784  //
785  EntityHandle srcT = localSrc.pop_front(); // also remove from local range
786  double P[10 * MAXEDGES], area; //
787  int nP = 0;
788  int nb[MAXEDGES] = { 0 };
789  int nr[MAXEDGES] = { 0 };
790 
791  int nsidesSrc;
792  // area is in 2d, points are in 3d (on a sphere), back-projected, or in a plane
793  // intersection points could include the vertices of initial elements
794  // nb [j] = 0 means no intersection on the side j for element src (markers)
795  // nb [j] = 1 means that the side j (from j to j+1) of src poly intersects the
796  // tgt poly. A potential next poly in the tgt queue is the tgt poly that is
797  // adjacent to this side
798  MB_CHK_SET_ERR( computeIntersectionBetweenTgtAndSrc( /* tgt */ currentTgt, srcT, P, nP, area, nb, nr,
799  nsidesSrc, nsidesTgt ),
800  "can't compute intersection between target and source" );
801  localSrcAlreadyTested.insert( srcT );
802 
803  if( nP > 0 )
804  {
805 #ifdef ENABLE_DEBUG
806  std::cout << " srcT: " << " hs:" << mb->id_from_handle( srcT )
807  << " g:" << global_id_ent( mb, srcT, gid ) << " nsidesSrc:" << nsidesSrc << "\n";
808  std::cout << " currentTgt: " << " ht:" << mb->id_from_handle( currentTgt )
809  << " g:" << global_id_ent( mb, currentTgt, gid )
810  << " stat:" << char_stat_ent( mb, currentTgt, TgtFlagTag ) << " nsidesTgt:" << nsidesTgt
811  << "\n";
812  unsigned char status = 1;
813  rval = mb->tag_set_data( TgtFlagTag, &currentTgt, 1, &status );MB_CHK_ERR( rval );
814  if( dbg_1 )
815  {
816  for( int k = 0; k < nsidesSrc; k++ )
817  std::cout << " nb[" << k << "]=" << nb[k];
818  std::cout << "\n";
819  for( int k = 0; k < nsidesTgt; k++ )
820  std::cout << " nr[" << k << "]=" << nr[k];
821  std::cout << "\n";
822  }
823 #endif
824 
825  // intersection found: output P and original triangles if nP > 2
826  EntityHandle neighbors[MAXEDGES] = { 0 };
827 
828  MB_CHK_SET_ERR( mb->tag_get_data( srcNeighTag, &srcT, 1, neighbors ),
829  "failed to get the neighbors for source element " << mb->id_from_handle( srcT ) );
830 
831  Range newPotentialSrc;
832  // add neighbors to the localSrc queue, if they are not marked
833  for( int nn = 0; nn < nsidesSrc; nn++ )
834  {
835  EntityHandle neighbor = neighbors[nn];
836  if( nb[nn] > 0 ) // advance across src boundary nn
837  {
838  if( neighbor > 0 )
839  {
840  if( localSrcAlreadyTested.index( neighbor ) < 0 ) // -1
841  {
842  localSrc.insert( neighbor );
843 #ifdef ENABLE_DEBUG
844  std::cout << " local src elem " << " hs:" << mb->id_from_handle( neighbor )
845  << " for tgt:" << "ht:" << mb->id_from_handle( currentTgt ) << "\n";
846 #endif
847  }
848  }
849  else // if it is on the boundary it is a special case, maybe we need to advance more on that side,
850  // because the boundary is non-convex
851  {
852  // find the ends of edge nn, and add adjacent sources to those vertices (if they are in rs1)
853  int NumNodesSrc = 0;
854  const EntityHandle* connS;
855  rval = mb->get_connectivity( srcT, connS, NumNodesSrc );MB_CHK_SET_ERR( rval, "can't get connectivity" );
856  EntityHandle v1 = connS[nn];
857  EntityHandle v2 = connS[( nn + 1 ) % NumNodesSrc];
858  Range adjacentSourceCells1, adjacentSourceCells2;
859  rval = mb->get_adjacencies( &v1, 1, 2, false, adjacentSourceCells1 );MB_CHK_SET_ERR( rval, "can't get adjacent cells" );
860  adjacentSourceCells1 = intersect( adjacentSourceCells1, rs1 );
861  rval = mb->get_adjacencies( &v2, 1, 2, false, adjacentSourceCells2 );MB_CHK_SET_ERR( rval, "can't get adjacent cells" );
862  adjacentSourceCells2 = intersect( adjacentSourceCells2, rs1 );
863  adjacentSourceCells1.merge( adjacentSourceCells2 );
864  Range potentialSrc = subtract( adjacentSourceCells1, localSrcAlreadyTested );
865  newPotentialSrc.merge( potentialSrc );
866  }
867  }
868  }
869  // these might come from non-convex boundary
870  if( !newPotentialSrc.empty() )
871  {
872  localSrc.merge( newPotentialSrc );
873  }
874  // n(find(nc>0))=ac; % ac is starting candidate for neighbor
875  for( int nn = 0; nn < nsidesTgt; nn++ )
876  {
877  if( nr[nn] > 0 && tgtNeighbors[nn] > 0 )
878  nextSrc[nn].insert( srcT ); // potential src cell that can intersect
879  // the tgt neighbor nn
880  }
881  if( nP > 1 )
882  { // this will also construct triangles/polygons in the new mesh, if needed
883  MB_CHK_SET_ERR( findNodes( currentTgt, nsidesTgt, srcT, nsidesSrc, P, nP ),
884  "can't find nodes" );
885 #ifdef ENABLE_DEBUG
886  std::cout << " intersect: " << " ht:" << mb->id_from_handle( currentTgt ) << " "
887  << " hs:" << mb->id_from_handle( srcT )
888  << " g:" << global_id_ent( mb, currentTgt, gid ) << " "
889  << " g:" << global_id_ent( mb, srcT, gid ) << " counting: " << counting << "\n";
890 #endif
891  }
892 
893  recoveredArea += area;
894  }
895 #ifdef ENABLE_DEBUG
896  else if( dbg_1 )
897  {
898  std::cout << " tgt, src, do not intersect: " << "ht:" << mb->id_from_handle( currentTgt ) << " "
899  << "hs:" << mb->id_from_handle( srcT ) << "\n";
900  }
901 #endif
902  } // end while (!localSrc.empty())
903  recoveredArea = ( recoveredArea - areaTgtCell ) / areaTgtCell; // replace now with recovery fraction
904 #if defined( ENABLE_DEBUG ) || defined( VERBOSE )
905  if( fabs( recoveredArea ) > epsilon_1 )
906  {
907 #ifdef VERBOSE
908  std::cout << " tgt area: " << areaTgtCell << " recovered :" << recoveredArea * ( 1 + areaTgtCell )
909  << " fraction error recovery:" << recoveredArea
910  << " tgtID: " << "ht:" << mb->id_from_handle( currentTgt )
911  << " countingStart:" << countingStart << "\n";
912 #endif
913  }
914 #endif
915  // here, we are finished with tgtCurrent, take it out of the rs22 range (tgt, arrival
916  // mesh)
917  rs22.erase( currentTgt );
918 #ifdef ENABLE_DEBUG
919  std::cout << " remove cell: " << "ht:" << mb->id_from_handle( currentTgt )
920  << " g:" << global_id_ent( mb, currentTgt, gid ) << " rs22.size():" << rs22.size() << "\n";
921 #endif
922  // also, look at its neighbors, and add to the seeds a next one
923 
924  //int savedGnoPlane = plane;
925  for( int j = 0; j < nsidesTgt; j++ )
926  {
927  EntityHandle tgtNeigh = tgtNeighbors[j];
928  if( tgtNeigh == 0 || nextSrc[j].size() == 0 ) // if tgt is bigger than src, there could be no src
929  // to advance on that side
930  continue;
931  int nsidesTgt2 = 0;
932  // this also changes gnomonic plane //plane//
933  setup_tgt_cell( tgtNeigh, nsidesTgt2 ); // find possible intersection with src cell from nextSrc
934  for( Range::iterator nit = nextSrc[j].begin(); nit != nextSrc[j].end(); ++nit )
935  {
936  EntityHandle nextB = *nit;
937  // we identified tgt quad n[j] as possibly intersecting with neighbor j of the
938  // src quad
939  double P[10 * MAXEDGES], area; //
940  int nP = 0;
941  int nb[MAXEDGES] = { 0 };
942  int nr[MAXEDGES] = { 0 };
943 
944  int nsidesSrc; ///
946  /* tgt */ tgtNeigh, nextB, P, nP, area, nb, nr, nsidesSrc, nsidesTgt2 ),
947  "can't compute intersection between target and source" );
948  if( area > 0 )
949  {
950  unsigned char is_used = 0;
951  rval = mb->tag_get_data( TgtFlagTag, &tgtNeigh, 1, &is_used );MB_CHK_ERR( rval );
952  if( 0 == is_used )
953  {
954  tgtQueue.push( tgtNeigh );
955  srcQueue.push( nextB );
956 #ifdef ENABLE_DEBUG
957  if( dbg_1 )
958  std::cout << "new polys pushed: src, tgt:" << " ht:" << mb->id_from_handle( tgtNeigh )
959  << " hs:" << mb->id_from_handle( nextB ) << " counting: " << counting
960  << std::endl;
961 #endif
962  MB_CHK_SET_ERR( mb->tag_set_data( TgtFlagTag, &tgtNeigh, 1, &used ),
963  "can't set target flag" );
964  }
965  break; // so we are done with this side of tgt, we have found a proper next
966  // seed
967  }
968  }
969  }
970 
971  } // end while (!tgtQueue.empty())
972  }
973 
974  // before cleaning up , we need to settle the position of the intersection points
975  // on the boundary edges
976  // this needs to be collective, so we should maybe wait something
977 #ifdef MOAB_HAVE_MPI
978  MB_CHK_SET_ERR( resolve_intersection_sharing(), "can't resolve intersection sharing" );
979 #endif
980 
981  this->clean();
982  return MB_SUCCESS;
983 }

References moab::Range::begin(), moab::AdaptiveKDTree::build_tree(), clean(), moab::Range::clear(), computeIntersectionBetweenTgtAndSrc(), counting, createTags(), moab::AdaptiveKDTree::distance_search(), moab::Range::empty(), moab::Range::end(), epsilon_1, moab::Range::erase(), ErrorCode, filterByMask(), findNodes(), moab::Range::front(), moab::Interface::get_adjacencies(), moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::Interface::get_entities_by_dimension(), gid, moab::Interface::id_from_handle(), imaskTag, moab::Range::index(), moab::Range::insert(), moab::intersect(), MAXEDGES, mb, MB_CHK_ERR, MB_CHK_SET_ERR, MB_SUCCESS, mbs1, mbs2, moab::Range::merge(), my_rank, outSet, moab::AdaptiveKDTree::parse_options(), moab::Range::pop_front(), moab::Range::rbegin(), moab::Range::rend(), rs1, rs2, setup_tgt_cell(), moab::Range::size(), srcNeighTag, moab::subtract(), moab::Interface::tag_get_data(), moab::Interface::tag_get_handle(), moab::Interface::tag_set_data(), TgtFlagTag, tgtNeighTag, and moab::Interface::write_mesh().

Referenced by moab::TempestRemapper::ComputeOverlapMesh(), and main().

◆ intersect_meshes_kdtree()

ErrorCode moab::Intx2Mesh::intersect_meshes_kdtree ( EntityHandle  mbset1,
EntityHandle  mbset2,
EntityHandle outputSet 
)

Slow KD-tree-based mesh intersection routine (no advancing-front).

Overview:

  • Builds a KD-tree over source (mbs1) faces and, for each target (mbs2) face, queries nearby source leaves using a distance-based search around target vertices.
  • For the candidate source faces gathered from nearby KD-tree leaves, computes exact polygonal intersections in a gnomonic plane, accumulates overlap area, and creates intersection polygons/nodes in outSet via findNodes.
  • This path is intentionally simpler and potentially more expensive than the advancing-front algorithm used by intersect_meshes.

Inputs/Assumptions:

  • mbset1 (source) fully covers mbset2 (target) on the sphere.
  • Both sets contain 2D elements (triangles, quads, or generic convex polygons).
  • On-sphere intersection math is performed using gnomonic projection; tolerances are derived from maximum edge lengths on the source mesh.

High-level Steps: 1) Cache 2D entities of source (rs1) and target (rs2). Optionally filter by GRID_IMASK tag to exclude masked-out elements. 2) Precompute and tag target-edge adjacency (__tgtEdgeNeighbors) for quick access when locating/creating intersection points on target boundaries. 3) Estimate tolerances: compute maximum source edge length to derive KD-tree search tolerance and box overlap epsilon; reduce across ranks under MPI. 4) Build an AdaptiveKDTree on the source faces with spherical options (PLANE_SET=1;SPLITS_PER_DIR=2;SPHERICAL;RADIUS=1.0;). 5) For each target face:

  • Gather its vertex coordinates; compute an average edge length av_len.
  • For each target vertex, perform kd.distance_search within radius av_len to collect nearby KD-tree leaves; accumulate their contained 2D source faces into close_source_cells.
  • For each candidate source face in that range, call computeIntersectionBetweenTgtAndSrc to compute polygon intersection points and area; if area > 0, call findNodes to create nodes/polygons in outSet.
  • Track recovered area vs. the target cell area (diagnostic). 6) Under MPI, reconcile shared intersection points across process boundaries via resolve_intersection_sharing. 7) Cleanup transient state and return.

Complexity Notes:

  • Building the KD-tree is roughly O(N log N). For each target face, the search radius heuristic (av_len) aims to limit candidates; worst-case behavior can still approach quadratic if meshes overlap densely.

Key Data/Tags:

  • tgtParentTag, srcParentTag, countTag maintain provenance and counters for created intersection entities; they are (re)created in this routine.
  • __tgtEdgeNeighbors stores per-target-face edge handles to speed boundary ops.

Error handling:

  • Uses MB_CHK_ERR/MB_CHK_SET_ERR macros for MOAB ErrorCode propagation.
  • Cleans up tags and temporary state before returning on success.

Definition at line 322 of file Intx2Mesh.cpp.

323 {
324  ErrorCode rval;
325  mbs1 = mbset1; // set 1 is departure, and it is completely covering the euler set on proc
326  mbs2 = mbset2;
327  outSet = outputSet;
328  MB_CHK_SET_ERR( mb->get_entities_by_dimension( mbs1, 2, rs1 ), "can't get source entities by dimension" );
329  MB_CHK_SET_ERR( mb->get_entities_by_dimension( mbs2, 2, rs2 ), "can't get target entities by dimension" );
330  // from create tags, copy relevant ones
333  if( countTag ) mb->tag_delete( countTag );
334 
335  // filter rs1 and rs2 by mask; remove everything with 0 mask
336  // get the mask tag if it exists; if not, leave it uninitialized (nullptr)
337  rval = mb->tag_get_handle( "GRID_IMASK", imaskTag );
338  if( imaskTag != nullptr && rval != MB_SUCCESS ) MB_CHK_SET_ERR( rval, "can't get GRID_IMASK tag" );
339  MB_CHK_SET_ERR( filterByMask( rs1 ), "can't filter source by mask" );
340  MB_CHK_SET_ERR( filterByMask( rs2 ), "can't filter target by mask" );
341  // create tgt edges if they do not exist yet; so when they are looked upon, they are found
342  // this is the only call that is potentially NlogN, in the whole method
344  "can't get adjacent target edges" );
345 
346  int index = 0;
347  extraNodesVec.resize( TgtEdges.size() );
348  for( Range::iterator eit = TgtEdges.begin(); eit != TgtEdges.end(); ++eit, index++ )
349  {
350  std::vector< EntityHandle >* nv = new std::vector< EntityHandle >;
351  extraNodesVec[index] = nv;
352  }
353 
354  int defaultInt = -1;
355  // Now let us create the association tags to source and target parent, along with internal counters
357  &defaultInt ),
358  "can't create target parent tag" );
360  &defaultInt ),
361  "can't create source parent tag" );
363  &defaultInt ),
364  "can't create Counting tag" );
365 
366  // for tgt cells, save a dense tag with the bordering edges, so we do not have to search for
367  // them each time edges were for sure created before (tgtEdges)
368  // if we have a tag with this name, it could be of a different size, so delete it
369  rval = mb->tag_get_handle( "__tgtEdgeNeighbors", neighTgtEdgeTag );
371  std::vector< EntityHandle > zeroh( max_edges_2, 0 );
373  MB_TAG_DENSE | MB_TAG_CREAT, &zeroh[0] ),
374  "can't create tgt edge neighbors tag" );
375 
376  for( Range::iterator rit = rs2.begin(); rit != rs2.end(); ++rit )
377  {
378  EntityHandle tgtCell = *rit;
379  int num_nodes = 0;
380  MB_CHK_SET_ERR( mb->get_connectivity( tgtCell, tgtConn, num_nodes ), "can't get target connectivity" );
381  // account for padded polygons
382  while( tgtConn[num_nodes - 2] == tgtConn[num_nodes - 1] && num_nodes > 3 )
383  num_nodes--;
384 
385  for( int i = 0; i < num_nodes; i++ )
386  {
387  EntityHandle v[2] = { tgtConn[i],
388  tgtConn[( i + 1 ) % num_nodes] }; // this is fine even for padded polygons
389  std::vector< EntityHandle > adj_entities;
390  rval = mb->get_adjacencies( v, 2, 1, false, adj_entities, Interface::INTERSECT );
391  if( rval != MB_SUCCESS || adj_entities.size() < 1 ) return rval; // get out , big error
392  zeroh[i] = adj_entities[0]; // should be only one edge between 2 nodes
393  // also, even if number of edges is less than max_edges_2, they will be ignored, even if
394  // the tag is dense
395  }
396  // now set the value of the tag
397  MB_CHK_SET_ERR( mb->tag_set_data( neighTgtEdgeTag, &tgtCell, 1, &( zeroh[0] ) ),
398  "can't set edge target edge neighbors tag" );
399  }
400 
401  // find out max edge on source mesh;
402  double max_length = 0;
403  {
404  std::vector< double > coords( 3 * max_edges_1, 0.0 );
405  for( Range::iterator it = rs1.begin(); it != rs1.end(); ++it )
406  {
407  const EntityHandle* conn = nullptr;
408  int nnodes;
409  MB_CHK_SET_ERR( mb->get_connectivity( *it, conn, nnodes ), "can't get source connectivity" );
410  while( conn[nnodes - 2] == conn[nnodes - 1] && nnodes > 3 )
411  nnodes--;
412  MB_CHK_SET_ERR( mb->get_coords( conn, nnodes, &coords[0] ), "can't get source coordinates" );
413  for( int j = 0; j < nnodes; j++ )
414  {
415  int next = ( j + 1 ) % nnodes;
416  double edge_length =
417  ( coords[3 * j] - coords[3 * next] ) * ( coords[3 * j] - coords[3 * next] ) +
418  ( coords[3 * j + 1] - coords[3 * next + 1] ) * ( coords[3 * j + 1] - coords[3 * next + 1] ) +
419  ( coords[3 * j + 2] - coords[3 * next + 2] ) * ( coords[3 * j + 2] - coords[3 * next + 2] );
420  if( edge_length > max_length ) max_length = edge_length;
421  }
422  }
423  max_length = std::sqrt( max_length );
424  }
425 
426  // maximum sag on a spherical mesh make sense only for intx on a sphere, with radius 1 :(
427  double tolerance = 1.e-15;
428  if( max_length < 1. )
429  {
430  // basically, the sag for an arc of length max_length on a circle of radius 1
431  tolerance = 1. - sqrt( 1 - max_length * max_length / 4 );
433  tolerance = 3 * tolerance; // we use it for gnomonic plane too, projected sag could be =* sqrt(2.)
434  // be more generous, use 1.5 ~= sqrt(2.)
435 
436  if( !my_rank )
437  {
438  std::cout << " max edge length: " << max_length << " tolerance for kd tree: " << tolerance << "\n";
439  std::cout << " box overlap tolerance: " << box_error << "\n";
440  }
441  }
442 #ifdef MOAB_HAVE_MPI
443  // reduce box tolerance on every task, if needed
444  double min_box_eps = box_error;
445  if( nullptr != parcomm ) MPI_Allreduce( &box_error, &min_box_eps, 1, MPI_DOUBLE, MPI_MIN, parcomm->comm() );
446  box_error = min_box_eps;
447 #endif
448 
449  // create the kd tree on source cells, and intersect all targets in an expensive loop
450  // build a kd tree with the rs1 (source) cells
451  FileOptions kdOpts( "PLANE_SET=1;SPLITS_PER_DIR=2;SPHERICAL;RADIUS=1.0;" );
452  AdaptiveKDTree kd( mb );
453  kd.parse_options( kdOpts );
454  EntityHandle tree_root = 0;
455  MB_CHK_SET_ERR( kd.build_tree( rs1, &tree_root ), "can't build Kd-tree on source cells" );
456 
457  for( Range::iterator it = rs2.begin(); it != rs2.end(); ++it )
458  {
459  EntityHandle tcell = *it;
460  // find vertex positions
461  const EntityHandle* conn = nullptr;
462  int nnodes = 0;
463  MB_CHK_SET_ERR( mb->get_connectivity( tcell, conn, nnodes ), "can't get target connectivity" );
464  // find leaves close to those positions
465  // setup_tgt_cell is called for its side effects (populates tgtConn /
466  // redCoords[] used by computeIntersectionBetweenTgtAndSrc below);
467  // the returned gnomonic-plane area is unused on this serial path.
468  (void)setup_tgt_cell( tcell, nnodes );
469  std::vector< double > positions;
470  positions.resize( nnodes * 3 );
471  MB_CHK_SET_ERR( mb->get_coords( conn, nnodes, &positions[0] ), "can't get target coordinates" );
472 
473  // distance to search will be based on average edge length
474  double av_len = 0;
475  for( int k = 0; k < nnodes; k++ )
476  {
477  int ik = ( k + 1 ) % nnodes;
478  double len1 = 0;
479  for( int j = 0; j < 3; j++ )
480  {
481  double len2 = positions[3 * k + j] - positions[3 * ik + j];
482  len1 += len2 * len2;
483  }
484  av_len += sqrt( len1 );
485  }
486  if( nnodes > 0 ) av_len /= nnodes;
487  // find leaves within a distance from each vertex of target
488  // in those leaves, collect all cells; we will try for an intx in there
489  Range close_source_cells;
490  std::vector< EntityHandle > leaves;
491  for( int i = 0; i < nnodes; i++ )
492  {
493  leaves.clear();
494  MB_CHK_SET_ERR( kd.distance_search( &positions[3 * i], av_len, leaves, tolerance, epsilon_1 ),
495  "can't search for leaves" );
496 
497  for( std::vector< EntityHandle >::iterator j = leaves.begin(); j != leaves.end(); ++j )
498  {
499  Range tmp;
500  MB_CHK_SET_ERR( mb->get_entities_by_dimension( *j, 2, tmp ), "can't get entities by dimension" );
501 
502  close_source_cells.merge( tmp.begin(), tmp.end() );
503  }
504  }
505 #ifdef VERBOSE
506  if( close_source_cells.empty() )
507  {
508  std::cout << " there are no close source cells to target cell " << tcell
509  << " ht:" << mb->id_from_handle( tcell ) << "\n";
510  }
511 #endif
512  for( Range::iterator it2 = close_source_cells.begin(); it2 != close_source_cells.end(); ++it2 )
513  {
514  EntityHandle startSrc = *it2;
515  double area = 0;
516  // if area is > 0 , we have intersections
517  double P[10 * MAXEDGES]; // max 8 intx points + 8 more in the polygon
518  //
519  int nP = 0;
520  int nb[MAXEDGES], nr[MAXEDGES]; // sides 3 or 4? also, check boxes first
521  int nsTgt, nsSrc;
522  MB_CHK_SET_ERR( computeIntersectionBetweenTgtAndSrc( tcell, startSrc, P, nP, area, nb, nr, nsSrc, nsTgt,
523  true ),
524  "can't compute intersection between target and source" );
525  if( area > 0 )
526  {
527  if( nP > 1 )
528  { // this will also construct triangles/polygons in the new mesh, if needed
529  MB_CHK_SET_ERR( findNodes( tcell, nnodes, startSrc, nsSrc, P, nP ), "can't find nodes" );
530 #ifdef ENABLE_DEBUG
531  std::cout << " intersect: " << " ht:" << mb->id_from_handle( tcell ) << " "
532  << " hs:" << mb->id_from_handle( startSrc ) << " g:" << global_id_ent( mb, tcell, gid )
533  << " g:" << global_id_ent( mb, startSrc, gid ) << " counting: " << counting << "\n";
534 #endif
535  }
536  // (Historical: serial path used to accumulate a per-cell
537  // recoveredArea / areaTgtCell ratio here, but neither value
538  // was ever read again. The verbose-print branch for that
539  // ratio lives only in the parallel path ~lines 893-899.)
540  }
541  }
542  }
543  // before cleaning up , we need to settle the position of the intersection points
544  // on the boundary edges
545  // this needs to be collective, so we should maybe wait something
546 #ifdef MOAB_HAVE_MPI
547  if( nullptr != parcomm )
548  {
549  MB_CHK_SET_ERR( resolve_intersection_sharing(), "can't resolve intersection sharing (correct position)" );
550  }
551 #endif
552 
553  this->clean();
554  return MB_SUCCESS;
555 }

References moab::Range::begin(), box_error, moab::AdaptiveKDTree::build_tree(), clean(), moab::Range::clear(), computeIntersectionBetweenTgtAndSrc(), counting, countTag, moab::AdaptiveKDTree::distance_search(), edge_length(), moab::Range::empty(), moab::Range::end(), epsilon_1, ErrorCode, extraNodesVec, filterByMask(), findNodes(), moab::Interface::get_adjacencies(), moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::Interface::get_entities_by_dimension(), gid, moab::Interface::id_from_handle(), imaskTag, moab::index, moab::Interface::INTERSECT, max_edges_1, max_edges_2, MAXEDGES, mb, MB_CHK_SET_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_HANDLE, MB_TYPE_INTEGER, mbs1, mbs2, moab::Range::merge(), my_rank, neighTgtEdgeTag, outSet, moab::AdaptiveKDTree::parse_options(), rs1, rs2, setup_tgt_cell(), moab::Range::size(), srcParentTag, moab::Interface::tag_delete(), moab::Interface::tag_get_handle(), moab::Interface::tag_set_data(), tgtConn, TgtEdges, tgtParentTag, moab::tolerance, and moab::Interface::UNION.

Referenced by moab::TempestRemapper::ComputeOverlapMesh(), and main().

◆ set_box_error()

void moab::Intx2Mesh::set_box_error ( double  berror)
inline

Definition at line 138 of file Intx2Mesh.hpp.

139  {
140  box_error = berror;
141  }

References box_error.

Referenced by moab::TempestRemapper::ConstructCoveringSet(), and main().

◆ set_error_tolerance()

void moab::Intx2Mesh::set_error_tolerance ( double  eps)
inline

Definition at line 121 of file Intx2Mesh.hpp.

122  {
123  epsilon_1 = eps;
124  epsilon_area = eps * sqrt( eps );
125  }

References epsilon_1, and epsilon_area.

Referenced by moab::TempestRemapper::ConstructCoveringSet(), and main().

◆ setup_tgt_cell()

virtual double moab::Intx2Mesh::setup_tgt_cell ( EntityHandle  tgt,
int &  nsTgt 
)
pure virtual

Member Data Documentation

◆ allBoxes

std::vector< double > moab::Intx2Mesh::allBoxes
protected

Definition at line 249 of file Intx2Mesh.hpp.

◆ box_error

◆ counting

◆ countTag

◆ epsilon_1

◆ epsilon_area

◆ extraNodesVec

std::vector< std::vector< EntityHandle >* > moab::Intx2Mesh::extraNodesVec
protected

◆ gid

◆ imaskTag

Tag moab::Intx2Mesh::imaskTag
protected

for coverage mesh, will store the original sender

Definition at line 226 of file Intx2Mesh.hpp.

Referenced by filterByMask(), intersect_meshes(), and intersect_meshes_kdtree().

◆ localEnts

Range moab::Intx2Mesh::localEnts
protected

Definition at line 253 of file Intx2Mesh.hpp.

◆ localRoot

EntityHandle moab::Intx2Mesh::localRoot
protected

Definition at line 252 of file Intx2Mesh.hpp.

◆ max_edges_1

int moab::Intx2Mesh::max_edges_1
protected

◆ max_edges_2

int moab::Intx2Mesh::max_edges_2
protected

◆ mb

◆ mbs1

EntityHandle moab::Intx2Mesh::mbs1
protected

Definition at line 199 of file Intx2Mesh.hpp.

Referenced by createTags(), intersect_meshes(), and intersect_meshes_kdtree().

◆ mbs2

EntityHandle moab::Intx2Mesh::mbs2
protected

◆ my_rank

unsigned int moab::Intx2Mesh::my_rank
protected

◆ neighTgtEdgeTag

◆ orgSendProcTag

Tag moab::Intx2Mesh::orgSendProcTag
protected

Definition at line 225 of file Intx2Mesh.hpp.

Referenced by moab::Intx2MeshOnSphere::findNodes().

◆ outSet

◆ rs1

◆ rs2

◆ srcConn

◆ srcCoords

◆ srcCoords2D

◆ srcNeighTag

Tag moab::Intx2Mesh::srcNeighTag
protected

Definition at line 218 of file Intx2Mesh.hpp.

Referenced by createTags(), and intersect_meshes().

◆ srcParentTag

◆ tgtConn

◆ tgtCoords

◆ tgtCoords2D

◆ TgtEdges

◆ TgtFlagTag

Tag moab::Intx2Mesh::TgtFlagTag
protected

Definition at line 208 of file Intx2Mesh.hpp.

Referenced by clean(), createTags(), and intersect_meshes().

◆ tgtNeighTag

Tag moab::Intx2Mesh::tgtNeighTag
protected

Definition at line 220 of file Intx2Mesh.hpp.

Referenced by createTags(), and intersect_meshes().

◆ tgtParentTag


The documentation for this class was generated from the following files: