proteus 1.9.0
C/C++/Fortran libraries
Loading...
Searching...
No Matches
MeshConverter.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <valarray>
3#include "MeshAdaptPUMI.h"
4#include "PCU.h"
5#include "mesh.h"
6#include "apfConvert.h"
7#include "apfShape.h"
8
9#include <sstream>
10
11static apf::Numbering* numberOwnedEntitiesFirst(apf::Mesh* m, int dimension,int initialReconstructed)
12{
13 std::stringstream ss;
14 ss << "proteus_number_" << dimension;
15 std::string s = ss.str();
16 apf::FieldShape* shape;
17 if (dimension) /* this switch is just to help rendering */
18 shape = apf::getConstant(dimension);
19 else
20 shape = m->getShape();
21 apf::Numbering* n = createNumbering(m, s.c_str(), shape, 1);
22 apf::MeshEntity* e;
23 apf::MeshIterator* it = m->begin(dimension);
24 int i = 0;
25 if(initialReconstructed){
26 while ((e = m->iterate(it)))
27 apf::number(n, e, 0, 0, i++);
28 m->end(it);
29 }
30 else{
31 while ((e = m->iterate(it)))
32 if (m->isOwned(e))
33 apf::number(n, e, 0, 0, i++);
34 m->end(it);
35 it = m->begin(dimension);
36 while ((e = m->iterate(it)))
37 if (!m->isOwned(e))
38 apf::number(n, e, 0, 0, i++);
39 m->end(it);
40 }
41 return n;
42}
43
44//Main API to construct a serial pumi mesh,
45//what we do is contruct the global mesh when working with serial
46//and let Proteus populate the subdomain data structures
47//(though it will be exactly same)
49{
50 assert(m != 0);
51 logEvent("Constructing global data structures",4);
52
53 int dim = m->getDimension();
54 mesh.nElements_global = m->count(dim);
55
56 mesh.nNodes_global = m->count(0);
57
58 mesh.nElementBoundaries_global = m->count(dim - 1);
59
60 mesh.nEdges_global = m->count(1);
61
62 //nNodes_element for now is constant for the entire mesh, Ask proteus about using mixed meshes
63 switch (dim) {
64 case 2:
65 mesh.nNodes_element = 3;
68 break;
69 case 3:
70 mesh.nNodes_element = 4;
73 break;
74 default:
75 apf::fail("dimension is not 2 or 3\n");
76 break;
77 }
78#ifdef MESH_INFO
79 std::cerr << "*******Proteus Mesh Stats*********\n";
80 std::cerr << "Number of elements " << mesh.nElements_global << "\n";
81 std::cerr << "Number of nodes " << mesh.nNodes_global << "\n";
82 std::cerr << "Number of boundaries " << mesh.nElementBoundaries_global << "\n";
83 std::cerr << "Number of edges " << mesh.nEdges_global << "\n";
84#endif
85
87 constructNodes(mesh);
88 constructElements(mesh);
89 constructBoundaries(mesh);
90 constructEdges(mesh);
91 constructMaterialArrays(mesh);
92
93 return 0;
94}
95
97{
98 for (int d = 0; d <= m->getDimension(); ++d) {
99 freeNumbering(local[d]);
100 local[d] = numberOwnedEntitiesFirst(m, d,initialReconstructed);
101 }
104}
105
106int MeshAdaptPUMIDrvr::localNumber(apf::MeshEntity* e)
107{
108 return getNumber(local[apf::getDimension(m, e)], e, 0, 0);
109}
110
111int MeshAdaptPUMIDrvr::constructNodes(Mesh& mesh)
112{
113 mesh.nodeArray = new double[mesh.nNodes_global * 3];
114 apf::MeshIterator* it = m->begin(0);
115 apf::MeshEntity* e;
116 while ((e = m->iterate(it))) {
117 int i = localNumber(e);
118 apf::Vector3 x;
119 m->getPoint(e, 0, x);
120 for(int j=0; j<3; j++)
121 mesh.nodeArray[i * 3 + j]= x[j];
122 }
123 m->end(it);
124 return 0;
125}
126
127int MeshAdaptPUMIDrvr::constructElements(Mesh& mesh)
128{
129 mesh.elementNodesArray = new int[mesh.nElements_global*mesh.nNodes_element];
130 apf::MeshIterator* it = m->begin(m->getDimension());
131 apf::MeshEntity* e;
132 while ((e = m->iterate(it))) {
133 int i = localNumber(e);
134 apf::Downward v;
135 int iNumVtx = m->getDownward(e, 0, v);
136 for (int j = 0; j < iNumVtx; ++j) {
137 int vtxID = localNumber(v[j]);
138 mesh.elementNodesArray[i * mesh.nNodes_element + j] = vtxID;
139 }
140 }
141 m->end(it);
142 return 0;
143}
144
145/* following is going to look adhoc and arbitrary but it is needed to
146 resolve a conflict between the way proteus handles faces and we handle faces.
147 The order in which we retrieve faces from adjacency is different to what
148 proteus expects them to be in their elementBoundaries array.
149 To resolve this we need to change the local number of the face of an element
150 to what proteus expects it to be and then it works. Whussh. magic.
151
152 original comment above preserved for entertainment.
153 This maps SCOREC's tet face numbering to that of proteus.
154*/
155
156int getProteusBoundaryIdx(apf::Mesh* m, apf::MeshEntity* e, apf::MeshEntity* f)
157{
158 apf::Downward fs;
159 int dim = m->getDimension();
160 int nfs = m->getDownward(e, dim - 1, fs);
161 int idx_apf = apf::findIn(fs, nfs, f);
162 /* Proteus convention is that the face index equals the vertex index
163 of the vertex opposite to the face.
164 Proteus and PUMI should have consistent vertex orderings for
165 simplices, but the above rule makes the side orderings different */
166 static int const tet_boundary_map[4] = {3,2,0,1};
167 static int const tri_boundary_map[3] = {2,0,1};
168 static int const* const boundary_maps[4] = {
169 0,
170 0,
171 tri_boundary_map,
172 tet_boundary_map
173 };
174 return boundary_maps[dim][idx_apf];
175}
176
177int MeshAdaptPUMIDrvr::constructBoundaries(Mesh& mesh)
178{
179 //build face list (elementBoundary and nodeBoundary arrays)
180 //Enter at your own peril for those who stray will be lost
181 std::set<int> interiorElementBoundaries;
182 std::set<int> exteriorElementBoundaries;
183
187 new int[mesh.nElementBoundaries_global * 2];
189 new int[mesh.nElementBoundaries_global * 2];
191 new int[mesh.nElements_global * mesh.nElementBoundaries_element];
193 new int[mesh.nElements_global * mesh.nElementBoundaries_element];
194 //exteriorGlobaltoLocalElementBoundariesArray =
195 // new int[mesh.nElementBoundaries_global];
196 //int exterior_count = 0; //counter for external boundaries
197
198 int dim = m->getDimension();
199 apf::MeshIterator* it = m->begin(dim - 1);
200 apf::MeshEntity* f;
201 while ((f = m->iterate(it))) {
202 int i = localNumber(f);
203 // get vertices from adjacency
204 apf::Downward vs;
205 int iNumVtx = m->getDownward(f, 0, vs);
206 for (int iVtx = 0; iVtx < iNumVtx; ++iVtx) {
207 int vtxID = localNumber(vs[iVtx]);
209 i * mesh.nNodes_elementBoundary + iVtx] = vtxID;
210 }
211 //get regions from adjacency
212 apf::Up rs;
213 m->getUp(f, rs);
214 int iNumRgn = rs.n;
215 int RgnID[2] = {-1,-1};
216 int localBoundaryNumber[2] = {-1,-1};
217 for (int iRgn = 0; iRgn < iNumRgn; ++iRgn) {
218 RgnID[iRgn] = localNumber(rs.e[iRgn]);
219 mesh.elementBoundaryElementsArray[i * 2 + iRgn]= RgnID[iRgn];
220 localBoundaryNumber[iRgn] = getProteusBoundaryIdx(m, rs.e[iRgn], f);
221 assert(localBoundaryNumber[iRgn] != -1);
223 i * 2 + iRgn] = localBoundaryNumber[iRgn];
224 }
225 //left and right regions are shared by this face we are currntly on
226 int leftRgnID = RgnID[0]; int leftLocalBoundaryNumber = localBoundaryNumber[0];
227 int rightRgnID = RgnID[1]; int rightLocalBoundaryNumber = localBoundaryNumber[1];
228 /*left region is always there, so either rightRgnID will have
229 an actual ID if this face is shared, or will contain -1
230 if it is an exterior face */
232 leftRgnID * mesh.nElementBoundaries_element + leftLocalBoundaryNumber]
233 = rightRgnID;
235 leftRgnID * mesh.nElementBoundaries_element + leftLocalBoundaryNumber]
236 = i;
237
238 /* if only 1 region is adjacent to this face,
239 that means it is an exterior face */
240 if(iNumRgn==1) {
241 assert(RgnID[1]==-1);
242 assert(localBoundaryNumber[1]==-1); //last 2 checks are only for sanity
243 mesh.elementBoundaryElementsArray[i * 2 + 1] = -1;
245 //exterior face as only 1 region adjacent
246 exteriorElementBoundaries.insert(i);
247
248 //construct inverse mapping
249 //exteriorGlobaltoLocalElementBoundariesArray[i] = exterior_count;
250 //exterior_count++;
251
252 } else { //2 regions are shared by this face so interior face
254 rightRgnID * mesh.nElementBoundaries_element + rightLocalBoundaryNumber]
255 = leftRgnID;
257 rightRgnID * mesh.nElementBoundaries_element + rightLocalBoundaryNumber]
258 = i;
259 interiorElementBoundaries.insert(i);
260 }
261 }
262 m->end(it);
263
264 //construct interior and exterior element boundaries array
265 mesh.nInteriorElementBoundaries_global = interiorElementBoundaries.size();
267 mesh.nExteriorElementBoundaries_global = exteriorElementBoundaries.size();
269
270 int ebNI=0,ebNE=0;
271 for (std::set<int>::iterator ebN=interiorElementBoundaries.begin();ebN != interiorElementBoundaries.end(); ebN++,ebNI++)
272 mesh.interiorElementBoundariesArray[ebNI] = *ebN;
273 for (std::set<int>::iterator ebN=exteriorElementBoundaries.begin();ebN != exteriorElementBoundaries.end(); ebN++,ebNE++)
274 mesh.exteriorElementBoundariesArray[ebNE] = *ebN;
275
276 return 0;
277}
278
279/* these algorithms are totally independent of SCOREC;
280 they form the proteus
281 vertex to vertex and vertex to element adjacency tables
282 from the edge to vertex and element to vertex tables */
283static void createStars(Mesh& mesh)
284{
285 std::vector<std::set<int> > nodeStar(mesh.nNodes_global);
286 for (int edgeN = 0; edgeN < mesh.nEdges_global; edgeN++) {
287 nodeStar[mesh.edgeNodesArray[edgeN * 2 + 0]].insert(
288 mesh.edgeNodesArray[edgeN * 2 + 1]);
289 nodeStar[mesh.edgeNodesArray[edgeN * 2 + 1]].insert(
290 mesh.edgeNodesArray[edgeN * 2 + 0]);
291 }
292
293 mesh.nodeStarOffsets = new int[mesh.nNodes_global + 1];
294 mesh.nodeStarOffsets[0] = 0;
295 for (int nN = 1; nN <= mesh.nNodes_global; nN++)
296 mesh.nodeStarOffsets[nN] =
297 mesh.nodeStarOffsets[nN - 1] + nodeStar[nN - 1].size();
298
299 mesh.nodeStarArray = new int[mesh.nodeStarOffsets[mesh.nNodes_global]];
300 for (int nN = 0, offset = 0; nN < mesh.nNodes_global; nN++)
301 for (std::set<int>::iterator nN_star=nodeStar[nN].begin();
302 nN_star!=nodeStar[nN].end();
303 nN_star++, offset++)
304 mesh.nodeStarArray[offset] = *nN_star;
305
307 for (int nN = 0; nN < mesh.nNodes_global; nN++)
309 std::max(mesh.max_nNodeNeighbors_node,
310 mesh.nodeStarOffsets[nN + 1] - mesh.nodeStarOffsets[nN]);
311
312 std::vector<std::set<int> > nodeElementsStar(mesh.nNodes_global);
313 for (int eN = 0; eN < mesh.nElements_global; eN++)
314 for (int nN = 0; nN < mesh.nNodes_element; nN++)
315 nodeElementsStar[
316 mesh.elementNodesArray[eN * mesh.nNodes_element + nN]
317 ].insert(eN);
318 mesh.nodeElementOffsets = new int[mesh.nNodes_global + 1];
319 mesh.nodeElementOffsets[0] = 0;
320 for (int nN = 0; nN < mesh.nNodes_global; nN++)
321 mesh.nodeElementOffsets[nN + 1] =
322 mesh.nodeElementOffsets[nN] + nodeElementsStar[nN].size();
323 mesh.nodeElementsArray = new int[mesh.nodeElementOffsets[mesh.nNodes_global]];
324 for (int nN=0,offset=0; nN < mesh.nNodes_global; nN++)
325 for (std::set<int>::iterator eN_star = nodeElementsStar[nN].begin();
326 eN_star != nodeElementsStar[nN].end();
327 eN_star++, offset++)
328 mesh.nodeElementsArray[offset] = *eN_star;
329}
330
331int MeshAdaptPUMIDrvr::constructEdges(Mesh& mesh)
332{
333 mesh.edgeNodesArray = new int[mesh.nEdges_global * 2];
334 apf::MeshIterator* it = m->begin(1);
335 apf::MeshEntity* e;
336 while ((e = m->iterate(it))) {
337 int i = localNumber(e);
338 apf::MeshEntity* v[2];
339 m->getDownward(e, 0, v);
340 for(int iVtx=0; iVtx < 2; ++iVtx) {
341 int vtxID = localNumber(v[iVtx]);
342 mesh.edgeNodesArray[i * 2 + iVtx] = vtxID;
343 }
344 }
345 m->end(it);
346 createStars(mesh);
347 return 0;
348}
349
350#define INTERIOR_MATERIAL 0
351#define EXTERIOR_MATERIAL 1
352#define DEFAULT_ELEMENT_MATERIAL INTERIOR_MATERIAL
353
354static int getInOutMaterial(apf::Mesh* m, apf::MeshEntity* e)
355{
356 if (m->getModelType(m->toModel(e)) == m->getDimension())
357 return INTERIOR_MATERIAL;
358 else
359 return EXTERIOR_MATERIAL;
360}
361
362/* This function builds the element, elementBoundary, and node
363 * Material arrays and fills them in with zero or one depending
364 * one whether the entity is classified on the geometric boundary
365 * or not.
366 * This forms a baseline material tagging for all entities,
367 * which later gets overwritten for some entities with more
368 * specific values in MeshAdaptPUMIDrvr::UpdateMaterialArrays.
369 */
370int MeshAdaptPUMIDrvr::constructMaterialArrays(Mesh& mesh)
371{
373 mesh.nodeMaterialTypes = new int[mesh.nNodes_global];
374 mesh.elementMaterialTypes = new int[mesh.nElements_global];
375 for (int i = 0; i < mesh.nElements_global; ++i)
377 int dim = m->getDimension();
378 apf::MeshIterator* it = m->begin(dim - 1);
379 apf::MeshEntity* f;
380 while ((f = m->iterate(it))) {
381 int i = localNumber(f);
382 mesh.elementBoundaryMaterialTypes[i] = getInOutMaterial(m, f);
383 }
384 m->end(it);
385 it = m->begin(0);
386 apf::MeshEntity* v;
387 while ((v = m->iterate(it))) {
388 int i = localNumber(v);
389 mesh.nodeMaterialTypes[i] = getInOutMaterial(m, v);
390 }
391 m->end(it);
392 return 0;
393}
394
395/* Given a geometric model face identified by the integer
396 * (scorec_tag), get all nodes and element boundaries
397 * classified on the closure of that model face and
398 * put the (proteus_material) integer in their material
399 * array slot.
400 */
402 int dim,
403 int proteus_material,
404 int scorec_tag)
405{
406 //int dim = m->getDimension();
407 apf::ModelEntity* geomEnt = m->findModelEntity(dim, scorec_tag);
408 apf::MeshIterator* it = m->begin(dim);
409 apf::MeshEntity* f;
410 if(dim==m->getDimension()){
411 while ((f = m->iterate(it))) {
412 if (m->toModel(f) == geomEnt) {
413 int i = localNumber(f);
414 mesh.elementMaterialTypes[i] = proteus_material;
415 }
416 }
417 }
418 else{
419 while ((f = m->iterate(it))) {
420 if (m->toModel(f) == geomEnt) {
421 int i = localNumber(f);
422 mesh.elementBoundaryMaterialTypes[i] = proteus_material;
423 }
424 }
425 apf::DynamicArray<apf::Node> nodes;
426 apf::getNodesOnClosure(m, geomEnt, nodes);
427 for (size_t i = 0; i < nodes.getSize(); ++i) {
428 int vtxId = localNumber(nodes[i].entity);
429 mesh.nodeMaterialTypes[vtxId] = proteus_material;
430 }
431 }
432 m->end(it);
433 return 0;
434}
435
436/* Overload updateMaterialArray for reconstructed SCOREC meshes.
437 * The material types are stored based on derived model entity.
438 * We can recover the material of a mesh entity by looking at its classified
439 * model entity
440 */
442{
443 int geomTag;
444 apf::ModelEntity* geomEnt;
445 apf::MeshIterator* it;
446 apf::MeshEntity* f;
447
448 int dim = 0;
449 it = m->begin(dim);
450 while(f = m->iterate(it)){
451 int i = localNumber(f);
452 geomEnt = m->toModel(f);
453 geomTag = m->getModelTag(geomEnt);
454 if(m->getModelType(geomEnt) == dim){
455 mesh.nodeMaterialTypes[i] =modelVertexMaterial[geomTag];
456 }
457 else if(m->getModelType(geomEnt)==(m->getDimension()-1)){ //on the boundary entity
459 }
460 //If 3D and is on an exterior edge
461 else if(m->getDimension()==3 && m->getModelType(geomEnt)==1){
462 apf::Adjacent vert_adjFace;
463 m->getAdjacent(f,2,vert_adjFace);
464 for(int j=0;j<vert_adjFace.getSize();j++){
465 apf::ModelEntity* adjEnt = m->toModel(vert_adjFace[j]);
466 if(m->getModelType(adjEnt) == 2){
467 mesh.nodeMaterialTypes[i] = modelBoundaryMaterial[m->getModelTag(adjEnt)];
468 }
469 }
470 }
471 else{
472 mesh.nodeMaterialTypes[i] = 0; //This assumes that all vertices on the boundary are model vertices
473 }
474 }
475 m->end(it);
476 if(m->getDimension()==2)
477 dim = 1;
478 else
479 dim = 2;
480 it = m->begin(dim);
481 while(f = m->iterate(it)){
482 geomEnt = m->toModel(f);
483 int i = localNumber(f);
484 if(m->getModelType(geomEnt) == dim){
485 geomTag = m->getModelTag(m->toModel(f));
487 }
488 else{
489 geomTag = m->getModelTag(m->toModel(f));
490 //Interior boundaries and entities have a material type of zero
491 mesh.elementBoundaryMaterialTypes[i] = 0;
492 }
493 }
494 m->end(it);
495
496 dim = dim+1; //the regions are necessarily one dimension higher than previous dim
497 it = m->begin(dim);
498 while(f = m->iterate(it)){
499 geomEnt = m->toModel(f);
500 int i = localNumber(f);
501 assert(m->getModelType(geomEnt)==dim);
502 geomTag = m->getModelTag(m->toModel(f));
503 //The geomTag is actually the right material for region entities
504 mesh.elementMaterialTypes[i] = geomTag; //modelRegionMaterial[geomTag];
505 }
506 m->end(it);
507 return 0;
508}
509
511{
512 logEvent("Starting to update material arrays",4);
513 int geomTag;
514 apf::ModelEntity* geomEnt;
515 apf::MeshIterator* it;
516 apf::MeshEntity* f;
517
518 //first associate all nodes with a material tag and synchronize fields to avoid mismatches
519 //The procedure is to have each vertex look for its classification.
520 //If it is classified in the region, then it is interior.
521 //Else, loop over adjacent faces and stop at first instance of mesh face classified on model boundary and take tag.
522 //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.
523 //If the vertex is shared, communicate value to remote copies.
524 //When receiving values, if the current value is -1, write to field the received value. Otherwise, do nothing.
525
526 apf::Field* nodeMaterials = apf::createLagrangeField(m, "nodeMaterials", apf::SCALAR, 1);
527 it = m->begin(0);
528 PCU_Comm_Begin(PCUObj);
529 while(f = m->iterate(it))
530 {
531 geomEnt = m->toModel(f);
532 //if classified in a region
533 if(m->getModelType(geomEnt) == m->getDimension())
534 {
535 apf::setScalar(nodeMaterials,f,0,0);
536 }
537 else
538 {
539 apf::Adjacent vert_adjFace;
540 m->getAdjacent(f,m->getDimension()-1,vert_adjFace);
541 apf::MeshEntity* face;
542 for(int i =0; i<vert_adjFace.getSize();i++)
543 {
544 face=vert_adjFace[i];
545 geomEnt = m->toModel(face);
546
547 //IF mesh face is classified on boundary
548 if(m->getModelType(geomEnt) == m->getDimension()-1)
549 {
550 geomTag = m->getModelTag(geomEnt);
551 apf::setScalar(nodeMaterials,f,0,geomTag);
552 if(m->isShared(f))
553 {
554 apf::Copies remotes;
555 m->getRemotes(f,remotes);
556 for(apf::Copies::iterator iter = remotes.begin(); iter != remotes.end(); ++iter)
557 {
558 PCU_COMM_PACK(PCUObj, iter->first,iter->second);
559 PCU_COMM_PACK(PCUObj, iter->first,geomTag);
560 }
561 }
562 break;
563 }
564 if(i == vert_adjFace.getSize()-1 )
565 apf::setScalar(nodeMaterials,f,0,-1);
566 }
567 }
568 }
569 m->end(it);
570 PCU_Comm_Send(PCUObj);
571 while(PCU_Comm_Receive(PCUObj))
572 {
573 PCU_COMM_UNPACK(PCUObj, f);
574 PCU_COMM_UNPACK(PCUObj, geomTag);
575 int currentTag = apf::getScalar(nodeMaterials,f,0);
576 int newTag = std::min(currentTag,geomTag);
577 //if vertex is not interior and had no adjacent faces, take received values
578 //else take minimum value of all tags
579 if(currentTag==-1)
580 apf::setScalar(nodeMaterials,f,0,geomTag);
581 else
582 apf::setScalar(nodeMaterials,f,0,newTag);
583 }
584 //Ensure there are no mismatches across parts and then assign node materials
585 apf::synchronize(nodeMaterials);
586 it = m->begin(0);
587 while(f=m->iterate(it))
588 {
589 int vID = localNumber(f);
590 mesh.nodeMaterialTypes[vID] = apf::getScalar(nodeMaterials,f,0);
591 }
592 m->end(it);
593
594 //First iterate over all faces in 3D, get the model tag and apply to all downward adjacencies
595 int dim = m->getDimension()-1;
596 it = m->begin(dim);
597 while(f = m->iterate(it))
598 {
599 int i = localNumber(f);
600 geomEnt = m->toModel(f);
601 geomTag = m->getModelTag(geomEnt);
602 if(m->getModelType(geomEnt) == dim)
603 {
604 mesh.elementBoundaryMaterialTypes[i] = geomTag;
605 }
606 }
607 m->end(it);
608
609 apf::destroyField(nodeMaterials);
610
611 //Loop over regions
612 dim = m->getDimension();
613 it = m->begin(dim);
614 while( f = m->iterate(it)){
615 int i = localNumber(f);
616 geomEnt = m->toModel(f);
617 geomTag = m->getModelTag(geomEnt);
618 if(m->getModelType(geomEnt) == dim){
619 mesh.elementMaterialTypes[i] = 0;//geomTag;
620 }
621 }
622 m->end(it);
623 return 0;
624}
625
626
627/**************************************************************************/
628
629/*This section of code is a modified version of the apf::construct() function available in
630 * scorec/core. This may be added into scorec/core eventually and removed.
631 */
632
633//#include <PCU.h>
634#include "apfConvert.h"
635#include "apfMesh2.h"
636#include "apf.h"
637#include "apfConvert.h"
638#include "apfNumbering.h"
639#include <map>
640
641namespace apf {
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 apf::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 apf::Gid getMax(const GlobalToVert& globalToVert, PCU_t PCUObj)
690 {
691 apf::Gid max = -1;
692 APF_CONST_ITERATE(GlobalToVert, globalToVert, it)
693 max = std::max(max, it->first);
694 return PCU_Max_Int(PCUObj, 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, PCU_t PCUObj)
703 {
704 Gid max = getMax(globalToVert, PCUObj);
705 Gid total = max + 1;
706 int peers = PCU_Comm_Peers(PCUObj);
707 int quotient = total / peers;
708 int remainder = total % peers;
709 int mySize = quotient;
710 int self = PCU_Comm_Self(PCUObj);
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(PCUObj);
718 APF_ITERATE(GlobalToVert, globalToVert, it) {
719 int gid = it->first;
720 int to = std::min(peers - 1, gid / quotient);
721 PCU_COMM_PACK(PCUObj, to, gid);
722 }
723 PCU_Comm_Send(PCUObj);
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(PCUObj)) {
728 int gid;
729 PCU_COMM_UNPACK(PCUObj, gid);
730 int from = PCU_Comm_Sender(PCUObj);
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(PCUObj);
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(PCUObj, to, gid);
743 PCU_COMM_PACK(PCUObj, to, nparts);
744 for (size_t k = 0; k < parts.size(); ++k)
745 PCU_COMM_PACK(PCUObj, to, parts[k]);
746 }
747 }
748 PCU_Comm_Send(PCUObj);
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(PCUObj)) {
753 int gid;
754 PCU_COMM_UNPACK(PCUObj, gid);
755 int nparts;
756 PCU_COMM_UNPACK(PCUObj, nparts);
757 Parts residence;
758 for (int i = 0; i < nparts; ++i) {
759 int part;
760 PCU_COMM_UNPACK(PCUObj, 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, PCU_t PCUObj)
772 {
773 int self = PCU_Comm_Self(PCUObj);
774 PCU_Comm_Begin(PCUObj);
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(PCUObj, *rit, gid);
783 PCU_COMM_PACK(PCUObj, *rit, vert);
784 }
785 }
786 PCU_Comm_Send(PCUObj);
787 while (PCU_Comm_Receive(PCUObj)) {
788 int gid;
789 PCU_COMM_UNPACK(PCUObj, gid);
790 MeshEntity* remote;
791 PCU_COMM_UNPACK(PCUObj, remote);
792 int from = PCU_Comm_Sender(PCUObj);
793 MeshEntity* vert = globalToVert[gid];
794 m->addRemote(vert, from, remote);
795 }
796 }
797
798 void construct(Mesh2* m, const Gid* conn, const Gid* conn_b, int nelem,
799 int nelem_b, int nverts,int etype, int etype_b, int* local2globalMap,
800 GlobalToVert& globalToVert, PCU_t PCUObj)
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, PCUObj);
806 constructRemotes(m, globalToVert, PCUObj);
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
855int 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
872int MeshAdaptPUMIDrvr::reconstructFromProteus(Mesh& mesh, Mesh& globalMesh,int hasModel)
873{
874 if(PCU_Comm_Self(PCUObj)==0)
875 std::cout<<"STARTING RECONSTRUCTION\n";
876 isReconstructed = 1; //True
877
878 /************Preliminaries**************/
879 comm_size = PCU_Comm_Peers(PCUObj);
880 comm_rank = PCU_Comm_Self(PCUObj);
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(PCUObj)+1]-globalMesh.nodeOffsets_subdomain_owned[PCU_Comm_Self(PCUObj)];
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(PCUObj, &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,&pcuObj_);
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 apf::Gid* local2global_elementBoundaryNodes;
989 local2global_elementBoundaryNodes = (apf::Gid*) malloc(sizeof(apf::Gid)*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 apf::Gid* local2global_elementNodes;
994 local2global_elementNodes = (apf::Gid*) malloc(sizeof(apf::Gid)*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,PCUObj);
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(PCUObj, &numModelOffsets[0],4);
1074 PCU_Add_Ints(PCUObj, &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(PCUObj);
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(PCUObj, it->first,it->second);
1179 PCU_COMM_PACK(PCUObj, it->first,gEnt);
1180 }
1181 }
1182
1183 } //endif owned
1184 vID++;
1185 }
1186 PCU_Comm_Send(PCUObj);
1187 //receive model entity classification from owning nodes
1188 while(PCU_Comm_Receive(PCUObj)){
1189 PCU_COMM_UNPACK(PCUObj, ent);
1190 PCU_COMM_UNPACK(PCUObj, gEnt);
1191 m->setModelEntity(ent,gEnt);
1192 }
1193 PCU_Barrier(PCUObj);
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(PCUObj);
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)
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(PCUObj, it->first,it->second);
1238 PCU_COMM_PACK(PCUObj, 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(PCUObj, it->first,it->second);
1271 PCU_COMM_PACK(PCUObj, it->first,gEnt);
1272 }
1273 }
1274 }
1275 }
1276
1277 }
1278 }
1279 }
1280 m->setModelEntity(ent,gEnt);
1281 boundaryID++;
1282 }
1283 PCU_Comm_Send(PCUObj);
1284 //receive model entity classification from owning edges
1285 while(PCU_Comm_Receive(PCUObj)){
1286 PCU_COMM_UNPACK(PCUObj, ent);
1287 PCU_COMM_UNPACK(PCUObj, gEnt);
1288 m->setModelEntity(ent,gEnt);
1289 }
1290 PCU_Barrier(PCUObj);
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(PCUObj, modelVertexMaterial,numModelTotals[0]);
1314 PCU_Add_Ints(PCUObj, modelBoundaryMaterial,numModelTotals[2]);
1315 PCU_Add_Ints(PCUObj, 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(PCUObj)==0)
1331 std::cout<<"FINISHING RECONSTRUCTION\n";
1332}
1333
1334int 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,&pcuObj_);
1387 std::valarray<apf::Gid> elementNodesArray(mesh.nElements_global*apf::Mesh::adjacentCount[elementType][0]);
1388 for(int i=0;i<mesh.nElements_global*apf::Mesh::adjacentCount[elementType][0];i++){
1389 elementNodesArray[i] = mesh.elementNodesArray[i];
1390 }
1391 apf::construct(m,&elementNodesArray[0],mesh.nElements_global,elementType,outMap);
1392
1393 apf::setCoords(m,mesh.nodeArray,mesh.nNodes_global,outMap);
1394
1395 std::map<int,apf::MeshEntity*> globalToRegion;
1396 apf::MeshIterator* it = m->begin(dim);
1397 apf::MeshEntity* ent;
1398 int counter = 0;
1399 while( ent = m->iterate(it) ){
1400 globalToRegion.insert(std::pair<int,apf::MeshEntity*> (counter,ent ));
1401 counter++;
1402 }
1403
1404 if(dim == 2)
1405 apf::derive2DMdlFromManifold(m,isModelVert_bool,nBFaces,bEdges_1D,outMap,globalToRegion);
1406 else
1407 apf::deriveMdlFromManifold(m,isModelVert_bool,nBFaces,bFaces_2D,outMap,globalToRegion);
1408 m->writeNative("Reconstructed.smb");
1409 gmi_write_dmg(m->getModel(),"Reconstructed.dmg");
1410 std::cout<<"Finished Reconstruction, terminating program. Rerun with PUMI workflow\n";
1411 std::exit(0);
1412
1413}
1414
Int n
Definition Headers.h:28
Double f
Definition Headers.h:64
Double s
Definition Headers.h:84
Double v
Definition Headers.h:95
#define DEFAULT_ELEMENT_MATERIAL
int getProteusBoundaryIdx(apf::Mesh *m, apf::MeshEntity *e, apf::MeshEntity *f)
#define EXTERIOR_MATERIAL
#define INTERIOR_MATERIAL
int updateMaterialArrays(Mesh &mesh, int dim, int bdryID, int GeomTag)
int reconstructFromProteus(Mesh &mesh, Mesh &globalMesh, int hasModel)
int reconstructFromProteus2(Mesh &mesh, int *isModelVert, int *bFaces)
int transferModelInfo(int *numGeomEntities, int *edges, int *faces, int *mVertex2Model, int *mEdgeVertex2Model, int *mBoundary2Model, int nMaxSegments)
int updateMaterialArrays2(Mesh &mesh)
int localNumber(apf::MeshEntity *e)
int constructFromSerialPUMIMesh(Mesh &mesh)
#define max(a, b)
void construct(Mesh2 *m, const Gid *conn, const Gid *conn_b, int nelem, int nelem_b, int nverts, int etype, int etype_b, int *local2globalMap, GlobalToVert &globalToVert, PCU_t PCUObj)
Definition mesh.h:30
int * elementBoundaryNodesArray
Definition mesh.h:49
int * nodeStarOffsets
Definition mesh.h:56
int nEdges_global
Definition mesh.h:41
double * nodeArray
Definition mesh.h:69
int nNodes_elementBoundary
Definition mesh.h:35
int * nodeNumbering_subdomain2global
Definition mesh.h:81
int nNodes_element
Definition mesh.h:34
int * elementBoundaryElementsArray
Definition mesh.h:50
int * nodeElementOffsets
Definition mesh.h:46
int * nodeElementsArray
Definition mesh.h:45
int nElements_global
Definition mesh.h:32
int nNodes_global
Definition mesh.h:33
int * nodeStarArray
Definition mesh.h:55
int * elementNodesArray
Definition mesh.h:44
int * elementNeighborsArray
Definition mesh.h:47
int * exteriorElementBoundariesArray
Definition mesh.h:53
int * elementBoundaryLocalElementBoundariesArray
Definition mesh.h:51
int nExteriorElementBoundaries_global
Definition mesh.h:39
int nElementBoundaries_element
Definition mesh.h:36
int * nodeOffsets_subdomain_owned
Definition mesh.h:80
int * elementBoundaryMaterialTypes
Definition mesh.h:58
int max_nNodeNeighbors_node
Definition mesh.h:42
int * elementMaterialTypes
Definition mesh.h:57
int * edgeNodesArray
Definition mesh.h:54
int nInteriorElementBoundaries_global
Definition mesh.h:38
int * elementBoundariesArray
Definition mesh.h:48
int * interiorElementBoundariesArray
Definition mesh.h:52
int nElementBoundaries_global
Definition mesh.h:37
int * nodeMaterialTypes
Definition mesh.h:59