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