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