proteus  1.8.1
C/C++/Fortran libraries
MeshConverter.cpp
Go to the documentation of this file.
1 #include <algorithm>
2 
3 #include "MeshAdaptPUMI.h"
4 #include <PCU.h>
5 #include "mesh.h"
6 #include <apfShape.h>
7 
8 #include <sstream>
9 
10 static apf::Numbering* numberOwnedEntitiesFirst(apf::Mesh* m, int dimension,int initialReconstructed)
11 {
12  std::stringstream ss;
13  ss << "proteus_number_" << dimension;
14  std::string s = ss.str();
15  apf::FieldShape* shape;
16  if (dimension) /* this switch is just to help rendering */
17  shape = apf::getConstant(dimension);
18  else
19  shape = m->getShape();
20  apf::Numbering* n = createNumbering(m, s.c_str(), shape, 1);
21  apf::MeshEntity* e;
22  apf::MeshIterator* it = m->begin(dimension);
23  int i = 0;
24  if(initialReconstructed){
25  while ((e = m->iterate(it)))
26  apf::number(n, e, 0, 0, i++);
27  m->end(it);
28  }
29  else{
30  while ((e = m->iterate(it)))
31  if (m->isOwned(e))
32  apf::number(n, e, 0, 0, i++);
33  m->end(it);
34  it = m->begin(dimension);
35  while ((e = m->iterate(it)))
36  if (!m->isOwned(e))
37  apf::number(n, e, 0, 0, i++);
38  m->end(it);
39  }
40  return n;
41 }
42 
43 //Main API to construct a serial pumi mesh,
44 //what we do is contruct the global mesh when working with serial
45 //and let Proteus populate the subdomain data structures
46 //(though it will be exactly same)
48 {
49  assert(m != 0);
50  logEvent("Constructing global data structures",4);
51 
52  int dim = m->getDimension();
53  mesh.nElements_global = m->count(dim);
54 
55  mesh.nNodes_global = m->count(0);
56 
57  mesh.nElementBoundaries_global = m->count(dim - 1);
58 
59  mesh.nEdges_global = m->count(1);
60 
61 //nNodes_element for now is constant for the entire mesh, Ask proteus about using mixed meshes
62  switch (dim) {
63  case 2:
64  mesh.nNodes_element = 3;
65  mesh.nNodes_elementBoundary = 2;
67  break;
68  case 3:
69  mesh.nNodes_element = 4;
70  mesh.nNodes_elementBoundary = 3;
72  break;
73  default:
74  apf::fail("dimension is not 2 or 3\n");
75  break;
76  }
77 #ifdef MESH_INFO
78  std::cerr << "*******Proteus Mesh Stats*********\n";
79  std::cerr << "Number of elements " << mesh.nElements_global << "\n";
80  std::cerr << "Number of nodes " << mesh.nNodes_global << "\n";
81  std::cerr << "Number of boundaries " << mesh.nElementBoundaries_global << "\n";
82  std::cerr << "Number of edges " << mesh.nEdges_global << "\n";
83 #endif
84 
85  numberLocally();
86  constructNodes(mesh);
87  constructElements(mesh);
88  constructBoundaries(mesh);
89  constructEdges(mesh);
90  constructMaterialArrays(mesh);
91 
92  return 0;
93 }
94 
96 {
97  for (int d = 0; d <= m->getDimension(); ++d) {
98  freeNumbering(local[d]);
99  local[d] = numberOwnedEntitiesFirst(m, d,initialReconstructed);
100  }
103 }
104 
105 int MeshAdaptPUMIDrvr::localNumber(apf::MeshEntity* e)
106 {
107  return getNumber(local[apf::getDimension(m, e)], e, 0, 0);
108 }
109 
110 int MeshAdaptPUMIDrvr::constructNodes(Mesh& mesh)
111 {
112  mesh.nodeArray = new double[mesh.nNodes_global * 3];
113  apf::MeshIterator* it = m->begin(0);
114  apf::MeshEntity* e;
115  while ((e = m->iterate(it))) {
116  int i = localNumber(e);
117  apf::Vector3 x;
118  m->getPoint(e, 0, x);
119  for(int j=0; j<3; j++)
120  mesh.nodeArray[i * 3 + j]= x[j];
121  }
122  m->end(it);
123  return 0;
124 }
125 
126 int MeshAdaptPUMIDrvr::constructElements(Mesh& mesh)
127 {
128  mesh.elementNodesArray = new int[mesh.nElements_global*mesh.nNodes_element];
129  apf::MeshIterator* it = m->begin(m->getDimension());
130  apf::MeshEntity* e;
131  while ((e = m->iterate(it))) {
132  int i = localNumber(e);
133  apf::Downward v;
134  int iNumVtx = m->getDownward(e, 0, v);
135  for (int j = 0; j < iNumVtx; ++j) {
136  int vtxID = localNumber(v[j]);
137  mesh.elementNodesArray[i * mesh.nNodes_element + j] = vtxID;
138  }
139  }
140  m->end(it);
141  return 0;
142 }
143 
144 /* following is going to look adhoc and arbitrary but it is needed to
145  resolve a conflict between the way proteus handles faces and we handle faces.
146  The order in which we retrieve faces from adjacency is different to what
147  proteus expects them to be in their elementBoundaries array.
148  To resolve this we need to change the local number of the face of an element
149  to what proteus expects it to be and then it works. Whussh. magic.
150 
151  original comment above preserved for entertainment.
152  This maps SCOREC's tet face numbering to that of proteus.
153  */
154 
155 int getProteusBoundaryIdx(apf::Mesh* m, apf::MeshEntity* e, apf::MeshEntity* f)
156 {
157  apf::Downward fs;
158  int dim = m->getDimension();
159  int nfs = m->getDownward(e, dim - 1, fs);
160  int idx_apf = apf::findIn(fs, nfs, f);
161  /* Proteus convention is that the face index equals the vertex index
162  of the vertex opposite to the face.
163  Proteus and PUMI should have consistent vertex orderings for
164  simplices, but the above rule makes the side orderings different */
165  static int const tet_boundary_map[4] = {3,2,0,1};
166  static int const tri_boundary_map[3] = {2,0,1};
167  static int const* const boundary_maps[4] = {
168  0,
169  0,
170  tri_boundary_map,
171  tet_boundary_map
172  };
173  return boundary_maps[dim][idx_apf];
174 }
175 
176 int MeshAdaptPUMIDrvr::constructBoundaries(Mesh& mesh)
177 {
178 //build face list (elementBoundary and nodeBoundary arrays)
179 //Enter at your own peril for those who stray will be lost
180  std::set<int> interiorElementBoundaries;
181  std::set<int> exteriorElementBoundaries;
182 
186  new int[mesh.nElementBoundaries_global * 2];
188  new int[mesh.nElementBoundaries_global * 2];
189  mesh.elementNeighborsArray =
190  new int[mesh.nElements_global * mesh.nElementBoundaries_element];
192  new int[mesh.nElements_global * mesh.nElementBoundaries_element];
193  //exteriorGlobaltoLocalElementBoundariesArray =
194  // new int[mesh.nElementBoundaries_global];
195  //int exterior_count = 0; //counter for external boundaries
196 
197  int dim = m->getDimension();
198  apf::MeshIterator* it = m->begin(dim - 1);
199  apf::MeshEntity* f;
200  while ((f = m->iterate(it))) {
201  int i = localNumber(f);
202 // get vertices from adjacency
203  apf::Downward vs;
204  int iNumVtx = m->getDownward(f, 0, vs);
205  for (int iVtx = 0; iVtx < iNumVtx; ++iVtx) {
206  int vtxID = localNumber(vs[iVtx]);
208  i * mesh.nNodes_elementBoundary + iVtx] = vtxID;
209  }
210 //get regions from adjacency
211  apf::Up rs;
212  m->getUp(f, rs);
213  int iNumRgn = rs.n;
214  int RgnID[2] = {-1,-1};
215  int localBoundaryNumber[2] = {-1,-1};
216  for (int iRgn = 0; iRgn < iNumRgn; ++iRgn) {
217  RgnID[iRgn] = localNumber(rs.e[iRgn]);
218  mesh.elementBoundaryElementsArray[i * 2 + iRgn]= RgnID[iRgn];
219  localBoundaryNumber[iRgn] = getProteusBoundaryIdx(m, rs.e[iRgn], f);
220  assert(localBoundaryNumber[iRgn] != -1);
222  i * 2 + iRgn] = localBoundaryNumber[iRgn];
223  }
224  //left and right regions are shared by this face we are currntly on
225  int leftRgnID = RgnID[0]; int leftLocalBoundaryNumber = localBoundaryNumber[0];
226  int rightRgnID = RgnID[1]; int rightLocalBoundaryNumber = localBoundaryNumber[1];
227  /*left region is always there, so either rightRgnID will have
228  an actual ID if this face is shared, or will contain -1
229  if it is an exterior face */
231  leftRgnID * mesh.nElementBoundaries_element + leftLocalBoundaryNumber]
232  = rightRgnID;
234  leftRgnID * mesh.nElementBoundaries_element + leftLocalBoundaryNumber]
235  = i;
236 
237  /* if only 1 region is adjacent to this face,
238  that means it is an exterior face */
239  if(iNumRgn==1) {
240  assert(RgnID[1]==-1);
241  assert(localBoundaryNumber[1]==-1); //last 2 checks are only for sanity
242  mesh.elementBoundaryElementsArray[i * 2 + 1] = -1;
243  mesh.elementBoundaryLocalElementBoundariesArray[i * 2 + 1] = -1;
244  //exterior face as only 1 region adjacent
245  exteriorElementBoundaries.insert(i);
246 
247  //construct inverse mapping
248  //exteriorGlobaltoLocalElementBoundariesArray[i] = exterior_count;
249  //exterior_count++;
250 
251  } else { //2 regions are shared by this face so interior face
253  rightRgnID * mesh.nElementBoundaries_element + rightLocalBoundaryNumber]
254  = leftRgnID;
256  rightRgnID * mesh.nElementBoundaries_element + rightLocalBoundaryNumber]
257  = i;
258  interiorElementBoundaries.insert(i);
259  }
260  }
261  m->end(it);
262 
263  //construct interior and exterior element boundaries array
264  mesh.nInteriorElementBoundaries_global = interiorElementBoundaries.size();
266  mesh.nExteriorElementBoundaries_global = exteriorElementBoundaries.size();
268 
269  int ebNI=0,ebNE=0;
270  for (std::set<int>::iterator ebN=interiorElementBoundaries.begin();ebN != interiorElementBoundaries.end(); ebN++,ebNI++)
271  mesh.interiorElementBoundariesArray[ebNI] = *ebN;
272  for (std::set<int>::iterator ebN=exteriorElementBoundaries.begin();ebN != exteriorElementBoundaries.end(); ebN++,ebNE++)
273  mesh.exteriorElementBoundariesArray[ebNE] = *ebN;
274 
275  return 0;
276 }
277 
278 /* these algorithms are totally independent of SCOREC;
279  they form the proteus
280  vertex to vertex and vertex to element adjacency tables
281  from the edge to vertex and element to vertex tables */
282 static void createStars(Mesh& mesh)
283 {
284  std::vector<std::set<int> > nodeStar(mesh.nNodes_global);
285  for (int edgeN = 0; edgeN < mesh.nEdges_global; edgeN++) {
286  nodeStar[mesh.edgeNodesArray[edgeN * 2 + 0]].insert(
287  mesh.edgeNodesArray[edgeN * 2 + 1]);
288  nodeStar[mesh.edgeNodesArray[edgeN * 2 + 1]].insert(
289  mesh.edgeNodesArray[edgeN * 2 + 0]);
290  }
291 
292  mesh.nodeStarOffsets = new int[mesh.nNodes_global + 1];
293  mesh.nodeStarOffsets[0] = 0;
294  for (int nN = 1; nN <= mesh.nNodes_global; nN++)
295  mesh.nodeStarOffsets[nN] =
296  mesh.nodeStarOffsets[nN - 1] + nodeStar[nN - 1].size();
297 
298  mesh.nodeStarArray = new int[mesh.nodeStarOffsets[mesh.nNodes_global]];
299  for (int nN = 0, offset = 0; nN < mesh.nNodes_global; nN++)
300  for (std::set<int>::iterator nN_star=nodeStar[nN].begin();
301  nN_star!=nodeStar[nN].end();
302  nN_star++, offset++)
303  mesh.nodeStarArray[offset] = *nN_star;
304 
305  mesh.max_nNodeNeighbors_node = 0;
306  for (int nN = 0; nN < mesh.nNodes_global; nN++)
309  mesh.nodeStarOffsets[nN + 1] - mesh.nodeStarOffsets[nN]);
310 
311  std::vector<std::set<int> > nodeElementsStar(mesh.nNodes_global);
312  for (int eN = 0; eN < mesh.nElements_global; eN++)
313  for (int nN = 0; nN < mesh.nNodes_element; nN++)
314  nodeElementsStar[
315  mesh.elementNodesArray[eN * mesh.nNodes_element + nN]
316  ].insert(eN);
317  mesh.nodeElementOffsets = new int[mesh.nNodes_global + 1];
318  mesh.nodeElementOffsets[0] = 0;
319  for (int nN = 0; nN < mesh.nNodes_global; nN++)
320  mesh.nodeElementOffsets[nN + 1] =
321  mesh.nodeElementOffsets[nN] + nodeElementsStar[nN].size();
322  mesh.nodeElementsArray = new int[mesh.nodeElementOffsets[mesh.nNodes_global]];
323  for (int nN=0,offset=0; nN < mesh.nNodes_global; nN++)
324  for (std::set<int>::iterator eN_star = nodeElementsStar[nN].begin();
325  eN_star != nodeElementsStar[nN].end();
326  eN_star++, offset++)
327  mesh.nodeElementsArray[offset] = *eN_star;
328 }
329 
330 int MeshAdaptPUMIDrvr::constructEdges(Mesh& mesh)
331 {
332  mesh.edgeNodesArray = new int[mesh.nEdges_global * 2];
333  apf::MeshIterator* it = m->begin(1);
334  apf::MeshEntity* e;
335  while ((e = m->iterate(it))) {
336  int i = localNumber(e);
337  apf::MeshEntity* v[2];
338  m->getDownward(e, 0, v);
339  for(int iVtx=0; iVtx < 2; ++iVtx) {
340  int vtxID = localNumber(v[iVtx]);
341  mesh.edgeNodesArray[i * 2 + iVtx] = vtxID;
342  }
343  }
344  m->end(it);
345  createStars(mesh);
346  return 0;
347 }
348 
349 #define INTERIOR_MATERIAL 0
350 #define EXTERIOR_MATERIAL 1
351 #define DEFAULT_ELEMENT_MATERIAL INTERIOR_MATERIAL
352 
353 static int getInOutMaterial(apf::Mesh* m, apf::MeshEntity* e)
354 {
355  if (m->getModelType(m->toModel(e)) == m->getDimension())
356  return INTERIOR_MATERIAL;
357  else
358  return EXTERIOR_MATERIAL;
359 }
360 
361 /* This function builds the element, elementBoundary, and node
362  * Material arrays and fills them in with zero or one depending
363  * one whether the entity is classified on the geometric boundary
364  * or not.
365  * This forms a baseline material tagging for all entities,
366  * which later gets overwritten for some entities with more
367  * specific values in MeshAdaptPUMIDrvr::UpdateMaterialArrays.
368  */
369 int MeshAdaptPUMIDrvr::constructMaterialArrays(Mesh& mesh)
370 {
372  mesh.nodeMaterialTypes = new int[mesh.nNodes_global];
373  mesh.elementMaterialTypes = new int[mesh.nElements_global];
374  for (int i = 0; i < mesh.nElements_global; ++i)
376  int dim = m->getDimension();
377  apf::MeshIterator* it = m->begin(dim - 1);
378  apf::MeshEntity* f;
379  while ((f = m->iterate(it))) {
380  int i = localNumber(f);
381  mesh.elementBoundaryMaterialTypes[i] = getInOutMaterial(m, f);
382  }
383  m->end(it);
384  it = m->begin(0);
385  apf::MeshEntity* v;
386  while ((v = m->iterate(it))) {
387  int i = localNumber(v);
388  mesh.nodeMaterialTypes[i] = getInOutMaterial(m, v);
389  }
390  m->end(it);
391  return 0;
392 }
393 
394 /* Given a geometric model face identified by the integer
395  * (scorec_tag), get all nodes and element boundaries
396  * classified on the closure of that model face and
397  * put the (proteus_material) integer in their material
398  * array slot.
399  */
401  int dim,
402  int proteus_material,
403  int scorec_tag)
404 {
405  //int dim = m->getDimension();
406  apf::ModelEntity* geomEnt = m->findModelEntity(dim, scorec_tag);
407  apf::MeshIterator* it = m->begin(dim);
408  apf::MeshEntity* f;
409  if(dim==m->getDimension()){
410  while ((f = m->iterate(it))) {
411  if (m->toModel(f) == geomEnt) {
412  int i = localNumber(f);
413  mesh.elementMaterialTypes[i] = proteus_material;
414  }
415  }
416  }
417  else{
418  while ((f = m->iterate(it))) {
419  if (m->toModel(f) == geomEnt) {
420  int i = localNumber(f);
421  mesh.elementBoundaryMaterialTypes[i] = proteus_material;
422  }
423  }
424  apf::DynamicArray<apf::Node> nodes;
425  apf::getNodesOnClosure(m, geomEnt, nodes);
426  for (size_t i = 0; i < nodes.getSize(); ++i) {
427  int vtxId = localNumber(nodes[i].entity);
428  mesh.nodeMaterialTypes[vtxId] = proteus_material;
429  }
430  }
431  m->end(it);
432  return 0;
433 }
434 
435 /* Overload updateMaterialArray for reconstructed SCOREC meshes.
436  * The material types are stored based on derived model entity.
437  * We can recover the material of a mesh entity by looking at its classified
438  * model entity
439  */
441 {
442  int geomTag;
443  apf::ModelEntity* geomEnt;
444  apf::MeshIterator* it;
445  apf::MeshEntity* f;
446 
447  int dim = 0;
448  it = m->begin(dim);
449  while(f = m->iterate(it)){
450  int i = localNumber(f);
451  geomEnt = m->toModel(f);
452  geomTag = m->getModelTag(geomEnt);
453  if(m->getModelType(geomEnt) == dim){
454  mesh.nodeMaterialTypes[i] =modelVertexMaterial[geomTag];
455  }
456  else if(m->getModelType(geomEnt)==(m->getDimension()-1)){ //on the boundary entity
457  mesh.nodeMaterialTypes[i] =modelBoundaryMaterial[geomTag];
458  }
459  //If 3D and is on an exterior edge
460  else if(m->getDimension()==3 && m->getModelType(geomEnt)==1){
461  apf::Adjacent vert_adjFace;
462  m->getAdjacent(f,2,vert_adjFace);
463  for(int j=0;j<vert_adjFace.getSize();j++){
464  apf::ModelEntity* adjEnt = m->toModel(vert_adjFace[j]);
465  if(m->getModelType(adjEnt) == 2){
466  mesh.nodeMaterialTypes[i] = modelBoundaryMaterial[m->getModelTag(adjEnt)];
467  }
468  }
469  }
470  else{
471  mesh.nodeMaterialTypes[i] = 0; //This assumes that all vertices on the boundary are model vertices
472  }
473  }
474  m->end(it);
475  if(m->getDimension()==2)
476  dim = 1;
477  else
478  dim = 2;
479  it = m->begin(dim);
480  while(f = m->iterate(it)){
481  geomEnt = m->toModel(f);
482  int i = localNumber(f);
483  if(m->getModelType(geomEnt) == dim){
484  geomTag = m->getModelTag(m->toModel(f));
486  }
487  else{
488  geomTag = m->getModelTag(m->toModel(f));
489  //Interior boundaries and entities have a material type of zero
490  mesh.elementBoundaryMaterialTypes[i] = 0;
491  }
492  }
493  m->end(it);
494 
495  dim = dim+1; //the regions are necessarily one dimension higher than previous dim
496  it = m->begin(dim);
497  while(f = m->iterate(it)){
498  geomEnt = m->toModel(f);
499  int i = localNumber(f);
500  assert(m->getModelType(geomEnt)==dim);
501  geomTag = m->getModelTag(m->toModel(f));
502  //The geomTag is actually the right material for region entities
503  mesh.elementMaterialTypes[i] = geomTag; //modelRegionMaterial[geomTag];
504  }
505  m->end(it);
506  return 0;
507 }
508 
510 {
511  logEvent("Starting to update material arrays",4);
512  int geomTag;
513  apf::ModelEntity* geomEnt;
514  apf::MeshIterator* it;
515  apf::MeshEntity* f;
516 
517  //first associate all nodes with a material tag and synchronize fields to avoid mismatches
518  //The procedure is to have each vertex look for its classification.
519  //If it is classified in the region, then it is interior.
520  //Else, loop over adjacent faces and stop at first instance of mesh face classified on model boundary and take tag.
521  //If there are no such adjacent mesh faces, then set the value to be -1. This should only happen if the vertex is a shared entity.
522  //If the vertex is shared, communicate value to remote copies.
523  //When receiving values, if the current value is -1, write to field the received value. Otherwise, do nothing.
524 
525  apf::Field* nodeMaterials = apf::createLagrangeField(m, "nodeMaterials", apf::SCALAR, 1);
526  it = m->begin(0);
527  PCU_Comm_Begin();
528  while(f = m->iterate(it))
529  {
530  geomEnt = m->toModel(f);
531  //if classified in a region
532  if(m->getModelType(geomEnt) == m->getDimension())
533  {
534  apf::setScalar(nodeMaterials,f,0,0);
535  }
536  else
537  {
538  apf::Adjacent vert_adjFace;
539  m->getAdjacent(f,m->getDimension()-1,vert_adjFace);
540  apf::MeshEntity* face;
541  for(int i =0; i<vert_adjFace.getSize();i++)
542  {
543  face=vert_adjFace[i];
544  geomEnt = m->toModel(face);
545 
546  //IF mesh face is classified on boundary
547  if(m->getModelType(geomEnt) == m->getDimension()-1)
548  {
549  geomTag = m->getModelTag(geomEnt);
550  apf::setScalar(nodeMaterials,f,0,geomTag);
551  if(m->isShared(f))
552  {
553  apf::Copies remotes;
554  m->getRemotes(f,remotes);
555  for(apf::Copies::iterator iter = remotes.begin(); iter != remotes.end(); ++iter)
556  {
557  PCU_COMM_PACK(iter->first,iter->second);
558  PCU_COMM_PACK(iter->first,geomTag);
559  }
560  }
561  break;
562  }
563  if(i == vert_adjFace.getSize()-1 )
564  apf::setScalar(nodeMaterials,f,0,-1);
565  }
566  }
567  }
568  m->end(it);
569  PCU_Comm_Send();
570  while(PCU_Comm_Receive())
571  {
572  PCU_COMM_UNPACK(f);
573  PCU_COMM_UNPACK(geomTag);
574  int currentTag = apf::getScalar(nodeMaterials,f,0);
575  int newTag = std::min(currentTag,geomTag);
576  //if vertex is not interior and had no adjacent faces, take received values
577  //else take minimum value of all tags
578  if(currentTag==-1)
579  apf::setScalar(nodeMaterials,f,0,geomTag);
580  else
581  apf::setScalar(nodeMaterials,f,0,newTag);
582  }
583  //Ensure there are no mismatches across parts and then assign node materials
584  apf::synchronize(nodeMaterials);
585  it = m->begin(0);
586  while(f=m->iterate(it))
587  {
588  int vID = localNumber(f);
589  mesh.nodeMaterialTypes[vID] = apf::getScalar(nodeMaterials,f,0);
590  }
591  m->end(it);
592 
593  //First iterate over all faces in 3D, get the model tag and apply to all downward adjacencies
594  int dim = m->getDimension()-1;
595  it = m->begin(dim);
596  while(f = m->iterate(it))
597  {
598  int i = localNumber(f);
599  geomEnt = m->toModel(f);
600  geomTag = m->getModelTag(geomEnt);
601  if(m->getModelType(geomEnt) == dim)
602  {
603  mesh.elementBoundaryMaterialTypes[i] = geomTag;
604  }
605  }
606  m->end(it);
607 
608  apf::destroyField(nodeMaterials);
609 
610  //Loop over regions
611  dim = m->getDimension();
612  it = m->begin(dim);
613  while( f = m->iterate(it)){
614  int i = localNumber(f);
615  geomEnt = m->toModel(f);
616  geomTag = m->getModelTag(geomEnt);
617  if(m->getModelType(geomEnt) == dim){
618  mesh.elementMaterialTypes[i] = 0;//geomTag;
619  }
620  }
621  m->end(it);
622  return 0;
623 }
624 
625 
626 /**************************************************************************/
627 
628 /*This section of code is a modified version of the apf::construct() function available in
629  * scorec/core. This may be added into scorec/core eventually and removed.
630  */
631 
632 //#include <PCU.h>
633 #include "apfConvert.h"
634 #include "apfMesh2.h"
635 #include "apf.h"
636 #include "apfNumbering.h"
637 #include <map>
638 
639 namespace apf {
640 
641 typedef int Gid;
642 
643 static void constructVerts(
644  Mesh2* m, int nverts,
645  int* local2globalMap,
646  GlobalToVert& result)
647 {
648  ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
649  for (int i = 0; i < nverts; ++i)
650  result[local2globalMap[i]] = m->createVert_(interior);
651 }
652 
653 
654 static void constructBoundaryElements(
655  Mesh2* m, const Gid* conn_b, int nelem_b, int etype_b,
656  GlobalToVert& globalToVert)
657 {
658  ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
659  int nev = apf::Mesh::adjacentCount[etype_b][0];
660  for (int i = 0; i < nelem_b; ++i) {
661  Downward verts;
662  int offset = i * nev;
663  for (int j = 0; j < nev; ++j){
664  verts[j] = globalToVert[conn_b[j + offset]];
665  }
666  //We only care about how boundary elements are created
667  //The intermediate entities need to inherit the classifications
668  if(m->getDimension()==2)
669  m->createEntity(etype_b,interior,verts);
670  else
671  apf::buildElement(m,interior,2,verts);
672  }
673 }
674 static void constructElements(
675  Mesh2* m, const Gid* conn, int nelem, int etype,
676  GlobalToVert& globalToVert)
677 {
678  ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
679  int nev = apf::Mesh::adjacentCount[etype][0];
680  for (int i = 0; i < nelem; ++i) {
681  Downward verts;
682  int offset = i * nev;
683  for (int j = 0; j < nev; ++j)
684  verts[j] = globalToVert[conn[j + offset]];
685  buildElement(m, interior, etype, verts);
686  }
687 }
688 
689 static Gid getMax(const GlobalToVert& globalToVert)
690 {
691  Gid max = -1;
692  APF_CONST_ITERATE(GlobalToVert, globalToVert, it)
693  max = std::max(max, it->first);
694  return PCU_Max_Int(max); // this is type-dependent
695 }
696 
697 
698 /* algorithm courtesy of Sebastian Rettenberger:
699  use brokers/routers for the vertex global ids.
700  Although we have used this trick before (see mpas/apfMPAS.cc),
701  I didn't think to use it here, so credit is given. */
702 static void constructResidence(Mesh2* m, GlobalToVert& globalToVert)
703 {
704  Gid max = getMax(globalToVert);
705  Gid total = max + 1;
706  int peers = PCU_Comm_Peers();
707  int quotient = total / peers;
708  int remainder = total % peers;
709  int mySize = quotient;
710  int self = PCU_Comm_Self();
711  if (self == (peers - 1))
712  mySize += remainder;
713  typedef std::vector< std::vector<int> > TmpParts;
714  TmpParts tmpParts(mySize);
715  /* if we have a vertex, send its global id to the
716  broker for that global id */
717  PCU_Comm_Begin();
718  APF_ITERATE(GlobalToVert, globalToVert, it) {
719  int gid = it->first;
720  int to = std::min(peers - 1, gid / quotient);
721  PCU_COMM_PACK(to, gid);
722  }
723  PCU_Comm_Send();
724  int myOffset = self * quotient;
725  /* brokers store all the part ids that sent messages
726  for each global id */
727  while (PCU_Comm_Receive()) {
728  int gid;
729  PCU_COMM_UNPACK(gid);
730  int from = PCU_Comm_Sender();
731  tmpParts.at(gid - myOffset).push_back(from);
732  }
733  /* for each global id, send all associated part ids
734  to all associated parts */
735  PCU_Comm_Begin();
736  for (int i = 0; i < mySize; ++i) {
737  std::vector<int>& parts = tmpParts[i];
738  for (size_t j = 0; j < parts.size(); ++j) {
739  int to = parts[j];
740  int gid = i + myOffset;
741  int nparts = parts.size();
742  PCU_COMM_PACK(to, gid);
743  PCU_COMM_PACK(to, nparts);
744  for (size_t k = 0; k < parts.size(); ++k)
745  PCU_COMM_PACK(to, parts[k]);
746  }
747  }
748  PCU_Comm_Send();
749  /* receiving a global id and associated parts,
750  lookup the vertex and classify it on the partition
751  model entity for that set of parts */
752  while (PCU_Comm_Receive()) {
753  int gid;
754  PCU_COMM_UNPACK(gid);
755  int nparts;
756  PCU_COMM_UNPACK(nparts);
757  Parts residence;
758  for (int i = 0; i < nparts; ++i) {
759  int part;
760  PCU_COMM_UNPACK(part);
761  residence.insert(part);
762  }
763  MeshEntity* vert = globalToVert[gid];
764  m->setResidence(vert, residence);
765  }
766 }
767 
768 /* given correct residence from the above algorithm,
769  negotiate remote copies by exchanging (gid,pointer)
770  pairs with parts in the residence of the vertex */
771 static void constructRemotes(Mesh2* m, GlobalToVert& globalToVert)
772 {
773  int self = PCU_Comm_Self();
774  PCU_Comm_Begin();
775  APF_ITERATE(GlobalToVert, globalToVert, it) {
776  int gid = it->first;
777  MeshEntity* vert = it->second;
778  Parts residence;
779  m->getResidence(vert, residence);
780  APF_ITERATE(Parts, residence, rit)
781  if (*rit != self) {
782  PCU_COMM_PACK(*rit, gid);
783  PCU_COMM_PACK(*rit, vert);
784  }
785  }
786  PCU_Comm_Send();
787  while (PCU_Comm_Receive()) {
788  int gid;
789  PCU_COMM_UNPACK(gid);
790  MeshEntity* remote;
791  PCU_COMM_UNPACK(remote);
792  int from = PCU_Comm_Sender();
793  MeshEntity* vert = globalToVert[gid];
794  m->addRemote(vert, from, remote);
795  }
796 }
797 
798 void construct(Mesh2* m, const int* conn, const int* conn_b, int nelem,
799  int nelem_b, int nverts,int etype, int etype_b, int* local2globalMap,
800  GlobalToVert& globalToVert)
801 {
802  constructVerts(m, nverts,local2globalMap,globalToVert);
803  constructBoundaryElements(m, conn_b, nelem_b, etype_b, globalToVert);
804  constructElements(m, conn, nelem, etype, globalToVert);
805  constructResidence(m, globalToVert);
806  constructRemotes(m, globalToVert);
807  stitchMesh(m);
808  m->acceptChanges();
809 }
810 
811 }
812 
813 /**************************************************************************/
814 
815 
816 //The following functions are used to facilitate and perform a reconstruction
817 //of the proteus mesh into a SCOREC mesh to enable adaptivity features.
818 //Currently, only 2D mesh reconstruction is supported.
819 //The basic strategy is to assume each exterior entity is a model entity since
820 //no geometric model is given. In Proteus, part boundary mesh entities are
821 //considered exterior and so there needs to be logic to avoid classifying those.
822 //Each model entity should be unique and is associated with a material type.
823 //These material types are kept track via material arrays and the size of such
824 //arrays are based on the total number of owned entities on each rank.
825 //
826 //There are some currently obsolete functionality for 2D model entity detection
827 //for mesh entities which will likely be developed/completed at a later time.
828 //
829 //To use, add the following to your case.py file (for example):
830 //
831 /*
832  adaptMesh = True
833  adaptMesh_nSteps = 10
834  adaptMesh_numIter = 2
835  MeshAdaptMesh=MeshAdaptPUMI.MeshAdaptPUMI(hmax=1.0, hmin=0.001, numIter=adaptMesh_numIter,sfConfig="ERM",logType="off",targetError=100,targetElementCount=8000)
836  useModel=False
837 */
838 
839 #include <apf.h>
840 #include <gmi_null.h>
841 #include <gmi_mesh.h>
842 #include <gmi.h>
843 #include <apfMDS.h>
844 #include <apfMesh2.h>
845 #include <apfConvert.h>
846 #include <ma.h>
847 #include <PCU.h>
848 
849 #include <cassert>
850 #include <gmi_lookup.h>
851 
852 //Function to transfer some model information from NumericalSolution into the
853 //MeshAdaptPUMIDrvr class.
854 
855 int MeshAdaptPUMIDrvr::transferModelInfo(int* numGeomEntities, int* edges, int* faces, int* mVertex2Model, int*mEdge2Model, int*mBoundary2Model,int nMaxSegments){
856  numModelEntities[0] = numGeomEntities[0];
857  numModelEntities[1] = numGeomEntities[1];
858  numModelEntities[2] = numGeomEntities[2];
859  numModelEntities[3] = numGeomEntities[3];
860  edgeList = edges;
861  faceList = faces;
862  meshVertex2Model = mVertex2Model;
863  meshEdge2Model = mEdge2Model;
864  meshBoundary2Model = mBoundary2Model;
865  numSegments = nMaxSegments;
866  return 0;
867 }
868 
869 //Actual function to prompt recontruction and takes in the subodomain mesh and
870 //the global mesh
871 
872 int MeshAdaptPUMIDrvr::reconstructFromProteus(Mesh& mesh, Mesh& globalMesh,int hasModel)
873 {
874  if(PCU_Comm_Self()==0)
875  std::cout<<"STARTING RECONSTRUCTION\n";
876  isReconstructed = 1; //True
877 
878  /************Preliminaries**************/
879  comm_size = PCU_Comm_Peers();
880  comm_rank = PCU_Comm_Self();
881 
882  int numModelNodes;
883  int numModelEdges;
884  int numModelBoundaries;
885  int numModelRegions;
886 
887  int nBoundaryNodes=0; //number of total boundary nodes regardless of ownership
888  int nNodes_owned = globalMesh.nodeOffsets_subdomain_owned[PCU_Comm_Self()+1]-globalMesh.nodeOffsets_subdomain_owned[PCU_Comm_Self()];
889 
890  for(int i =0;i<mesh.nNodes_global;i++){
891  if(mesh.nodeMaterialTypes[i]>0){
892  nBoundaryNodes++;
893  }
894  }
895 
896  int numDim;
897  if(mesh.nNodes_element==3)
898  numDim = 2;
899  else
900  numDim = 3;
901 
902  //Depending on the dimension of the problem, exterior boundaries may refer to
903  //edges or faces
904  if(hasModel){
905  numModelNodes=numModelEntities[0];
906  numModelEdges=numModelEntities[1];
907  numModelBoundaries=numModelEntities[2];
908  numModelRegions=numModelEntities[3];
909  if(numDim=2){
910  //should add some sort of assertion statement here
911  numModelBoundaries = numModelEdges;
912  }
913  }
914  else{
915  numModelNodes = nBoundaryNodes;
916  numModelEdges = mesh.nEdges_global;
917  numModelBoundaries = mesh.nExteriorElementBoundaries_global;
918  numModelRegions = numModelEntities[3];
919  }
920 
921  assert(numModelRegions>0);
922 
923  numModelTotals[0] = numModelNodes;
924  numModelTotals[1] = numModelEdges;
925  numModelTotals[2] = numModelBoundaries;
926  numModelTotals[3] = 0;//The total number of regions is known so no need to set a value
927  PCU_Add_Ints(&numModelTotals[0],4); //get all offsets at the same time
928  numModelTotals[3] = numModelRegions;
929 
930  /************Model Allocation**************/
931  //This section starts the process to derive the geometric
932  //model associated with the mesh
933 
934  gmi_model* gMod;
935 
936  struct gmi_base* gMod_base;
937  gMod_base = (gmi_base*)malloc(sizeof(*gMod_base));
938  gMod_base->model.ops = &gmi_base_ops;
939  gmi_base_init(gMod_base);
940 
941  struct agm_ent e;
942  struct agm_bdry b;
943  struct agm_ent d;
944 
945  //gvertices
946  gmi_base_reserve(gMod_base,AGM_VERTEX,numModelTotals[0]);
947 
948  if(numDim==2){
949  //gedges
950  gmi_base_reserve(gMod_base,AGM_EDGE,numModelTotals[2]);
951  //gfaces
952  gmi_base_reserve(gMod_base,AGM_FACE,numModelTotals[3]);
953  //gregions
954  gmi_base_reserve(gMod_base,AGM_REGION,0);
955  }
956  else if(numDim==3){
957  //gedges
958  gmi_base_reserve(gMod_base,AGM_EDGE,numModelTotals[1]);
959  //gfaces
960  gmi_base_reserve(gMod_base,AGM_FACE,numModelTotals[2]);
961  //gregions
962  gmi_base_reserve(gMod_base,AGM_REGION,numModelTotals[3]);
963  }
964 
965  gMod = &gMod_base->model;
966 
967  /************Mesh Creation**************/
968  //We can use apf::construct() which takes in a mapping of the elements
969  //to their global vertices as well as boundary elements to their global
970  //vertices and outputs a topologically correct mesh.
971  //
972  m = apf::makeEmptyMdsMesh(gMod,numDim,false);
973 
974  int etype,etype_b;
975  int boundaryDim = numDim-1;
976  apf::GlobalToVert outMap;
977  if(numDim == 2){
978  etype = apf::Mesh::TRIANGLE;
979  etype_b = apf::Mesh::EDGE;
980  }
981  else{
982  etype = apf::Mesh::TET;
983  etype_b = apf::Mesh::TRIANGLE;
984  }
985 
986 
987  //create the mappings from proteus data structures
988  int* local2global_elementBoundaryNodes;
989  local2global_elementBoundaryNodes = (int*) malloc(sizeof(int)*mesh.nElementBoundaries_global*apf::Mesh::adjacentCount[etype_b][0]);
990  for(int i=0;i<mesh.nElementBoundaries_global*apf::Mesh::adjacentCount[etype_b][0];i++){ //should use adjacent count function from core
991  local2global_elementBoundaryNodes[i] = globalMesh.nodeNumbering_subdomain2global[mesh.elementBoundaryNodesArray[i]];
992  }
993  int* local2global_elementNodes;
994  local2global_elementNodes = (int*) malloc(sizeof(int)*mesh.nElements_global*apf::Mesh::adjacentCount[etype][0]);
995  for(int i=0;i<mesh.nElements_global*apf::Mesh::adjacentCount[etype][0];i++){ //should use adjacent count function from core
996  local2global_elementNodes[i] = globalMesh.nodeNumbering_subdomain2global[mesh.elementNodesArray[i]];
997  }
998 
999  //construct the mesh
1000  apf::construct(m,local2global_elementNodes,local2global_elementBoundaryNodes,
1001  mesh.nElements_global,mesh.nElementBoundaries_global,mesh.nNodes_global,etype,etype_b,
1002  globalMesh.nodeNumbering_subdomain2global,outMap);
1003 
1004  //Get the global model offsets after the mesh has been created
1005  //Need to get the number of owned element boundaries on the current rank
1006  //Also need to get the number of owned exterior entities for proper processor communication
1007  //This is necessary because a shared mesh entity should point to the same model entity
1008 
1009  nBoundaryNodes = 0;
1010  apf::MeshIterator* entIter=m->begin(0);
1011  apf::MeshEntity* ent;
1012  int idx = 0;
1013  while((ent=m->iterate(entIter))){
1014  if(m->isOwned(ent)){
1015  if(mesh.nodeMaterialTypes[idx]>0)
1016  nBoundaryNodes++;
1017  }
1018  idx++;
1019  }
1020  m->end(entIter);
1021 
1022  entIter=m->begin(boundaryDim);
1023  idx=0;
1024  int nExteriorElementBoundaries_owned = 0;
1025  while((ent=m->iterate(entIter))){
1026  if(m->isOwned(ent)){
1027  if(mesh.elementBoundaryMaterialTypes[idx]>0)
1028  nExteriorElementBoundaries_owned++;
1029  }
1030  idx++;
1031  }
1032  m->end(entIter);
1033 
1034  if(hasModel){
1035  numModelNodes=numModelEntities[0];
1036  numModelEdges=numModelEntities[1];
1037  numModelBoundaries=numModelEntities[2];
1038  numModelRegions=numModelEntities[3];
1039  if(numDim=2){
1040  numModelBoundaries = numModelEdges;
1041  }
1042  }
1043  else{
1044  numModelNodes = nBoundaryNodes;
1045  numModelEdges = mesh.nEdges_global;
1046  numModelBoundaries = nExteriorElementBoundaries_owned;
1047  numModelRegions = numModelEntities[3];
1048  }
1049 
1050  numModelOffsets[0] = numModelNodes;
1051  numModelOffsets[1] = numModelEdges;
1052  numModelOffsets[2] = numModelBoundaries;
1053  numModelOffsets[3] = 0;
1054 
1055  numModelTotals[0] = numModelNodes;
1056  numModelTotals[1] = numModelEdges;
1057  numModelTotals[2] = numModelBoundaries;
1058  numModelTotals[3] = 0;
1059 
1060  //Get Region starting material
1061  entIter = m->begin(numDim);
1062  int regStartMaterial = 100;
1063  int rID = 0;
1064  while(ent = m->iterate(entIter)){
1065  if(mesh.elementMaterialTypes[rID] < regStartMaterial)
1066  regStartMaterial = mesh.elementMaterialTypes[rID];
1067  rID++;
1068  }
1069  m->end(entIter);
1070 
1071 
1072  //get all offsets at the same time
1073  PCU_Exscan_Ints(&numModelOffsets[0],4);
1074  PCU_Add_Ints(&numModelTotals[0],4);
1075  numModelTotals[3] = numModelRegions;
1076 
1077  //classify mesh entities on model entities
1078 
1079  apf::Vector3 pt;
1080 
1081  apf::ModelEntity* g_vertEnt;
1082  apf::ModelEntity* g_edgeEnt;
1083  apf::ModelEntity* g_faceEnt;
1084  apf::MeshEntity* vertEnt;
1085 
1086  modelVertexMaterial = (int*)calloc(numModelTotals[0],sizeof(int));
1087  modelBoundaryMaterial = (int*)calloc(numModelTotals[2],sizeof(int));
1088  modelRegionMaterial = (int*)calloc(numModelTotals[3],sizeof(int));
1089 
1090  //gmi set entities
1091  //more entities were reserved than necessary, but that's okay
1092 
1093  gmi_unfreeze_lookups(gMod_base->lookup);
1094  for(int i=0;i<numModelTotals[0];i++){
1095  e = agm_add_ent(gMod_base->topo, AGM_VERTEX);
1096  gmi_set_lookup(gMod_base->lookup, e, i);
1097  }
1098  gmi_freeze_lookup(gMod_base->lookup, (agm_ent_type)0);
1099 
1100  for(int i=0;i<numModelTotals[2];i++){
1101  if(numDim==2)
1102  e = agm_add_ent(gMod_base->topo, AGM_EDGE);
1103  else
1104  e = agm_add_ent(gMod_base->topo, AGM_FACE);
1105  gmi_set_lookup(gMod_base->lookup, e, i);
1106  }
1107  gmi_freeze_lookup(gMod_base->lookup, (agm_ent_type)boundaryDim);
1108 
1109  for(int i=0;i<numModelRegions;i++){
1110  if(numDim == 2)
1111  e = agm_add_ent(gMod_base->topo, AGM_FACE);
1112  else
1113  e = agm_add_ent(gMod_base->topo, AGM_REGION);
1114 
1115  //assumes material types are enumerated starting from 1
1116  gmi_set_lookup(gMod_base->lookup, e, i+regStartMaterial);
1117  if(hasModel){
1118  b = agm_add_bdry(gMod_base->topo, e);
1119  for(int k=0;k<numSegments;k++){
1120  if(faceList[(i)*numSegments+k]==-1) break;
1121  else{
1122  d = gmi_look_up(gMod_base->lookup,AGM_EDGE,faceList[(i)*numSegments+k]);
1123  agm_add_use(gMod_base->topo,b,d);
1124  }
1125  }
1126  }
1127  }
1128  gmi_freeze_lookup(gMod_base->lookup, (agm_ent_type)numDim);
1129 
1130  if(numDim==3){
1131  for(int i=0;i<numModelTotals[1];i++){
1132  e = agm_add_ent(gMod_base->topo, AGM_EDGE);
1133  gmi_set_lookup(gMod_base->lookup, e, i);
1134  }
1135  gmi_freeze_lookup(gMod_base->lookup, (agm_ent_type)1);
1136  }
1137 
1138  int matTag;
1139  apf::ModelEntity* gEnt;
1140  int vertCounter = numModelOffsets[0];
1141 
1142  //Iterate over the vertices and set the coordinates and model classification
1143  int vID = 0;
1144  entIter = m->begin(0);
1145  PCU_Comm_Begin();
1146  while(ent = m->iterate(entIter)){
1147  pt[0]=mesh.nodeArray[vID*3+0];
1148  pt[1]=mesh.nodeArray[vID*3+1];
1149  pt[2]=mesh.nodeArray[vID*3+2];
1150  m->setPoint(ent,0,pt);
1151  if(m->isOwned(ent)){
1152  matTag = mesh.nodeMaterialTypes[vID];
1153  if(hasModel){
1154  gEnt = m->findModelEntity(meshVertex2Model[2*vID+1],meshVertex2Model[2*vID]);
1155  //if entity is a model vertex
1156  if(meshVertex2Model[2*vID+1]==0)
1157  modelVertexMaterial[meshVertex2Model[2*vID]] = matTag;
1158  }
1159  else{
1160  //if entity is interior, it should be classified on a region
1161  if(matTag==0){
1162  matTag = mesh.elementMaterialTypes[mesh.nodeElementsArray[mesh.nodeElementOffsets[vID]]];
1163  gEnt = m->findModelEntity(numDim,matTag);
1164  }
1165  //else there is an associated model entity
1166  else{
1167  gEnt = m->findModelEntity(0,vertCounter);
1168  modelVertexMaterial[vertCounter] = matTag;
1169  vertCounter++;
1170  }
1171  }
1172  m->setModelEntity(ent,gEnt);
1173  //if the owner and entity is shared, share the model classification with other entities
1174  if(m->isShared(ent)){
1175  apf::Copies remotes;
1176  m->getRemotes(ent,remotes);
1177  for(apf::Copies::iterator it = remotes.begin(); it != remotes.end(); ++it){
1178  PCU_COMM_PACK(it->first,it->second);
1179  PCU_COMM_PACK(it->first,gEnt);
1180  }
1181  }
1182 
1183  } //endif owned
1184  vID++;
1185  }
1186  PCU_Comm_Send();
1187  //receive model entity classification from owning nodes
1188  while(PCU_Comm_Receive()){
1189  PCU_COMM_UNPACK(ent);
1190  PCU_COMM_UNPACK(gEnt);
1191  m->setModelEntity(ent,gEnt);
1192  }
1193  PCU_Barrier();
1194  m->end(entIter);
1195 
1196  //Classify the mesh boundary entities
1197  //If the edge is on a model edge, it should have a material tag greater than 0.
1198  //If the edge is on a partition boundary, the material tag should be 0.
1199  //There is no direct control over ownership when constructing the mesh, so it
1200  //must be left general.
1201  int boundaryID = 0; //this is a counter for the set of boundary elements
1202  int boundaryCounter = 0; //this is a counter for the set of exterior boundary elements
1203  int boundaryMaterialCounter = numModelOffsets[2]; //this is a counter for the storage array used to map material types to the new mesh
1204  int edgCounter = numModelOffsets[1]; //this is a counter for the set of exterior edge entities
1205  apf::ModelEntity* edg_gEnt;
1206  entIter=m->begin(boundaryDim);
1207  PCU_Comm_Begin();
1208  while(ent = m->iterate(entIter)){
1209  if(hasModel){
1210  gEnt = m->findModelEntity(meshBoundary2Model[2*boundaryID+1],meshBoundary2Model[2*boundaryID]);
1211  //if entity is a on a model boundary
1212  if(meshBoundary2Model[2*boundaryID+1]==1)
1213  modelBoundaryMaterial[meshBoundary2Model[2*boundaryID]] = mesh.elementBoundaryMaterialTypes[boundaryID];
1214  }
1215  else{
1216  if(mesh.exteriorElementBoundariesArray[boundaryCounter]==boundaryID && (mesh.elementBoundaryMaterialTypes[boundaryID]!=0)){
1217  gEnt = m->findModelEntity(boundaryDim,boundaryMaterialCounter);
1218  modelBoundaryMaterial[boundaryMaterialCounter] = mesh.elementBoundaryMaterialTypes[boundaryID];
1219  boundaryCounter++;
1220  boundaryMaterialCounter++;
1221 
1222  //If 3D, need to set exterior edge classification
1223  if(numDim==3){
1224  apf::Adjacent adj_edges;
1225  m->getAdjacent(ent,1,adj_edges);
1226  for(int i=0;i<adj_edges.getSize();i++){
1227  //If the edge is classified on a higher order entity than gEnt or if the edge hasn't been classified yet
1228  if(m->getModelType(m->toModel(adj_edges[i]))>m->getModelType(gEnt) || (m->getModelType(m->toModel(adj_edges[i]))==0)){
1229  edg_gEnt = m->findModelEntity(1,edgCounter);
1230  m->setModelEntity(adj_edges[i],edg_gEnt);
1231  edgCounter++;
1232  //if the owner and entity is shared, share the model classification with other entities
1233  if(m->isOwned(adj_edges[i]) && m->isShared(adj_edges[i])){
1234  apf::Copies remotes;
1235  m->getRemotes(ent,remotes);
1236  for(apf::Copies::iterator it = remotes.begin(); it != remotes.end(); ++it){
1237  PCU_COMM_PACK(it->first,it->second);
1238  PCU_COMM_PACK(it->first,edg_gEnt);
1239  }
1240  }
1241 
1242  }
1243  }
1244  }
1245 
1246  }
1247  else {
1248  //If the current exterior entity is an edge on a partition boundary, need to check material and
1249  //get to the next item in the exterior array
1250  if(m->isShared(ent) && mesh.elementBoundaryMaterialTypes[mesh.exteriorElementBoundariesArray[boundaryCounter]]==0)
1251  boundaryCounter++;
1252  //assert((mesh.elementBoundaryMaterialTypes[boundaryID]==0 || numModelTotals[3]>1) && "If working with multi-region cases, turn this assertion off");
1253  //There are always two entities adjacent to an element boundary
1254  //Pick one and take that as the material type for classification
1255  matTag = mesh.elementMaterialTypes[mesh.elementBoundaryElementsArray[2*boundaryID]];
1256  gEnt = m->findModelEntity(numDim,matTag);
1257  //If 3D, need to set edge classification
1258  if(numDim==3){
1259  apf::Adjacent adj_edges;
1260  m->getAdjacent(ent,1,adj_edges);
1261  for(int i=0;i<adj_edges.getSize();i++){
1262  //If the edge is classified on a higher order entity than gEnt or if the edge hasn't been classified yet
1263  if(m->getModelType(m->toModel(adj_edges[i]))>m->getModelType(gEnt) || (m->getModelType(m->toModel(adj_edges[i]))==0)){
1264  m->setModelEntity(adj_edges[i],gEnt);
1265  //if the owner and entity is shared, share the model classification with other entities
1266  if(m->isOwned(adj_edges[i]) && m->isShared(adj_edges[i])){
1267  apf::Copies remotes;
1268  m->getRemotes(ent,remotes);
1269  for(apf::Copies::iterator it = remotes.begin(); it != remotes.end(); ++it){
1270  PCU_COMM_PACK(it->first,it->second);
1271  PCU_COMM_PACK(it->first,gEnt);
1272  }
1273  }
1274  }
1275  }
1276 
1277  }
1278  }
1279  }
1280  m->setModelEntity(ent,gEnt);
1281  boundaryID++;
1282  }
1283  PCU_Comm_Send();
1284  //receive model entity classification from owning edges
1285  while(PCU_Comm_Receive()){
1286  PCU_COMM_UNPACK(ent);
1287  PCU_COMM_UNPACK(gEnt);
1288  m->setModelEntity(ent,gEnt);
1289  }
1290  PCU_Barrier();
1291 
1292  m->end(entIter);
1293 
1294  //Iterate over regions
1295 
1296  //Populate the region materials
1297  //Assumes that the regions are numbered sequentially from 1 onward
1298  for(int i=0;i<numModelRegions;i++)
1299  modelRegionMaterial[i] = i+regStartMaterial;
1300 
1301  rID=0;
1302  entIter = m->begin(numDim);
1303  while(ent = m->iterate(entIter)){
1304  gEnt = m->findModelEntity(numDim,mesh.elementMaterialTypes[rID]);
1305  m->setModelEntity(ent,gEnt);
1306  rID++;
1307  }
1308  m->end(entIter);
1309 
1310  //Sum all of the material arrays to get the model-material mapping across all
1311  //ranks
1312 
1313  PCU_Add_Ints(modelVertexMaterial,numModelTotals[0]);
1314  PCU_Add_Ints(modelBoundaryMaterial,numModelTotals[2]);
1315  PCU_Add_Ints(modelRegionMaterial,numModelTotals[3]);
1316 
1317  //check that the mesh is consistent
1318  m->acceptChanges();
1319  apf::alignMdsRemotes(m);
1320  m->verify();
1322  //renumber for compatibility with Proteus
1323  numberLocally();
1324  m->verify();
1325 
1326  //free mappings
1327  free(local2global_elementBoundaryNodes);
1328  free(local2global_elementNodes);
1329 
1330  if(PCU_Comm_Self()==0)
1331  std::cout<<"FINISHING RECONSTRUCTION\n";
1332 }
1333 
1334 int MeshAdaptPUMIDrvr::reconstructFromProteus2(Mesh& mesh,int* isModelVert,int* bFaces){
1335 
1336 //This function only applies for 3D meshes
1337 
1338  int dim;
1339  int elementType;
1340  if(mesh.nNodes_element == 3){
1341  dim = 2;
1342  elementType = apf::Mesh::TRIANGLE;
1343  }
1344  else{
1345  dim = 3;
1346  elementType = apf::Mesh::TET;
1347  }
1348 
1349  isReconstructed = 2;
1350  int nBFaces = mesh.nExteriorElementBoundaries_global;
1351  bool isModelVert_bool[mesh.nNodes_global];
1352  for(int i=0;i<mesh.nNodes_global;i++){
1353  isModelVert_bool[i] = isModelVert[i] != 0;
1354  }
1355  static int numEntries = 2+dim;
1356 
1357  int bEdges_1D[nBFaces][4];
1358  int bFaces_2D[nBFaces][5];
1359 
1360  if(dim==2){
1361  for(int i=0;i<nBFaces;i++){
1362  int idx = i*numEntries;
1363  for(int j=0;j<numEntries;j++)
1364  bEdges_1D[i][j] = bFaces[idx+j];
1365  }
1366  }
1367  if(dim==3){
1368  for(int i=0;i<nBFaces;i++){
1369  int idx = i*numEntries;
1370  for(int j=0;j<numEntries;j++)
1371  bFaces_2D[i][j] = bFaces[idx+j];
1372  }
1373  }
1374 
1375 /*
1376  bFaces_2D[i][0] = bFaces[idx+0];
1377  bFaces_2D[i][1] = bFaces[idx+1];
1378  bFaces_2D[i][2] = bFaces[idx+2];
1379  bFaces_2D[i][3] = bFaces[idx+3];
1380  bFaces_2D[i][4] = bFaces[idx+4];
1381 */
1382 
1383  apf::GlobalToVert outMap;
1384 
1385  gmi_model* tempModel = gmi_load(".null");
1386  m = apf::makeEmptyMdsMesh(tempModel,dim,false);
1387  apf::construct(m,mesh.elementNodesArray,mesh.nElements_global,elementType,outMap);
1388 
1389  apf::setCoords(m,mesh.nodeArray,mesh.nNodes_global,outMap);
1390 
1391  std::map<int,apf::MeshEntity*> globalToRegion;
1392  apf::MeshIterator* it = m->begin(dim);
1393  apf::MeshEntity* ent;
1394  int counter = 0;
1395  while( ent = m->iterate(it) ){
1396  globalToRegion.insert(std::pair<int,apf::MeshEntity*> (counter,ent ));
1397  counter++;
1398  }
1399 
1400  if(dim == 2)
1401  apf::derive2DMdlFromManifold(m,isModelVert_bool,nBFaces,bEdges_1D,outMap,globalToRegion);
1402  else
1403  apf::deriveMdlFromManifold(m,isModelVert_bool,nBFaces,bFaces_2D,outMap,globalToRegion);
1404  m->writeNative("Reconstructed.smb");
1405  gmi_write_dmg(m->getModel(),"Reconstructed.dmg");
1406  std::cout<<"Finished Reconstruction, terminating program. Rerun with PUMI workflow\n";
1407  std::exit(0);
1408 
1409 }
1410 
MeshAdaptPUMIDrvr::modelVertexMaterial
int * modelVertexMaterial
Definition: MeshAdaptPUMI.h:148
MeshAdaptPUMIDrvr::updateMaterialArrays
int updateMaterialArrays(Mesh &mesh, int dim, int bdryID, int GeomTag)
Definition: MeshConverter.cpp:400
MeshAdaptPUMIDrvr::constructFromSerialPUMIMesh
int constructFromSerialPUMIMesh(Mesh &mesh)
Definition: MeshConverter.cpp:47
DEFAULT_ELEMENT_MATERIAL
#define DEFAULT_ELEMENT_MATERIAL
Definition: MeshConverter.cpp:351
Mesh::interiorElementBoundariesArray
int * interiorElementBoundariesArray
Definition: mesh.h:50
MeshAdaptPUMIDrvr::numberLocally
void numberLocally()
Definition: MeshConverter.cpp:95
getProteusBoundaryIdx
int getProteusBoundaryIdx(apf::Mesh *m, apf::MeshEntity *e, apf::MeshEntity *f)
Definition: MeshConverter.cpp:155
Mesh::elementBoundaryNodesArray
int * elementBoundaryNodesArray
Definition: mesh.h:47
MeshAdaptPUMI.h
Mesh::nodeArray
double * nodeArray
Definition: mesh.h:67
Mesh::nodeElementsArray
int * nodeElementsArray
Definition: mesh.h:43
MeshAdaptPUMIDrvr::meshBoundary2Model
int * meshBoundary2Model
Definition: MeshAdaptPUMI.h:47
Mesh::nodeElementOffsets
int * nodeElementOffsets
Definition: mesh.h:44
Mesh
Definition: mesh.h:28
Mesh::nEdges_global
int nEdges_global
Definition: mesh.h:39
Mesh::exteriorElementBoundariesArray
int * exteriorElementBoundariesArray
Definition: mesh.h:51
f
Double f
Definition: Headers.h:64
number
Int number
Definition: Headers.h:33
MeshAdaptPUMIDrvr::initialReconstructed
int initialReconstructed
Definition: MeshAdaptPUMI.h:147
s
Double s
Definition: Headers.h:84
Mesh::nodeStarOffsets
int * nodeStarOffsets
Definition: mesh.h:54
MeshAdaptPUMIDrvr::localNumber
int localNumber(apf::MeshEntity *e)
Definition: MeshConverter.cpp:105
Mesh::nNodes_elementBoundary
int nNodes_elementBoundary
Definition: mesh.h:33
Mesh::nElementBoundaries_global
int nElementBoundaries_global
Definition: mesh.h:35
apf
Definition: MeshConverter.cpp:639
n
Int n
Definition: Headers.h:28
Mesh::nInteriorElementBoundaries_global
int nInteriorElementBoundaries_global
Definition: mesh.h:36
MeshAdaptPUMIDrvr::modelBoundaryMaterial
int * modelBoundaryMaterial
Definition: MeshAdaptPUMI.h:149
Mesh::nodeOffsets_subdomain_owned
int * nodeOffsets_subdomain_owned
Definition: mesh.h:78
Mesh::nodeStarArray
int * nodeStarArray
Definition: mesh.h:53
apf::construct
void construct(Mesh2 *m, const int *conn, const int *conn_b, int nelem, int nelem_b, int nverts, int etype, int etype_b, int *local2globalMap, GlobalToVert &globalToVert)
Definition: MeshConverter.cpp:798
Mesh::nNodes_element
int nNodes_element
Definition: mesh.h:32
min
#define min(a, b)
Definition: jf.h:71
Mesh::elementBoundaryLocalElementBoundariesArray
int * elementBoundaryLocalElementBoundariesArray
Definition: mesh.h:49
MeshAdaptPUMIDrvr::transferModelInfo
int transferModelInfo(int *numGeomEntities, int *edges, int *faces, int *mVertex2Model, int *mEdgeVertex2Model, int *mBoundary2Model, int nMaxSegments)
Definition: MeshConverter.cpp:855
v
Double v
Definition: Headers.h:95
Mesh::elementBoundaryMaterialTypes
int * elementBoundaryMaterialTypes
Definition: mesh.h:56
MeshAdaptPUMIDrvr::edgeList
int * edgeList
Definition: MeshAdaptPUMI.h:45
Mesh::elementNodesArray
int * elementNodesArray
Definition: mesh.h:42
Mesh::elementBoundariesArray
int * elementBoundariesArray
Definition: mesh.h:46
Mesh::nElements_global
int nElements_global
Definition: mesh.h:30
mesh.h
MeshAdaptPUMIDrvr::faceList
int * faceList
Definition: MeshAdaptPUMI.h:46
MeshAdaptPUMIDrvr::numModelEntities
int numModelEntities[4]
Definition: MeshAdaptPUMI.h:48
Mesh::nodeMaterialTypes
int * nodeMaterialTypes
Definition: mesh.h:57
Mesh::nElementBoundaries_element
int nElementBoundaries_element
Definition: mesh.h:34
MeshAdaptPUMIDrvr::meshEdge2Model
int * meshEdge2Model
Definition: MeshAdaptPUMI.h:47
Mesh::elementMaterialTypes
int * elementMaterialTypes
Definition: mesh.h:55
INTERIOR_MATERIAL
#define INTERIOR_MATERIAL
Definition: MeshConverter.cpp:349
MeshAdaptPUMIDrvr::numModelOffsets
int numModelOffsets[4]
Definition: MeshAdaptPUMI.h:151
Mesh::nNodes_global
int nNodes_global
Definition: mesh.h:31
Mesh::nExteriorElementBoundaries_global
int nExteriorElementBoundaries_global
Definition: mesh.h:37
Mesh::max_nNodeNeighbors_node
int max_nNodeNeighbors_node
Definition: mesh.h:40
Mesh::nodeNumbering_subdomain2global
int * nodeNumbering_subdomain2global
Definition: mesh.h:79
MeshAdaptPUMIDrvr::updateMaterialArrays2
int updateMaterialArrays2(Mesh &mesh)
Definition: MeshConverter.cpp:509
apf::Gid
int Gid
Definition: MeshConverter.cpp:641
MeshAdaptPUMIDrvr::isReconstructed
int isReconstructed
Definition: MeshAdaptPUMI.h:146
EXTERIOR_MATERIAL
#define EXTERIOR_MATERIAL
Definition: MeshConverter.cpp:350
MeshAdaptPUMIDrvr::numModelTotals
int numModelTotals[4]
Definition: MeshAdaptPUMI.h:152
max
#define max(a, b)
Definition: analyticalSolutions.h:14
Mesh::edgeNodesArray
int * edgeNodesArray
Definition: mesh.h:52
MeshAdaptPUMIDrvr::meshVertex2Model
int * meshVertex2Model
Definition: MeshAdaptPUMI.h:47
MeshAdaptPUMIDrvr::reconstructFromProteus
int reconstructFromProteus(Mesh &mesh, Mesh &globalMesh, int hasModel)
Definition: MeshConverter.cpp:872
MeshAdaptPUMIDrvr::modelRegionMaterial
int * modelRegionMaterial
Definition: MeshAdaptPUMI.h:150
MeshAdaptPUMIDrvr::numSegments
int numSegments
Definition: MeshAdaptPUMI.h:44
Mesh::elementBoundaryElementsArray
int * elementBoundaryElementsArray
Definition: mesh.h:48
MeshAdaptPUMIDrvr::reconstructFromProteus2
int reconstructFromProteus2(Mesh &mesh, int *isModelVert, int *bFaces)
Definition: MeshConverter.cpp:1334
Mesh::elementNeighborsArray
int * elementNeighborsArray
Definition: mesh.h:45