Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
Intx2Mesh.cpp
Go to the documentation of this file.
1 /*
2  * Intx2Mesh.cpp
3  *
4  * Created on: Oct 2, 2012
5  */
6 
7 #include <limits>
8 #include <queue>
9 #include <sstream>
10 #include <algorithm> // std::max
11 //
13 #ifdef MOAB_HAVE_MPI
14 #include "moab/ParallelComm.hpp"
15 #include "MBParallelConventions.h"
17 #endif /* MOAB_HAVE_MPI */
18 #include "MBTagConventions.hpp"
19 #include "moab/GeomUtil.hpp"
20 #include "moab/AdaptiveKDTree.hpp"
21 
22 namespace moab
23 {
24 //#define ENABLE_DEBUG
25 #ifdef ENABLE_DEBUG
26 int dbg_1 = 1;
27 int global_id_ent( Interface* mbi, EntityHandle eh, Tag glid )
28 {
29  int gidval = 0;
30  mbi->tag_get_data( glid, &eh, 1, &gidval );
31  return gidval;
32 }
33 
34 int char_stat_ent( Interface* mbi, EntityHandle eh, Tag glid )
35 {
36  char tagval = 0;
37  mbi->tag_get_data( glid, &eh, 1, &tagval );
38  return (int)( tagval );
39 }
40 
41 #endif
42 
44  : mb( mbimpl ), mbs1( 0 ), mbs2( 0 ), outSet( 0 ), gid( 0 ), TgtFlagTag( 0 ), tgtParentTag( 0 ), srcParentTag( 0 ),
45  countTag( 0 ), srcNeighTag( 0 ), tgtNeighTag( 0 ), neighTgtEdgeTag( 0 ), orgSendProcTag( 0 ), imaskTag( 0 ),
46  tgtConn( nullptr ), srcConn( nullptr ), epsilon_1( 0.0 ), epsilon_area( 0.0 ), box_error( 0.0 ), localRoot( 0 ),
47  my_rank( 0 )
48 #ifdef MOAB_HAVE_MPI
49  ,
50  parcomm( nullptr ), remote_cells( nullptr ), remote_cells_with_tracers( nullptr )
51 #endif
52  ,
53  max_edges_1( 0 ), max_edges_2( 0 ), counting( 0 )
54 {
55  gid = mbimpl->globalId_tag();
56 }
57 
59 {
60  // TODO Auto-generated destructor stub
61 #ifdef MOAB_HAVE_MPI
62  if( remote_cells )
63  {
64  delete remote_cells;
65  remote_cells = nullptr;
66  }
67 #endif
68 }
69 
71 {
72  Range cells;
73  MB_CHK_SET_ERR( mb->get_entities_by_dimension( eset, 2, cells ), "can't get entities by dimension" );
74 
75  max_edges = 0; // can be 0 for point clouds
76  for( Range::iterator cit = cells.begin(); cit != cells.end(); ++cit )
77  {
78  EntityHandle cell = *cit;
79  const EntityHandle* conn4;
80  int nnodes = 3;
81  MB_CHK_SET_ERR( mb->get_connectivity( cell, conn4, nnodes ), "can't get connectivity of a cell" );
82  if( nnodes > max_edges ) max_edges = nnodes;
83  }
84  // if in parallel, communicate the actual max_edges; it is not needed for tgt mesh (to be
85  // global) but it is better to be consistent
86 #ifdef MOAB_HAVE_MPI
87  if( parcomm )
88  {
89  int local_max_edges = max_edges;
90  // now reduce max_edges over all processors
91  int mpi_err =
92  MPI_Allreduce( &local_max_edges, &max_edges, 1, MPI_INT, MPI_MAX, parcomm->proc_config().proc_comm() );
93  if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
94  }
95 #endif
96 
97  return MB_SUCCESS;
98 }
99 
101 {
102  MB_CHK_SET_ERR( FindMaxEdgesInSet( set1, max_edges_1 ), "can't determine max_edges in set 1" );
103  MB_CHK_SET_ERR( FindMaxEdgesInSet( set2, max_edges_2 ), "can't determine max_edges in set 2" );
104 
105  // Numerous routines below use fixed-size stack buffers dimensioned from
106  // MAXEDGES (coordinates, edge-neighbor tags, connectivity scratch, ...),
107  // but max_edges_1/2 are whatever the meshes actually contain. A cell with
108  // more vertices than MAXEDGES silently overruns those buffers, which shows
109  // up much later as corrupted geometry or a crash far from the cause.
110  // Fail here instead, where the diagnosis is obvious.
111  //
112  // Dual meshes of high-order spectral-element grids are the usual source of
113  // high-valence cells; if this triggers, either raise MAXEDGES in
114  // IntxUtils.hpp or regenerate the mesh with lower-valence cells.
115  const int max_edges = std::max( max_edges_1, max_edges_2 );
116  if( max_edges > MAXEDGES )
117  {
118  MB_SET_ERR( MB_FAILURE, "mesh contains a cell with "
119  << max_edges << " vertices, which exceeds MAXEDGES (" << MAXEDGES
120  << "); source mesh max = " << max_edges_1
121  << ", target mesh max = " << max_edges_2
122  << ". Increase MAXEDGES in moab/IntxMesh/IntxUtils.hpp and rebuild." );
123  }
124 
125  return MB_SUCCESS;
126 }
127 
129 {
132  if( countTag ) mb->tag_delete( countTag );
133 
134  unsigned char def_data_bit = 0; // unused by default
135  // maybe the tgt tag is better to be deleted every time, and recreated;
136  // or is it easy to set all values to something again? like 0?
137  MB_CHK_SET_ERR( mb->tag_get_handle( "tgtFlag", 1, MB_TYPE_BIT, TgtFlagTag, MB_TAG_CREAT, &def_data_bit ),
138  "can't get tgt flag tag" );
139  // create tgt edges if they do not exist yet; so when they are looked upon, they are found
140  // this is the only call that is potentially NlogN, in the whole method
141  MB_CHK_SET_ERR( mb->get_adjacencies( rs2, 1, true, TgtEdges, Interface::UNION ), "can't get adjacent tgt edges" );
142 
143  // now, create a map from each edge to a list of potential new nodes on a tgt edge
144  // this memory has to be cleaned up
145  // change it to a vector, and use the index in range of tgt edges
146  int indx = 0;
147  extraNodesVec.resize( TgtEdges.size() );
148  for( Range::iterator eit = TgtEdges.begin(); eit != TgtEdges.end(); ++eit, indx++ )
149  {
150  std::vector< EntityHandle >* nv = new std::vector< EntityHandle >;
151  extraNodesVec[indx] = nv;
152  }
153 
154  int defaultInt = -1;
155 
157  &defaultInt ),
158  "can't create TargetParent tag" );
159 
161  &defaultInt ),
162  "can't create SourceParent tag" );
163 
165  &defaultInt ),
166  "can't create Counting tag" );
167 
168  // for each cell in set 1, determine its neigh in set 1 (could be nullptr too)
169  // for each cell in set 2, determine its neigh in set 2 (if on boundary, could be 0)
171  "can't determine neighbors for set 1" );
173  "can't determine neighbors for set 2" );
174 
175  // for tgt cells, save a dense tag with the bordering edges, so we do not have to search for
176  // them each time edges were for sure created before (tgtEdges)
177  std::vector< EntityHandle > zeroh( max_edges_2, 0 );
178  // if we have a tag with this name, it could be of a different size, so delete it if it exists
179  if( mb->tag_get_handle( "__tgtEdgeNeighbors", neighTgtEdgeTag ) == MB_SUCCESS ) mb->tag_delete( neighTgtEdgeTag );
181  MB_TAG_DENSE | MB_TAG_CREAT, &zeroh[0] ),
182  "can't create target edge neighbors tag" );
183  for( Range::iterator rit = rs2.begin(); rit != rs2.end(); ++rit )
184  {
185  EntityHandle tgtCell = *rit;
186  int num_nodes = 0;
187  MB_CHK_SET_ERR( mb->get_connectivity( tgtCell, tgtConn, num_nodes ), "can't get target connectivity" );
188  // account for padded polygons
189  while( tgtConn[num_nodes - 2] == tgtConn[num_nodes - 1] && num_nodes > 3 )
190  num_nodes--;
191 
192  int i = 0;
193  for( i = 0; i < num_nodes; i++ )
194  {
195  EntityHandle v[2] = { tgtConn[i],
196  tgtConn[( i + 1 ) % num_nodes] }; // this is fine even for padded polygons
197  std::vector< EntityHandle > adj_entities;
198  MB_CHK_SET_ERR( mb->get_adjacencies( v, 2, 1, false, adj_entities, Interface::INTERSECT ),
199  "can't get adjacencies" );
200  if( !adj_entities.size() ) MB_CHK_SET_ERR( MB_FAILURE, "no adjacencies found" ); // get out , big error
201  zeroh[i] = adj_entities[0]; // should be only one edge between 2 nodes
202  // also, even if number of edges is less than max_edges_2, they will be ignored, even if
203  // the tag is dense
204  }
205  // zero out the rest
206  for( i = num_nodes; i < max_edges_2; i++ )
207  zeroh[i] = 0;
208  // now set the value of the tag
209  MB_CHK_SET_ERR( mb->tag_set_data( neighTgtEdgeTag, &tgtCell, 1, &( zeroh[0] ) ),
210  "can't set edge target edge neighbors tag" );
211  }
212  return MB_SUCCESS;
213 }
214 
215 ErrorCode Intx2Mesh::DetermineOrderedNeighbors( EntityHandle inputSet, int max_edges, Tag& neighTag )
216 {
217  Range cells;
218  MB_CHK_SET_ERR( mb->get_entities_by_dimension( inputSet, 2, cells ), "can't get cells in set" );
219 
220  std::vector< EntityHandle > neighbors( max_edges );
221  std::vector< EntityHandle > zeroh( max_edges, 0 );
222  // nameless tag, as the name is not important; we will have 2 related tags, but one on tgt mesh,
223  // one on src mesh
225  &zeroh[0] ),
226  "can't create neighbors tag" );
227 
228  for( Range::iterator cit = cells.begin(); cit != cells.end(); ++cit )
229  {
230  EntityHandle cell = *cit;
231  int nnodes = 3;
232  // will get the nnodes ordered neighbors;
233  // first cell is for nodes 0, 1, second to 1, 2, third to 2, 3, last to nnodes-1,
234  const EntityHandle* conn4;
235  MB_CHK_SET_ERR( mb->get_connectivity( cell, conn4, nnodes ), "can't get connectivity of a cell" );
236  int nsides = nnodes;
237  // account for possible padded polygons
238  while( conn4[nsides - 2] == conn4[nsides - 1] && nsides > 3 )
239  nsides--;
240 
241  for( int i = 0; i < nsides; i++ )
242  {
243  EntityHandle v[2];
244  v[0] = conn4[i];
245  v[1] = conn4[( i + 1 ) % nsides];
246  // get all cells adjacent to these 2 vertices on the edge
247  std::vector< EntityHandle > adjcells;
248  std::vector< EntityHandle > cellsInSet;
249  MB_CHK_SET_ERR( mb->get_adjacencies( v, 2, 2, false, adjcells, Interface::INTERSECT ),
250  "can't get adjacency to 2 verts" );
251  // now look for the cells contained in the input set;
252  // the input set should be a correct mesh, not overlapping cells, and manifold
253  size_t siz = adjcells.size();
254  for( size_t j = 0; j < siz; j++ )
255  if( mb->contains_entities( inputSet, &( adjcells[j] ), 1 ) ) cellsInSet.push_back( adjcells[j] );
256  siz = cellsInSet.size();
257 
258  if( siz > 2 )
259  {
260  std::cout << "non manifold mesh, error" << mb->list_entities( &( cellsInSet[0] ), cellsInSet.size() )
261  << std::endl;
262  MB_CHK_SET_ERR( MB_FAILURE, "non-manifold input mesh set" ); // non-manifold
263  }
264  if( siz == 1 )
265  {
266  // it must be the border of the input mesh;
267  neighbors[i] = 0; // we are guaranteed that ids are !=0; this is marking a border
268  // borders do not appear for a sphere in serial, but they do appear for
269  // parallel processing anyway
270  continue;
271  }
272  // here siz ==2, it is either the first or second
273  if( cell == cellsInSet[0] )
274  neighbors[i] = cellsInSet[1];
275  else
276  neighbors[i] = cellsInSet[0];
277  }
278  // fill the rest with 0
279  for( int i = nsides; i < max_edges; i++ )
280  neighbors[i] = 0;
281  // now simply set the neighbors tag; the last few positions will not be used, but for
282  // simplicity will keep them all (MAXEDGES)
283  MB_CHK_SET_ERR( mb->tag_set_data( neighTag, &cell, 1, &neighbors[0] ), "can't set neighbors tag" );
284  }
285  return MB_SUCCESS;
286 }
287 
288 /**
289  * Slow KD-tree-based mesh intersection routine (no advancing-front).
290  *
291  * Overview:
292  * - Builds a KD-tree over source (mbs1) faces and, for each target (mbs2) face,
293  * queries nearby source leaves using a distance-based search around target vertices.
294  * - For the candidate source faces gathered from nearby KD-tree leaves, computes
295  * exact polygonal intersections in a gnomonic plane, accumulates overlap area,
296  * and creates intersection polygons/nodes in `outSet` via `findNodes`.
297  * - This path is intentionally simpler and potentially more expensive than the
298  * advancing-front algorithm used by `intersect_meshes`.
299  *
300  * Inputs/Assumptions:
301  * - `mbset1` (source) fully covers `mbset2` (target) on the sphere.
302  * - Both sets contain 2D elements (triangles, quads, or generic convex polygons).
303  * - On-sphere intersection math is performed using gnomonic projection; tolerances
304  * are derived from maximum edge lengths on the source mesh.
305  *
306  * High-level Steps:
307  * 1) Cache 2D entities of source (`rs1`) and target (`rs2`). Optionally filter by
308  * `GRID_IMASK` tag to exclude masked-out elements.
309  * 2) Precompute and tag target-edge adjacency (`__tgtEdgeNeighbors`) for quick
310  * access when locating/creating intersection points on target boundaries.
311  * 3) Estimate tolerances: compute maximum source edge length to derive KD-tree
312  * search tolerance and box overlap epsilon; reduce across ranks under MPI.
313  * 4) Build an `AdaptiveKDTree` on the source faces with spherical options
314  * (`PLANE_SET=1;SPLITS_PER_DIR=2;SPHERICAL;RADIUS=1.0;`).
315  * 5) For each target face:
316  * - Gather its vertex coordinates; compute an average edge length `av_len`.
317  * - For each target vertex, perform `kd.distance_search` within radius `av_len`
318  * to collect nearby KD-tree leaves; accumulate their contained 2D source faces
319  * into `close_source_cells`.
320  * - For each candidate source face in that range, call
321  * `computeIntersectionBetweenTgtAndSrc` to compute polygon intersection points
322  * and area; if area > 0, call `findNodes` to create nodes/polygons in `outSet`.
323  * - Track recovered area vs. the target cell area (diagnostic).
324  * 6) Under MPI, reconcile shared intersection points across process boundaries via
325  * `resolve_intersection_sharing`.
326  * 7) Cleanup transient state and return.
327  *
328  * Complexity Notes:
329  * - Building the KD-tree is roughly O(N log N). For each target face, the search
330  * radius heuristic (`av_len`) aims to limit candidates; worst-case behavior can
331  * still approach quadratic if meshes overlap densely.
332  *
333  * Key Data/Tags:
334  * - `tgtParentTag`, `srcParentTag`, `countTag` maintain provenance and counters for
335  * created intersection entities; they are (re)created in this routine.
336  * - `__tgtEdgeNeighbors` stores per-target-face edge handles to speed boundary ops.
337  *
338  * Error handling:
339  * - Uses MB_CHK_ERR/MB_CHK_SET_ERR macros for MOAB `ErrorCode` propagation.
340  * - Cleans up tags and temporary state before returning on success.
341  */
342 // some are triangles, some are quads, some are polygons ...
344 {
345  ErrorCode rval;
346  mbs1 = mbset1; // set 1 is departure, and it is completely covering the euler set on proc
347  mbs2 = mbset2;
348  outSet = outputSet;
349  MB_CHK_SET_ERR( mb->get_entities_by_dimension( mbs1, 2, rs1 ), "can't get source entities by dimension" );
350  MB_CHK_SET_ERR( mb->get_entities_by_dimension( mbs2, 2, rs2 ), "can't get target entities by dimension" );
351  // from create tags, copy relevant ones
354  if( countTag ) mb->tag_delete( countTag );
355 
356  // filter rs1 and rs2 by mask; remove everything with 0 mask
357  // get the mask tag if it exists; if not, leave it uninitialized (nullptr)
358  rval = mb->tag_get_handle( "GRID_IMASK", imaskTag );
359  if( imaskTag != nullptr && rval != MB_SUCCESS ) MB_CHK_SET_ERR( rval, "can't get GRID_IMASK tag" );
360  MB_CHK_SET_ERR( filterByMask( rs1 ), "can't filter source by mask" );
361  MB_CHK_SET_ERR( filterByMask( rs2 ), "can't filter target by mask" );
362  // create tgt edges if they do not exist yet; so when they are looked upon, they are found
363  // this is the only call that is potentially NlogN, in the whole method
365  "can't get adjacent target edges" );
366 
367  int index = 0;
368  extraNodesVec.resize( TgtEdges.size() );
369  for( Range::iterator eit = TgtEdges.begin(); eit != TgtEdges.end(); ++eit, index++ )
370  {
371  std::vector< EntityHandle >* nv = new std::vector< EntityHandle >;
372  extraNodesVec[index] = nv;
373  }
374 
375  int defaultInt = -1;
376  // Now let us create the association tags to source and target parent, along with internal counters
378  &defaultInt ),
379  "can't create target parent tag" );
381  &defaultInt ),
382  "can't create source parent tag" );
384  &defaultInt ),
385  "can't create Counting tag" );
386 
387  // for tgt cells, save a dense tag with the bordering edges, so we do not have to search for
388  // them each time edges were for sure created before (tgtEdges)
389  // if we have a tag with this name, it could be of a different size, so delete it
390  rval = mb->tag_get_handle( "__tgtEdgeNeighbors", neighTgtEdgeTag );
392  std::vector< EntityHandle > zeroh( max_edges_2, 0 );
394  MB_TAG_DENSE | MB_TAG_CREAT, &zeroh[0] ),
395  "can't create tgt edge neighbors tag" );
396 
397  for( Range::iterator rit = rs2.begin(); rit != rs2.end(); ++rit )
398  {
399  EntityHandle tgtCell = *rit;
400  int num_nodes = 0;
401  MB_CHK_SET_ERR( mb->get_connectivity( tgtCell, tgtConn, num_nodes ), "can't get target connectivity" );
402  // account for padded polygons
403  while( tgtConn[num_nodes - 2] == tgtConn[num_nodes - 1] && num_nodes > 3 )
404  num_nodes--;
405 
406  for( int i = 0; i < num_nodes; i++ )
407  {
408  EntityHandle v[2] = { tgtConn[i],
409  tgtConn[( i + 1 ) % num_nodes] }; // this is fine even for padded polygons
410  std::vector< EntityHandle > adj_entities;
411  rval = mb->get_adjacencies( v, 2, 1, false, adj_entities, Interface::INTERSECT );
412  if( rval != MB_SUCCESS || adj_entities.size() < 1 ) return rval; // get out , big error
413  zeroh[i] = adj_entities[0]; // should be only one edge between 2 nodes
414  // also, even if number of edges is less than max_edges_2, they will be ignored, even if
415  // the tag is dense
416  }
417  // now set the value of the tag
418  MB_CHK_SET_ERR( mb->tag_set_data( neighTgtEdgeTag, &tgtCell, 1, &( zeroh[0] ) ),
419  "can't set edge target edge neighbors tag" );
420  }
421 
422  // find out max edge on source mesh;
423  double max_length = 0;
424  {
425  std::vector< double > coords( 3 * max_edges_1, 0.0 );
426  for( Range::iterator it = rs1.begin(); it != rs1.end(); ++it )
427  {
428  const EntityHandle* conn = nullptr;
429  int nnodes;
430  MB_CHK_SET_ERR( mb->get_connectivity( *it, conn, nnodes ), "can't get source connectivity" );
431  while( conn[nnodes - 2] == conn[nnodes - 1] && nnodes > 3 )
432  nnodes--;
433  MB_CHK_SET_ERR( mb->get_coords( conn, nnodes, &coords[0] ), "can't get source coordinates" );
434  for( int j = 0; j < nnodes; j++ )
435  {
436  int next = ( j + 1 ) % nnodes;
437  double edge_length =
438  ( coords[3 * j] - coords[3 * next] ) * ( coords[3 * j] - coords[3 * next] ) +
439  ( coords[3 * j + 1] - coords[3 * next + 1] ) * ( coords[3 * j + 1] - coords[3 * next + 1] ) +
440  ( coords[3 * j + 2] - coords[3 * next + 2] ) * ( coords[3 * j + 2] - coords[3 * next + 2] );
441  if( edge_length > max_length ) max_length = edge_length;
442  }
443  }
444  max_length = std::sqrt( max_length );
445  }
446 
447  // maximum sag on a spherical mesh make sense only for intx on a sphere, with radius 1 :(
448  double tolerance = 1.e-15;
449  if( max_length < 1. )
450  {
451  // basically, the sag for an arc of length max_length on a circle of radius 1
452  tolerance = 1. - sqrt( 1 - max_length * max_length / 4 );
454  tolerance = 3 * tolerance; // we use it for gnomonic plane too, projected sag could be =* sqrt(2.)
455  // be more generous, use 1.5 ~= sqrt(2.)
456 
457  if( !my_rank )
458  {
459  std::cout << " max edge length: " << max_length << " tolerance for kd tree: " << tolerance << "\n";
460  std::cout << " box overlap tolerance: " << box_error << "\n";
461  }
462  }
463 #ifdef MOAB_HAVE_MPI
464  // reduce box tolerance on every task, if needed
465  double min_box_eps = box_error;
466  if( nullptr != parcomm ) MPI_Allreduce( &box_error, &min_box_eps, 1, MPI_DOUBLE, MPI_MIN, parcomm->comm() );
467  box_error = min_box_eps;
468 #endif
469 
470  // create the kd tree on source cells, and intersect all targets in an expensive loop
471  // build a kd tree with the rs1 (source) cells
472  FileOptions kdOpts( "PLANE_SET=1;SPLITS_PER_DIR=2;SPHERICAL;RADIUS=1.0;" );
473  AdaptiveKDTree kd( mb );
474  kd.parse_options( kdOpts );
475  EntityHandle tree_root = 0;
476  MB_CHK_SET_ERR( kd.build_tree( rs1, &tree_root ), "can't build Kd-tree on source cells" );
477 
478  for( Range::iterator it = rs2.begin(); it != rs2.end(); ++it )
479  {
480  EntityHandle tcell = *it;
481  // find vertex positions
482  const EntityHandle* conn = nullptr;
483  int nnodes = 0;
484  MB_CHK_SET_ERR( mb->get_connectivity( tcell, conn, nnodes ), "can't get target connectivity" );
485  // find leaves close to those positions
486  // setup_tgt_cell is called for its side effects (populates tgtConn /
487  // redCoords[] used by computeIntersectionBetweenTgtAndSrc below);
488  // the returned gnomonic-plane area is unused on this serial path.
489  (void)setup_tgt_cell( tcell, nnodes );
490  std::vector< double > positions;
491  positions.resize( nnodes * 3 );
492  MB_CHK_SET_ERR( mb->get_coords( conn, nnodes, &positions[0] ), "can't get target coordinates" );
493 
494  // distance to search will be based on average edge length
495  double av_len = 0;
496  for( int k = 0; k < nnodes; k++ )
497  {
498  int ik = ( k + 1 ) % nnodes;
499  double len1 = 0;
500  for( int j = 0; j < 3; j++ )
501  {
502  double len2 = positions[3 * k + j] - positions[3 * ik + j];
503  len1 += len2 * len2;
504  }
505  av_len += sqrt( len1 );
506  }
507  if( nnodes > 0 ) av_len /= nnodes;
508  // find leaves within a distance from each vertex of target
509  // in those leaves, collect all cells; we will try for an intx in there
510  Range close_source_cells;
511  std::vector< EntityHandle > leaves;
512  for( int i = 0; i < nnodes; i++ )
513  {
514  leaves.clear();
515  MB_CHK_SET_ERR( kd.distance_search( &positions[3 * i], av_len, leaves, tolerance, epsilon_1 ),
516  "can't search for leaves" );
517 
518  for( std::vector< EntityHandle >::iterator j = leaves.begin(); j != leaves.end(); ++j )
519  {
520  Range tmp;
521  MB_CHK_SET_ERR( mb->get_entities_by_dimension( *j, 2, tmp ), "can't get entities by dimension" );
522 
523  close_source_cells.merge( tmp.begin(), tmp.end() );
524  }
525  }
526 #ifdef VERBOSE
527  if( close_source_cells.empty() )
528  {
529  std::cout << " there are no close source cells to target cell " << tcell
530  << " ht:" << mb->id_from_handle( tcell ) << "\n";
531  }
532 #endif
533  for( Range::iterator it2 = close_source_cells.begin(); it2 != close_source_cells.end(); ++it2 )
534  {
535  EntityHandle startSrc = *it2;
536  double area = 0;
537  // if area is > 0 , we have intersections
538  double P[10 * MAXEDGES]; // max 8 intx points + 8 more in the polygon
539  //
540  int nP = 0;
541  int nb[MAXEDGES], nr[MAXEDGES]; // sides 3 or 4? also, check boxes first
542  int nsTgt, nsSrc;
543  MB_CHK_SET_ERR( computeIntersectionBetweenTgtAndSrc( tcell, startSrc, P, nP, area, nb, nr, nsSrc, nsTgt,
544  true ),
545  "can't compute intersection between target and source" );
546  if( area > 0 )
547  {
548  if( nP > 1 )
549  { // this will also construct triangles/polygons in the new mesh, if needed
550  MB_CHK_SET_ERR( findNodes( tcell, nnodes, startSrc, nsSrc, P, nP ), "can't find nodes" );
551 #ifdef ENABLE_DEBUG
552  std::cout << " intersect: " << " ht:" << mb->id_from_handle( tcell ) << " "
553  << " hs:" << mb->id_from_handle( startSrc ) << " g:" << global_id_ent( mb, tcell, gid )
554  << " g:" << global_id_ent( mb, startSrc, gid ) << " counting: " << counting << "\n";
555 #endif
556  }
557  // (Historical: serial path used to accumulate a per-cell
558  // recoveredArea / areaTgtCell ratio here, but neither value
559  // was ever read again. The verbose-print branch for that
560  // ratio lives only in the parallel path ~lines 893-899.)
561  }
562  }
563  }
564  // before cleaning up , we need to settle the position of the intersection points
565  // on the boundary edges
566  // this needs to be collective, so we should maybe wait something
567 #ifdef MOAB_HAVE_MPI
568  if( nullptr != parcomm )
569  {
570  MB_CHK_SET_ERR( resolve_intersection_sharing(), "can't resolve intersection sharing (correct position)" );
571  }
572 #endif
573 
574  this->clean();
575  return MB_SUCCESS;
576 }
577 
578 // main interface; this will do the advancing front trick
579 // some are triangles, some are quads, some are polygons ...
581 {
582  mbs1 = mbset1; // set 1 is departure, and it is completely covering the euler set on proc
583  mbs2 = mbset2;
584  outSet = outputSet;
585 #ifdef VERBOSE
586  std::stringstream ffs, fft;
587  ffs << "source_rank0" << my_rank << ".vtk";
588  MB_CHK_SET_ERR( mb->write_mesh( ffs.str().c_str(), &mbset1, 1 ), "can't write source mesh" );
589  fft << "target_rank0" << my_rank << ".vtk";
590  MB_CHK_SET_ERR( mb->write_mesh( fft.str().c_str(), &mbset2, 1 ), "can't write target mesh" );
591 
592 #endif
593  // really, should be something from t1 and t2; src is 1 (lagrange), tgt is 2 (euler)
594 
595  EntityHandle startSrc = 0, startTgt = 0;
596 
597  MB_CHK_SET_ERR( mb->get_entities_by_dimension( mbs1, 2, rs1 ), "can't get source entities by dimension" );
598  MB_CHK_SET_ERR( mb->get_entities_by_dimension( mbs2, 2, rs2 ), "can't get target entities by dimension" );
599 
600  // filter rs1 and rs2 by mask; remove everything with 0 mask
601  // get the mask tag if it exists; if not, leave it uninitialized (nullptr)
602  ErrorCode rval = mb->tag_get_handle( "GRID_IMASK", imaskTag );
603  if( imaskTag != nullptr && rval != MB_SUCCESS ) MB_CHK_SET_ERR( rval, "can't get GRID_IMASK tag" );
604 
605  MB_CHK_SET_ERR( filterByMask( rs1 ), "can't filter source by mask" );
606  MB_CHK_SET_ERR( filterByMask( rs2 ), "can't filter target by mask" );
607 
608  createTags(); // will also determine max_edges_1, max_edges_2 (for src and tgt meshes)
609 
610  Range rs22 = rs2; // a copy of the initial range; we will remove from it elements as we
611  // advance ; rs2 is needed for marking the polygon to the tgt parent
612 
613  // create the local kdd tree with source elements; will use it to search
614  // more efficiently for the seeds in advancing front;
615  // some of the target cells will not be covered by source cells, and they need to be eliminated
616  // early from contention
617  FileOptions kdOpts( "PLANE_SET=1;SPLITS_PER_DIR=2;SPHERICAL;RADIUS=1.0;" );
618  AdaptiveKDTree kd( mb );
619  kd.parse_options( kdOpts );
620  EntityHandle tree_root = 0;
621 
622  // build a kd tree with the rs1 (source) cells
623  MB_CHK_SET_ERR( kd.build_tree( rs1, &tree_root ), "can't build kd tree on source cells" );
624 #if defined( ENABLE_DEBUG )
625  for( auto it = rs22.begin(); it != rs22.end(); ++it )
626  {
627  EntityHandle cell = *it;
628  const EntityHandle* conn = nullptr;
629  int nnodes = 0;
630  rval = mb->get_connectivity( cell, conn, nnodes );MB_CHK_ERR( rval );
631  std::cout << " cell: \t" << " ht:" << mb->id_from_handle( cell ) << " nodes: " << nnodes
632  << " gt:" << global_id_ent( mb, cell, gid ) << " stat: " << char_stat_ent( mb, cell, TgtFlagTag )
633  << "\n";
634  }
635 #endif
636 
637  while( !rs22.empty() )
638  {
639 #if defined( ENABLE_DEBUG ) || defined( VERBOSE )
640  if( rs22.size() < rs2.size() )
641  {
642  std::cout << " possible not connected arrival mesh; my_rank: " << my_rank << " counting: " << counting
643  << " rs22.size():" << rs22.size() << "\n";
644  std::stringstream ffo;
645  ffo << "file0" << counting << "rank0" << my_rank << ".h5m";
646  MB_CHK_SET_ERR( mb->write_mesh( ffo.str().c_str(), &outSet, 1 ), "can't write output mesh" );
647  for( auto it = rs22.begin(); it != rs22.end(); ++it )
648  {
649  EntityHandle cell = *it;
650  const EntityHandle* conn = nullptr;
651  int nnodes = 0;
652  rval = mb->get_connectivity( cell, conn, nnodes );MB_CHK_ERR( rval );
653  std::cout << " cell: \t" << " ht:" << mb->id_from_handle( cell ) << " nodes: " << nnodes
654  << " g:" << global_id_ent( mb, cell, gid )
655  << " stat: " << char_stat_ent( mb, cell, TgtFlagTag ) << "\n";
656  }
657  }
658 #endif
659  bool seedFound = false;
660  Range verified_seeds;
661  for( Range::reverse_iterator it = rs22.rbegin(); it != rs22.rend(); ++it )
662  {
663  startTgt = *it;
664  unsigned char status = 0;
665  rval = mb->tag_get_data( TgtFlagTag, &startTgt, 1, &status );MB_CHK_ERR( rval );
666  if( 1 == status )
667  {
668  verified_seeds.insert( startTgt );
669  continue;
670  }
671  int found = 0;
672  // find vertex positions
673  const EntityHandle* conn = nullptr;
674  int nnodes = 0;
675  MB_CHK_SET_ERR( mb->get_connectivity( startTgt, conn, nnodes ), "can't get target connectivity" );
676  // find leaves close to those positions
677  std::vector< double > positions;
678  positions.resize( nnodes * 3 );
679  MB_CHK_SET_ERR( mb->get_coords( conn, nnodes, &positions[0] ), "can't get target coordinates" );
680  // find leaves within a distance from each vertex of target
681  // in those leaves, collect all cells; we will try for an intx in there, instead of
682  // looping over all rs1 cells, as before
683  Range close_source_cells;
684  std::vector< EntityHandle > leaves;
685  for( int i = 0; i < nnodes; i++ )
686  {
687  leaves.clear();
688  MB_CHK_SET_ERR( kd.distance_search( &positions[3 * i], epsilon_1, leaves, epsilon_1, epsilon_1 ),
689  "can't search for leaves" );
690 
691  for( std::vector< EntityHandle >::iterator j = leaves.begin(); j != leaves.end(); ++j )
692  {
693  Range tmp;
694  MB_CHK_SET_ERR( mb->get_entities_by_dimension( *j, 2, tmp ), "can't get entities by dimension" );
695 
696  close_source_cells.merge( tmp.begin(), tmp.end() );
697  }
698  }
699 
700  for( Range::iterator it2 = close_source_cells.begin(); it2 != close_source_cells.end() && !found; ++it2 )
701  {
702  startSrc = *it2;
703  double area = 0;
704  // if area is > 0 , we have intersections
705  double P[10 * MAXEDGES]; // max 8 intx points + 8 more in the polygon
706  //
707  int nP = 0;
708  int nb[MAXEDGES], nr[MAXEDGES]; // sides 3 or 4? also, check boxes first
709  int nsTgt, nsSrc;
710  MB_CHK_SET_ERR( computeIntersectionBetweenTgtAndSrc( startTgt, startSrc, P, nP, area, nb, nr, nsSrc,
711  nsTgt, true ),
712  "can't compute intersection between target and source" );
713  if( area > 0 )
714  {
715  found = 1;
716  seedFound = true;
717  break; // found 2 elements that intersect; these will be the seeds
718  }
719  }
720  if( found )
721  break;
722  else
723  {
724 #ifdef ENABLE_DEBUG
725  std::cout << " on rank " << my_rank << " target cell " << " ht:" << mb->id_from_handle( startTgt )
726  << " g:" << global_id_ent( mb, startTgt, gid ) << " not intx with any source\n";
727 #endif
728  verified_seeds.insert( startTgt );
729  }
730  }
731  rs22 = subtract( rs22, verified_seeds );
732  if( !seedFound ) continue; // continue while(!rs22.empty())
733 
734  std::queue< EntityHandle > srcQueue; // these are corresponding to Ta,
735  srcQueue.push( startSrc );
736  std::queue< EntityHandle > tgtQueue;
737  tgtQueue.push( startTgt );
738 
739  unsigned char used = 1;
740  // mark the start tgt quad as used, so it will not come back again
741  MB_CHK_SET_ERR( mb->tag_set_data( TgtFlagTag, &startTgt, 1, &used ), "can't set target flag" );
742  while( !tgtQueue.empty() )
743  {
744  // flags for the side : 0 means a src cell not found on side
745  // a paired src not found yet for the neighbors of tgt
746  Range nextSrc[MAXEDGES]; // there are new ranges of possible next src cells for
747  // seeding the side j of tgt cell
748 
749  EntityHandle currentTgt = tgtQueue.front();
750  tgtQueue.pop();
751  int nsidesTgt; // will be initialized now
752  double areaTgtCell = setup_tgt_cell( currentTgt, nsidesTgt ); // this is the area in the gnomonic plane
753  double recoveredArea = 0;
754  // get the neighbors of tgt, and if they are solved already, do not bother with that
755  // side of tgt
756  EntityHandle tgtNeighbors[MAXEDGES] = { 0 };
757  MB_CHK_SET_ERR( mb->tag_get_data( tgtNeighTag, &currentTgt, 1, tgtNeighbors ),
758  "can't get target neighbors" );
759 #ifdef ENABLE_DEBUG
760  if( dbg_1 )
761  {
762  std::cout << "Next: neighbors for current tgt nsidesTgt: " << nsidesTgt << " ";
763  for( int kk = 0; kk < nsidesTgt; kk++ )
764  {
765  if( tgtNeighbors[kk] > 0 )
766  std::cout << " ht:" << mb->id_from_handle( tgtNeighbors[kk] ) << " ";
767  else
768  std::cout << 0 << " ";
769  }
770  std::cout << std::endl;
771  }
772 #endif
773  // now get the status of neighbors; if already solved, make them 0, so not to bother
774  // anymore on that side of tgt
775  for( int j = 0; j < nsidesTgt; j++ )
776  {
777  EntityHandle tgtNeigh = tgtNeighbors[j];
778  unsigned char status = 1;
779  if( tgtNeigh == 0 ) continue;
780  MB_CHK_SET_ERR( mb->tag_get_data( TgtFlagTag, &tgtNeigh, 1, &status ),
781  "can't get target flag" ); // status 0 is unused
782  if( 1 == status ) tgtNeighbors[j] = 0; // so will not look anymore on this side of tgt
783  }
784 
785  EntityHandle currentSrc = srcQueue.front();
786  // tgt and src queues are parallel; for clarity we should have kept in the queue pairs
787  // of entity handle std::pair<EntityHandle, EntityHandle>; so just one queue, with
788  // pairs;
789  // at every moment, the queue contains pairs of cells that intersect, and they form the
790  // "advancing front"
791  srcQueue.pop();
792 
793  Range localSrc;
794  Range localSrcAlreadyTested;
795  localSrc.insert( currentSrc );
796 #ifdef VERBOSE
797  int countingStart = counting;
798 #endif
799  // will advance-front search in the neighborhood of tgt cell, until we finish processing
800  // all
801  // possible src cells; localSrc set will contain all possible src cells that cover
802  // the current tgt cell
803  while( !localSrc.empty() )
804  {
805  //
806  EntityHandle srcT = localSrc.pop_front(); // also remove from local range
807  double P[10 * MAXEDGES], area; //
808  int nP = 0;
809  int nb[MAXEDGES] = { 0 };
810  int nr[MAXEDGES] = { 0 };
811 
812  int nsidesSrc;
813  // area is in 2d, points are in 3d (on a sphere), back-projected, or in a plane
814  // intersection points could include the vertices of initial elements
815  // nb [j] = 0 means no intersection on the side j for element src (markers)
816  // nb [j] = 1 means that the side j (from j to j+1) of src poly intersects the
817  // tgt poly. A potential next poly in the tgt queue is the tgt poly that is
818  // adjacent to this side
819  MB_CHK_SET_ERR( computeIntersectionBetweenTgtAndSrc( /* tgt */ currentTgt, srcT, P, nP, area, nb, nr,
820  nsidesSrc, nsidesTgt ),
821  "can't compute intersection between target and source" );
822  localSrcAlreadyTested.insert( srcT );
823 
824  if( nP > 0 )
825  {
826 #ifdef ENABLE_DEBUG
827  std::cout << " srcT: " << " hs:" << mb->id_from_handle( srcT )
828  << " g:" << global_id_ent( mb, srcT, gid ) << " nsidesSrc:" << nsidesSrc << "\n";
829  std::cout << " currentTgt: " << " ht:" << mb->id_from_handle( currentTgt )
830  << " g:" << global_id_ent( mb, currentTgt, gid )
831  << " stat:" << char_stat_ent( mb, currentTgt, TgtFlagTag ) << " nsidesTgt:" << nsidesTgt
832  << "\n";
833  unsigned char status = 1;
834  rval = mb->tag_set_data( TgtFlagTag, &currentTgt, 1, &status );MB_CHK_ERR( rval );
835  if( dbg_1 )
836  {
837  for( int k = 0; k < nsidesSrc; k++ )
838  std::cout << " nb[" << k << "]=" << nb[k];
839  std::cout << "\n";
840  for( int k = 0; k < nsidesTgt; k++ )
841  std::cout << " nr[" << k << "]=" << nr[k];
842  std::cout << "\n";
843  }
844 #endif
845 
846  // intersection found: output P and original triangles if nP > 2
847  EntityHandle neighbors[MAXEDGES] = { 0 };
848 
849  MB_CHK_SET_ERR( mb->tag_get_data( srcNeighTag, &srcT, 1, neighbors ),
850  "failed to get the neighbors for source element " << mb->id_from_handle( srcT ) );
851 
852  Range newPotentialSrc;
853  // add neighbors to the localSrc queue, if they are not marked
854  for( int nn = 0; nn < nsidesSrc; nn++ )
855  {
856  EntityHandle neighbor = neighbors[nn];
857  if( nb[nn] > 0 ) // advance across src boundary nn
858  {
859  if( neighbor > 0 )
860  {
861  if( localSrcAlreadyTested.index( neighbor ) < 0 ) // -1
862  {
863  localSrc.insert( neighbor );
864 #ifdef ENABLE_DEBUG
865  std::cout << " local src elem " << " hs:" << mb->id_from_handle( neighbor )
866  << " for tgt:" << "ht:" << mb->id_from_handle( currentTgt ) << "\n";
867 #endif
868  }
869  }
870  else // if it is on the boundary it is a special case, maybe we need to advance more on that side,
871  // because the boundary is non-convex
872  {
873  // find the ends of edge nn, and add adjacent sources to those vertices (if they are in rs1)
874  int NumNodesSrc = 0;
875  const EntityHandle* connS;
876  rval = mb->get_connectivity( srcT, connS, NumNodesSrc );MB_CHK_SET_ERR( rval, "can't get connectivity" );
877  EntityHandle v1 = connS[nn];
878  EntityHandle v2 = connS[( nn + 1 ) % NumNodesSrc];
879  Range adjacentSourceCells1, adjacentSourceCells2;
880  rval = mb->get_adjacencies( &v1, 1, 2, false, adjacentSourceCells1 );MB_CHK_SET_ERR( rval, "can't get adjacent cells" );
881  adjacentSourceCells1 = intersect( adjacentSourceCells1, rs1 );
882  rval = mb->get_adjacencies( &v2, 1, 2, false, adjacentSourceCells2 );MB_CHK_SET_ERR( rval, "can't get adjacent cells" );
883  adjacentSourceCells2 = intersect( adjacentSourceCells2, rs1 );
884  adjacentSourceCells1.merge( adjacentSourceCells2 );
885  Range potentialSrc = subtract( adjacentSourceCells1, localSrcAlreadyTested );
886  newPotentialSrc.merge( potentialSrc );
887  }
888  }
889  }
890  // these might come from non-convex boundary
891  if( !newPotentialSrc.empty() )
892  {
893  localSrc.merge( newPotentialSrc );
894  }
895  // n(find(nc>0))=ac; % ac is starting candidate for neighbor
896  for( int nn = 0; nn < nsidesTgt; nn++ )
897  {
898  if( nr[nn] > 0 && tgtNeighbors[nn] > 0 )
899  nextSrc[nn].insert( srcT ); // potential src cell that can intersect
900  // the tgt neighbor nn
901  }
902  if( nP > 1 )
903  { // this will also construct triangles/polygons in the new mesh, if needed
904  MB_CHK_SET_ERR( findNodes( currentTgt, nsidesTgt, srcT, nsidesSrc, P, nP ),
905  "can't find nodes" );
906 #ifdef ENABLE_DEBUG
907  std::cout << " intersect: " << " ht:" << mb->id_from_handle( currentTgt ) << " "
908  << " hs:" << mb->id_from_handle( srcT )
909  << " g:" << global_id_ent( mb, currentTgt, gid ) << " "
910  << " g:" << global_id_ent( mb, srcT, gid ) << " counting: " << counting << "\n";
911 #endif
912  }
913 
914  recoveredArea += area;
915  }
916 #ifdef ENABLE_DEBUG
917  else if( dbg_1 )
918  {
919  std::cout << " tgt, src, do not intersect: " << "ht:" << mb->id_from_handle( currentTgt ) << " "
920  << "hs:" << mb->id_from_handle( srcT ) << "\n";
921  }
922 #endif
923  } // end while (!localSrc.empty())
924  recoveredArea = ( recoveredArea - areaTgtCell ) / areaTgtCell; // replace now with recovery fraction
925 #if defined( ENABLE_DEBUG ) || defined( VERBOSE )
926  if( fabs( recoveredArea ) > epsilon_1 )
927  {
928 #ifdef VERBOSE
929  std::cout << " tgt area: " << areaTgtCell << " recovered :" << recoveredArea * ( 1 + areaTgtCell )
930  << " fraction error recovery:" << recoveredArea
931  << " tgtID: " << "ht:" << mb->id_from_handle( currentTgt )
932  << " countingStart:" << countingStart << "\n";
933 #endif
934  }
935 #endif
936  // here, we are finished with tgtCurrent, take it out of the rs22 range (tgt, arrival
937  // mesh)
938  rs22.erase( currentTgt );
939 #ifdef ENABLE_DEBUG
940  std::cout << " remove cell: " << "ht:" << mb->id_from_handle( currentTgt )
941  << " g:" << global_id_ent( mb, currentTgt, gid ) << " rs22.size():" << rs22.size() << "\n";
942 #endif
943  // also, look at its neighbors, and add to the seeds a next one
944 
945  //int savedGnoPlane = plane;
946  for( int j = 0; j < nsidesTgt; j++ )
947  {
948  EntityHandle tgtNeigh = tgtNeighbors[j];
949  if( tgtNeigh == 0 || nextSrc[j].size() == 0 ) // if tgt is bigger than src, there could be no src
950  // to advance on that side
951  continue;
952  int nsidesTgt2 = 0;
953  // this also changes gnomonic plane //plane//
954  setup_tgt_cell( tgtNeigh, nsidesTgt2 ); // find possible intersection with src cell from nextSrc
955  for( Range::iterator nit = nextSrc[j].begin(); nit != nextSrc[j].end(); ++nit )
956  {
957  EntityHandle nextB = *nit;
958  // we identified tgt quad n[j] as possibly intersecting with neighbor j of the
959  // src quad
960  double P[10 * MAXEDGES], area; //
961  int nP = 0;
962  int nb[MAXEDGES] = { 0 };
963  int nr[MAXEDGES] = { 0 };
964 
965  int nsidesSrc; ///
967  /* tgt */ tgtNeigh, nextB, P, nP, area, nb, nr, nsidesSrc, nsidesTgt2 ),
968  "can't compute intersection between target and source" );
969  if( area > 0 )
970  {
971  unsigned char is_used = 0;
972  rval = mb->tag_get_data( TgtFlagTag, &tgtNeigh, 1, &is_used );MB_CHK_ERR( rval );
973  if( 0 == is_used )
974  {
975  tgtQueue.push( tgtNeigh );
976  srcQueue.push( nextB );
977 #ifdef ENABLE_DEBUG
978  if( dbg_1 )
979  std::cout << "new polys pushed: src, tgt:" << " ht:" << mb->id_from_handle( tgtNeigh )
980  << " hs:" << mb->id_from_handle( nextB ) << " counting: " << counting
981  << std::endl;
982 #endif
983  MB_CHK_SET_ERR( mb->tag_set_data( TgtFlagTag, &tgtNeigh, 1, &used ),
984  "can't set target flag" );
985  }
986  break; // so we are done with this side of tgt, we have found a proper next
987  // seed
988  }
989  }
990  }
991 
992  } // end while (!tgtQueue.empty())
993  }
994 
995  // before cleaning up , we need to settle the position of the intersection points
996  // on the boundary edges
997  // this needs to be collective, so we should maybe wait something
998 #ifdef MOAB_HAVE_MPI
999  MB_CHK_SET_ERR( resolve_intersection_sharing(), "can't resolve intersection sharing" );
1000 #endif
1001 
1002  this->clean();
1003  return MB_SUCCESS;
1004 }
1005 
1007 {
1008  if( !imaskTag ) return MB_SUCCESS; // nothing to do
1009  size_t sz = cells.size();
1010  std::vector< int > masks( sz );
1011 
1012  MB_CHK_SET_ERR( mb->tag_get_data( imaskTag, cells, &masks[0] ), "can't get mask tag" );
1013  Range cellsToRemove;
1014  size_t indx = 0;
1015  for( Range::iterator eit = cells.begin(); eit != cells.end(); ++eit, ++indx )
1016  {
1017  if( masks[indx] ) continue;
1018  cellsToRemove.insert( *eit );
1019  }
1020  cells = subtract( cells, cellsToRemove );
1021  return MB_SUCCESS;
1022 }
1023 
1024 // clean some memory allocated
1026 {
1027  //
1028  int indx = 0;
1029  for( Range::iterator eit = TgtEdges.begin(); eit != TgtEdges.end(); ++eit, indx++ )
1030  {
1031  delete extraNodesVec[indx];
1032  }
1033  // extraNodesMap.clear();
1034  extraNodesVec.clear();
1035  // also, delete some bit tags, used to mark processed tgts and srcs
1036  mb->tag_delete( TgtFlagTag );
1037  counting = 0; // reset counting to original value
1038 }
1039 
1040 // this method will reduce number of nodes, collapse edges that are of length 0
1041 // so a polygon like 428 431 431 will become a line 428 431
1042 // or something like 428 431 431 531 -> 428 431 531
1044 {
1045  int i = 0;
1046  while( i < nP )
1047  {
1048  int nextIndex = ( i + 1 ) % nP;
1049  if( nodes[i] == nodes[nextIndex] )
1050  {
1051 #ifdef ENABLE_DEBUG
1052  // we need to reduce nP, and collapse nodes
1053  if( dbg_1 )
1054  {
1055  std::cout << " nodes duplicated in list: ";
1056  for( int j = 0; j < nP; j++ )
1057  std::cout << nodes[j] << " ";
1058  std::cout << "\n";
1059  std::cout << " node " << nodes[i] << " at index " << i << " is duplicated" << "\n";
1060  }
1061 #endif
1062  // this will work even if we start from 1 2 3 1; when i is 3, we find nextIndex is 0,
1063  // then next thing does nothing
1064  // (nP-1 is 3, so k is already >= nP-1); it will result in nodes -> 1, 2, 3
1065  for( int k = i; k < nP - 1; k++ )
1066  nodes[k] = nodes[k + 1];
1067  nP--; // decrease the number of nodes; also, decrease i, just if we may need to check
1068  // again
1069  i--;
1070  }
1071  i++;
1072  }
1073  return;
1074 }
1075 
1076 #ifdef MOAB_HAVE_MPI
1077 
1078 ErrorCode Intx2Mesh::build_processor_euler_boxes( EntityHandle euler_set, Range& local_verts, bool gnomonic )
1079 {
1080  // if it comes here, we want regular 3d boxes
1081  // need to refactor this code
1082  if( gnomonic ) gnomonic = false;
1083  localEnts.clear();
1084  ErrorCode rval = mb->get_entities_by_dimension( euler_set, 2, localEnts );ERRORR( rval, "can't get ents by dimension" );
1085 
1086  rval = mb->get_connectivity( localEnts, local_verts );
1087  int num_local_verts = (int)local_verts.size();ERRORR( rval, "can't get local vertices" );
1088 
1089  assert( parcomm != nullptr );
1090 
1091  // get the position of local vertices, and decide local boxes (allBoxes...)
1092  double bmin[3] = { std::numeric_limits< double >::max(), std::numeric_limits< double >::max(),
1093  std::numeric_limits< double >::max() };
1094  double bmax[3] = { -std::numeric_limits< double >::max(), -std::numeric_limits< double >::max(),
1095  -std::numeric_limits< double >::max() };
1096 
1097  std::vector< double > coords( 3 * num_local_verts );
1098  rval = mb->get_coords( local_verts, &coords[0] );ERRORR( rval, "can't get coords of vertices " );
1099 
1100  for( int i = 0; i < num_local_verts; i++ )
1101  {
1102  for( int k = 0; k < 3; k++ )
1103  {
1104  double val = coords[3 * i + k];
1105  if( val < bmin[k] ) bmin[k] = val;
1106  if( val > bmax[k] ) bmax[k] = val;
1107  }
1108  }
1109  int numprocs = parcomm->proc_config().proc_size();
1110  allBoxes.resize( 6 * numprocs );
1111 
1112  my_rank = parcomm->proc_config().proc_rank();
1113  for( int k = 0; k < 3; k++ )
1114  {
1115  allBoxes[6 * my_rank + k] = bmin[k];
1116  allBoxes[6 * my_rank + 3 + k] = bmax[k];
1117  }
1118 
1119  // now communicate to get all boxes
1120  int mpi_err;
1121 #if ( MPI_VERSION >= 2 )
1122  // use "in place" option
1123  mpi_err = MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, &allBoxes[0], 6, MPI_DOUBLE,
1124  parcomm->proc_config().proc_comm() );
1125 #else
1126  {
1127  std::vector< double > allBoxes_tmp( 6 * parcomm->proc_config().proc_size() );
1128  mpi_err = MPI_Allgather( &allBoxes[6 * my_rank], 6, MPI_DOUBLE, &allBoxes_tmp[0], 6, MPI_DOUBLE,
1129  parcomm->proc_config().proc_comm() );
1130  allBoxes = allBoxes_tmp;
1131  }
1132 #endif
1133  if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
1134 
1135 #ifdef VERBOSE
1136  if( my_rank == 0 )
1137  {
1138  std::cout << " maximum number of vertices per cell are " << max_edges_1 << " on first mesh and " << max_edges_2
1139  << " on second mesh \n";
1140  for( int i = 0; i < numprocs; i++ )
1141  {
1142  std::cout << "proc: " << i << " box min: " << allBoxes[6 * i] << " " << allBoxes[6 * i + 1] << " "
1143  << allBoxes[6 * i + 2] << " \n";
1144  std::cout << " box max: " << allBoxes[6 * i + 3] << " " << allBoxes[6 * i + 4] << " "
1145  << allBoxes[6 * i + 5] << " \n";
1146  }
1147  }
1148 #endif
1149 
1150  return MB_SUCCESS;
1151 }
1152 
1154 {
1155  // compute the bounding box on each proc
1156  assert( parcomm != nullptr );
1157 
1158  localEnts.clear();
1159  ErrorCode rval = mb->get_entities_by_dimension( euler_set, 2, localEnts );ERRORR( rval, "can't get ents by dimension" );
1160 
1161  Tag dpTag = 0;
1162  std::string tag_name( "DP" );
1163  rval = mb->tag_get_handle( tag_name.c_str(), 3, MB_TYPE_DOUBLE, dpTag, MB_TAG_DENSE );ERRORR( rval, "can't get DP tag" );
1164 
1165  EntityHandle dum = 0;
1166  Tag corrTag;
1167  rval = mb->tag_get_handle( CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE | MB_TAG_CREAT, &dum );ERRORR( rval, "can't get CORR tag" );
1168  // get all local verts
1169  Range local_verts;
1170  rval = mb->get_connectivity( localEnts, local_verts );
1171  int num_local_verts = (int)local_verts.size();ERRORR( rval, "can't get local vertices" );
1172 
1173  rval = Intx2Mesh::build_processor_euler_boxes( euler_set, local_verts );ERRORR( rval, "can't build processor boxes" );
1174 
1175  std::vector< int > gids( num_local_verts );
1176  rval = mb->tag_get_data( gid, local_verts, &gids[0] );ERRORR( rval, "can't get local vertices gids" );
1177 
1178  // now see the departure points; to what boxes should we send them?
1179  std::vector< double > dep_points( 3 * num_local_verts );
1180  rval = mb->tag_get_data( dpTag, local_verts, (void*)&dep_points[0] );ERRORR( rval, "can't get DP tag values" );
1181  // ranges to send to each processor; will hold vertices and elements (quads?)
1182  // will look if the box of the dep quad covers box of euler mesh on proc (with tolerances)
1183  std::map< int, Range > Rto;
1184  int numprocs = parcomm->proc_config().proc_size();
1185 
1186  for( Range::iterator eit = localEnts.begin(); eit != localEnts.end(); ++eit )
1187  {
1188  EntityHandle q = *eit;
1189  const EntityHandle* conn4;
1190  int num_nodes;
1191  rval = mb->get_connectivity( q, conn4, num_nodes );ERRORR( rval, "can't get DP tag values" );
1192  CartVect qbmin( std::numeric_limits< double >::max() );
1193  CartVect qbmax( -std::numeric_limits< double >::max() );
1194  for( int i = 0; i < num_nodes; i++ )
1195  {
1196  EntityHandle v = conn4[i];
1197  size_t index = local_verts.find( v ) - local_verts.begin();
1198  CartVect dp( &dep_points[3 * index] ); // will use constructor
1199  for( int j = 0; j < 3; j++ )
1200  {
1201  if( qbmin[j] > dp[j] ) qbmin[j] = dp[j];
1202  if( qbmax[j] < dp[j] ) qbmax[j] = dp[j];
1203  }
1204  }
1205  for( int p = 0; p < numprocs; p++ )
1206  {
1207  CartVect bbmin( &allBoxes[6 * p] );
1208  CartVect bbmax( &allBoxes[6 * p + 3] );
1209  if( GeomUtil::boxes_overlap( bbmin, bbmax, qbmin, qbmax, box_error ) )
1210  {
1211  Rto[p].insert( q );
1212  }
1213  }
1214  }
1215 
1216  // now, build TLv and TLq, for each p
1217  size_t numq = 0;
1218  size_t numv = 0;
1219  for( int p = 0; p < numprocs; p++ )
1220  {
1221  if( p == (int)my_rank ) continue; // do not "send" it, because it is already here
1222  Range& range_to_P = Rto[p];
1223  // add the vertices to it
1224  if( range_to_P.empty() ) continue; // nothing to send to proc p
1225  Range vertsToP;
1226  rval = mb->get_connectivity( range_to_P, vertsToP );ERRORR( rval, "can't get connectivity" );
1227  numq = numq + range_to_P.size();
1228  numv = numv + vertsToP.size();
1229  range_to_P.merge( vertsToP );
1230  }
1231  TupleList TLv;
1232  TupleList TLq;
1233  TLv.initialize( 2, 0, 0, 3, numv ); // to proc, GLOBAL ID, DP points
1234  TLv.enableWriteAccess();
1235 
1236  int sizeTuple = 2 + max_edges_1; // determined earlier, for src, first mesh
1237  TLq.initialize( 2 + max_edges_1, 0, 1, 0,
1238  numq ); // to proc, elem GLOBAL ID, connectivity[10] (global ID v), local eh
1239  TLq.enableWriteAccess();
1240 #ifdef VERBOSE
1241  std::cout << "from proc " << my_rank << " send " << numv << " vertices and " << numq << " elements\n";
1242 #endif
1243  for( int to_proc = 0; to_proc < numprocs; to_proc++ )
1244  {
1245  if( to_proc == (int)my_rank ) continue;
1246  Range& range_to_P = Rto[to_proc];
1247  Range V = range_to_P.subset_by_type( MBVERTEX );
1248 
1249  for( Range::iterator it = V.begin(); it != V.end(); ++it )
1250  {
1251  EntityHandle v = *it;
1252  unsigned int index = local_verts.find( v ) - local_verts.begin();
1253  int n = TLv.get_n();
1254  TLv.vi_wr[2 * n] = to_proc; // send to processor
1255  TLv.vi_wr[2 * n + 1] = gids[index]; // global id needs index in the local_verts range
1256  TLv.vr_wr[3 * n] = dep_points[3 * index]; // departure position, of the node local_verts[i]
1257  TLv.vr_wr[3 * n + 1] = dep_points[3 * index + 1];
1258  TLv.vr_wr[3 * n + 2] = dep_points[3 * index + 2];
1259  TLv.inc_n();
1260  }
1261  // also, prep the quad for sending ...
1262  Range Q = range_to_P.subset_by_dimension( 2 );
1263  for( Range::iterator it = Q.begin(); it != Q.end(); ++it )
1264  {
1265  EntityHandle q = *it;
1266  int global_id;
1267  rval = mb->tag_get_data( gid, &q, 1, &global_id );ERRORR( rval, "can't get gid for polygon" );
1268  int n = TLq.get_n();
1269  TLq.vi_wr[sizeTuple * n] = to_proc; //
1270  TLq.vi_wr[sizeTuple * n + 1] = global_id; // global id of element, used to identify it ...
1271  const EntityHandle* conn4;
1272  int num_nodes;
1273  rval = mb->get_connectivity( q, conn4,
1274  num_nodes ); // could be up to MAXEDGES, but it is limited by max_edges_1
1275  ERRORR( rval, "can't get connectivity for cell" );
1276  if( num_nodes > MAXEDGES ) ERRORR( MB_FAILURE, "too many nodes in a polygon" );
1277  for( int i = 0; i < num_nodes; i++ )
1278  {
1279  EntityHandle v = conn4[i];
1280  unsigned int index = local_verts.find( v ) - local_verts.begin();
1281  TLq.vi_wr[sizeTuple * n + 2 + i] = gids[index];
1282  }
1283  for( int k = num_nodes; k < max_edges_1; k++ )
1284  {
1285  TLq.vi_wr[sizeTuple * n + 2 + k] =
1286  0; // fill the rest of node ids with 0; we know that the node ids start from 1!
1287  }
1288  TLq.vul_wr[n] = q; // save here the entity handle, it will be communicated back
1289  // maybe we should forget about global ID
1290  TLq.inc_n();
1291  }
1292  }
1293 
1294  // now we are done populating the tuples; route them to the appropriate processors
1295  ( parcomm->proc_config().crystal_router() )->gs_transfer( 1, TLv, 0 );
1296  ( parcomm->proc_config().crystal_router() )->gs_transfer( 1, TLq, 0 );
1297  // the elements are already in localEnts;
1298 
1299  // maps from global ids to new vertex and quad handles, that are added
1300  std::map< int, EntityHandle > globalID_to_handle;
1301  /*std::map<int, EntityHandle> globalID_to_eh;*/
1302  globalID_to_eh.clear(); // need for next iteration
1303  // now, look at every TLv, and see if we have to create a vertex there or not
1304  int n = TLv.get_n(); // the size of the points received
1305  for( int i = 0; i < n; i++ )
1306  {
1307  int globalId = TLv.vi_rd[2 * i + 1];
1308  if( globalID_to_handle.find( globalId ) == globalID_to_handle.end() )
1309  {
1310  EntityHandle new_vert;
1311  double dp_pos[3] = { TLv.vr_wr[3 * i], TLv.vr_wr[3 * i + 1], TLv.vr_wr[3 * i + 2] };
1312  rval = mb->create_vertex( dp_pos, new_vert );ERRORR( rval, "can't create new vertex " );
1313  globalID_to_handle[globalId] = new_vert;
1314  }
1315  }
1316 
1317  // now, all dep points should be at their place
1318  // look in the local list of q for this proc, and create all those quads and vertices if needed
1319  // it may be an overkill, but because it does not involve communication, we do it anyway
1320  Range& local = Rto[my_rank];
1321  Range local_q = local.subset_by_dimension( 2 );
1322  // the local should have all the vertices in local_verts
1323  for( Range::iterator it = local_q.begin(); it != local_q.end(); ++it )
1324  {
1325  EntityHandle q = *it;
1326  int nnodes;
1327  const EntityHandle* conn4;
1328  rval = mb->get_connectivity( q, conn4, nnodes );ERRORR( rval, "can't get connectivity of local q " );
1329  EntityHandle new_conn[MAXEDGES];
1330  for( int i = 0; i < nnodes; i++ )
1331  {
1332  EntityHandle v1 = conn4[i];
1333  unsigned int index = local_verts.find( v1 ) - local_verts.begin();
1334  int globalId = gids[index];
1335  if( globalID_to_handle.find( globalId ) == globalID_to_handle.end() )
1336  {
1337  // we need to create that vertex, at this position dep_points
1338  double dp_pos[3] = { dep_points[3 * index], dep_points[3 * index + 1], dep_points[3 * index + 2] };
1339  EntityHandle new_vert;
1340  rval = mb->create_vertex( dp_pos, new_vert );ERRORR( rval, "can't create new vertex " );
1341  globalID_to_handle[globalId] = new_vert;
1342  }
1343  new_conn[i] = globalID_to_handle[gids[index]];
1344  }
1345  EntityHandle new_element;
1346  //
1347  EntityType entType = MBQUAD;
1348  if( nnodes > 4 ) entType = MBPOLYGON;
1349  if( nnodes < 4 ) entType = MBTRI;
1350 
1351  rval = mb->create_element( entType, new_conn, nnodes, new_element );ERRORR( rval, "can't create new quad " );
1352  rval = mb->add_entities( covering_lagr_set, &new_element, 1 );ERRORR( rval, "can't add new element to dep set" );
1353  int gid_el;
1354  // get the global ID of the initial quad
1355  rval = mb->tag_get_data( gid, &q, 1, &gid_el );ERRORR( rval, "can't get element global ID " );
1356  globalID_to_eh[gid_el] = new_element;
1357  // is this redundant or not?
1358  rval = mb->tag_set_data( corrTag, &new_element, 1, &q );ERRORR( rval, "can't set corr tag on new el" );
1359  // set the global id on new elem
1360  rval = mb->tag_set_data( gid, &new_element, 1, &gid_el );ERRORR( rval, "can't set global id tag on new el" );
1361  }
1362  // now look at all elements received through; we do not want to duplicate them
1363  n = TLq.get_n(); // number of elements received by this processor
1364  // form the remote cells, that will be used to send the tracer info back to the originating proc
1365  remote_cells = new TupleList();
1366  remote_cells->initialize( 2, 0, 1, 0, n ); // will not have tracer data anymore
1367  remote_cells->enableWriteAccess();
1368  for( int i = 0; i < n; i++ )
1369  {
1370  int globalIdEl = TLq.vi_rd[sizeTuple * i + 1];
1371  int from_proc = TLq.vi_wr[sizeTuple * i];
1372  // do we already have a quad with this global ID, represented?
1373  if( globalID_to_eh.find( globalIdEl ) == globalID_to_eh.end() )
1374  {
1375  // construct the conn quad
1376  EntityHandle new_conn[MAXEDGES];
1377  int nnodes = -1;
1378  for( int j = 0; j < max_edges_1; j++ )
1379  {
1380  int vgid = TLq.vi_rd[sizeTuple * i + 2 + j]; // vertex global ID
1381  if( vgid == 0 )
1382  new_conn[j] = 0;
1383  else
1384  {
1385  assert( globalID_to_handle.find( vgid ) != globalID_to_handle.end() );
1386  new_conn[j] = globalID_to_handle[vgid];
1387  nnodes = j + 1; // nodes are at the beginning, and are variable number
1388  }
1389  }
1390  EntityHandle new_element;
1391  //
1392  EntityType entType = MBQUAD;
1393  if( nnodes > 4 ) entType = MBPOLYGON;
1394  if( nnodes < 4 ) entType = MBTRI;
1395  rval = mb->create_element( entType, new_conn, nnodes, new_element );ERRORR( rval, "can't create new element " );
1396  globalID_to_eh[globalIdEl] = new_element;
1397  rval = mb->add_entities( covering_lagr_set, &new_element, 1 );ERRORR( rval, "can't add new element to dep set" );
1398  /* rval = mb->tag_set_data(corrTag, &new_element, 1, &q);ERRORR(rval, "can't set corr tag on new el");*/
1399  remote_cells->vi_wr[2 * i] = from_proc;
1400  remote_cells->vi_wr[2 * i + 1] = globalIdEl;
1401  // remote_cells->vr_wr[i] = 0.; // no contribution yet sent back
1402  remote_cells->vul_wr[i] = TLq.vul_rd[i]; // this is the corresponding tgt cell (arrival)
1403  remote_cells->inc_n();
1404  // set the global id on new elem
1405  rval = mb->tag_set_data( gid, &new_element, 1, &globalIdEl );ERRORR( rval, "can't set global id tag on new el" );
1406  }
1407  }
1408  // order the remote cells tuple list, with the global id, because we will search in it
1409  // remote_cells->print("remote_cells before sorting");
1410  moab::TupleList::buffer sort_buffer;
1411  sort_buffer.buffer_init( n );
1412  remote_cells->sort( 1, &sort_buffer );
1413  sort_buffer.reset();
1414  return MB_SUCCESS;
1415 }
1416 
1417 // this algorithm assumes lagr set is already created, and some elements will be coming from
1418 // other procs, and populate the covering_set
1419 // we need to keep in a tuple list the remote cells from other procs, because we need to send back
1420 // the intersection info (like area of the intx polygon, and the current concentration) maybe total
1421 // mass in that intx
1423 {
1424  EntityHandle dum = 0;
1425 
1426  Tag corrTag;
1428  // start copy from 2nd alg
1429  // compute the bounding box on each proc
1430  assert( parcomm != nullptr );
1431  if( 1 == parcomm->proc_config().proc_size() )
1432  {
1433  covering_set = lagr_set; // nothing to communicate, it must be serial
1434  return MB_SUCCESS;
1435  }
1436 
1437  // get all local verts
1438  Range local_verts;
1439  rval = mb->get_connectivity( localEnts, local_verts );
1440  int num_local_verts = (int)local_verts.size();ERRORR( rval, "can't get local vertices" );
1441 
1442  std::vector< int > gids( num_local_verts );
1443  rval = mb->tag_get_data( gid, local_verts, &gids[0] );ERRORR( rval, "can't get local vertices gids" );
1444 
1445  Range localDepCells;
1446  rval = mb->get_entities_by_dimension( lagr_set, 2, localDepCells );ERRORR( rval, "can't get ents by dimension from lagr set" );
1447 
1448  // get all lagr verts (departure vertices)
1449  Range lagr_verts;
1450  rval = mb->get_connectivity( localDepCells, lagr_verts ); // they should be created in
1451  // the same order as the euler vertices
1452  int num_lagr_verts = (int)lagr_verts.size();ERRORR( rval, "can't get local lagr vertices" );
1453 
1454  // now see the departure points position; to what boxes should we send them?
1455  std::vector< double > dep_points( 3 * num_lagr_verts );
1456  rval = mb->get_coords( lagr_verts, &dep_points[0] );ERRORR( rval, "can't get departure points position" );
1457  // ranges to send to each processor; will hold vertices and elements (quads?)
1458  // will look if the box of the dep quad covers box of euler mesh on proc (with tolerances)
1459  std::map< int, Range > Rto;
1460  int numprocs = parcomm->proc_config().proc_size();
1461 
1462  for( Range::iterator eit = localDepCells.begin(); eit != localDepCells.end(); ++eit )
1463  {
1464  EntityHandle q = *eit;
1465  const EntityHandle* conn4;
1466  int num_nodes;
1467  rval = mb->get_connectivity( q, conn4, num_nodes );ERRORR( rval, "can't get DP tag values" );
1468  CartVect qbmin( std::numeric_limits< double >::max() );
1469  CartVect qbmax( -std::numeric_limits< double >::max() );
1470  for( int i = 0; i < num_nodes; i++ )
1471  {
1472  EntityHandle v = conn4[i];
1473  int index = lagr_verts.index( v );
1474  assert( -1 != index );
1475  CartVect dp( &dep_points[3 * index] ); // will use constructor
1476  for( int j = 0; j < 3; j++ )
1477  {
1478  if( qbmin[j] > dp[j] ) qbmin[j] = dp[j];
1479  if( qbmax[j] < dp[j] ) qbmax[j] = dp[j];
1480  }
1481  }
1482  for( int p = 0; p < numprocs; p++ )
1483  {
1484  CartVect bbmin( &allBoxes[6 * p] );
1485  CartVect bbmax( &allBoxes[6 * p + 3] );
1486  if( GeomUtil::boxes_overlap( bbmin, bbmax, qbmin, qbmax, box_error ) )
1487  {
1488  Rto[p].insert( q );
1489  }
1490  }
1491  }
1492 
1493  // now, build TLv and TLq, for each p
1494  size_t numq = 0;
1495  size_t numv = 0;
1496  for( int p = 0; p < numprocs; p++ )
1497  {
1498  if( p == (int)my_rank ) continue; // do not "send" it, because it is already here
1499  Range& range_to_P = Rto[p];
1500  // add the vertices to it
1501  if( range_to_P.empty() ) continue; // nothing to send to proc p
1502  Range vertsToP;
1503  rval = mb->get_connectivity( range_to_P, vertsToP );ERRORR( rval, "can't get connectivity" );
1504  numq = numq + range_to_P.size();
1505  numv = numv + vertsToP.size();
1506  range_to_P.merge( vertsToP );
1507  }
1508  TupleList TLv;
1509  TupleList TLq;
1510  TLv.initialize( 2, 0, 0, 3, numv ); // to proc, GLOBAL ID, DP points
1511  TLv.enableWriteAccess();
1512 
1513  int sizeTuple = 2 + max_edges_1; // max edges could be up to MAXEDGES :) for polygons
1514  TLq.initialize( 2 + max_edges_1, 0, 1, 0,
1515  numq ); // to proc, elem GLOBAL ID, connectivity[max_edges] (global ID v)
1516  // send also the corresponding tgt cell it will come to
1517  TLq.enableWriteAccess();
1518 #ifdef VERBOSE
1519  std::cout << "from proc " << my_rank << " send " << numv << " vertices and " << numq << " elements\n";
1520 #endif
1521 
1522  for( int to_proc = 0; to_proc < numprocs; to_proc++ )
1523  {
1524  if( to_proc == (int)my_rank ) continue;
1525  Range& range_to_P = Rto[to_proc];
1526  Range V = range_to_P.subset_by_type( MBVERTEX );
1527 
1528  for( Range::iterator it = V.begin(); it != V.end(); ++it )
1529  {
1530  EntityHandle v = *it;
1531  int index = lagr_verts.index( v ); // will be the same index as the corresponding vertex in euler verts
1532  assert( -1 != index );
1533  int n = TLv.get_n();
1534  TLv.vi_wr[2 * n] = to_proc; // send to processor
1535  TLv.vi_wr[2 * n + 1] = gids[index]; // global id needs index in the local_verts range
1536  TLv.vr_wr[3 * n] = dep_points[3 * index]; // departure position, of the node local_verts[i]
1537  TLv.vr_wr[3 * n + 1] = dep_points[3 * index + 1];
1538  TLv.vr_wr[3 * n + 2] = dep_points[3 * index + 2];
1539  TLv.inc_n();
1540  }
1541  // also, prep the 2d cells for sending ...
1542  Range Q = range_to_P.subset_by_dimension( 2 );
1543  for( Range::iterator it = Q.begin(); it != Q.end(); ++it )
1544  {
1545  EntityHandle q = *it; // this is a src cell
1546  int global_id;
1547  rval = mb->tag_get_data( gid, &q, 1, &global_id );ERRORR( rval, "can't get gid for polygon" );
1548  int n = TLq.get_n();
1549  TLq.vi_wr[sizeTuple * n] = to_proc; //
1550  TLq.vi_wr[sizeTuple * n + 1] = global_id; // global id of element, used to identify it ...
1551  const EntityHandle* conn4;
1552  int num_nodes;
1553  rval = mb->get_connectivity(
1554  q, conn4, num_nodes ); // could be up to 10;ERRORR( rval, "can't get connectivity for quad" );
1555  if( num_nodes > MAXEDGES ) ERRORR( MB_FAILURE, "too many nodes in a polygon" );
1556  for( int i = 0; i < num_nodes; i++ )
1557  {
1558  EntityHandle v = conn4[i];
1559  int index = lagr_verts.index( v );
1560  assert( -1 != index );
1561  TLq.vi_wr[sizeTuple * n + 2 + i] = gids[index];
1562  }
1563  for( int k = num_nodes; k < max_edges_1; k++ )
1564  {
1565  TLq.vi_wr[sizeTuple * n + 2 + k] =
1566  0; // fill the rest of node ids with 0; we know that the node ids start from 1!
1567  }
1568  EntityHandle tgtCell;
1569  rval = mb->tag_get_data( corrTag, &q, 1, &tgtCell );ERRORR( rval, "can't get corresponding tgt cell for dep cell" );
1570  TLq.vul_wr[n] = tgtCell; // this will be sent to remote_cells, to be able to come back
1571  TLq.inc_n();
1572  }
1573  }
1574  // now we can route them to each processor
1575  // now we are done populating the tuples; route them to the appropriate processors
1576  ( parcomm->proc_config().crystal_router() )->gs_transfer( 1, TLv, 0 );
1577  ( parcomm->proc_config().crystal_router() )->gs_transfer( 1, TLq, 0 );
1578  // the elements are already in localEnts;
1579 
1580  // maps from global ids to new vertex and quad handles, that are added
1581  std::map< int, EntityHandle > globalID_to_handle;
1582  // we already have vertices from lagr set; they are already in the processor, even before
1583  // receiving other verts from neighbors
1584  int k = 0;
1585  for( Range::iterator vit = lagr_verts.begin(); vit != lagr_verts.end(); ++vit, k++ )
1586  {
1587  globalID_to_handle[gids[k]] = *vit; // a little bit of overkill
1588  // we do know that the global ids between euler and lagr verts are parallel
1589  }
1590  /*std::map<int, EntityHandle> globalID_to_eh;*/ // do we need this one?
1591  globalID_to_eh.clear();
1592  // now, look at every TLv, and see if we have to create a vertex there or not
1593  int n = TLv.get_n(); // the size of the points received
1594  for( int i = 0; i < n; i++ )
1595  {
1596  int globalId = TLv.vi_rd[2 * i + 1];
1597  if( globalID_to_handle.find( globalId ) == globalID_to_handle.end() )
1598  {
1599  EntityHandle new_vert;
1600  double dp_pos[3] = { TLv.vr_wr[3 * i], TLv.vr_wr[3 * i + 1], TLv.vr_wr[3 * i + 2] };
1601  rval = mb->create_vertex( dp_pos, new_vert );ERRORR( rval, "can't create new vertex " );
1602  globalID_to_handle[globalId] = new_vert;
1603  }
1604  }
1605 
1606  // now, all dep points should be at their place
1607  // look in the local list of 2d cells for this proc, and create all those cells if needed
1608  // it may be an overkill, but because it does not involve communication, we do it anyway
1609  Range& local = Rto[my_rank];
1610  Range local_q = local.subset_by_dimension( 2 );
1611  // the local should have all the vertices in lagr_verts
1612  for( Range::iterator it = local_q.begin(); it != local_q.end(); ++it )
1613  {
1614  EntityHandle q = *it; // these are from lagr cells, local
1615  int gid_el;
1616  rval = mb->tag_get_data( gid, &q, 1, &gid_el );ERRORR( rval, "can't get element global ID " );
1617  globalID_to_eh[gid_el] = q; // do we need this? maybe to just mark the ones on this processor
1618  // maybe a range of global cell ids is fine?
1619  }
1620  // now look at all elements received through; we do not want to duplicate them
1621  n = TLq.get_n(); // number of elements received by this processor
1622  // a cell should be received from one proc only; so why are we so worried about duplicated
1623  // elements? a vertex can be received from multiple sources, that is fine
1624 
1625  remote_cells = new TupleList();
1626  remote_cells->initialize( 2, 0, 1, 0, n ); // no tracers anymore in these tuples
1627  remote_cells->enableWriteAccess();
1628  for( int i = 0; i < n; i++ )
1629  {
1630  int globalIdEl = TLq.vi_rd[sizeTuple * i + 1];
1631  int from_proc = TLq.vi_rd[sizeTuple * i];
1632  // do we already have a quad with this global ID, represented?
1633  if( globalID_to_eh.find( globalIdEl ) == globalID_to_eh.end() )
1634  {
1635  // construct the conn quad
1636  EntityHandle new_conn[MAXEDGES];
1637  int nnodes = -1;
1638  for( int j = 0; j < max_edges_1; j++ )
1639  {
1640  int vgid = TLq.vi_rd[sizeTuple * i + 2 + j]; // vertex global ID
1641  if( vgid == 0 )
1642  new_conn[j] = 0;
1643  else
1644  {
1645  assert( globalID_to_handle.find( vgid ) != globalID_to_handle.end() );
1646  new_conn[j] = globalID_to_handle[vgid];
1647  nnodes = j + 1; // nodes are at the beginning, and are variable number
1648  }
1649  }
1650  EntityHandle new_element;
1651  //
1652  EntityType entType = MBQUAD;
1653  if( nnodes > 4 ) entType = MBPOLYGON;
1654  if( nnodes < 4 ) entType = MBTRI;
1655  rval = mb->create_element( entType, new_conn, nnodes, new_element );ERRORR( rval, "can't create new element " );
1656  globalID_to_eh[globalIdEl] = new_element;
1657  local_q.insert( new_element );
1658  rval = mb->tag_set_data( gid, &new_element, 1, &globalIdEl );ERRORR( rval, "can't set gid on new element " );
1659  }
1660  remote_cells->vi_wr[2 * i] = from_proc;
1661  remote_cells->vi_wr[2 * i + 1] = globalIdEl;
1662  // remote_cells->vr_wr[i] = 0.; will have a different tuple for communication
1663  remote_cells->vul_wr[i] = TLq.vul_rd[i]; // this is the corresponding tgt cell (arrival)
1664  remote_cells->inc_n();
1665  }
1666  // now, create a new set, covering_set
1667  rval = mb->create_meshset( MESHSET_SET, covering_set );ERRORR( rval, "can't create new mesh set " );
1668  rval = mb->add_entities( covering_set, local_q );ERRORR( rval, "can't add entities to new mesh set " );
1669  // order the remote cells tuple list, with the global id, because we will search in it
1670  // remote_cells->print("remote_cells before sorting");
1671  moab::TupleList::buffer sort_buffer;
1672  sort_buffer.buffer_init( n );
1673  remote_cells->sort( 1, &sort_buffer );
1674  sort_buffer.reset();
1675  return MB_SUCCESS;
1676  // end copy
1677 }
1678 
1679 ErrorCode Intx2Mesh::resolve_intersection_sharing()
1680 {
1681  if( parcomm && parcomm->size() > 1 )
1682  {
1683  /*
1684  moab::ParallelMergeMesh pm(parcomm, epsilon_1);
1685  ErrorCode rval = pm.merge(outSet, false, 2); // resolve only the output set, do not skip
1686  local merge, use dim 2 ERRORR(rval, "can't merge intersection ");
1687  */
1688  // look at non-owned shared vertices, that could be part of original source set
1689  // they should be removed from intx set reference, because they might not have a
1690  // correspondent on the other task
1691  Range nonOwnedVerts;
1692  Range vertsInIntx;
1693  Range intxCells;
1694  MB_CHK_SET_ERR( mb->get_entities_by_dimension( outSet, 2, intxCells ), "can't get entities by dimension" );
1695  MB_CHK_SET_ERR( mb->get_connectivity( intxCells, vertsInIntx ), "can't get connectivity" );
1696 
1697  MB_CHK_SET_ERR( parcomm->filter_pstatus( vertsInIntx, PSTATUS_NOT_OWNED, PSTATUS_AND, -1, &nonOwnedVerts ),
1698  "can't filter pstatus" );
1699 
1700  // some of these vertices can be in original set 1, which was covered, transported;
1701  // but they should not be "shared" from the intx point of view, because they are not shared
1702  // with another task they might have come from coverage as a plain vertex, so losing the
1703  // sharing property ?
1704 
1705  Range coverVerts;
1706  MB_CHK_SET_ERR( mb->get_connectivity( rs1, coverVerts ), "can't get connectivity" );
1707  // find out those that are on the interface
1708  Range vertsCovInterface;
1709  MB_CHK_SET_ERR( parcomm->filter_pstatus( coverVerts, PSTATUS_INTERFACE, PSTATUS_AND, -1, &vertsCovInterface ),
1710  "can't filter pstatus" );
1711  // how many of these are in
1712  Range nodesToDuplicate = intersect( vertsCovInterface, nonOwnedVerts );
1713  // first, get all cells connected to these vertices, from intxCells
1714 
1715  Range connectedCells;
1716  MB_CHK_ERR( mb->get_adjacencies( nodesToDuplicate, 2, false, connectedCells, Interface::UNION ) );
1717  // only those in intx set:
1718  connectedCells = intersect( connectedCells, intxCells );
1719  // first duplicate vertices in question:
1720  std::map< EntityHandle, EntityHandle > duplicatedVerticesMap;
1721  for( Range::iterator vit = nodesToDuplicate.begin(); vit != nodesToDuplicate.end(); ++vit )
1722  {
1723  EntityHandle vertex = *vit;
1724  double coords[3];
1725  MB_CHK_SET_ERR( mb->get_coords( &vertex, 1, coords ), "can't get coords" );
1726  EntityHandle newVertex;
1727  MB_CHK_SET_ERR( mb->create_vertex( coords, newVertex ), "can't create vertex" );
1728  duplicatedVerticesMap[vertex] = newVertex;
1729  }
1730 
1731  // look now at connectedCells, and change their connectivities:
1732  for( Range::iterator eit = connectedCells.begin(); eit != connectedCells.end(); ++eit )
1733  {
1734  EntityHandle intxCell = *eit;
1735  // replace connectivity
1736  std::vector< EntityHandle > connectivity;
1737  MB_CHK_SET_ERR( mb->get_connectivity( &intxCell, 1, connectivity ), "can't get connectivity" );
1738  for( size_t i = 0; i < connectivity.size(); i++ )
1739  {
1740  EntityHandle currentVertex = connectivity[i];
1741  std::map< EntityHandle, EntityHandle >::iterator mit = duplicatedVerticesMap.find( currentVertex );
1742  if( mit != duplicatedVerticesMap.end() )
1743  {
1744  connectivity[i] = mit->second; // replace connectivity directly
1745  }
1746  }
1747  int nnodes = (int)connectivity.size();
1748  MB_CHK_SET_ERR( mb->set_connectivity( intxCell, &connectivity[0], nnodes ), "can't set connectivity" );
1749  }
1750  }
1751  return MB_SUCCESS;
1752 }
1753 #endif /* MOAB_HAVE_MPI */
1754 #undef ENABLE_DEBUG
1755 } /* namespace moab */