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