1 /*
2 * Intx2Mesh.cpp
3 *
4 * Created on: Oct 2, 2012
5 */
6
7 #include "moab/IntxMesh/Intx2Mesh.hpp"
8 #ifdef MOAB_HAVE_MPI
9 #include "moab/ParallelComm.hpp"
10 #include "MBParallelConventions.h"
11 #endif /* MOAB_HAVE_MPI */
12 #include "MBTagConventions.hpp"
13 // this is for DBL_MAX
14 #include <float.h>
15 #include <queue>
16 #include <sstream>
17 #include "moab/GeomUtil.hpp"
18
19 namespace moab {
20
21 #ifdef ENABLE_DEBUG
22 int Intx2Mesh::dbg_1=0;
23 #endif
24
Intx2Mesh(Interface * mbimpl)25 Intx2Mesh::Intx2Mesh(Interface * mbimpl): mb(mbimpl),
26 mbs1(0), mbs2(0), outSet(0),
27 gid(0), RedFlagTag(0), redParentTag(0), blueParentTag(0), countTag(0), blueNeighTag(0), redNeighTag(0), neighRedEdgeTag(0),
28 orgSendProcTag(0),
29 redConn(NULL), blueConn(NULL),
30 epsilon_1(0.0), epsilon_area(0.0), box_error(0.0),
31 localRoot(0), my_rank(0)
32 #ifdef MOAB_HAVE_MPI
33 , parcomm(NULL), remote_cells(NULL), remote_cells_with_tracers(NULL)
34 #endif
35 , max_edges_1(0), max_edges_2(0), counting(0)
36 {
37 mbimpl->tag_get_handle(GLOBAL_ID_TAG_NAME, 1, MB_TYPE_INTEGER, gid);
38
39 }
40
~Intx2Mesh()41 Intx2Mesh::~Intx2Mesh()
42 {
43 // TODO Auto-generated destructor stub
44 #ifdef MOAB_HAVE_MPI
45 if (remote_cells)
46 {
47 delete remote_cells;
48 remote_cells=NULL;
49 }
50 #endif
51 }
FindMaxEdgesInSet(EntityHandle eset,int & max_edges)52 ErrorCode Intx2Mesh::FindMaxEdgesInSet(EntityHandle eset, int & max_edges)
53 {
54 Range cells;
55 ErrorCode rval = mb->get_entities_by_dimension(eset, 2, cells);MB_CHK_ERR(rval);
56
57 max_edges = 3; // should be at least 3
58 for (Range::iterator cit=cells.begin(); cit!=cells.end(); cit++)
59 {
60 EntityHandle cell = *cit;
61 const EntityHandle * conn4;
62 int nnodes = 3;
63 rval = mb->get_connectivity(cell, conn4, nnodes); MB_CHK_SET_ERR(rval, "can't get connectivity of a cell");
64 if (nnodes>max_edges)
65 max_edges = nnodes;
66 }
67 // if in parallel, communicate the actual max_edges; it is not needed for red mesh (to be global) but it is better to be consistent
68 #ifdef MOAB_HAVE_MPI
69 if (parcomm){
70 int local_max_edges = max_edges;
71 // now reduce max_edges over all processors
72 int mpi_err = MPI_Allreduce(&local_max_edges, &max_edges, 1, MPI_INT, MPI_MAX, parcomm->proc_config().proc_comm());
73 if (MPI_SUCCESS != mpi_err) return MB_FAILURE;
74 }
75 #endif
76
77 return MB_SUCCESS;
78 }
FindMaxEdges(EntityHandle set1,EntityHandle set2)79 ErrorCode Intx2Mesh::FindMaxEdges(EntityHandle set1, EntityHandle set2)
80 {
81 ErrorCode rval = FindMaxEdgesInSet(set1, max_edges_1);MB_CHK_SET_ERR(rval, "can't determine max_edges in set 1");
82 rval = FindMaxEdgesInSet(set2, max_edges_2);MB_CHK_SET_ERR(rval, "can't determine max_edges in set 2");
83
84 return MB_SUCCESS;
85 }
86
createTags()87 ErrorCode Intx2Mesh::createTags()
88 {
89 if (redParentTag)
90 mb->tag_delete(redParentTag);
91 if(blueParentTag)
92 mb->tag_delete(blueParentTag);
93 if (countTag)
94 mb->tag_delete(countTag);
95
96 unsigned char def_data_bit = 0; // unused by default
97 // maybe the red 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("redFlag", 1, MB_TYPE_BIT, RedFlagTag, MB_TAG_CREAT,
100 &def_data_bit);MB_CHK_SET_ERR(rval, "can't get red flag tag");
101
102 // create red edges if they do not exist yet; so when they are looked upon, they are found
103 // this is the only call that is potentially NlogN, in the whole method
104 rval = mb->get_adjacencies(rs2, 1, true, RedEdges, Interface::UNION);MB_CHK_SET_ERR(rval, "can't get adjacent red edges");
105
106 // now, create a map from each edge to a list of potential new nodes on a red edge
107 // this memory has to be cleaned up
108 // change it to a vector, and use the index in range of red edges
109 int indx = 0;
110 extraNodesVec.resize(RedEdges.size());
111 for (Range::iterator eit = RedEdges.begin(); eit != RedEdges.end(); ++eit, indx++)
112 {
113 std::vector<EntityHandle> * nv = new std::vector<EntityHandle>;
114 extraNodesVec[indx]=nv;
115 }
116
117 int defaultInt = -1;
118
119 rval = mb->tag_get_handle("RedParent", 1, MB_TYPE_INTEGER, redParentTag,
120 MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt);MB_CHK_SET_ERR(rval, "can't create positive tag");
121
122 rval = mb->tag_get_handle("BlueParent", 1, MB_TYPE_INTEGER, blueParentTag,
123 MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt);MB_CHK_SET_ERR(rval, "can't create negative tag");
124
125 rval = mb->tag_get_handle("Counting", 1, MB_TYPE_INTEGER, countTag,
126 MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt);MB_CHK_SET_ERR(rval, "can't create Counting tag");
127
128 // for each cell in set 1, determine its neigh in set 1 (could be null too)
129 // for each cell in set 2, determine its neigh in set 2 (if on boundary, could be 0)
130 rval = DetermineOrderedNeighbors(mbs1, max_edges_1, blueNeighTag); MB_CHK_SET_ERR(rval, "can't determine neighbors for set 1");
131 rval = DetermineOrderedNeighbors(mbs2, max_edges_2, redNeighTag); MB_CHK_SET_ERR(rval, "can't determine neighbors for set 2");
132
133 // for red cells, save a dense tag with the bordering edges, so we do not have to search for them each time
134 // edges were for sure created before (redEdges)
135 std::vector<EntityHandle> zeroh(max_edges_2, 0);
136 rval = mb->tag_get_handle("__redEdgeNeighbors", max_edges_2, MB_TYPE_HANDLE, neighRedEdgeTag,
137 MB_TAG_DENSE | MB_TAG_CREAT, &zeroh[0] );MB_CHK_SET_ERR(rval, "can't create red edge neighbors tag");
138 for (Range::iterator rit=rs2.begin(); rit!=rs2.end(); rit++ )
139 {
140 EntityHandle redCell= *rit;
141 int num_nodes=0;
142 rval = mb->get_connectivity(redCell, redConn, num_nodes);MB_CHK_SET_ERR(rval, "can't get red conn");
143 // account for padded polygons
144 while ( redConn[num_nodes-2]==redConn[num_nodes-1] && num_nodes>3)
145 num_nodes--;
146
147 int i = 0;
148 for (i = 0; i < num_nodes; i++)
149 {
150 EntityHandle v[2] = { redConn[i], redConn[(i + 1) % num_nodes] };// this is fine even for padded polygons
151 std::vector<EntityHandle> adj_entities;
152 rval = mb->get_adjacencies(v, 2, 1, false, adj_entities,
153 Interface::INTERSECT);
154 if (rval != MB_SUCCESS || adj_entities.size() < 1)
155 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 the tag is dense
158 }
159 // now set the value of the tag
160 rval = mb->tag_set_data(neighRedEdgeTag, &redCell, 1, &(zeroh[0]));MB_CHK_SET_ERR(rval, "can't set edge red tag");
161 }
162 return MB_SUCCESS;
163 }
164
DetermineOrderedNeighbors(EntityHandle inputSet,int max_edges,Tag & neighTag)165 ErrorCode Intx2Mesh::DetermineOrderedNeighbors(EntityHandle inputSet, int max_edges, Tag & neighTag)
166 {
167 Range cells;
168 ErrorCode rval = mb->get_entities_by_dimension(inputSet, 2, cells); MB_CHK_SET_ERR(rval, "can't get cells in set");
169
170 std::vector<EntityHandle> neighbors(max_edges);
171 std::vector<EntityHandle> zeroh(max_edges, 0);
172 // nameless tag, as the name is not important; we will have 2 related tags, but one on red mesh, one on blue mesh
173 rval = mb->tag_get_handle("", max_edges, MB_TYPE_HANDLE, neighTag,
174 MB_TAG_DENSE | MB_TAG_CREAT, &zeroh[0] );MB_CHK_SET_ERR(rval, "can't create neighbors tag");
175
176 for (Range::iterator cit=cells.begin(); cit!=cells.end(); cit++)
177 {
178 EntityHandle cell = *cit;
179 int nnodes = 3;
180 // will get the nnodes ordered neighbors;
181 // first cell is for nodes 0, 1, second to 1, 2, third to 2, 3, last to nnodes-1,
182 const EntityHandle * conn4;
183 rval = mb->get_connectivity(cell, conn4, nnodes);MB_CHK_SET_ERR(rval, "can't get connectivity of a cell");
184 int nsides = nnodes;
185 // account for possible padded polygons
186 while (conn4[nsides-2]==conn4[nsides-1] && nsides>3)
187 nsides--;
188
189 for (int i = 0; i < nsides; i++)
190 {
191 EntityHandle v[2];
192 v[0] = conn4[i];
193 v[1] = conn4[(i + 1) % nsides];
194 // get all cells adjacent to these 2 vertices on the edge
195 std::vector<EntityHandle> adjcells;
196 std::vector<EntityHandle> cellsInSet;
197 rval = mb->get_adjacencies(v, 2, 2, false, adjcells, Interface::INTERSECT);MB_CHK_SET_ERR(rval, "can't adjacency to 2 verts");
198 // now look for the cells contained in the input set;
199 // the input set should be a correct mesh, not overlapping cells, and manifold
200 size_t siz = adjcells.size();
201 for (size_t j = 0; j < siz; j++)
202 if (mb->contains_entities(inputSet, &(adjcells[j]), 1))
203 cellsInSet.push_back(adjcells[j]);
204 siz = cellsInSet.size();
205
206 if (siz > 2)
207 {
208 std::cout << "non manifold mesh, error"
209 << mb->list_entities(&(cellsInSet[0]), cellsInSet.size()) << "\n";
210 MB_CHK_SET_ERR(MB_FAILURE, "non-manifold input mesh set");// non-manifold
211 }
212 if (siz == 1)
213 {
214 // it must be the border of the input mesh;
215 neighbors[i] = 0; // we are guaranteed that ids are !=0; this is marking a border
216 // borders do not appear for a sphere in serial, but they do appear for
217 // parallel processing anyway
218 continue;
219 }
220 // here siz ==2, it is either the first or second
221 if (cell == cellsInSet[0])
222 neighbors[i] = cellsInSet[1];
223 else
224 neighbors[i] = cellsInSet[0];
225 }
226 // fill the rest with 0
227 for (int i = nsides; i<max_edges; i++)
228 neighbors[i] = 0;
229 // now simply set the neighbors tag; the last few positions will not be used, but for simplicity will keep
230 // them all (MAXEDGES)
231 rval = mb->tag_set_data(neighTag, &cell, 1, &neighbors[0]); MB_CHK_SET_ERR(rval, "can't set neigh tag");
232
233 }
234 return MB_SUCCESS;
235 }
236
237
238 // main interface; this will do the advancing front trick
239 // some are triangles, some are quads, some are polygons ...
intersect_meshes(EntityHandle mbset1,EntityHandle mbset2,EntityHandle & outputSet)240 ErrorCode Intx2Mesh::intersect_meshes(EntityHandle mbset1, EntityHandle mbset2,
241 EntityHandle & outputSet)
242 {
243 ErrorCode rval;
244 mbs1 = mbset1; // set 1 is departure, and it is completely covering the euler set on proc
245 mbs2 = mbset2;
246 outSet = outputSet;
247 #ifdef VERBOSE
248 std::stringstream ffs, fft;
249 ffs << "source_rank0"<< my_rank << ".vtk";
250 rval = mb->write_mesh(ffs.str().c_str(), &mbset1, 1);MB_CHK_ERR(rval);
251 fft << "target_rank0"<< my_rank << ".vtk";
252 rval = mb->write_mesh(fft.str().c_str(), &mbset2, 1);MB_CHK_ERR(rval);
253
254 #endif
255 // really, should be something from t1 and t2; blue is 1 (lagrange), red is 2 (euler)
256
257 EntityHandle startBlue=0, startRed=0;
258
259 rval = mb->get_entities_by_dimension(mbs1, 2, rs1);MB_CHK_ERR(rval);
260 rval = mb->get_entities_by_dimension(mbs2, 2, rs2);MB_CHK_ERR(rval);
261 // std::cout << "rs1.size() = " << rs1.size() << " and rs2.size() = " << rs2.size() << "\n"; std::cout.flush();
262
263 createTags(); // will also determine max_edges_1, max_edges_2 (for blue and red meshes)
264
265 Range rs22=rs2; // a copy of the initial range; we will remove from it elements as we
266 // advance ; rs2 is needed for marking the polygon to the red parent
267 while (!rs22.empty())
268 {
269 if (rs22.size()<rs2.size())
270 {
271 #if defined(ENABLE_DEBUG) || defined(VERBOSE)
272 std::cout<< " possible not connected arrival mesh; my_rank: " << my_rank << " counting: " << counting <<"\n";
273 std::stringstream ffo;
274 ffo << "file0" << counting<<"rank0"<< my_rank << ".vtk";
275 rval = mb->write_mesh(ffo.str().c_str(), &outSet, 1);MB_CHK_ERR(rval);
276 #endif
277 }
278 for (Range::iterator it = rs22.begin(); it != rs22.end(); ++it)
279 {
280 startRed = *it;
281 int found = 0;
282 for (Range::iterator it2 = rs1.begin(); it2 != rs1.end() && !found; ++it2)
283 {
284 startBlue = *it2;
285 double area = 0;
286 // if area is > 0 , we have intersections
287 double P[10*MAXEDGES]; // max 8 intx points + 8 more in the polygon
288 //
289 int nP = 0;
290 int nb[MAXEDGES], nr[MAXEDGES]; // sides 3 or 4? also, check boxes first
291 int nsRed, nsBlue;
292 rval = computeIntersectionBetweenRedAndBlue(startRed, startBlue, P, nP, area, nb, nr,
293 nsBlue, nsRed, true);MB_CHK_ERR(rval);
294 if (area > 0)
295 {
296 found = 1;
297 break; // found 2 elements that intersect; these will be the seeds
298 }
299 }
300 if (found)
301 break;
302 }
303
304 std::queue<EntityHandle> blueQueue; // these are corresponding to Ta,
305 blueQueue.push(startBlue);
306 std::queue<EntityHandle> redQueue;
307 redQueue.push(startRed);
308
309 Range toResetBlues; // will be used to reset blue flags for every red quad
310 // processed
311
312 /*if (my_rank==0)
313 dbg_1 = 1;*/
314 unsigned char used = 1;
315 // mark the start red quad as used, so it will not come back again
316 rval = mb->tag_set_data(RedFlagTag, &startRed, 1, &used);MB_CHK_ERR(rval);
317 while (!redQueue.empty())
318 {
319 // flags for the side : 0 means a blue cell not found on side
320 // a paired blue not found yet for the neighbors of red
321 Range nextBlue[MAXEDGES]; // there are new ranges of possible next blue cells for seeding the side j of red cell
322
323 EntityHandle currentRed = redQueue.front();
324 redQueue.pop();
325 int nsidesRed; // will be initialized now
326 double areaRedCell = setup_red_cell(currentRed, nsidesRed); // this is the area in the gnomonic plane
327 double recoveredArea = 0;
328 // get the neighbors of red, and if they are solved already, do not bother with that side of red
329 EntityHandle redNeighbors[MAXEDGES]= {0};
330 rval = mb->tag_get_data(redNeighTag, ¤tRed, 1, redNeighbors); MB_CHK_SET_ERR(rval, "can't get neighbors of current red");
331 #ifdef ENABLE_DEBUG
332 if (dbg_1)
333 {
334 std::cout << "Next: neighbors for current red ";
335 for (int kk = 0; kk < nsidesRed; kk++)
336 {
337 if (redNeighbors[kk] > 0)
338 std::cout << mb->id_from_handle(redNeighbors[kk]) << " ";
339 else
340 std::cout << 0 << " ";
341 }
342 std::cout << std::endl;
343 }
344 #endif
345 // now get the status of neighbors; if already solved, make them 0, so not to bother anymore on that side of red
346 for (int j = 0; j < nsidesRed; j++)
347 {
348 EntityHandle redNeigh = redNeighbors[j];
349 unsigned char status = 1;
350 if (redNeigh == 0)
351 continue;
352 rval = mb->tag_get_data(RedFlagTag, &redNeigh, 1, &status);MB_CHK_ERR(rval); // status 0 is unused
353 if (1==status)
354 redNeighbors[j]=0; // so will not look anymore on this side of red
355 }
356
357 #ifdef ENABLE_DEBUG
358 if (dbg_1)
359 {
360 std::cout << "reset blues: ";
361 for (Range::iterator itr = toResetBlues.begin(); itr != toResetBlues.end();
362 ++itr)
363 std::cout << mb->id_from_handle(*itr) << " ";
364 std::cout << std::endl;
365 }
366 #endif
367 EntityHandle currentBlue = blueQueue.front();
368 // red and blue queues are parallel; for clarity we should have kept in the queue pairs
369 // of entity handle std::pair<EntityHandle, EntityHandle>; so just one queue, with pairs;
370 // at every moment, the queue contains pairs of cells that intersect, and they form the
371 // "advancing front"
372 blueQueue.pop();
373 toResetBlues.clear(); // empty the range of used blues, will have to be set unused again,
374 // at the end of red element processing
375 toResetBlues.insert(currentBlue);
376 //mb2->set_tag_data
377 std::queue<EntityHandle> localBlue;
378 localBlue.push(currentBlue);
379 #ifdef VERBOSE
380 int countingStart = counting;
381 #endif
382 // will advance-front search in the neighborhood of red cell, until we finish processing all
383 // possible blue cells; localBlue queue will contain all possible blue cells that cover the current red cell
384 while (!localBlue.empty())
385 {
386 //
387 EntityHandle blueT = localBlue.front();
388 localBlue.pop();
389 double P[10*MAXEDGES], area; //
390 int nP = 0;
391 int nb[MAXEDGES] = {0};
392 int nr[MAXEDGES] = {0};
393
394 int nsidesBlue; ///
395 // area is in 2d, points are in 3d (on a sphere), back-projected, or in a plane
396 // intersection points could include the vertices of initial elements
397 // nb [j] = 0 means no intersection on the side j for element blue (markers)
398 // nb [j] = 1 means that the side j (from j to j+1) of blue poly intersects the
399 // red poly. A potential next poly in the red queue is the red poly that is adjacent to this side
400 rval = computeIntersectionBetweenRedAndBlue(/* red */currentRed, blueT, P, nP,
401 area, nb, nr, nsidesBlue, nsidesRed);MB_CHK_ERR(rval);
402 if (nP > 0)
403 {
404 #ifdef ENABLE_DEBUG
405 if (dbg_1)
406 {
407 for (int k=0; k<3; k++)
408 {
409 std::cout << " nb, nr: " << k << " " << nb[k] << " " << nr[k] << "\n";
410 }
411 }
412 #endif
413
414 // intersection found: output P and original triangles if nP > 2
415 EntityHandle neighbors[MAXEDGES]={0};
416 rval = mb->tag_get_data(blueNeighTag, &blueT, 1, neighbors);
417 if (rval != MB_SUCCESS)
418 {
419 std::cout << " can't get the neighbors for blue element "
420 << mb->id_from_handle(blueT);
421 return MB_FAILURE;
422 }
423
424 // add neighbors to the localBlue queue, if they are not marked
425 for (int nn = 0; nn < nsidesBlue; nn++)
426 {
427 EntityHandle neighbor = neighbors[nn];
428 if (neighbor > 0 && nb[nn]>0) // advance across blue boundary nn
429 {
430 if (toResetBlues.find(neighbor)==toResetBlues.end())
431 {
432 localBlue.push(neighbor);
433 #ifdef ENABLE_DEBUG
434 if (dbg_1)
435 {
436 std::cout << " local blue elem " << mb->id_from_handle(neighbor)
437 << " for red:" << mb->id_from_handle(currentRed) << "\n";
438 mb->list_entities(&neighbor, 1);
439 }
440 #endif
441 toResetBlues.insert(neighbor);
442 }
443 }
444 }
445 // n(find(nc>0))=ac; % ac is starting candidate for neighbor
446 for (int nn=0; nn<nsidesRed; nn++)
447 {
448 if (nr[nn] > 0 && redNeighbors[nn]>0)
449 nextBlue[nn].insert(blueT); // potential blue cell that can intersect the red neighbor nn
450 }
451 if (nP > 1) { // this will also construct triangles/polygons in the new mesh, if needed
452 rval = findNodes(currentRed, nsidesRed, blueT, nsidesBlue, P, nP);MB_CHK_ERR(rval);
453 }
454
455 recoveredArea+=area;
456 }
457 #ifdef ENABLE_DEBUG
458 else if (dbg_1)
459 {
460 std::cout << " red, blue, do not intersect: "
461 << mb->id_from_handle(currentRed) << " "
462 << mb->id_from_handle(blueT) << "\n";
463 }
464 #endif
465 } // end while (!localBlue.empty())
466 recoveredArea = (recoveredArea-areaRedCell)/areaRedCell; // replace now with recovery fraction
467 #if defined(ENABLE_DEBUG) || defined(VERBOSE)
468 if ( fabs(recoveredArea) > epsilon_1)
469 {
470 #ifdef VERBOSE
471 std::cout << " red area: " << areaRedCell << " recovered :" <<recoveredArea*(1+areaRedCell) <<
472 " fraction error recovery:" << recoveredArea <<
473 " redID: " << mb->id_from_handle(currentRed) << " countingStart:" << countingStart << "\n";
474 #endif
475 }
476 #endif
477 // here, we are finished with redCurrent, take it out of the rs22 range (red, arrival mesh)
478 rs22.erase(currentRed);
479 // also, look at its neighbors, and add to the seeds a next one
480
481 for (int j = 0; j < nsidesRed; j++)
482 {
483 EntityHandle redNeigh = redNeighbors[j];
484 if (redNeigh==0 || nextBlue[j].size()==0) // if red is bigger than blue, there could be no blue to advance on that side
485 continue;
486 int nsidesRed2=0;
487 setup_red_cell(redNeigh, nsidesRed2); // find possible intersection with blue cell from nextBlue
488 for (Range::iterator nit =nextBlue[j].begin(); nit!=nextBlue[j].end(); ++nit)
489 {
490 EntityHandle nextB=*nit;
491 // we identified red quad n[j] as possibly intersecting with neighbor j of the blue quad
492 double P[10*MAXEDGES], area; //
493 int nP = 0;
494 int nb[MAXEDGES] = {0};
495 int nr[MAXEDGES] = {0};
496
497 int nsidesBlue; ///
498 rval = computeIntersectionBetweenRedAndBlue(/* red */redNeigh, nextB, P, nP,
499 area, nb, nr, nsidesBlue, nsidesRed2);MB_CHK_ERR(rval);
500 if (area>0)
501 {
502 redQueue.push(redNeigh);
503 blueQueue.push(nextB);
504 #ifdef ENABLE_DEBUG
505 if (dbg_1)
506 std::cout << "new polys pushed: blue, red:"
507 << mb->id_from_handle(redNeigh) << " "
508 << mb->id_from_handle(nextB) << std::endl;
509 #endif
510 rval = mb->tag_set_data(RedFlagTag, &redNeigh, 1, &used);MB_CHK_ERR(rval);
511 break; // so we are done with this side of red, we have found a proper next seed
512 }
513 }
514 }
515
516 } // end while (!redQueue.empty())
517 }
518 #ifdef ENABLE_DEBUG
519 if (dbg_1)
520 {
521 for (int k = 0; k < 6; k++)
522 mout_1[k].close();
523 }
524 #endif
525 // before cleaning up , we need to settle the position of the intersection points
526 // on the boundary edges
527 // this needs to be collective, so we should maybe wait something
528 #ifdef MOAB_HAVE_MPI
529 rval = correct_intersection_points_positions();MB_CHK_SET_ERR(rval, "can't correct position, Intx2Mesh.cpp \n");
530 #endif
531
532 this->clean();
533 return MB_SUCCESS;
534 }
535
536 // clean some memory allocated
clean()537 void Intx2Mesh::clean()
538 {
539 //
540 int indx = 0;
541 for (Range::iterator eit = RedEdges.begin(); eit != RedEdges.end();
542 ++eit, indx++)
543 {
544 delete extraNodesVec[indx];
545 }
546 //extraNodesMap.clear();
547 extraNodesVec.clear();
548 // also, delete some bit tags, used to mark processed reds and blues
549 mb->tag_delete(RedFlagTag);
550 counting = 0; // reset counting to original value
551
552 }
553 // this method will reduce number of nodes, collapse edges that are of length 0
554 // so a polygon like 428 431 431 will become a line 428 431
555 // or something like 428 431 431 531 -> 428 431 531
correct_polygon(EntityHandle * nodes,int & nP)556 void Intx2Mesh::correct_polygon(EntityHandle * nodes, int & nP)
557 {
558 int i = 0;
559 while(i<nP)
560 {
561 int nextIndex = (i+1)%nP;
562 if (nodes[i]==nodes[nextIndex])
563 {
564 #ifdef ENABLE_DEBUG
565 // we need to reduce nP, and collapse nodes
566 if (dbg_1)
567 {
568 std::cout<<" nodes duplicated in list: " ;
569 for (int j=0; j<nP; j++)
570 std::cout<<nodes[j] << " " ;
571 std::cout<<"\n";
572 std::cout<<" node " << nodes[i] << " at index " << i << " is duplicated" << "\n";
573 }
574 #endif
575 // this will work even if we start from 1 2 3 1; when i is 3, we find nextIndex is 0, then next thing does nothing
576 // (nP-1 is 3, so k is already >= nP-1); it will result in nodes -> 1, 2, 3
577 for (int k=i; k<nP-1; k++)
578 nodes[k] = nodes[k+1];
579 nP--; // decrease the number of nodes; also, decrease i, just if we may need to check again
580 i--;
581 }
582 i++;
583 }
584 return;
585 }
586 #ifdef MOAB_HAVE_MPI
build_processor_euler_boxes(EntityHandle euler_set,Range & local_verts)587 ErrorCode Intx2Mesh::build_processor_euler_boxes(EntityHandle euler_set, Range & local_verts)
588 {
589 localEnts.clear();
590 ErrorCode rval = mb->get_entities_by_dimension(euler_set, 2, localEnts);
591 ERRORR(rval, "can't get ents by dimension");
592
593 rval = mb->get_connectivity(localEnts, local_verts);
594 int num_local_verts = (int) local_verts.size();
595 ERRORR(rval, "can't get local vertices");
596
597 assert(parcomm != NULL);
598
599 // get the position of local vertices, and decide local boxes (allBoxes...)
600 double bmin[3]={DBL_MAX, DBL_MAX, DBL_MAX};
601 double bmax[3] ={-DBL_MAX, -DBL_MAX, -DBL_MAX};
602
603 std::vector<double> coords(3*num_local_verts);
604 rval = mb->get_coords(local_verts, &coords[0]);
605 ERRORR(rval, "can't get coords of vertices ");
606
607 for (int i=0; i< num_local_verts; i++)
608 {
609 for (int k=0; k<3; k++)
610 {
611 double val=coords[3*i+k];
612 if (val < bmin[k])
613 bmin[k]=val;
614 if (val > bmax[k])
615 bmax[k] = val;
616 }
617 }
618 int numprocs=parcomm->proc_config().proc_size();
619 allBoxes.resize(6*numprocs);
620
621 my_rank = parcomm->proc_config().proc_rank() ;
622 for (int k=0; k<3; k++)
623 {
624 allBoxes[6*my_rank+k]=bmin[k];
625 allBoxes[6*my_rank+3+k] = bmax[k];
626 }
627
628 // now communicate to get all boxes
629 int mpi_err;
630 #if (MPI_VERSION >= 2)
631 // use "in place" option
632 mpi_err = MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
633 &allBoxes[0], 6, MPI_DOUBLE,
634 parcomm->proc_config().proc_comm());
635 #else
636 {
637 std::vector<double> allBoxes_tmp(6*parcomm->proc_config().proc_size());
638 mpi_err = MPI_Allgather( &allBoxes[6*my_rank], 6, MPI_DOUBLE,
639 &allBoxes_tmp[0], 6, MPI_DOUBLE,
640 parcomm->proc_config().proc_comm());
641 allBoxes = allBoxes_tmp;
642 }
643 #endif
644 if (MPI_SUCCESS != mpi_err) return MB_FAILURE;
645
646 if (my_rank==0)
647 {
648 std::cout << " maximum number of vertices per cell are " << max_edges_1 << " on first mesh and "
649 << max_edges_2 << " on second mesh \n";
650 for (int i=0; i<numprocs; i++)
651 {
652 std::cout<<"proc: " << i << " box min: " << allBoxes[6*i ] << " " <<allBoxes[6*i+1] << " " << allBoxes[6*i+2] << " \n";
653 std::cout<< " box max: " << allBoxes[6*i+3] << " " <<allBoxes[6*i+4] << " " << allBoxes[6*i+5] << " \n";
654 }
655 }
656
657 return MB_SUCCESS;
658 }
create_departure_mesh_2nd_alg(EntityHandle & euler_set,EntityHandle & covering_lagr_set)659 ErrorCode Intx2Mesh::create_departure_mesh_2nd_alg(EntityHandle & euler_set, EntityHandle & covering_lagr_set)
660 {
661 // compute the bounding box on each proc
662 assert(parcomm != NULL);
663
664 localEnts.clear();
665 ErrorCode rval = mb->get_entities_by_dimension(euler_set, 2, localEnts);
666 ERRORR(rval, "can't get ents by dimension");
667
668 Tag dpTag = 0;
669 std::string tag_name("DP");
670 rval = mb->tag_get_handle(tag_name.c_str(), 3, MB_TYPE_DOUBLE, dpTag, MB_TAG_DENSE);
671 ERRORR(rval, "can't get DP tag");
672
673 EntityHandle dum=0;
674 Tag corrTag;
675 rval = mb->tag_get_handle(CORRTAGNAME,
676 1, MB_TYPE_HANDLE, corrTag,
677 MB_TAG_DENSE|MB_TAG_CREAT, &dum);
678 ERRORR(rval, "can't get CORR tag");
679 // get all local verts
680 Range local_verts;
681 rval = mb->get_connectivity(localEnts, local_verts);
682 int num_local_verts = (int) local_verts.size();
683 ERRORR(rval, "can't get local vertices");
684
685 rval = Intx2Mesh::build_processor_euler_boxes(euler_set, local_verts);
686 ERRORR(rval, "can't build processor boxes");
687
688 std::vector<int> gids(num_local_verts);
689 rval = mb->tag_get_data(gid, local_verts, &gids[0]);
690 ERRORR(rval, "can't get local vertices gids");
691
692 // now see the departure points; to what boxes should we send them?
693 std::vector<double> dep_points(3*num_local_verts);
694 rval = mb->tag_get_data(dpTag, local_verts, (void*)&dep_points[0]);
695 ERRORR(rval, "can't get DP tag values");
696 // ranges to send to each processor; will hold vertices and elements (quads?)
697 // will look if the box of the dep quad covers box of euler mesh on proc (with tolerances)
698 std::map<int, Range> Rto;
699 int numprocs=parcomm->proc_config().proc_size();
700
701 for (Range::iterator eit = localEnts.begin(); eit!=localEnts.end(); ++eit)
702 {
703 EntityHandle q=*eit;
704 const EntityHandle * conn4;
705 int num_nodes;
706 rval= mb->get_connectivity(q, conn4, num_nodes);
707 ERRORR(rval, "can't get DP tag values");
708 CartVect qbmin(DBL_MAX);
709 CartVect qbmax(-DBL_MAX);
710 for (int i=0; i<num_nodes; i++)
711 {
712 EntityHandle v=conn4[i];
713 size_t index=local_verts.find(v)-local_verts.begin();
714 CartVect dp( &dep_points[3*index] ); // will use constructor
715 for (int j=0; j<3; j++)
716 {
717 if (qbmin[j]>dp[j])
718 qbmin[j]=dp[j];
719 if (qbmax[j]<dp[j])
720 qbmax[j]=dp[j];
721 }
722 }
723 for (int p=0; p<numprocs; p++)
724 {
725 CartVect bbmin(&allBoxes[6*p]);
726 CartVect bbmax(&allBoxes[6*p+3]);
727 if ( GeomUtil::boxes_overlap( bbmin, bbmax, qbmin, qbmax, box_error) )
728 {
729 Rto[p].insert(q);
730 }
731 }
732 }
733
734 // now, build TLv and TLq, for each p
735 size_t numq=0;
736 size_t numv=0;
737 for (int p=0; p<numprocs; p++)
738 {
739 if (p==(int)my_rank)
740 continue; // do not "send" it, because it is already here
741 Range & range_to_P = Rto[p];
742 // add the vertices to it
743 if (range_to_P.empty())
744 continue;// nothing to send to proc p
745 Range vertsToP;
746 rval = mb->get_connectivity(range_to_P, vertsToP);
747 ERRORR(rval, "can't get connectivity");
748 numq=numq+range_to_P.size();
749 numv=numv+vertsToP.size();
750 range_to_P.merge(vertsToP);
751 }
752 TupleList TLv;
753 TupleList TLq;
754 TLv.initialize(2, 0, 0, 3, numv); // to proc, GLOBAL ID, DP points
755 TLv.enableWriteAccess();
756
757 int sizeTuple = 2+max_edges_1; // determined earlier, for blue, first mesh
758 TLq.initialize(2+max_edges_1, 0, 1, 0, numq); // to proc, elem GLOBAL ID, connectivity[10] (global ID v), local eh
759 TLq.enableWriteAccess();
760 #ifdef VERBOSE
761 std::cout << "from proc " << my_rank << " send " << numv << " vertices and " << numq << " elements\n";
762 #endif
763 for (int to_proc=0; to_proc<numprocs; to_proc++)
764 {
765 if (to_proc==(int)my_rank)
766 continue;
767 Range & range_to_P = Rto[to_proc];
768 Range V = range_to_P.subset_by_type(MBVERTEX);
769
770 for (Range::iterator it=V.begin(); it!=V.end(); ++it)
771 {
772 EntityHandle v=*it;
773 unsigned int index = local_verts.find(v)-local_verts.begin();
774 int n=TLv.get_n();
775 TLv.vi_wr[2*n] = to_proc; // send to processor
776 TLv.vi_wr[2*n+1] = gids[index]; // global id needs index in the local_verts range
777 TLv.vr_wr[3*n] = dep_points[3*index]; // departure position, of the node local_verts[i]
778 TLv.vr_wr[3*n+1] = dep_points[3*index+1];
779 TLv.vr_wr[3*n+2] = dep_points[3*index+2];
780 TLv.inc_n();
781 }
782 // also, prep the quad for sending ...
783 Range Q = range_to_P.subset_by_dimension(2);
784 for (Range::iterator it=Q.begin(); it!=Q.end(); ++it)
785 {
786 EntityHandle q=*it;
787 int global_id;
788 rval = mb->tag_get_data(gid, &q, 1, &global_id);
789 ERRORR(rval, "can't get gid for polygon");
790 int n=TLq.get_n();
791 TLq.vi_wr[sizeTuple*n] = to_proc; //
792 TLq.vi_wr[sizeTuple*n+1] = global_id; // global id of element, used to identify it ...
793 const EntityHandle * conn4;
794 int num_nodes;
795 rval = mb->get_connectivity(q, conn4, num_nodes);// could be up to MAXEDGES, but it is limited by max_edges_1
796 ERRORR(rval, "can't get connectivity for cell");
797 if (num_nodes > MAXEDGES)
798 ERRORR(MB_FAILURE, "too many nodes in a polygon");
799 for (int i=0; i<num_nodes; i++)
800 {
801 EntityHandle v = conn4[i];
802 unsigned int index = local_verts.find(v)-local_verts.begin();
803 TLq.vi_wr[sizeTuple*n+2+i] = gids[index];
804 }
805 for (int k=num_nodes; k<max_edges_1; k++)
806 {
807 TLq.vi_wr[sizeTuple*n+2+k] = 0; // fill the rest of node ids with 0; we know that the node ids start from 1!
808 }
809 TLq.vul_wr[n]=q; // save here the entity handle, it will be communicated back
810 // maybe we should forget about global ID
811 TLq.inc_n();
812
813 }
814
815 }
816
817 // now we are done populating the tuples; route them to the appropriate processors
818 (parcomm->proc_config().crystal_router())->gs_transfer(1, TLv, 0);
819 (parcomm->proc_config().crystal_router())->gs_transfer(1, TLq, 0);
820 // the elements are already in localEnts;
821
822 // maps from global ids to new vertex and quad handles, that are added
823 std::map<int, EntityHandle> globalID_to_handle;
824 /*std::map<int, EntityHandle> globalID_to_eh;*/
825 globalID_to_eh.clear();// need for next iteration
826 // now, look at every TLv, and see if we have to create a vertex there or not
827 int n=TLv.get_n();// the size of the points received
828 for (int i=0; i<n; i++)
829 {
830 int globalId = TLv.vi_rd[2*i+1];
831 if (globalID_to_handle.find(globalId)==globalID_to_handle.end())
832 {
833 EntityHandle new_vert;
834 double dp_pos[3]= {TLv.vr_wr[3*i], TLv.vr_wr[3*i+1], TLv.vr_wr[3*i+2]};
835 rval = mb->create_vertex(dp_pos, new_vert);
836 ERRORR(rval, "can't create new vertex ");
837 globalID_to_handle[globalId]= new_vert;
838 }
839 }
840
841 // now, all dep points should be at their place
842 // look in the local list of q for this proc, and create all those quads and vertices if needed
843 // it may be an overkill, but because it does not involve communication, we do it anyway
844 Range & local=Rto[my_rank];
845 Range local_q = local.subset_by_dimension(2);
846 // the local should have all the vertices in local_verts
847 for (Range::iterator it=local_q.begin(); it!=local_q.end(); ++it)
848 {
849 EntityHandle q=*it;
850 int nnodes;
851 const EntityHandle * conn4;
852 rval = mb->get_connectivity(q, conn4, nnodes);
853 ERRORR(rval, "can't get connectivity of local q ");
854 EntityHandle new_conn[MAXEDGES];
855 for (int i=0; i<nnodes; i++)
856 {
857 EntityHandle v1=conn4[i];
858 unsigned int index = local_verts.find(v1)-local_verts.begin();
859 int globalId=gids[index];
860 if(globalID_to_handle.find(globalId)==globalID_to_handle.end())
861 {
862 // we need to create that vertex, at this position dep_points
863 double dp_pos[3]={dep_points[3*index], dep_points[3*index+1], dep_points[3*index+2]};
864 EntityHandle new_vert;
865 rval = mb->create_vertex(dp_pos, new_vert);
866 ERRORR(rval, "can't create new vertex ");
867 globalID_to_handle[globalId]= new_vert;
868 }
869 new_conn[i] = globalID_to_handle[gids[index]];
870 }
871 EntityHandle new_element;
872 //
873 EntityType entType = MBQUAD;
874 if (nnodes >4)
875 entType = MBPOLYGON;
876 if (nnodes <4)
877 entType = MBTRI;
878
879 rval = mb->create_element(entType, new_conn, nnodes, new_element);
880 ERRORR(rval, "can't create new quad ");
881 rval = mb->add_entities(covering_lagr_set, &new_element, 1);
882 ERRORR(rval, "can't add new element to dep set");
883 int gid_el;
884 // get the global ID of the initial quad
885 rval=mb->tag_get_data(gid, &q, 1, &gid_el);
886 ERRORR(rval, "can't get element global ID ");
887 globalID_to_eh[gid_el]=new_element;
888 // is this redundant or not?
889 rval = mb->tag_set_data(corrTag, &new_element, 1, &q);
890 ERRORR(rval, "can't set corr tag on new el");
891 // set the global id on new elem
892 rval = mb->tag_set_data(gid, &new_element, 1, &gid_el);
893 ERRORR(rval, "can't set global id tag on new el");
894 }
895 // now look at all elements received through; we do not want to duplicate them
896 n=TLq.get_n();// number of elements received by this processor
897 // form the remote cells, that will be used to send the tracer info back to the originating proc
898 remote_cells = new TupleList();
899 remote_cells->initialize(2, 0, 1, 0, n); // will not have tracer data anymore
900 remote_cells->enableWriteAccess();
901 for (int i=0; i<n; i++)
902 {
903 int globalIdEl = TLq.vi_rd[sizeTuple*i+1];
904 int from_proc = TLq.vi_wr[sizeTuple*i];
905 // do we already have a quad with this global ID, represented?
906 if (globalID_to_eh.find(globalIdEl)==globalID_to_eh.end())
907 {
908 // construct the conn quad
909 EntityHandle new_conn[MAXEDGES];
910 int nnodes = -1;
911 for (int j=0; j<max_edges_1; j++)
912 {
913 int vgid = TLq.vi_rd[sizeTuple*i+2+j];// vertex global ID
914 if (vgid==0)
915 new_conn[j] = 0;
916 else
917 {
918 assert(globalID_to_handle.find(vgid)!=globalID_to_handle.end());
919 new_conn[j]=globalID_to_handle[vgid];
920 nnodes = j+1;// nodes are at the beginning, and are variable number
921 }
922 }
923 EntityHandle new_element;
924 //
925 EntityType entType = MBQUAD;
926 if (nnodes >4)
927 entType = MBPOLYGON;
928 if (nnodes <4)
929 entType = MBTRI;
930 rval = mb->create_element(entType, new_conn, nnodes, new_element);
931 ERRORR(rval, "can't create new element ");
932 globalID_to_eh[globalIdEl]=new_element;
933 rval = mb->add_entities(covering_lagr_set, &new_element, 1);
934 ERRORR(rval, "can't add new element to dep set");
935 /* rval = mb->tag_set_data(corrTag, &new_element, 1, &q);
936 ERRORR(rval, "can't set corr tag on new el");*/
937 remote_cells->vi_wr[2*i]=from_proc;
938 remote_cells->vi_wr[2*i+1]=globalIdEl;
939 // remote_cells->vr_wr[i] = 0.; // no contribution yet sent back
940 remote_cells->vul_wr[i]= TLq.vul_rd[i];// this is the corresponding red cell (arrival)
941 remote_cells->inc_n();
942 // set the global id on new elem
943 rval = mb->tag_set_data(gid, &new_element, 1, &globalIdEl);
944 ERRORR(rval, "can't set global id tag on new el");
945 }
946 }
947 // order the remote cells tuple list, with the global id, because we will search in it
948 //remote_cells->print("remote_cells before sorting");
949 moab::TupleList::buffer sort_buffer;
950 sort_buffer.buffer_init(n);
951 remote_cells->sort(1, &sort_buffer);
952 sort_buffer.reset();
953 return MB_SUCCESS;
954 }
955
956 // this algorithm assumes lagr set is already created, and some elements will be coming from
957 // other procs, and populate the covering_set
958 // we need to keep in a tuple list the remote cells from other procs, because we need to send back
959 // the intersection info (like area of the intx polygon, and the current concentration) maybe total
960 // mass in that intx
create_departure_mesh_3rd_alg(EntityHandle & lagr_set,EntityHandle & covering_set)961 ErrorCode Intx2Mesh::create_departure_mesh_3rd_alg(EntityHandle & lagr_set,
962 EntityHandle & covering_set)
963 {
964 EntityHandle dum = 0;
965
966 Tag corrTag;
967 ErrorCode rval = mb->tag_get_handle(CORRTAGNAME,
968 1, MB_TYPE_HANDLE, corrTag,
969 MB_TAG_DENSE|MB_TAG_CREAT, &dum);
970 //start copy from 2nd alg
971 // compute the bounding box on each proc
972 assert(parcomm != NULL);
973 if ( 1 == parcomm->proc_config().proc_size())
974 {
975 covering_set = lagr_set; // nothing to communicate, it must be serial
976 return MB_SUCCESS;
977 }
978
979 // get all local verts
980 Range local_verts;
981 rval = mb->get_connectivity(localEnts, local_verts);
982 int num_local_verts = (int) local_verts.size();
983 ERRORR(rval, "can't get local vertices");
984
985 std::vector<int> gids(num_local_verts);
986 rval = mb->tag_get_data(gid, local_verts, &gids[0]);
987 ERRORR(rval, "can't get local vertices gids");
988
989 Range localDepCells;
990 rval = mb->get_entities_by_dimension(lagr_set, 2, localDepCells);
991 ERRORR(rval, "can't get ents by dimension from lagr set");
992
993 // get all lagr verts (departure vertices)
994 Range lagr_verts;
995 rval = mb->get_connectivity(localDepCells, lagr_verts);// they should be created in
996 // the same order as the euler vertices
997 int num_lagr_verts = (int) lagr_verts.size();
998 ERRORR(rval, "can't get local lagr vertices");
999
1000 // now see the departure points position; to what boxes should we send them?
1001 std::vector<double> dep_points(3 * num_lagr_verts);
1002 rval = mb->get_coords(lagr_verts, &dep_points[0]);
1003 ERRORR(rval, "can't get departure points position");
1004 // ranges to send to each processor; will hold vertices and elements (quads?)
1005 // will look if the box of the dep quad covers box of euler mesh on proc (with tolerances)
1006 std::map<int, Range> Rto;
1007 int numprocs = parcomm->proc_config().proc_size();
1008
1009 for (Range::iterator eit = localDepCells.begin(); eit != localDepCells.end(); ++eit)
1010 {
1011 EntityHandle q = *eit;
1012 const EntityHandle * conn4;
1013 int num_nodes;
1014 rval = mb->get_connectivity(q, conn4, num_nodes);
1015 ERRORR(rval, "can't get DP tag values");
1016 CartVect qbmin(DBL_MAX);
1017 CartVect qbmax(-DBL_MAX);
1018 for (int i = 0; i < num_nodes; i++)
1019 {
1020 EntityHandle v = conn4[i];
1021 int index = lagr_verts.index(v);
1022 assert(-1!=index);
1023 CartVect dp(&dep_points[3 * index]); // will use constructor
1024 for (int j = 0; j < 3; j++)
1025 {
1026 if (qbmin[j] > dp[j])
1027 qbmin[j] = dp[j];
1028 if (qbmax[j] < dp[j])
1029 qbmax[j] = dp[j];
1030 }
1031 }
1032 for (int p = 0; p < numprocs; p++)
1033 {
1034 CartVect bbmin(&allBoxes[6 * p]);
1035 CartVect bbmax(&allBoxes[6 * p + 3]);
1036 if (GeomUtil::boxes_overlap(bbmin, bbmax, qbmin, qbmax, box_error))
1037 {
1038 Rto[p].insert(q);
1039 }
1040 }
1041 }
1042
1043 // now, build TLv and TLq, for each p
1044 size_t numq = 0;
1045 size_t numv = 0;
1046 for (int p = 0; p < numprocs; p++)
1047 {
1048 if (p == (int) my_rank)
1049 continue; // do not "send" it, because it is already here
1050 Range & range_to_P = Rto[p];
1051 // add the vertices to it
1052 if (range_to_P.empty())
1053 continue; // nothing to send to proc p
1054 Range vertsToP;
1055 rval = mb->get_connectivity(range_to_P, vertsToP);
1056 ERRORR(rval, "can't get connectivity");
1057 numq = numq + range_to_P.size();
1058 numv = numv + vertsToP.size();
1059 range_to_P.merge(vertsToP);
1060 }
1061 TupleList TLv;
1062 TupleList TLq;
1063 TLv.initialize(2, 0, 0, 3, numv); // to proc, GLOBAL ID, DP points
1064 TLv.enableWriteAccess();
1065
1066 int sizeTuple = 2 + max_edges_1; // max edges could be up to MAXEDGES :) for polygons
1067 TLq.initialize(2+max_edges_1, 0, 1, 0, numq); // to proc, elem GLOBAL ID, connectivity[max_edges] (global ID v)
1068 // send also the corresponding red cell it will come to
1069 TLq.enableWriteAccess();
1070 #ifdef VERBOSE
1071 std::cout << "from proc " << my_rank << " send " << numv << " vertices and "
1072 << numq << " elements\n";
1073 #endif
1074
1075 for (int to_proc = 0; to_proc < numprocs; to_proc++)
1076 {
1077 if (to_proc == (int) my_rank)
1078 continue;
1079 Range & range_to_P = Rto[to_proc];
1080 Range V = range_to_P.subset_by_type(MBVERTEX);
1081
1082 for (Range::iterator it = V.begin(); it != V.end(); ++it)
1083 {
1084 EntityHandle v = *it;
1085 int index = lagr_verts.index(v);// will be the same index as the corresponding vertex in euler verts
1086 assert(-1!=index);
1087 int n = TLv.get_n();
1088 TLv.vi_wr[2 * n] = to_proc; // send to processor
1089 TLv.vi_wr[2 * n + 1] = gids[index]; // global id needs index in the local_verts range
1090 TLv.vr_wr[3 * n] = dep_points[3 * index]; // departure position, of the node local_verts[i]
1091 TLv.vr_wr[3 * n + 1] = dep_points[3 * index + 1];
1092 TLv.vr_wr[3 * n + 2] = dep_points[3 * index + 2];
1093 TLv.inc_n();
1094 }
1095 // also, prep the 2d cells for sending ...
1096 Range Q = range_to_P.subset_by_dimension(2);
1097 for (Range::iterator it = Q.begin(); it != Q.end(); ++it)
1098 {
1099 EntityHandle q = *it; // this is a blue cell
1100 int global_id;
1101 rval = mb->tag_get_data(gid, &q, 1, &global_id);
1102 ERRORR(rval, "can't get gid for polygon");
1103 int n = TLq.get_n();
1104 TLq.vi_wr[sizeTuple * n] = to_proc; //
1105 TLq.vi_wr[sizeTuple * n + 1] = global_id; // global id of element, used to identify it ...
1106 const EntityHandle * conn4;
1107 int num_nodes;
1108 rval = mb->get_connectivity(q, conn4, num_nodes); // could be up to 10;
1109 ERRORR(rval, "can't get connectivity for quad");
1110 if (num_nodes > MAXEDGES)
1111 ERRORR(MB_FAILURE, "too many nodes in a polygon");
1112 for (int i = 0; i < num_nodes; i++)
1113 {
1114 EntityHandle v = conn4[i];
1115 int index = lagr_verts.index(v);
1116 assert(-1!=index);
1117 TLq.vi_wr[sizeTuple * n + 2 + i] = gids[index];
1118 }
1119 for (int k = num_nodes; k < max_edges_1; k++)
1120 {
1121 TLq.vi_wr[sizeTuple * n + 2 + k] = 0; // fill the rest of node ids with 0; we know that the node ids start from 1!
1122 }
1123 EntityHandle redCell;
1124 rval = mb->tag_get_data(corrTag, &q, 1, &redCell);
1125 ERRORR(rval, "can't get corresponding red cell for dep cell");
1126 TLq.vul_wr[n]=redCell; // this will be sent to remote_cells, to be able to come back
1127 TLq.inc_n();
1128
1129 }
1130
1131 }
1132 // now we can route them to each processor
1133 // now we are done populating the tuples; route them to the appropriate processors
1134 (parcomm->proc_config().crystal_router())->gs_transfer(1, TLv, 0);
1135 (parcomm->proc_config().crystal_router())->gs_transfer(1, TLq, 0);
1136 // the elements are already in localEnts;
1137
1138 // maps from global ids to new vertex and quad handles, that are added
1139 std::map<int, EntityHandle> globalID_to_handle;
1140 // we already have vertices from lagr set; they are already in the processor, even before receiving other
1141 // verts from neighbors
1142 int k=0;
1143 for (Range::iterator vit=lagr_verts.begin(); vit!=lagr_verts.end(); ++vit, k++)
1144 {
1145 globalID_to_handle[gids[k]] = *vit; // a little bit of overkill
1146 // we do know that the global ids between euler and lagr verts are parallel
1147 }
1148 /*std::map<int, EntityHandle> globalID_to_eh;*/ // do we need this one?
1149 globalID_to_eh.clear();
1150 // now, look at every TLv, and see if we have to create a vertex there or not
1151 int n = TLv.get_n(); // the size of the points received
1152 for (int i = 0; i < n; i++)
1153 {
1154 int globalId = TLv.vi_rd[2 * i + 1];
1155 if (globalID_to_handle.find(globalId) == globalID_to_handle.end())
1156 {
1157 EntityHandle new_vert;
1158 double dp_pos[3] = { TLv.vr_wr[3 * i], TLv.vr_wr[3 * i + 1], TLv.vr_wr[3
1159 * i + 2] };
1160 rval = mb->create_vertex(dp_pos, new_vert);
1161 ERRORR(rval, "can't create new vertex ");
1162 globalID_to_handle[globalId] = new_vert;
1163 }
1164 }
1165
1166 // now, all dep points should be at their place
1167 // look in the local list of 2d cells for this proc, and create all those cells if needed
1168 // it may be an overkill, but because it does not involve communication, we do it anyway
1169 Range & local = Rto[my_rank];
1170 Range local_q = local.subset_by_dimension(2);
1171 // the local should have all the vertices in lagr_verts
1172 for (Range::iterator it = local_q.begin(); it != local_q.end(); ++it)
1173 {
1174 EntityHandle q = *it;// these are from lagr cells, local
1175 int gid_el;
1176 rval = mb->tag_get_data(gid, &q, 1, &gid_el);
1177 ERRORR(rval, "can't get element global ID ");
1178 globalID_to_eh[gid_el] = q; // do we need this? maybe to just mark the ones on this processor
1179 // maybe a range of global cell ids is fine?
1180 }
1181 // now look at all elements received through; we do not want to duplicate them
1182 n = TLq.get_n(); // number of elements received by this processor
1183 // a cell should be received from one proc only; so why are we so worried about duplicated elements?
1184 // a vertex can be received from multiple sources, that is fine
1185
1186 remote_cells = new TupleList();
1187 remote_cells->initialize(2, 0, 1, 0, n); // no tracers anymore in these tuples
1188 remote_cells->enableWriteAccess();
1189 for (int i = 0; i < n; i++)
1190 {
1191 int globalIdEl = TLq.vi_rd[sizeTuple * i + 1];
1192 int from_proc=TLq.vi_rd[sizeTuple * i ];
1193 // do we already have a quad with this global ID, represented?
1194 if (globalID_to_eh.find(globalIdEl) == globalID_to_eh.end())
1195 {
1196 // construct the conn quad
1197 EntityHandle new_conn[MAXEDGES];
1198 int nnodes = -1;
1199 for (int j = 0; j < max_edges_1; j++)
1200 {
1201 int vgid = TLq.vi_rd[sizeTuple * i + 2 + j]; // vertex global ID
1202 if (vgid == 0)
1203 new_conn[j] = 0;
1204 else
1205 {
1206 assert(globalID_to_handle.find(vgid)!=globalID_to_handle.end());
1207 new_conn[j] = globalID_to_handle[vgid];
1208 nnodes = j + 1; // nodes are at the beginning, and are variable number
1209 }
1210 }
1211 EntityHandle new_element;
1212 //
1213 EntityType entType = MBQUAD;
1214 if (nnodes > 4)
1215 entType = MBPOLYGON;
1216 if (nnodes < 4)
1217 entType = MBTRI;
1218 rval = mb->create_element(entType, new_conn, nnodes, new_element);
1219 ERRORR(rval, "can't create new element ");
1220 globalID_to_eh[globalIdEl] = new_element;
1221 local_q.insert(new_element);
1222 rval = mb->tag_set_data(gid, &new_element, 1, &globalIdEl);
1223 ERRORR(rval, "can't set gid on new element ");
1224 }
1225 remote_cells->vi_wr[2*i]=from_proc;
1226 remote_cells->vi_wr[2*i+1]=globalIdEl;
1227 // remote_cells->vr_wr[i] = 0.; will have a different tuple for communication
1228 remote_cells->vul_wr[i]= TLq.vul_rd[i];// this is the corresponding red cell (arrival)
1229 remote_cells->inc_n();
1230 }
1231 // now, create a new set, covering_set
1232 rval = mb->create_meshset(MESHSET_SET, covering_set);
1233 ERRORR(rval, "can't create new mesh set ");
1234 rval = mb->add_entities(covering_set, local_q);
1235 ERRORR(rval, "can't add entities to new mesh set ");
1236 // order the remote cells tuple list, with the global id, because we will search in it
1237 //remote_cells->print("remote_cells before sorting");
1238 moab::TupleList::buffer sort_buffer;
1239 sort_buffer.buffer_init(n);
1240 remote_cells->sort(1, &sort_buffer);
1241 sort_buffer.reset();
1242 return MB_SUCCESS;
1243 //end copy
1244 }
1245
1246
correct_intersection_points_positions()1247 ErrorCode Intx2Mesh::correct_intersection_points_positions()
1248 {
1249 if (parcomm)
1250 {
1251 // first, find out the edges that are shared between processors, and owned by the current processor
1252 Range shared_edges_owned;
1253 ErrorCode rval = parcomm->get_shared_entities(-1, // all other proc
1254 shared_edges_owned,
1255 1,
1256 true, // only on the interface
1257 true); // only the edges owned by the current processor
1258 ERRORR(rval, "can't get shared edges owned");
1259
1260 shared_edges_owned = intersect(RedEdges, shared_edges_owned);
1261 rval = parcomm->settle_intersection_points(RedEdges, shared_edges_owned, extraNodesVec, epsilon_1);
1262 ERRORR(rval, "can't settle intx points");
1263 }
1264 return MB_SUCCESS;
1265 }
1266 #endif /* MOAB_HAVE_MPI */
1267 } /* namespace moab */
1268