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