1/*
2 * Intx2Mesh.cpp
3 *
4 * Created on: Oct 2, 2012
5 */67#include<limits>8#include<queue>9#include<sstream>10//11#include"moab/IntxMesh/Intx2Mesh.hpp"12#ifdef MOAB_HAVE_MPI13#include"moab/ParallelComm.hpp"14#include"MBParallelConventions.h"15#include"moab/ParallelMergeMesh.hpp"16#endif/* MOAB_HAVE_MPI */17#include"MBTagConventions.hpp"18#include"moab/GeomUtil.hpp"19#include"moab/AdaptiveKDTree.hpp"2021namespace moab
22 {
2324#ifdef ENABLE_DEBUG25int Intx2Mesh::dbg_1 = 0;
26#endif2728 Intx2Mesh::Intx2Mesh( Interface* mbimpl )
29 : mb( mbimpl ), mbs1( 0 ), mbs2( 0 ), outSet( 0 ), gid( 0 ), TgtFlagTag( 0 ), tgtParentTag( 0 ), srcParentTag( 0 ),
30countTag( 0 ), srcNeighTag( 0 ), tgtNeighTag( 0 ), neighTgtEdgeTag( 0 ), orgSendProcTag( 0 ), imaskTag( 0 ),
31tgtConn( NULL ), srcConn( NULL ), epsilon_1( 0.0 ), epsilon_area( 0.0 ), box_error( 0.0 ), localRoot( 0 ),
32my_rank( 0 )
33#ifdef MOAB_HAVE_MPI34 ,
35parcomm( NULL ), remote_cells( NULL ), remote_cells_with_tracers( NULL )
36#endif37 ,
38max_edges_1( 0 ), max_edges_2( 0 ), counting( 0 )
39 {
40 gid = mbimpl->globalId_tag();
41 }
4243 Intx2Mesh::~Intx2Mesh()
44 {
45// TODO Auto-generated destructor stub46#ifdef MOAB_HAVE_MPI47if( remote_cells )
48 {
49delete remote_cells;
50 remote_cells = NULL;
51 }
52#endif53 }
5455ErrorCode Intx2Mesh::FindMaxEdgesInSet( EntityHandle eset, int& max_edges )
56 {
57 Range cells;
58 ErrorCode rval = mb->get_entities_by_dimension( eset, 2, cells );MB_CHK_ERR( rval );
5960 max_edges = 0; // can be 0 for point clouds61for( Range::iterator cit = cells.begin(); cit != cells.end(); cit++ )
62 {
63 EntityHandle cell = *cit;
64const EntityHandle* conn4;
65int nnodes = 3;
66 rval = mb->get_connectivity( cell, conn4, nnodes );MB_CHK_SET_ERR( rval, "can't get connectivity of a cell" );
67if( nnodes > max_edges ) max_edges = nnodes;
68 }
69// if in parallel, communicate the actual max_edges; it is not needed for tgt mesh (to be70// global) but it is better to be consistent71#ifdef MOAB_HAVE_MPI72if( parcomm )
73 {
74int local_max_edges = max_edges;
75// now reduce max_edges over all processors76int mpi_err =
77MPI_Allreduce( &local_max_edges, &max_edges, 1, MPI_INT, MPI_MAX, parcomm->proc_config().proc_comm() );
78if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
79 }
80#endif8182return MB_SUCCESS;
83 }
8485ErrorCode Intx2Mesh::FindMaxEdges( EntityHandle set1, EntityHandle set2 )
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" );
8990return MB_SUCCESS;
91 }
9293ErrorCode Intx2Mesh::createTags()
94 {
95if( tgtParentTag ) mb->tag_delete( tgtParentTag );
96if( srcParentTag ) mb->tag_delete( srcParentTag );
97if( countTag ) mb->tag_delete( countTag );
9899unsignedchar def_data_bit = 0; // unused by default100// 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 found104// this is the only call that is potentially NlogN, in the whole method105 rval = mb->get_adjacencies( rs2, 1, true, TgtEdges, Interface::UNION );MB_CHK_SET_ERR( rval, "can't get adjacent tgt edges" );
106107// now, create a map from each edge to a list of potential new nodes on a tgt edge108// this memory has to be cleaned up109// change it to a vector, and use the index in range of tgt edges110int indx = 0;
111 extraNodesVec.resize( TgtEdges.size() );
112for( 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 }
117118int defaultInt = -1;
119120 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" );
122123 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" );
125126 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" );
127128// 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" );
132133// for tgt cells, save a dense tag with the bordering edges, so we do not have to search for134// them each time edges were for sure created before (tgtEdges)135std::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 it137 rval = mb->tag_get_handle( "__tgtEdgeNeighbors", neighTgtEdgeTag );
138if( rval == MB_SUCCESS && neighTgtEdgeTag ) mb->tag_delete( 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" );
141for( Range::iterator rit = rs2.begin(); rit != rs2.end(); rit++ )
142 {
143 EntityHandle tgtCell = *rit;
144int 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 polygons147while( tgtConn[num_nodes - 2] == tgtConn[num_nodes - 1] && num_nodes > 3 )
148 num_nodes--;
149150int i = 0;
151for( 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 polygons155 std::vector< EntityHandle > adj_entities;
156 rval = mb->get_adjacencies( v, 2, 1, false, adj_entities, Interface::INTERSECT );
157if( rval != MB_SUCCESS || adj_entities.size() < 1 ) return rval; // get out , big error158 zeroh[i] = adj_entities[0]; // should be only one edge between 2 nodes159// also, even if number of edges is less than max_edges_2, they will be ignored, even if160// the tag is dense161 }
162// now set the value of the tag163 rval = mb->tag_set_data( neighTgtEdgeTag, &tgtCell, 1, &( zeroh[0] ) );MB_CHK_SET_ERR( rval, "can't set edge tgt tag" );
164 }
165return MB_SUCCESS;
166 }
167168ErrorCode 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" );
172173std::vector< EntityHandle > neighbors( max_edges );
174std::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 mesh177 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" );
178179for( Range::iterator cit = cells.begin(); cit != cells.end(); cit++ )
180 {
181 EntityHandle cell = *cit;
182int 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,185const EntityHandle* conn4;
186 rval = mb->get_connectivity( cell, conn4, nnodes );MB_CHK_SET_ERR( rval, "can't get connectivity of a cell" );
187int nsides = nnodes;
188// account for possible padded polygons189while( conn4[nsides - 2] == conn4[nsides - 1] && nsides > 3 )
190 nsides--;
191192for( 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 edge198 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 manifold203size_t siz = adjcells.size();
204for( size_t j = 0; j < siz; j++ )
205if( mb->contains_entities( inputSet, &( adjcells[j] ), 1 ) ) cellsInSet.push_back( adjcells[j] );
206 siz = cellsInSet.size();
207208if( siz > 2 )
209 {
210 std::cout << "non manifold mesh, error" << mb->list_entities( &( cellsInSet[0] ), cellsInSet.size() )
211 << std::endl;
212MB_CHK_SET_ERR( MB_FAILURE, "non-manifold input mesh set" ); // non-manifold213 }
214if( 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 border218// borders do not appear for a sphere in serial, but they do appear for219// parallel processing anyway220continue;
221 }
222// here siz ==2, it is either the first or second223if( cell == cellsInSet[0] )
224 neighbors[i] = cellsInSet[1];
225else226 neighbors[i] = cellsInSet[0];
227 }
228// fill the rest with 0229for( 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 for232// 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 }
235return MB_SUCCESS;
236 }
237238// slow interface; this will not do the advancing front trick239// some are triangles, some are quads, some are polygons ...240ErrorCode Intx2Mesh::intersect_meshes_kdtree( EntityHandle mbset1, EntityHandle mbset2, EntityHandle& outputSet )
241 {
242 ErrorCode rval;
243 mbs1 = mbset1; // set 1 is departure, and it is completely covering the euler set on proc244 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 ones249if( tgtParentTag ) mb->tag_delete( tgtParentTag );
250if( srcParentTag ) mb->tag_delete( srcParentTag );
251if( countTag ) mb->tag_delete( countTag );
252253// filter rs1 and rs2 by mask; remove everything with 0 mask254// get the mask tag if it exists; if not, leave it uninitialized (NULL)255 rval = mb->tag_get_handle( "GRID_IMASK", imaskTag );
256if( 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 found260// this is the only call that is potentially NlogN, in the whole method261 rval = mb->get_adjacencies( rs2, 1, true, TgtEdges, Interface::UNION );MB_CHK_SET_ERR( rval, "can't get adjacent tgt edges" );
262263int index = 0;
264 extraNodesVec.resize( TgtEdges.size() );
265for( 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 }
270271int defaultInt = -1;
272// Now let us create the association tags to source and target parent, along with internal counters273 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" );
278279// for tgt cells, save a dense tag with the bordering edges, so we do not have to search for280// 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 it282 rval = mb->tag_get_handle( "__tgtEdgeNeighbors", neighTgtEdgeTag );
283if( rval == MB_SUCCESS && neighTgtEdgeTag ) mb->tag_delete( neighTgtEdgeTag );
284std::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" );
287288for( Range::iterator rit = rs2.begin(); rit != rs2.end(); rit++ )
289 {
290 EntityHandle tgtCell = *rit;
291int 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 polygons294while( tgtConn[num_nodes - 2] == tgtConn[num_nodes - 1] && num_nodes > 3 )
295 num_nodes--;
296297for( 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 polygons301 std::vector< EntityHandle > adj_entities;
302 rval = mb->get_adjacencies( v, 2, 1, false, adj_entities, Interface::INTERSECT );
303if( rval != MB_SUCCESS || adj_entities.size() < 1 ) return rval; // get out , big error304 zeroh[i] = adj_entities[0]; // should be only one edge between 2 nodes305// also, even if number of edges is less than max_edges_2, they will be ignored, even if306// the tag is dense307 }
308// now set the value of the tag309 rval = mb->tag_set_data( neighTgtEdgeTag, &tgtCell, 1, &( zeroh[0] ) );MB_CHK_SET_ERR( rval, "can't set edge tgt tag" );
310 }
311312// find out max edge on source mesh;313double max_length = 0;
314 {
315std::vector< double > coords( 3 * max_edges_1, 0.0 );
316for( Range::iterator it = rs1.begin(); it != rs1.end(); it++ )
317 {
318const EntityHandle* conn = NULL;
319int nnodes;
320 rval = mb->get_connectivity( *it, conn, nnodes );MB_CHK_SET_ERR( rval, "can't get connectivity" );
321while( 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" );
324for( int j = 0; j < nnodes; j++ )
325 {
326int next = ( j + 1 ) % nnodes;
327double 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] );
331if( edge_length > max_length ) max_length = edge_length;
332 }
333 }
334 max_length = std::sqrt( max_length );
335 }
336337// maximum sag on a spherical mesh make sense only for intx on a sphere, with radius 1 :(338double tolerance = 1.e-15;
339if( max_length < 1. )
340 {
341// basically, the sag for an arc of length max_length on a circle of radius 1342 tolerance = 1. - sqrt( 1 - max_length * max_length / 4 );
343if( box_error < tolerance ) box_error = tolerance;
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.)346347if( !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_MPI354// reduce box tolerance on every task, if needed355double min_box_eps;
356MPI_Allreduce( &box_error, &min_box_eps, 1, MPI_DOUBLE, MPI_MIN, parcomm->comm() );
357 box_error = min_box_eps;
358#endif359360// create the kd tree on source cells, and intersect all targets in an expensive loop361// build a kd tree with the rs1 (source) cells362FileOptions kdOpts( "PLANE_SET=1;SPLITS_PER_DIR=2;SPHERICAL;RADIUS=1.0;" );
363AdaptiveKDTree kd( mb );
364 kd.parse_options( kdOpts );
365 EntityHandle tree_root = 0;
366 rval = kd.build_tree( rs1, &tree_root );MB_CHK_ERR( rval );
367368for( Range::iterator it = rs2.begin(); it != rs2.end(); ++it )
369 {
370 EntityHandle tcell = *it;
371// find vertex positions372const EntityHandle* conn = NULL;
373int nnodes = 0;
374 rval = mb->get_connectivity( tcell, conn, nnodes );MB_CHK_ERR( rval );
375// find leaves close to those positions376double areaTgtCell = setup_tgt_cell( tcell, nnodes ); // this is the area in the gnomonic plane377double 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 );
381382// distance to search will be based on average edge length383double av_len = 0;
384for( int k = 0; k < nnodes; k++ )
385 {
386int ik = ( k + 1 ) % nnodes;
387double len1 = 0;
388for( int j = 0; j < 3; j++ )
389 {
390double len2 = positions[3 * k + j] - positions[3 * ik + j];
391 len1 += len2 * len2;
392 }
393 av_len += sqrt( len1 );
394 }
395if( nnodes > 0 ) av_len /= nnodes;
396// find leaves within a distance from each vertex of target397// in those leaves, collect all cells; we will try for an intx in there398 Range close_source_cells;
399 std::vector< EntityHandle > leaves;
400for( 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 );
404405for( 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 );
409410 close_source_cells.merge( tmp.begin(), tmp.end() );
411 }
412 }
413#ifdef VERBOSE414if( 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#endif420for( Range::iterator it2 = close_source_cells.begin(); it2 != close_source_cells.end(); ++it2 )
421 {
422 EntityHandle startSrc = *it2;
423double area = 0;
424// if area is > 0 , we have intersections425double P[10 * MAXEDGES]; // max 8 intx points + 8 more in the polygon426//427int nP = 0;
428int nb[MAXEDGES], nr[MAXEDGES]; // sides 3 or 4? also, check boxes first429int nsTgt, nsSrc;
430 rval = computeIntersectionBetweenTgtAndSrc( tcell, startSrc, P, nP, area, nb, nr, nsSrc, nsTgt, true );MB_CHK_ERR( rval );
431if( area > 0 )
432 {
433if( nP > 1 )
434 { // this will also construct triangles/polygons in the new mesh, if needed435 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 fract441 }
442// before cleaning up , we need to settle the position of the intersection points443// on the boundary edges444// this needs to be collective, so we should maybe wait something445#ifdef MOAB_HAVE_MPI446 rval = resolve_intersection_sharing();MB_CHK_SET_ERR( rval, "can't correct position, Intx2Mesh.cpp \n" );
447#endif448449this->clean();
450return MB_SUCCESS;
451 }
452453// main interface; this will do the advancing front trick454// some are triangles, some are quads, some are polygons ...455ErrorCode Intx2Mesh::intersect_meshes( EntityHandle mbset1, EntityHandle mbset2, EntityHandle& outputSet )
456 {
457 ErrorCode rval;
458 mbs1 = mbset1; // set 1 is departure, and it is completely covering the euler set on proc459 mbs2 = mbset2;
460 outSet = outputSet;
461#ifdef VERBOSE462 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 );
467468#endif469// really, should be something from t1 and t2; src is 1 (lagrange), tgt is 2 (euler)470471 EntityHandle startSrc = 0, startTgt = 0;
472473 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 );
475476// filter rs1 and rs2 by mask; remove everything with 0 mask477// get the mask tag if it exists; if not, leave it uninitialized (NULL)478 mb->tag_get_handle( "GRID_IMASK", imaskTag );
479if( imaskTag != NULL && rval != MB_SUCCESS ) MB_CHK_SET_ERR( rval, "can't get GRID_IMASK tag" );
480481 rval = filterByMask( rs1 );MB_CHK_ERR( rval );
482 rval = filterByMask( rs2 );MB_CHK_ERR( rval );
483484createTags(); // will also determine max_edges_1, max_edges_2 (for src and tgt meshes)485486 Range rs22 = rs2; // a copy of the initial range; we will remove from it elements as we487// advance ; rs2 is needed for marking the polygon to the tgt parent488489// create the local kdd tree with source elements; will use it to search490// 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 eliminated492// early from contention493494// build a kd tree with the rs1 (source) cells495FileOptions kdOpts( "PLANE_SET=1;SPLITS_PER_DIR=2;SPHERICAL;RADIUS=1.0;" );
496AdaptiveKDTree kd( mb );
497 kd.parse_options( kdOpts );
498 EntityHandle tree_root = 0;
499 rval = kd.build_tree( rs1, &tree_root );MB_CHK_ERR( rval );
500501while( !rs22.empty() )
502 {
503#if defined( ENABLE_DEBUG ) || defined( VERBOSE )504if( 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#endif513bool seedFound = false;
514for( Range::iterator it = rs22.begin(); it != rs22.end(); ++it )
515 {
516 startTgt = *it;
517int found = 0;
518// find vertex positions519const EntityHandle* conn = NULL;
520int nnodes = 0;
521 rval = mb->get_connectivity( startTgt, conn, nnodes );MB_CHK_ERR( rval );
522// find leaves close to those positions523 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 target527// in those leaves, collect all cells; we will try for an intx in there, instead of528// looping over all rs1 cells, as before529 Range close_source_cells;
530 std::vector< EntityHandle > leaves;
531for( 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 );
535536for( 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 );
540541 close_source_cells.merge( tmp.begin(), tmp.end() );
542 }
543 }
544545for( Range::iterator it2 = close_source_cells.begin(); it2 != close_source_cells.end() && !found; ++it2 )
546 {
547 startSrc = *it2;
548double area = 0;
549// if area is > 0 , we have intersections550double P[10 * MAXEDGES]; // max 8 intx points + 8 more in the polygon551//552int nP = 0;
553int nb[MAXEDGES], nr[MAXEDGES]; // sides 3 or 4? also, check boxes first554int nsTgt, nsSrc;
555 rval =
556computeIntersectionBetweenTgtAndSrc( startTgt, startSrc, P, nP, area, nb, nr, nsSrc, nsTgt, true );MB_CHK_ERR( rval );
557if( area > 0 )
558 {
559 found = 1;
560 seedFound = true;
561break; // found 2 elements that intersect; these will be the seeds562 }
563 }
564if( found )
565break;
566else567 {
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#endif572 rs22.erase( startTgt );
573 }
574 }
575if( !seedFound ) continue; // continue while(!rs22.empty())576577 std::queue< EntityHandle > srcQueue; // these are corresponding to Ta,578 srcQueue.push( startSrc );
579 std::queue< EntityHandle > tgtQueue;
580 tgtQueue.push( startTgt );
581582 Range toResetSrcs; // will be used to reset src flags for every tgt element processed583584/*if (my_rank==0)
585 dbg_1 = 1;*/586unsignedchar used = 1;
587// mark the start tgt quad as used, so it will not come back again588 rval = mb->tag_set_data( TgtFlagTag, &startTgt, 1, &used );MB_CHK_ERR( rval );
589while( !tgtQueue.empty() )
590 {
591// flags for the side : 0 means a src cell not found on side592// a paired src not found yet for the neighbors of tgt593 Range nextSrc[MAXEDGES]; // there are new ranges of possible next src cells for594// seeding the side j of tgt cell595596 EntityHandle currentTgt = tgtQueue.front();
597 tgtQueue.pop();
598int nsidesTgt; // will be initialized now599double areaTgtCell = setup_tgt_cell( currentTgt, nsidesTgt ); // this is the area in the gnomonic plane600double recoveredArea = 0;
601// get the neighbors of tgt, and if they are solved already, do not bother with that602// side of tgt603 EntityHandle tgtNeighbors[MAXEDGES] = { 0 };
604 rval = mb->tag_get_data( tgtNeighTag, ¤tTgt, 1, tgtNeighbors );MB_CHK_SET_ERR( rval, "can't get neighbors of current tgt" );
605#ifdef ENABLE_DEBUG606if( dbg_1 )
607 {
608 std::cout << "Next: neighbors for current tgt ";
609for( int kk = 0; kk < nsidesTgt; kk++ )
610 {
611if( tgtNeighbors[kk] > 0 )
612 std::cout << mb->id_from_handle( tgtNeighbors[kk] ) << " ";
613else614 std::cout << 0 << " ";
615 }
616 std::cout << std::endl;
617 }
618#endif619// now get the status of neighbors; if already solved, make them 0, so not to bother620// anymore on that side of tgt621for( int j = 0; j < nsidesTgt; j++ )
622 {
623 EntityHandle tgtNeigh = tgtNeighbors[j];
624unsignedchar status = 1;
625if( tgtNeigh == 0 ) continue;
626 rval = mb->tag_get_data( TgtFlagTag, &tgtNeigh, 1, &status );MB_CHK_ERR( rval ); // status 0 is unused627if( 1 == status ) tgtNeighbors[j] = 0; // so will not look anymore on this side of tgt628 }
629630#ifdef ENABLE_DEBUG631if( dbg_1 )
632 {
633 std::cout << "reset sources: ";
634for( Range::iterator itr = toResetSrcs.begin(); itr != toResetSrcs.end(); ++itr )
635 std::cout << mb->id_from_handle( *itr ) << " ";
636 std::cout << std::endl;
637 }
638#endif639 EntityHandle currentSrc = srcQueue.front();
640// tgt and src queues are parallel; for clarity we should have kept in the queue pairs641// of entity handle std::pair<EntityHandle, EntityHandle>; so just one queue, with642// pairs;643// at every moment, the queue contains pairs of cells that intersect, and they form the644// "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 processing648 toResetSrcs.insert( currentSrc );
649// mb2->set_tag_data650 std::queue< EntityHandle > localSrc;
651 localSrc.push( currentSrc );
652#ifdef VERBOSE653int countingStart = counting;
654#endif655// will advance-front search in the neighborhood of tgt cell, until we finish processing656// all657// possible src cells; localSrc queue will contain all possible src cells that cover658// the current tgt cell659while( !localSrc.empty() )
660 {
661//662 EntityHandle srcT = localSrc.front();
663 localSrc.pop();
664double P[10 * MAXEDGES], area; //665int nP = 0;
666int nb[MAXEDGES] = { 0 };
667int nr[MAXEDGES] = { 0 };
668669int nsidesSrc; ///670// area is in 2d, points are in 3d (on a sphere), back-projected, or in a plane671// intersection points could include the vertices of initial elements672// 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 the674// tgt poly. A potential next poly in the tgt queue is the tgt poly that is675// adjacent to this side676 rval = computeIntersectionBetweenTgtAndSrc( /* tgt */ currentTgt, srcT, P, nP, area, nb, nr, nsidesSrc,
677 nsidesTgt );MB_CHK_ERR( rval );
678if( nP > 0 )
679 {
680#ifdef ENABLE_DEBUG681if( dbg_1 )
682 {
683for( int k = 0; k < 3; k++ )
684 {
685 std::cout << " nb, nr: " << k << " " << nb[k] << " " << nr[k] << "\n";
686 }
687 }
688#endif689690// intersection found: output P and original triangles if nP > 2691 EntityHandle neighbors[MAXEDGES] = { 0 };
692 rval = mb->tag_get_data( srcNeighTag, &srcT, 1, neighbors );
693if( rval != MB_SUCCESS )
694 {
695 std::cout << " can't get the neighbors for src element " << mb->id_from_handle( srcT );
696return MB_FAILURE;
697 }
698699// add neighbors to the localSrc queue, if they are not marked700for( int nn = 0; nn < nsidesSrc; nn++ )
701 {
702 EntityHandle neighbor = neighbors[nn];
703if( neighbor > 0 && nb[nn] > 0 ) // advance across src boundary nn704 {
705if( toResetSrcs.find( neighbor ) == toResetSrcs.end() )
706 {
707 localSrc.push( neighbor );
708#ifdef ENABLE_DEBUG709if( 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#endif716 toResetSrcs.insert( neighbor );
717 }
718 }
719 }
720// n(find(nc>0))=ac; % ac is starting candidate for neighbor721for( int nn = 0; nn < nsidesTgt; nn++ )
722 {
723if( nr[nn] > 0 && tgtNeighbors[nn] > 0 )
724 nextSrc[nn].insert( srcT ); // potential src cell that can intersect725// the tgt neighbor nn726 }
727if( nP > 1 )
728 { // this will also construct triangles/polygons in the new mesh, if needed729 rval = findNodes( currentTgt, nsidesTgt, srcT, nsidesSrc, P, nP );MB_CHK_ERR( rval );
730 }
731732 recoveredArea += area;
733 }
734#ifdef ENABLE_DEBUG735elseif( 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#endif741 } // end while (!localSrc.empty())742 recoveredArea = ( recoveredArea - areaTgtCell ) / areaTgtCell; // replace now with recovery fraction743#if defined( ENABLE_DEBUG ) || defined( VERBOSE )744if( fabs( recoveredArea ) > epsilon_1 )
745 {
746#ifdef VERBOSE747 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#endif752 }
753#endif754// here, we are finished with tgtCurrent, take it out of the rs22 range (tgt, arrival755// mesh)756 rs22.erase( currentTgt );
757// also, look at its neighbors, and add to the seeds a next one758759for( int j = 0; j < nsidesTgt; j++ )
760 {
761 EntityHandle tgtNeigh = tgtNeighbors[j];
762if( tgtNeigh == 0 || nextSrc[j].size() == 0 ) // if tgt is bigger than src, there could be no src763// to advance on that side764continue;
765int nsidesTgt2 = 0;
766setup_tgt_cell( tgtNeigh,
767 nsidesTgt2 ); // find possible intersection with src cell from nextSrc768for( 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 the772// src quad773double P[10 * MAXEDGES], area; //774int nP = 0;
775int nb[MAXEDGES] = { 0 };
776int nr[MAXEDGES] = { 0 };
777778int nsidesSrc; ///779 rval = computeIntersectionBetweenTgtAndSrc(
780/* tgt */ tgtNeigh, nextB, P, nP, area, nb, nr, nsidesSrc, nsidesTgt2 );MB_CHK_ERR( rval );
781if( area > 0 )
782 {
783 tgtQueue.push( tgtNeigh );
784 srcQueue.push( nextB );
785#ifdef ENABLE_DEBUG786if( dbg_1 )
787 std::cout << "new polys pushed: src, tgt:" << mb->id_from_handle( tgtNeigh ) << " "788 << mb->id_from_handle( nextB ) << std::endl;
789#endif790 rval = mb->tag_set_data( TgtFlagTag, &tgtNeigh, 1, &used );MB_CHK_ERR( rval );
791break; // so we are done with this side of tgt, we have found a proper next792// seed793 }
794 }
795 }
796797 } // end while (!tgtQueue.empty())798 }
799#ifdef ENABLE_DEBUG800if( dbg_1 )
801 {
802for( int k = 0; k < 6; k++ )
803 mout_1[k].close();
804 }
805#endif806// before cleaning up , we need to settle the position of the intersection points807// on the boundary edges808// this needs to be collective, so we should maybe wait something809#ifdef MOAB_HAVE_MPI810 rval = resolve_intersection_sharing();MB_CHK_SET_ERR( rval, "can't correct position, Intx2Mesh.cpp \n" );
811#endif812813this->clean();
814return MB_SUCCESS;
815 }
816817ErrorCode Intx2Mesh::filterByMask( Range& cells )
818 {
819if( !imaskTag ) return MB_SUCCESS; // nothing to do820size_t sz = cells.size();
821std::vector< int > masks( sz );
822823 ErrorCode rval = mb->tag_get_data( imaskTag, cells, &masks[0] );MB_CHK_ERR( rval );
824 Range cellsToRemove;
825size_t indx = 0;
826for( Range::iterator eit = cells.begin(); eit != cells.end(); ++eit, ++indx )
827 {
828if( masks[indx] ) continue;
829 cellsToRemove.insert( *eit );
830 }
831 cells = subtract( cells, cellsToRemove );
832return MB_SUCCESS;
833 }
834835// clean some memory allocated836voidIntx2Mesh::clean()
837 {
838//839int indx = 0;
840for( Range::iterator eit = TgtEdges.begin(); eit != TgtEdges.end(); ++eit, indx++ )
841 {
842delete extraNodesVec[indx];
843 }
844// extraNodesMap.clear();845 extraNodesVec.clear();
846// also, delete some bit tags, used to mark processed tgts and srcs847 mb->tag_delete( TgtFlagTag );
848 counting = 0; // reset counting to original value849 }
850851// this method will reduce number of nodes, collapse edges that are of length 0852// so a polygon like 428 431 431 will become a line 428 431853// or something like 428 431 431 531 -> 428 431 531854voidIntx2Mesh::correct_polygon( EntityHandle* nodes, int& nP )
855 {
856int i = 0;
857while( i < nP )
858 {
859int nextIndex = ( i + 1 ) % nP;
860if( nodes[i] == nodes[nextIndex] )
861 {
862#ifdef ENABLE_DEBUG863// we need to reduce nP, and collapse nodes864if( dbg_1 )
865 {
866 std::cout << " nodes duplicated in list: ";
867for( 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#endif873// 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 nothing875// (nP-1 is 3, so k is already >= nP-1); it will result in nodes -> 1, 2, 3876for( 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 check879// again880 i--;
881 }
882 i++;
883 }
884return;
885 }
886887#ifdef MOAB_HAVE_MPI888889ErrorCode Intx2Mesh::build_processor_euler_boxes( EntityHandle euler_set, Range& local_verts, bool gnomonic )
890 {
891// if it comes here, we want regular 3d boxes892// need to refactor this code893if( 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" );
896897 rval = mb->get_connectivity( localEnts, local_verts );
898int num_local_verts = (int)local_verts.size();ERRORR( rval, "can't get local vertices" );
899900assert( parcomm != NULL );
901902// get the position of local vertices, and decide local boxes (allBoxes...)903double bmin[3] = { std::numeric_limits< double >::max(), std::numeric_limits< double >::max(),
904 std::numeric_limits< double >::max() };
905double bmax[3] = { -std::numeric_limits< double >::max(), -std::numeric_limits< double >::max(),
906 -std::numeric_limits< double >::max() };
907908std::vector< double > coords( 3 * num_local_verts );
909 rval = mb->get_coords( local_verts, &coords[0] );ERRORR( rval, "can't get coords of vertices " );
910911for( int i = 0; i < num_local_verts; i++ )
912 {
913for( int k = 0; k < 3; k++ )
914 {
915double val = coords[3 * i + k];
916if( val < bmin[k] ) bmin[k] = val;
917if( val > bmax[k] ) bmax[k] = val;
918 }
919 }
920int numprocs = parcomm->proc_config().proc_size();
921 allBoxes.resize( 6 * numprocs );
922923 my_rank = parcomm->proc_config().proc_rank();
924for( 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 }
929930// now communicate to get all boxes931int mpi_err;
932#if( MPI_VERSION >= 2 )933// use "in place" option934 mpi_err = MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, &allBoxes[0], 6, MPI_DOUBLE,
935 parcomm->proc_config().proc_comm() );
936#else937 {
938std::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#endif944if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
945946#ifdef VERBOSE947if( 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";
951for( 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#endif960961return MB_SUCCESS;
962 }
963964ErrorCode Intx2Mesh::create_departure_mesh_2nd_alg( EntityHandle& euler_set, EntityHandle& covering_lagr_set )
965 {
966// compute the bounding box on each proc967assert( parcomm != NULL );
968969 localEnts.clear();
970 ErrorCode rval = mb->get_entities_by_dimension( euler_set, 2, localEnts );ERRORR( rval, "can't get ents by dimension" );
971972 Tag dpTag = 0;
973std::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" );
975976 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 verts980 Range local_verts;
981 rval = mb->get_connectivity( localEnts, local_verts );
982int num_local_verts = (int)local_verts.size();ERRORR( rval, "can't get local vertices" );
983984 rval = Intx2Mesh::build_processor_euler_boxes( euler_set, local_verts );ERRORR( rval, "can't build processor boxes" );
985986std::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" );
988989// now see the departure points; to what boxes should we send them?990std::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;
995int numprocs = parcomm->proc_config().proc_size();
996997for( Range::iterator eit = localEnts.begin(); eit != localEnts.end(); ++eit )
998 {
999 EntityHandle q = *eit;
1000const EntityHandle* conn4;
1001int num_nodes;
1002 rval = mb->get_connectivity( q, conn4, num_nodes );ERRORR( rval, "can't get DP tag values" );
1003CartVect qbmin( std::numeric_limits< double >::max() );
1004CartVect qbmax( -std::numeric_limits< double >::max() );
1005for( int i = 0; i < num_nodes; i++ )
1006 {
1007 EntityHandle v = conn4[i];
1008size_t index = local_verts.find( v ) - local_verts.begin();
1009CartVect dp( &dep_points[3 * index] ); // will use constructor1010for( int j = 0; j < 3; j++ )
1011 {
1012if( qbmin[j] > dp[j] ) qbmin[j] = dp[j];
1013if( qbmax[j] < dp[j] ) qbmax[j] = dp[j];
1014 }
1015 }
1016for( int p = 0; p < numprocs; p++ )
1017 {
1018CartVect bbmin( &allBoxes[6 * p] );
1019CartVect bbmax( &allBoxes[6 * p + 3] );
1020if( GeomUtil::boxes_overlap( bbmin, bbmax, qbmin, qbmax, box_error ) )
1021 {
1022 Rto[p].insert( q );
1023 }
1024 }
1025 }
10261027// now, build TLv and TLq, for each p1028size_t numq = 0;
1029size_t numv = 0;
1030for( int p = 0; p < numprocs; p++ )
1031 {
1032if( p == (int)my_rank ) continue; // do not "send" it, because it is already here1033 Range& range_to_P = Rto[p];
1034// add the vertices to it1035if( range_to_P.empty() ) continue; // nothing to send to proc p1036 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 points1045 TLv.enableWriteAccess();
10461047int sizeTuple = 2 + max_edges_1; // determined earlier, for src, first mesh1048 TLq.initialize( 2 + max_edges_1, 0, 1, 0,
1049 numq ); // to proc, elem GLOBAL ID, connectivity[10] (global ID v), local eh1050 TLq.enableWriteAccess();
1051#ifdef VERBOSE1052 std::cout << "from proc " << my_rank << " send " << numv << " vertices and " << numq << " elements\n";
1053#endif1054for( int to_proc = 0; to_proc < numprocs; to_proc++ )
1055 {
1056if( to_proc == (int)my_rank ) continue;
1057 Range& range_to_P = Rto[to_proc];
1058 Range V = range_to_P.subset_by_type( MBVERTEX );
10591060for( Range::iterator it = V.begin(); it != V.end(); ++it )
1061 {
1062 EntityHandle v = *it;
1063unsignedint index = local_verts.find( v ) - local_verts.begin();
1064int n = TLv.get_n();
1065 TLv.vi_wr[2 * n] = to_proc; // send to processor1066 TLv.vi_wr[2 * n + 1] = gids[index]; // global id needs index in the local_verts range1067 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 );
1074for( Range::iterator it = Q.begin(); it != Q.end(); ++it )
1075 {
1076 EntityHandle q = *it;
1077int global_id;
1078 rval = mb->tag_get_data( gid, &q, 1, &global_id );ERRORR( rval, "can't get gid for polygon" );
1079int 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 ...1082const EntityHandle* conn4;
1083int num_nodes;
1084 rval = mb->get_connectivity( q, conn4,
1085 num_nodes ); // could be up to MAXEDGES, but it is limited by max_edges_11086ERRORR( rval, "can't get connectivity for cell" );
1087if( num_nodes > MAXEDGES ) ERRORR( MB_FAILURE, "too many nodes in a polygon" );
1088for( int i = 0; i < num_nodes; i++ )
1089 {
1090 EntityHandle v = conn4[i];
1091unsignedint index = local_verts.find( v ) - local_verts.begin();
1092 TLq.vi_wr[sizeTuple * n + 2 + i] = gids[index];
1093 }
1094for( int k = num_nodes; k < max_edges_1; k++ )
1095 {
1096 TLq.vi_wr[sizeTuple * n + 2 + k] =
10970; // 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 back1100// maybe we should forget about global ID1101 TLq.inc_n();
1102 }
1103 }
11041105// now we are done populating the tuples; route them to the appropriate processors1106 ( 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;11091110// maps from global ids to new vertex and quad handles, that are added1111 std::map< int, EntityHandle > globalID_to_handle;
1112/*std::map<int, EntityHandle> globalID_to_eh;*/1113 globalID_to_eh.clear(); // need for next iteration1114// now, look at every TLv, and see if we have to create a vertex there or not1115int n = TLv.get_n(); // the size of the points received1116for( int i = 0; i < n; i++ )
1117 {
1118int globalId = TLv.vi_rd[2 * i + 1];
1119if( globalID_to_handle.find( globalId ) == globalID_to_handle.end() )
1120 {
1121 EntityHandle new_vert;
1122double 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 }
11271128// now, all dep points should be at their place1129// look in the local list of q for this proc, and create all those quads and vertices if needed1130// it may be an overkill, but because it does not involve communication, we do it anyway1131 Range& local = Rto[my_rank];
1132 Range local_q = local.subset_by_dimension( 2 );
1133// the local should have all the vertices in local_verts1134for( Range::iterator it = local_q.begin(); it != local_q.end(); ++it )
1135 {
1136 EntityHandle q = *it;
1137int nnodes;
1138const EntityHandle* conn4;
1139 rval = mb->get_connectivity( q, conn4, nnodes );ERRORR( rval, "can't get connectivity of local q " );
1140 EntityHandle new_conn[MAXEDGES];
1141for( int i = 0; i < nnodes; i++ )
1142 {
1143 EntityHandle v1 = conn4[i];
1144unsignedint index = local_verts.find( v1 ) - local_verts.begin();
1145int globalId = gids[index];
1146if( globalID_to_handle.find( globalId ) == globalID_to_handle.end() )
1147 {
1148// we need to create that vertex, at this position dep_points1149double 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;
1159if( nnodes > 4 ) entType = MBPOLYGON;
1160if( nnodes < 4 ) entType = MBTRI;
11611162 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" );
1164int gid_el;
1165// get the global ID of the initial quad1166 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 elem1171 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 them1174 n = TLq.get_n(); // number of elements received by this processor1175// form the remote cells, that will be used to send the tracer info back to the originating proc1176 remote_cells = newTupleList();
1177 remote_cells->initialize( 2, 0, 1, 0, n ); // will not have tracer data anymore1178 remote_cells->enableWriteAccess();
1179for( int i = 0; i < n; i++ )
1180 {
1181int globalIdEl = TLq.vi_rd[sizeTuple * i + 1];
1182int from_proc = TLq.vi_wr[sizeTuple * i];
1183// do we already have a quad with this global ID, represented?1184if( globalID_to_eh.find( globalIdEl ) == globalID_to_eh.end() )
1185 {
1186// construct the conn quad1187 EntityHandle new_conn[MAXEDGES];
1188int nnodes = -1;
1189for( int j = 0; j < max_edges_1; j++ )
1190 {
1191int vgid = TLq.vi_rd[sizeTuple * i + 2 + j]; // vertex global ID1192if( vgid == 0 )
1193 new_conn[j] = 0;
1194else1195 {
1196assert( 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 number1199 }
1200 }
1201 EntityHandle new_element;
1202//1203 EntityType entType = MBQUAD;
1204if( nnodes > 4 ) entType = MBPOLYGON;
1205if( 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 back1213 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 elem1216 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 it1220// 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();
1225return MB_SUCCESS;
1226 }
12271228// this algorithm assumes lagr set is already created, and some elements will be coming from1229// other procs, and populate the covering_set1230// we need to keep in a tuple list the remote cells from other procs, because we need to send back1231// the intersection info (like area of the intx polygon, and the current concentration) maybe total1232// mass in that intx1233ErrorCode Intx2Mesh::create_departure_mesh_3rd_alg( EntityHandle& lagr_set, EntityHandle& covering_set )
1234 {
1235 EntityHandle dum = 0;
12361237 Tag corrTag;
1238 ErrorCode rval = mb->tag_get_handle( CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE | MB_TAG_CREAT, &dum );
1239// start copy from 2nd alg1240// compute the bounding box on each proc1241assert( parcomm != NULL );
1242if( 1 == parcomm->proc_config().proc_size() )
1243 {
1244 covering_set = lagr_set; // nothing to communicate, it must be serial1245return MB_SUCCESS;
1246 }
12471248// get all local verts1249 Range local_verts;
1250 rval = mb->get_connectivity( localEnts, local_verts );
1251int num_local_verts = (int)local_verts.size();ERRORR( rval, "can't get local vertices" );
12521253std::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" );
12551256 Range localDepCells;
1257 rval = mb->get_entities_by_dimension( lagr_set, 2, localDepCells );ERRORR( rval, "can't get ents by dimension from lagr set" );
12581259// get all lagr verts (departure vertices)1260 Range lagr_verts;
1261 rval = mb->get_connectivity( localDepCells, lagr_verts ); // they should be created in1262// the same order as the euler vertices1263int num_lagr_verts = (int)lagr_verts.size();ERRORR( rval, "can't get local lagr vertices" );
12641265// now see the departure points position; to what boxes should we send them?1266std::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;
1271int numprocs = parcomm->proc_config().proc_size();
12721273for( Range::iterator eit = localDepCells.begin(); eit != localDepCells.end(); ++eit )
1274 {
1275 EntityHandle q = *eit;
1276const EntityHandle* conn4;
1277int num_nodes;
1278 rval = mb->get_connectivity( q, conn4, num_nodes );ERRORR( rval, "can't get DP tag values" );
1279CartVect qbmin( std::numeric_limits< double >::max() );
1280CartVect qbmax( -std::numeric_limits< double >::max() );
1281for( int i = 0; i < num_nodes; i++ )
1282 {
1283 EntityHandle v = conn4[i];
1284int index = lagr_verts.index( v );
1285assert( -1 != index );
1286CartVect dp( &dep_points[3 * index] ); // will use constructor1287for( int j = 0; j < 3; j++ )
1288 {
1289if( qbmin[j] > dp[j] ) qbmin[j] = dp[j];
1290if( qbmax[j] < dp[j] ) qbmax[j] = dp[j];
1291 }
1292 }
1293for( int p = 0; p < numprocs; p++ )
1294 {
1295CartVect bbmin( &allBoxes[6 * p] );
1296CartVect bbmax( &allBoxes[6 * p + 3] );
1297if( GeomUtil::boxes_overlap( bbmin, bbmax, qbmin, qbmax, box_error ) )
1298 {
1299 Rto[p].insert( q );
1300 }
1301 }
1302 }
13031304// now, build TLv and TLq, for each p1305size_t numq = 0;
1306size_t numv = 0;
1307for( int p = 0; p < numprocs; p++ )
1308 {
1309if( p == (int)my_rank ) continue; // do not "send" it, because it is already here1310 Range& range_to_P = Rto[p];
1311// add the vertices to it1312if( range_to_P.empty() ) continue; // nothing to send to proc p1313 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 points1322 TLv.enableWriteAccess();
13231324int sizeTuple = 2 + max_edges_1; // max edges could be up to MAXEDGES :) for polygons1325 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 to1328 TLq.enableWriteAccess();
1329#ifdef VERBOSE1330 std::cout << "from proc " << my_rank << " send " << numv << " vertices and " << numq << " elements\n";
1331#endif13321333for( int to_proc = 0; to_proc < numprocs; to_proc++ )
1334 {
1335if( to_proc == (int)my_rank ) continue;
1336 Range& range_to_P = Rto[to_proc];
1337 Range V = range_to_P.subset_by_type( MBVERTEX );
13381339for( Range::iterator it = V.begin(); it != V.end(); ++it )
1340 {
1341 EntityHandle v = *it;
1342int index = lagr_verts.index( v ); // will be the same index as the corresponding vertex in euler verts1343assert( -1 != index );
1344int n = TLv.get_n();
1345 TLv.vi_wr[2 * n] = to_proc; // send to processor1346 TLv.vi_wr[2 * n + 1] = gids[index]; // global id needs index in the local_verts range1347 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 );
1354for( Range::iterator it = Q.begin(); it != Q.end(); ++it )
1355 {
1356 EntityHandle q = *it; // this is a src cell1357int global_id;
1358 rval = mb->tag_get_data( gid, &q, 1, &global_id );ERRORR( rval, "can't get gid for polygon" );
1359int 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 ...1362const EntityHandle* conn4;
1363int 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" );1366if( num_nodes > MAXEDGES ) ERRORR( MB_FAILURE, "too many nodes in a polygon" );
1367for( int i = 0; i < num_nodes; i++ )
1368 {
1369 EntityHandle v = conn4[i];
1370int index = lagr_verts.index( v );
1371assert( -1 != index );
1372 TLq.vi_wr[sizeTuple * n + 2 + i] = gids[index];
1373 }
1374for( int k = num_nodes; k < max_edges_1; k++ )
1375 {
1376 TLq.vi_wr[sizeTuple * n + 2 + k] =
13770; // 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 back1382 TLq.inc_n();
1383 }
1384 }
1385// now we can route them to each processor1386// now we are done populating the tuples; route them to the appropriate processors1387 ( 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;13901391// maps from global ids to new vertex and quad handles, that are added1392 std::map< int, EntityHandle > globalID_to_handle;
1393// we already have vertices from lagr set; they are already in the processor, even before1394// receiving other verts from neighbors1395int k = 0;
1396for( Range::iterator vit = lagr_verts.begin(); vit != lagr_verts.end(); ++vit, k++ )
1397 {
1398 globalID_to_handle[gids[k]] = *vit; // a little bit of overkill1399// we do know that the global ids between euler and lagr verts are parallel1400 }
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 not1404int n = TLv.get_n(); // the size of the points received1405for( int i = 0; i < n; i++ )
1406 {
1407int globalId = TLv.vi_rd[2 * i + 1];
1408if( globalID_to_handle.find( globalId ) == globalID_to_handle.end() )
1409 {
1410 EntityHandle new_vert;
1411double 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 }
14161417// now, all dep points should be at their place1418// look in the local list of 2d cells for this proc, and create all those cells if needed1419// it may be an overkill, but because it does not involve communication, we do it anyway1420 Range& local = Rto[my_rank];
1421 Range local_q = local.subset_by_dimension( 2 );
1422// the local should have all the vertices in lagr_verts1423for( Range::iterator it = local_q.begin(); it != local_q.end(); ++it )
1424 {
1425 EntityHandle q = *it; // these are from lagr cells, local1426int 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 processor1429// maybe a range of global cell ids is fine?1430 }
1431// now look at all elements received through; we do not want to duplicate them1432 n = TLq.get_n(); // number of elements received by this processor1433// a cell should be received from one proc only; so why are we so worried about duplicated1434// elements? a vertex can be received from multiple sources, that is fine14351436 remote_cells = newTupleList();
1437 remote_cells->initialize( 2, 0, 1, 0, n ); // no tracers anymore in these tuples1438 remote_cells->enableWriteAccess();
1439for( int i = 0; i < n; i++ )
1440 {
1441int globalIdEl = TLq.vi_rd[sizeTuple * i + 1];
1442int from_proc = TLq.vi_rd[sizeTuple * i];
1443// do we already have a quad with this global ID, represented?1444if( globalID_to_eh.find( globalIdEl ) == globalID_to_eh.end() )
1445 {
1446// construct the conn quad1447 EntityHandle new_conn[MAXEDGES];
1448int nnodes = -1;
1449for( int j = 0; j < max_edges_1; j++ )
1450 {
1451int vgid = TLq.vi_rd[sizeTuple * i + 2 + j]; // vertex global ID1452if( vgid == 0 )
1453 new_conn[j] = 0;
1454else1455 {
1456assert( 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 number1459 }
1460 }
1461 EntityHandle new_element;
1462//1463 EntityType entType = MBQUAD;
1464if( nnodes > 4 ) entType = MBPOLYGON;
1465if( 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 communication1474 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_set1478 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 it1481// 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();
1486return MB_SUCCESS;
1487// end copy1488 }
14891490ErrorCode Intx2Mesh::resolve_intersection_sharing()
1491 {
1492if( 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 set1500// they should be removed from intx set reference, because they might not have a1501// correspondent on the other task1502 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 );
15071508 rval = parcomm->filter_pstatus( vertsInIntx, PSTATUS_NOT_OWNED, PSTATUS_AND, -1, &nonOwnedVerts );MB_CHK_ERR( rval );
15091510// 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 shared1512// with another task they might have come from coverage as a plain vertex, so losing the1513// sharing property ?15141515 Range coverVerts;
1516 rval = mb->get_connectivity( rs1, coverVerts );MB_CHK_ERR( rval );
1517// find out those that are on the interface1518 Range vertsCovInterface;
1519 rval = parcomm->filter_pstatus( coverVerts, PSTATUS_INTERFACE, PSTATUS_AND, -1, &vertsCovInterface );MB_CHK_ERR( rval );
1520// how many of these are in1521 Range nodesToDuplicate = intersect( vertsCovInterface, nonOwnedVerts );
1522// first, get all cells connected to these vertices, from intxCells15231524 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;
1530for( Range::iterator vit = nodesToDuplicate.begin(); vit != nodesToDuplicate.end(); vit++ )
1531 {
1532 EntityHandle vertex = *vit;
1533double 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 }
15391540// look now at connectedCells, and change their connectivities:1541for( Range::iterator eit = connectedCells.begin(); eit != connectedCells.end(); eit++ )
1542 {
1543 EntityHandle intxCell = *eit;
1544// replace connectivity1545 std::vector< EntityHandle > connectivity;
1546 rval = mb->get_connectivity( &intxCell, 1, connectivity );MB_CHK_ERR( rval );
1547for( size_t i = 0; i < connectivity.size(); i++ )
1548 {
1549 EntityHandle currentVertex = connectivity[i];
1550 std::map< EntityHandle, EntityHandle >::iterator mit = duplicatedVerticesMap.find( currentVertex );
1551if( mit != duplicatedVerticesMap.end() )
1552 {
1553 connectivity[i] = mit->second; // replace connectivity directly1554 }
1555 }
1556int nnodes = (int)connectivity.size();
1557 rval = mb->set_connectivity( intxCell, &connectivity[0], nnodes );MB_CHK_ERR( rval );
1558 }
1559 }
1560return MB_SUCCESS;
1561 }
1562#endif/* MOAB_HAVE_MPI */1563 } /* namespace moab */