proteus  1.8.1
C/C++/Fortran libraries
ParallelMeshConverter.cpp
Go to the documentation of this file.
1 #include <algorithm>
2 #include <mpi.h>
3 #include <PCU.h>
4 #include <sstream>
5 
6 #include "MeshAdaptPUMI.h"
7 #include "mesh.h"
8 
9 #include "DumpMesh.h"
10 
12 const int DEFAULT_NODE_MATERIAL=-1;
17 
18 static int countTotal(apf::Mesh* m, int dim)
19 {
20  int total = apf::countOwned(m, dim);
21  PCU_Add_Ints(&total, 1);
22  return total;
23 }
24 
26 {
27  mesh.subdomainp = &subdomain_mesh;
28  initializeMesh(subdomain_mesh);
29  if (!PCU_Comm_Self())
30  std::cerr << "Constructing parallel proteus mesh\n";
31 
32  int dim = m->getDimension();
33  int numGlobElem = countTotal(m, dim);
34  mesh.nElements_global = numGlobElem;
35 
36  int numLocElem = m->count(dim);
37  mesh.subdomainp->nElements_global = numLocElem;
38 
39  int numGlobNodes = countTotal(m, 0);
40  mesh.nNodes_global = numGlobNodes;
41 
42  int numLocNodes = m->count(0);
43  mesh.subdomainp->nNodes_global = numLocNodes;
44 
45  int numGlobFaces = countTotal(m, 2);
46  int numLocFaces = m->count(2);
47 
48  int numGlobEdges = countTotal(m, 1);
49  mesh.nEdges_global = numGlobEdges;
50 
51  int numLocEdges = m->count(1);
52  mesh.subdomainp->nEdges_global = numLocEdges;
53 
54  if(dim==3){
55  mesh.nElementBoundaries_global = numGlobFaces;
56  mesh.subdomainp->nElementBoundaries_global = numLocFaces;
57  //nNodes_element for now is constant for the entire mesh, Ask proteus about using mixed meshes
58  //therefore currently this code only supports tet meshes
59  mesh.subdomainp->nNodes_element = 4; //hardcode: for tets, number of nodes per element
60  mesh.subdomainp->nNodes_elementBoundary = 3; //hardcode: for tets, looks like number of nodes of a face
61  mesh.subdomainp->nElementBoundaries_element = 4; //hardcode: for tets, looks like number of faces/element
62  }
63  else if(dim==2){
64  mesh.nElementBoundaries_global = numGlobEdges;
65  mesh.subdomainp->nElementBoundaries_global = numLocEdges;
66  mesh.subdomainp->nNodes_element = 3; //hardcode: for tets, number of nodes per element
67  mesh.subdomainp->nNodes_elementBoundary = 2; //hardcode: for tets, looks like number of nodes of a face
68  mesh.subdomainp->nElementBoundaries_element = 3; //hardcode: for tets, looks like number of faces/element
69  }
70 
71 
72 #ifdef MESH_INFO
73  for (int i = 0; i < PCU_Comm_Peers(); ++i) {
74  if (i == PCU_Comm_Self()) {
75  std::cerr << "*******Local Proteus Mesh Stats*********\n";
76  std::cerr << "Rank: " << comm_rank << ": Number of elements " << mesh.subdomainp->nElements_global << "\n";
77  std::cerr << "Rank: " << comm_rank << ": Number of nodes " << mesh.subdomainp->nNodes_global << "\n";
78  std::cerr << "Rank: " << comm_rank << ": Number of boundaries " << mesh.subdomainp->nElementBoundaries_global << "\n";
79  std::cerr << "Rank: " << comm_rank << ": Number of edges " << mesh.subdomainp->nEdges_global << "\n";
80  std::cerr << "*****************************************\n";
81  }
82  PCU_Barrier();
83  }
84 
85  if(comm_rank==0) {
86  std::cerr << "*******Global Proteus Mesh Stats*********\n";
87  std::cerr << ": Number of elements " << mesh.nElements_global << "\n";
88  std::cerr << ": Number of nodes " << mesh.nNodes_global << "\n";
89  std::cerr << ": Number of boundaries " << mesh.nElementBoundaries_global << "\n";
90  std::cerr << ": Number of edges " << mesh.nEdges_global << "\n";
91  std::cerr << "*****************************************\n";
92  }
93 #endif
94 
95  constructGlobalNumbering(mesh);
96  numberLocally();
97  constructNodes(*mesh.subdomainp);
98  constructElements(*mesh.subdomainp);
99  constructBoundaries(*mesh.subdomainp);
100  constructEdges(*mesh.subdomainp);
101  constructMaterialArrays(*mesh.subdomainp);
102  constructGlobalStructures(mesh);
103 
104 /* Turn on only for debugging
105  std::stringstream ss;
106  ss << "ToProteus_t" << nAdapt<<".smb";
107  std::string s = ss.str();
108  m->writeNative(s.c_str());
109 */
110  return 0;
111 }
112 
113 #include <cstring>
114 int MeshAdaptPUMIDrvr::constructGlobalNumbering(Mesh &mesh)
115 {
116  /* N^2 data structures and algorithms are terrible for scalability.
117  Going along because Proteus is structured this way. */
118  mesh.elementOffsets_subdomain_owned = new int[comm_size+1];
119  mesh.elementBoundaryOffsets_subdomain_owned = new int[comm_size+1];
120  mesh.edgeOffsets_subdomain_owned = new int[comm_size+1];
121  mesh.nodeOffsets_subdomain_owned = new int[comm_size+1];
122 
123  if(m->getDimension()==3){
124  for (int dim = 0; dim <= m->getDimension(); ++dim) {
125 
126  int nLocalOwned = apf::countOwned(m, dim);
127  int localOffset = nLocalOwned;
128  PCU_Exscan_Ints(&localOffset, 1);
129 
130  int* allOffsets;
131  if(dim==3){
132  allOffsets = mesh.elementOffsets_subdomain_owned;
133  }
134  if(dim==2){
135  allOffsets = mesh.elementBoundaryOffsets_subdomain_owned;
136  }
137  if(dim==1){
138  allOffsets = mesh.edgeOffsets_subdomain_owned;
139  }
140  if(dim==0){
141  allOffsets = mesh.nodeOffsets_subdomain_owned;
142  }
143 
144  /* one of the many reasons N^2 algorithms are bad */
145  MPI_Allgather(&localOffset, 1, MPI_INT,
146  allOffsets, 1, MPI_INT, MPI_COMM_WORLD);
147  allOffsets[PCU_Comm_Peers()] = countTotal(m, dim);
148 
149  std::stringstream ss;
150  ss << "proteus_global_";
151  ss << dim;
152  std::string name = ss.str();
153  /* this algorithm does global numbering properly,
154  without O(#procs) runtime */
155  global[dim] = apf::makeGlobal(apf::numberOwnedDimension(m, name.c_str(), dim));
156  apf::synchronize(global[dim]);
157  } //loop on entity dimensions
158  }
159  else if(m->getDimension()==2){
160  for (int dim = 0; dim <= m->getDimension(); ++dim) {
161 
162  int nLocalOwned = apf::countOwned(m, dim);
163  int localOffset = nLocalOwned;
164  PCU_Exscan_Ints(&localOffset, 1);
165 
166  int* allOffsets;
167  if(dim==2){
168  allOffsets = mesh.elementOffsets_subdomain_owned;
169  }
170  if(dim==1){
171  allOffsets = mesh.elementBoundaryOffsets_subdomain_owned;
172  }
173  if(dim==0){
174  allOffsets = mesh.nodeOffsets_subdomain_owned;
175  }
176 
177  /* one of the many reasons N^2 algorithms are bad */
178  MPI_Allgather(&localOffset, 1, MPI_INT,
179  allOffsets, 1, MPI_INT, MPI_COMM_WORLD);
180  allOffsets[PCU_Comm_Peers()] = countTotal(m, dim);
181  std::stringstream ss;
182  ss << "proteus_global_";
183  ss << dim;
184  std::string name = ss.str();
185  /* this algorithm does global numbering properly,
186  without O(#procs) runtime */
187  global[dim] = apf::makeGlobal(apf::numberOwnedDimension(m, name.c_str(), dim));
188  apf::synchronize(global[dim]);
189  } //loop on entity dimensions
190  std::memcpy(mesh.edgeOffsets_subdomain_owned,mesh.elementBoundaryOffsets_subdomain_owned,sizeof(int)*(comm_size+1));
191  }
192  return 0;
193 }
194 
195 int MeshAdaptPUMIDrvr::constructGlobalStructures(Mesh &mesh)
196 {
201 
202  if(m->getDimension()==3){
203  for (int d = 0; d <= m->getDimension(); ++d) {
204  int* temp_subdomain2global;
205  if(d==3) temp_subdomain2global = mesh.elementNumbering_subdomain2global;
206  if(d==2) temp_subdomain2global = mesh.elementBoundaryNumbering_subdomain2global;
207  if(d==1) temp_subdomain2global = mesh.edgeNumbering_subdomain2global;
208  if(d==0) temp_subdomain2global = mesh.nodeNumbering_subdomain2global;
209 
210  apf::MeshIterator* it = m->begin(d);
211  apf::MeshEntity* e;
212  while ((e = m->iterate(it))) {
213  int i = localNumber(e);
214  temp_subdomain2global[i] = apf::getNumber(global[d], apf::Node(e, 0));
215  }
216  m->end(it);
217  apf::destroyGlobalNumbering(global[d]);
218  }
219  }
220  else if(m->getDimension()==2){
221  for (int d = 0; d <= m->getDimension(); ++d) {
222  int* temp_subdomain2global;
223  int* temp_subdomain2global2; //just for the edge and element boundary array overlap
224  if(d==2) temp_subdomain2global = mesh.elementNumbering_subdomain2global;
225  if(d==1) temp_subdomain2global = mesh.elementBoundaryNumbering_subdomain2global;
226  if(d==0) temp_subdomain2global = mesh.nodeNumbering_subdomain2global;
227  apf::MeshIterator* it = m->begin(d);
228  apf::MeshEntity* e;
229  while ((e = m->iterate(it))) {
230  int i = localNumber(e);
231  temp_subdomain2global[i] = apf::getNumber(global[d], apf::Node(e, 0));
232  }
233  m->end(it);
234  apf::destroyGlobalNumbering(global[d]);
235  }
237  }
238 
239  return 0;
240 }
241 
243 {
244  std::stringstream ss;
245  ss << "dan_debug_" << PCU_Comm_Self() << ".txt";
246  std::string s = ss.str();
247  FILE* f = fopen(s.c_str(), "w");
248  dump_proteus_mesh(&mesh, f);
249  fclose(f);
250  return 0;
251 }
252 
EXTERIOR_ELEMENT_BOUNDARY_MATERIAL
const int EXTERIOR_ELEMENT_BOUNDARY_MATERIAL
Definition: ParallelMeshConverter.cpp:16
Mesh::elementBoundaryOffsets_subdomain_owned
int * elementBoundaryOffsets_subdomain_owned
Definition: mesh.h:80
MeshAdaptPUMIDrvr::numberLocally
void numberLocally()
Definition: MeshConverter.cpp:95
INTERIOR_NODE_MATERIAL
const int INTERIOR_NODE_MATERIAL
Definition: ParallelMeshConverter.cpp:13
MeshAdaptPUMI.h
Mesh
Definition: mesh.h:28
Mesh::nEdges_global
int nEdges_global
Definition: mesh.h:39
f
Double f
Definition: Headers.h:64
s
Double s
Definition: Headers.h:84
MeshAdaptPUMIDrvr::localNumber
int localNumber(apf::MeshEntity *e)
Definition: MeshConverter.cpp:105
Mesh::nNodes_elementBoundary
int nNodes_elementBoundary
Definition: mesh.h:33
MeshAdaptPUMIDrvr::dumpMesh
int dumpMesh(Mesh &mesh)
Definition: ParallelMeshConverter.cpp:242
Mesh::nElementBoundaries_global
int nElementBoundaries_global
Definition: mesh.h:35
Mesh::nodeOffsets_subdomain_owned
int * nodeOffsets_subdomain_owned
Definition: mesh.h:78
Mesh::nNodes_element
int nNodes_element
Definition: mesh.h:32
Mesh::edgeNumbering_subdomain2global
int * edgeNumbering_subdomain2global
Definition: mesh.h:83
INTERIOR_ELEMENT_BOUNDARY_MATERIAL
const int INTERIOR_ELEMENT_BOUNDARY_MATERIAL
Definition: ParallelMeshConverter.cpp:15
Mesh::edgeOffsets_subdomain_owned
int * edgeOffsets_subdomain_owned
Definition: mesh.h:82
MeshAdaptPUMIDrvr::constructFromParallelPUMIMesh
int constructFromParallelPUMIMesh(Mesh &mesh, Mesh &subdomain_mesh)
Definition: ParallelMeshConverter.cpp:25
Mesh::nElements_global
int nElements_global
Definition: mesh.h:30
mesh.h
Mesh::subdomainp
Mesh * subdomainp
Definition: mesh.h:84
Mesh::nElementBoundaries_element
int nElementBoundaries_element
Definition: mesh.h:34
Mesh::elementOffsets_subdomain_owned
int * elementOffsets_subdomain_owned
Definition: mesh.h:76
Mesh::elementBoundaryNumbering_subdomain2global
int * elementBoundaryNumbering_subdomain2global
Definition: mesh.h:81
initializeMesh
void initializeMesh(Mesh &mesh)
Definition: mesh.h:87
Mesh::nNodes_global
int nNodes_global
Definition: mesh.h:31
DEFAULT_ELEMENT_MATERIAL
const int DEFAULT_ELEMENT_MATERIAL
Definition: ParallelMeshConverter.cpp:11
DumpMesh.h
Mesh::nodeNumbering_subdomain2global
int * nodeNumbering_subdomain2global
Definition: mesh.h:79
DEFAULT_NODE_MATERIAL
const int DEFAULT_NODE_MATERIAL
Definition: ParallelMeshConverter.cpp:12
EXTERIOR_NODE_MATERIAL
const int EXTERIOR_NODE_MATERIAL
Definition: ParallelMeshConverter.cpp:14
Mesh::elementNumbering_subdomain2global
int * elementNumbering_subdomain2global
Definition: mesh.h:77
dump_proteus_mesh
void dump_proteus_mesh(Mesh *m, FILE *f)
Definition: DumpMesh.cpp:163