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, &currentRed, 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