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 1000 of file Intx2Mesh.cpp.

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

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 1018 of file Intx2Mesh.cpp.

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

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 981 of file Intx2Mesh.cpp.

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

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 555 of file Intx2Mesh.cpp.

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

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  double areaTgtCell = setup_tgt_cell( tcell, nnodes ); // this is the area in the gnomonic plane
466  double recoveredArea = 0;
467  std::vector< double > positions;
468  positions.resize( nnodes * 3 );
469  MB_CHK_SET_ERR( mb->get_coords( conn, nnodes, &positions[0] ), "can't get target coordinates" );
470 
471  // distance to search will be based on average edge length
472  double av_len = 0;
473  for( int k = 0; k < nnodes; k++ )
474  {
475  int ik = ( k + 1 ) % nnodes;
476  double len1 = 0;
477  for( int j = 0; j < 3; j++ )
478  {
479  double len2 = positions[3 * k + j] - positions[3 * ik + j];
480  len1 += len2 * len2;
481  }
482  av_len += sqrt( len1 );
483  }
484  if( nnodes > 0 ) av_len /= nnodes;
485  // find leaves within a distance from each vertex of target
486  // in those leaves, collect all cells; we will try for an intx in there
487  Range close_source_cells;
488  std::vector< EntityHandle > leaves;
489  for( int i = 0; i < nnodes; i++ )
490  {
491  leaves.clear();
492  MB_CHK_SET_ERR( kd.distance_search( &positions[3 * i], av_len, leaves, tolerance, epsilon_1 ),
493  "can't search for leaves" );
494 
495  for( std::vector< EntityHandle >::iterator j = leaves.begin(); j != leaves.end(); ++j )
496  {
497  Range tmp;
498  MB_CHK_SET_ERR( mb->get_entities_by_dimension( *j, 2, tmp ), "can't get entities by dimension" );
499 
500  close_source_cells.merge( tmp.begin(), tmp.end() );
501  }
502  }
503 #ifdef VERBOSE
504  if( close_source_cells.empty() )
505  {
506  std::cout << " there are no close source cells to target cell " << tcell
507  << " ht:" << mb->id_from_handle( tcell ) << "\n";
508  }
509 #endif
510  for( Range::iterator it2 = close_source_cells.begin(); it2 != close_source_cells.end(); ++it2 )
511  {
512  EntityHandle startSrc = *it2;
513  double area = 0;
514  // if area is > 0 , we have intersections
515  double P[10 * MAXEDGES]; // max 8 intx points + 8 more in the polygon
516  //
517  int nP = 0;
518  int nb[MAXEDGES], nr[MAXEDGES]; // sides 3 or 4? also, check boxes first
519  int nsTgt, nsSrc;
520  MB_CHK_SET_ERR( computeIntersectionBetweenTgtAndSrc( tcell, startSrc, P, nP, area, nb, nr, nsSrc, nsTgt,
521  true ),
522  "can't compute intersection between target and source" );
523  if( area > 0 )
524  {
525  if( nP > 1 )
526  { // this will also construct triangles/polygons in the new mesh, if needed
527  MB_CHK_SET_ERR( findNodes( tcell, nnodes, startSrc, nsSrc, P, nP ), "can't find nodes" );
528 #ifdef ENABLE_DEBUG
529  std::cout << " intersect: " << " ht:" << mb->id_from_handle( tcell ) << " "
530  << " hs:" << mb->id_from_handle( startSrc ) << " g:" << global_id_ent( mb, tcell, gid )
531  << " g:" << global_id_ent( mb, startSrc, gid ) << " counting: " << counting << "\n";
532 #endif
533  }
534  recoveredArea += area;
535  }
536  }
537  recoveredArea = ( recoveredArea - areaTgtCell ) / areaTgtCell; // replace now with recovery fract
538  }
539  // before cleaning up , we need to settle the position of the intersection points
540  // on the boundary edges
541  // this needs to be collective, so we should maybe wait something
542 #ifdef MOAB_HAVE_MPI
543  if( nullptr != parcomm )
544  {
545  MB_CHK_SET_ERR( resolve_intersection_sharing(), "can't resolve intersection sharing (correct position)" );
546  }
547 #endif
548 
549  this->clean();
550  return MB_SUCCESS;
551 }

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: