proteus 1.9.0
C/C++/Fortran libraries
Loading...
Searching...
No Matches
partitioning.cpp
Go to the documentation of this file.
1#include "partitioning.h"
3
4namespace proteus
5{
6//todo add overlap for element based partitions
7int partitionElementsOriginal(const MPI_Comm& PROTEUS_COMM_WORLD, Mesh& mesh, int nElements_overlap)
8{
9 using namespace std;
10 int ierr,size,rank;
11
12 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);
13 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);
14
15 //Contents
16 //
17 //1. Partition the elements in the "default" partition (contiguous
18 //chunks in given ordering)
19 //
20 //2. Partition the elementNeighbors based on this partition
21 //
22 //3. Pass to Parmetis to build a better partition of the elements
23 //
24 //4. Tag a subset of the nodes on the subdomain elements as owned
25 //using a mark and pass approach.**
26 //
27 //5. Extract the nodes in the
28 //overlapping elements.**
29 //
30 //6. Build the subdomain mesh from the
31 //subdomain elements
32 //
33 //**To be more general we could get all the support (i.e. faces
34 //and edges) and partitiong them, but the main reason for
35 //partitioning is to keep track of a global numbering for degrees
36 //of freedom that live on each type of geometric entity. We only
37 //have node and element based DOFs so I just rebuild the other
38 //information once we have elements and nodes partitioned.
39 //
40 // \todo check that I restore all data that PETSc expects to have
41 // back, add PETSc error checking macros
42 //
43 //1. Build default partitioning
44 //
45 //get offsets so we can calculate the processor to global mapping
46 //for elements in the old (default) partitioning
47 valarray<int> elementOffsets_old(size+1);
48 elementOffsets_old[0] = 0;
49 for(int sdN=0;sdN<size;sdN++)
50 elementOffsets_old[sdN+1] = elementOffsets_old[sdN] +
51 int(mesh.nElements_global)/size +
52 (int(mesh.nElements_global)%size > sdN);
53
54 //2. Extract subdomain element adjacency information could read
55 //only the required portion from a file
56 int nElements_subdomain = (elementOffsets_old[rank+1] - elementOffsets_old[rank]);
57 PetscInt *elementNeighborsOffsets_subdomain,*elementNeighbors_subdomain,*weights_subdomain;
58 PetscMalloc(sizeof(PetscInt)*(nElements_subdomain+1),&elementNeighborsOffsets_subdomain);
59 PetscMalloc(sizeof(PetscInt)*(nElements_subdomain*mesh.nElementBoundaries_element),&elementNeighbors_subdomain);
60 PetscMalloc(sizeof(PetscInt)*(nElements_subdomain*mesh.nElementBoundaries_element),&weights_subdomain);
61 //this wastes a little space
62 elementNeighborsOffsets_subdomain[0] = 0;
63 for (int eN=0,offset=0; eN < nElements_subdomain; eN++)
64 {
65 int eN_global = elementOffsets_old[rank] + eN;
66 int offsetStart=offset;
67 for (int ebN=0; ebN< mesh.nElementBoundaries_element;ebN++)
68 {
69 int eN_neighbor_global = mesh.elementNeighborsArray[eN_global*mesh.nElementBoundaries_element + ebN];
70 if (eN_neighbor_global >= 0 )
71 elementNeighbors_subdomain[offset++] = eN_neighbor_global;
72 }
73 elementNeighborsOffsets_subdomain[eN+1]=offset;
74 sort(&elementNeighbors_subdomain[offsetStart],&elementNeighbors_subdomain[offset]);
75 int weight = (elementNeighborsOffsets_subdomain[eN+1] - elementNeighborsOffsets_subdomain[eN]);
76 for (int k=elementNeighborsOffsets_subdomain[eN];k < elementNeighborsOffsets_subdomain[eN+1];k++)
77 weights_subdomain[k] = weight;
78 // for (int o = offsetStart; o < offset; o++)
79 // {
80 // std::cout<<elementNeighbors_subdomain[o]<<'\t';
81 // }
82 // std::cout<<std::endl;
83 }
84 //3. Generate the new partitiong using PETSc, this is done in parallel using parmetis
85 Mat petscAdjacency;
86 // MatCreateMPIAdj(PROTEUS_COMM_WORLD,
87 // nElements_subdomain, mesh.nElements_global,
88 // &elementNeighborsOffsets_subdomain[0], &elementNeighbors_subdomain[0],
89 // &weights_subdomain[0],
90 // &petscAdjacency);
91 ierr = MatCreateMPIAdj(PROTEUS_COMM_WORLD,
92 nElements_subdomain,
94 elementNeighborsOffsets_subdomain,
95 elementNeighbors_subdomain,
96 PETSC_NULL,//weights_subdomain,
97 &petscAdjacency);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
98 MatPartitioning petscPartition;
99 MatPartitioningCreate(PROTEUS_COMM_WORLD,&petscPartition);
100 MatPartitioningSetAdjacency(petscPartition,petscAdjacency);
101 MatPartitioningSetFromOptions(petscPartition);
102
103 //get a petsc index set that has the new submdomain number for each element
104 IS elementPartitioningIS_new;
105 MatPartitioningApply(petscPartition,&elementPartitioningIS_new);
106 MatPartitioningDestroy(&petscPartition);
107 //MatDestroy(petscAdjacency);
108 //ISView(elementPartitioningIS_new,PETSC_VIEWER_STDOUT_WORLD);
109
110 //experiment with metis
111 //mwf set some defaults and not call if size == 1 since metis crashes
112 //cek commenting out for now
113 //int etype=1,edgecut=0,base=0;
114 //epart assign everything to processor zero by default
115 //valarray<int> epart(0,mesh.nElements_global),npart(mesh.nNodes_global);
116 //if (size > 1)
117 // METIS_PartMeshNodal(&mesh.nElements_global,&mesh.nNodes_global,mesh.elementNodesArray,&etype,&base,&size,&edgecut,&epart[0],&npart[0]);
118 //ISCreateGeneralWithArray(PETSC_COMM_SELF,mesh.nElements_global,&epart[0],&elementPartitioningIS_new);
119 //write mesh to view with showme
120 // std::ofstream nodeout("mesh.node"),eleout("mesh.ele"),partout("mesh.part");
121 // eleout<<mesh.nElements_global<<" 3 0"<<std::endl;
122 // partout<<mesh.nElements_global<<"\t"<<size<<std::endl;
123 // for (int eN=0;eN<mesh.nElements_global;eN++)
124 // {
125 // partout<<(eN+1)<<"\t"<<(1+epart[eN])<<std::endl;
126 // eleout<<(eN+1)<<"\t"<<(1+mesh.elementNodesArray[eN*3+0])
127 // <<"\t"<<(1+mesh.elementNodesArray[eN*3+1])
128 // <<"\t"<<(1+mesh.elementNodesArray[eN*3+2])
129 // <<std::endl;
130 // }
131 // nodeout<<mesh.nNodes_global<<" 2 0 0"<<std::endl;
132 // for (int nN=0;nN<mesh.nNodes_global;nN++)
133 // {
134 // nodeout<<(nN+1)<<"\t"<<mesh.nodeArray[nN*3+0]<<"\t"<<mesh.nodeArray[nN*3+1]<<std::endl;
135 // }
136 // eleout.close();
137 // partout.close();
138 //count the new number of elements on each subdomain
139 valarray<int> nElements_subdomain_new(size);
140 ISPartitioningCount(elementPartitioningIS_new,size,&nElements_subdomain_new[0]);
141
142 //get the new offsets for the subdomain to global numbering
143 valarray<int> elementOffsets_new(size+1);
144 elementOffsets_new[0] = 0;
145 for (int sdN=0;sdN<size;sdN++)
146 elementOffsets_new[sdN+1] = elementOffsets_new[sdN] + nElements_subdomain_new[sdN];
147
148 //get the new element numbers for the elements on this subdomain
149 IS elementNumberingIS_subdomain_old2new;
150 ISPartitioningToNumbering(elementPartitioningIS_new,&elementNumberingIS_subdomain_old2new);
151
152 //now get the new element numbers for the whole mesh so that we
153 //can just read this processors elements, reorder, and renumber**
154 //
155 //**We could do this in parallel by scattering all the element
156 //information
157 IS elementNumberingIS_global_old2new;
158 ISAllGather(elementNumberingIS_subdomain_old2new,&elementNumberingIS_global_old2new);
159 //ISView(elementNumberingIS_global_old2new,PETSC_VIEWER_STDOUT_SELF);
160 const PetscInt *elementNumbering_global_old2new;
161 ISGetIndices(elementNumberingIS_global_old2new,&elementNumbering_global_old2new);
162 valarray<int> elementNumbering_global_new2old(mesh.nElements_global);
163 for(int eN=0;eN<mesh.nElements_global;eN++)
164 elementNumbering_global_new2old[elementNumbering_global_old2new[eN]] = eN;
165
166 //Sort element based arrays, maybe I don't need to do this, maybe
167 //I just need to start writing into the subdomain mesh here and
168 //preserve subdomain2old and subdomain2global mappings
169 valarray<int> elementNodesArray_new(mesh.nElements_global*mesh.nNodes_element),
170 elementNeighborsArray_new(mesh.nElements_global*mesh.nElementBoundaries_element),
171 elementMaterialTypes_new(mesh.nElements_global),
172 elementBoundaryElementsArray_new(mesh.nElementBoundaries_global*2),
173 elementBoundaryNodesArray_new(mesh.nElementBoundaries_global*mesh.nNodes_elementBoundary),
174 edgeNodesArray_new(mesh.nEdges_global*2);
175 valarray<int> elementBoundaryMaterialTypes_new(mesh.nElementBoundaries_global);
176 for (int eN=0;eN<mesh.nElements_global;eN++)
177 {
178 for (int nN=0;nN<mesh.nNodes_element;nN++)
179 elementNodesArray_new[eN*mesh.nNodes_element + nN] =
180 mesh.elementNodesArray[elementNumbering_global_new2old[eN]*mesh.nNodes_element+nN];
181 for (int ebN=0;ebN<mesh.nElementBoundaries_element;ebN++)
182 elementNeighborsArray_new[eN*mesh.nElementBoundaries_element+ebN] =
183 mesh.elementNeighborsArray[elementNumbering_global_new2old[eN]*mesh.nElementBoundaries_element+ebN];
184 elementMaterialTypes_new[eN] = mesh.elementMaterialTypes[elementNumbering_global_new2old[eN]];
185 }
186 //renumber references to element numbers
187 for (int eN=0;eN<mesh.nElements_global;eN++)
188 {
189 for (int ebN=0;ebN<mesh.nElementBoundaries_element;ebN++)
190 {
191 int eN_ebN = elementNeighborsArray_new[eN*mesh.nElementBoundaries_element+ebN];
192 if (eN_ebN >= 0)
193 elementNeighborsArray_new[eN*mesh.nElementBoundaries_element+ebN] =
194 elementNumbering_global_old2new[eN_ebN];
195 }
196 }
197 for(int ebN=0;ebN<mesh.nElementBoundaries_global;ebN++)
198 {
199 int eN_L_old = mesh.elementBoundaryElementsArray[ebN*2+0],
200 eN_R_old = mesh.elementBoundaryElementsArray[ebN*2+1];
201 elementBoundaryElementsArray_new[ebN*2+0] = elementNumbering_global_old2new[eN_L_old];
202 if(eN_R_old >= 0)
203 elementBoundaryElementsArray_new[ebN*2+1] = elementNumbering_global_old2new[eN_R_old];
204 //mwf assume same numbering scheme for element boundaries for now?
205 elementBoundaryMaterialTypes_new[ebN] = mesh.elementBoundaryMaterialTypes[ebN];
206 }
207 //4. now we need to build a new node ordering with better data locality for C0 finite elements
208 //otherwise we could just grab the nodes on the subdomain and not worry about ownership
209 //in the long run it wouldn't be bad to do a global repartition of faces and edges for mixed hybrid
210 //and non-conforming finite elements
211 MPI_Status status;
212 PetscBT nodeMask;
213 PetscBTCreate(mesh.nNodes_global,&nodeMask);
214 if (rank > 0)
215 {
216 MPI_Recv(nodeMask,PetscBTLength(mesh.nNodes_global),MPI_CHAR,rank-1,0,PROTEUS_COMM_WORLD,&status);
217 }
218 //mark the unmarked nodes on this subdomain and store the node numbers
219 set<int> nodes_subdomain_owned;
220 for(int eN=elementOffsets_new[rank];eN<elementOffsets_new[rank+1];eN++)
221 for(int nN=0;nN<mesh.nNodes_element;nN++)
222 {
223 int nN_global = elementNodesArray_new[eN*mesh.nNodes_element+nN];
224 if (!PetscBTLookupSet(nodeMask,nN_global))
225 nodes_subdomain_owned.insert(nN_global);
226 }
227 //ship off the mask
228 if (rank < size-1)
229 MPI_Send(nodeMask,PetscBTLength(mesh.nNodes_global),MPI_CHAR,rank+1,0,PROTEUS_COMM_WORLD);
230 ierr = PetscBTDestroy(&nodeMask);
231 if (ierr)
232 cerr<<"Error in PetscBTDestroy"<<endl;
233 //get the number of nodes on each processor
234 valarray<int> nNodes_subdomain_new(size),
235 nodeOffsets_new(size+1);
236 for (int sdN=0;sdN<size;sdN++)
237 if (sdN == rank)
238 nNodes_subdomain_new[sdN] = nodes_subdomain_owned.size();
239 else
240 nNodes_subdomain_new[sdN] = 0;
241 valarray<int> nNodes_subdomain_new_send=nNodes_subdomain_new;
242 MPI_Allreduce(&nNodes_subdomain_new_send[0],&nNodes_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
243 nodeOffsets_new[0] = 0;
244 for (int sdN=0;sdN<size;sdN++)
245 nodeOffsets_new[sdN+1] = nodeOffsets_new[sdN]+nNodes_subdomain_new[sdN];
246 //Now as with elements build a global node numbering, sort node
247 //based information, and renumber references to node numbers
248 valarray<int> nodeNumbering_new2old(nodes_subdomain_owned.size());
249 set<int>::iterator nN_ownedp=nodes_subdomain_owned.begin();
250 for (int nN=0;nN<int(nodes_subdomain_owned.size());nN++)
251 {
252 nodeNumbering_new2old[nN] = *nN_ownedp++;
253 }
254 IS nodeNumberingIS_new2old;
255 ISCreateGeneral(PROTEUS_COMM_WORLD,nodes_subdomain_owned.size(),&nodeNumbering_new2old[0],PETSC_COPY_VALUES,&nodeNumberingIS_new2old);
256 IS nodeNumberingIS_global_new2old;
257 ISAllGather(nodeNumberingIS_new2old,&nodeNumberingIS_global_new2old);
258 const PetscInt *nodeNumbering_global_new2old;
259 valarray<int> nodeNumbering_old2new_global(mesh.nNodes_global);
260 ISGetIndices(nodeNumberingIS_global_new2old,&nodeNumbering_global_new2old);
261 for (int nN=0;nN<mesh.nNodes_global;nN++)
262 {
263 nodeNumbering_old2new_global[nodeNumbering_global_new2old[nN]] = nN;
264 }
265 for (int eN=0;eN < mesh.nElements_global; eN++)
266 {
267 int nN_old;
268 for (int nN=0;nN < mesh.nNodes_element; nN++)
269 {
270 nN_old = elementNodesArray_new[eN*mesh.nNodes_element+nN];
271 elementNodesArray_new[eN*mesh.nNodes_element+nN] = nodeNumbering_old2new_global[nN_old];
272 }
273 }
274 for (int i=0;i<mesh.nElementBoundaries_global*mesh.nNodes_elementBoundary;i++)
275 {
276 int nN_old = mesh.elementBoundaryNodesArray[i];
277 elementBoundaryNodesArray_new[i] = nodeNumbering_old2new_global[nN_old];
278 }
279 for (int i=0;i<mesh.nEdges_global*2;i++)
280 {
281 int nN_old = mesh.edgeNodesArray[i];
282 edgeNodesArray_new[i] = nodeNumbering_old2new_global[nN_old];
283 }
284 valarray<int> nodeStarArray_new(mesh.nodeStarOffsets[mesh.nNodes_global]);
285 for (int i=0;i<mesh.nodeStarOffsets[mesh.nNodes_global];i++)
286 {
287 int nN_old = mesh.nodeStarArray[i];
288 nodeStarArray_new[i] = nodeNumbering_old2new_global[nN_old];
289 }
290 valarray<double> nodeArray_new(mesh.nNodes_global*3);
291 valarray<int> nodeMaterialTypes_new(mesh.nNodes_global);
292 for (int nN=0;nN<mesh.nNodes_global;nN++)
293 {
294 int nN_new = nodeNumbering_old2new_global[nN];
295 nodeArray_new[nN_new*3+0] = mesh.nodeArray[nN*3+0];
296 nodeArray_new[nN_new*3+1] = mesh.nodeArray[nN*3+1];
297 nodeArray_new[nN_new*3+2] = mesh.nodeArray[nN*3+2];
298 nodeMaterialTypes_new[nN_new] = mesh.nodeMaterialTypes[nN];
299 }
300 //write partitioned mesh to view with "showme"
301 // std::ofstream nodeout("mesh.node"),eleout("mesh.ele"),partout("mesh.part");
302 // eleout<<mesh.nElements_global<<" 3 0"<<std::endl;
303 // partout<<mesh.nElements_global<<"\t"<<size<<std::endl;
304 // for (int eN=0;eN<mesh.nElements_global;eN++)
305 // {
306 // partout<<(eN+1)<<"\t"<<(1+epart[elementNumbering_global_new2old[eN]])<<std::endl;
307 // //partout<<(eN+1)<<"\t"<<(1+epart[eN])<<std::endl;
308 // eleout<<(eN+1)<<"\t"<<(1+elementNodesArray_new[eN*3+0])
309 // <<"\t"<<(1+elementNodesArray_new[eN*3+1])
310 // <<"\t"<<(1+elementNodesArray_new[eN*3+2])
311 // <<std::endl;
312 // }
313 // nodeout<<mesh.nNodes_global<<" 2 0 0"<<std::endl;
314 // for (int nN=0;nN<mesh.nNodes_global;nN++)
315 // {
316 // nodeout<<(nN+1)<<"\t"<<nodeArray_new[nN*3+0]<<"\t"<<nodeArray_new[nN*3+1]<<std::endl;
317 // }
318 // eleout.close();
319 // partout.close();
320 //5. At this point we have new, renumbered and sorted the global element and node based information, and
321 //we have it all on each processor so we can add overlap
322 set<int> elements_overlap,nodes_overlap;
323 for(int eN=elementOffsets_new[rank];eN<elementOffsets_new[rank+1];eN++)
324 for (int nN=0;nN<mesh.nNodes_element;nN++)
325 {
326 int nN_global = elementNodesArray_new[eN*mesh.nNodes_element+nN];
327 if (nN_global < nodeOffsets_new[rank] || nN_global >= nodeOffsets_new[rank+1])
328 nodes_overlap.insert(nN_global);
329 }
330
331
332 if (nElements_overlap > 0)
333 {
334 //get all elements in the node stars and their nodes
335 // for (int nN_new=nodeOffsets_new[rank]; nN_new < nodeOffsets_new[rank+1]; nN_new++)
336 // {
337 // int nN = nodeNumbering_global_new2old[nN_new];
338 // for (int offset =mesh.nodeElementOffsets[nN];offset<mesh.nodeElementOffsets[nN+1];offset++)
339 // {
340 // int eN = mesh.nodeElementsArray[offset];
341 // int eN_new = elementNumbering_global_old2new[eN];
342 // if (eN_new < elementOffsets_new[rank] or eN_new >= elementOffsets_new[rank+1])
343 // {
344 // elements_overlap.insert(eN_new);
345 // for (int nN_element=0;nN_element<mesh.nNodes_element;nN_element++)
346 // {
347 // int nN_global = elementNodesArray_new[eN_new*mesh.nNodes_element+nN_element];
348 // if (nN_global < nodeOffsets_new[rank] or nN_global >= nodeOffsets_new[rank+1])
349 // nodes_overlap.insert(nN_global);
350 // }
351 // }
352 // }
353 // }
354 //get all elements in the node stars of owned nodes and those elements' nodes
355 for (set<int>::iterator nN=nodes_subdomain_owned.begin();nN != nodes_subdomain_owned.end();nN++)
356 {
357 for (int offset =mesh.nodeElementOffsets[*nN];offset<mesh.nodeElementOffsets[(*nN)+1];offset++)
358 {
359 int eN = mesh.nodeElementsArray[offset];
360 int eN_new = elementNumbering_global_old2new[eN];
361 if (eN_new < elementOffsets_new[rank] or eN_new >= elementOffsets_new[rank+1])
362 {
363 elements_overlap.insert(eN_new);
364 for (int nN_element=0;nN_element<mesh.nNodes_element;nN_element++)
365 {
366 int nN_global = elementNodesArray_new[eN_new*mesh.nNodes_element+nN_element];
367 if (nN_global < nodeOffsets_new[rank] or nN_global >= nodeOffsets_new[rank+1])
368 nodes_overlap.insert(nN_global);
369 }
370 }
371 }
372 }
373 //get all the element neighbors
374 for(int eN=elementOffsets_new[rank];eN<elementOffsets_new[rank+1];eN++)
375 for(int ebN=0;ebN<mesh.nElementBoundaries_element;ebN++)
376 {
377 int eN_ebN = elementNeighborsArray_new[eN*mesh.nElementBoundaries_element+ebN];
378 if (eN_ebN >= 0 &&
379 (eN_ebN < elementOffsets_new[rank] || eN_ebN >= elementOffsets_new[rank+1]))
380 {
381 elements_overlap.insert(eN_ebN);
382 for (int nN=0;nN<mesh.nNodes_element;nN++)
383 {
384 int nN_global = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN];
385 if (nN_global < nodeOffsets_new[rank] || nN_global >= nodeOffsets_new[rank+1])
386 nodes_overlap.insert(nN_global);
387 }
388 }
389 }
390 }
391 for (int layer=1;layer<nElements_overlap;layer++)
392 {
393 for (set<int>::iterator eN_p=elements_overlap.begin();eN_p != elements_overlap.end();eN_p++)
394 {
395 int eN_global = *eN_p;
396 for(int ebN=0;ebN<mesh.nElementBoundaries_element;ebN++)
397 {
398 int eN_ebN = elementNeighborsArray_new[eN_global*mesh.nElementBoundaries_element+ebN];
399 if (eN_ebN >= 0 &&
400 (eN_ebN < elementOffsets_new[rank] || eN_ebN >= elementOffsets_new[rank+1]))
401 {
402 elements_overlap.insert(eN_ebN);
403 for (int nN=0;nN<mesh.nNodes_element;nN++)
404 {
405 int nN_global = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN];
406 if (nN_global < nodeOffsets_new[rank] || nN_global >= nodeOffsets_new[rank+1])
407 nodes_overlap.insert(nN_global);
408 }
409 }
410 }
411 }
412 }
413 //6. Now build subdomain mesh
414 //
415 //set what we know
416 if (mesh.subdomainp == NULL)
417 mesh.subdomainp = new Mesh();
418 mesh.subdomainp->usePlex = mesh.usePlex;
419 mesh.subdomainp->nElements_global = nElements_subdomain_new[rank] + elements_overlap.size();
420 mesh.subdomainp->nNodes_global = nNodes_subdomain_new[rank] + nodes_overlap.size();
424 //load the elements and nodes
425 valarray<int> nodeNumbering_subdomain2global(mesh.subdomainp->nNodes_global);
426 map<int,int> nodeNumbering_global2subdomain;
427 mesh.subdomainp->nodeArray = new double[mesh.subdomainp->nNodes_global*3];
429 for(int nN=0;nN<nNodes_subdomain_new[rank];nN++)
430 {
431 int nN_global = nN + nodeOffsets_new[rank];
432 nodeNumbering_subdomain2global[nN] = nN_global;
433 nodeNumbering_global2subdomain[nN_global] = nN;
434 mesh.subdomainp->nodeArray[nN*3+0] = nodeArray_new[nN_global*3+0];
435 mesh.subdomainp->nodeArray[nN*3+1] = nodeArray_new[nN_global*3+1];
436 mesh.subdomainp->nodeArray[nN*3+2] = nodeArray_new[nN_global*3+2];
437 mesh.subdomainp->nodeMaterialTypes[nN]= nodeMaterialTypes_new[nN_global];
438 }
439 //note: sets in C++ are sorted so the overlap is laid out in
440 //contiguous chunks corresponding to the partitions
441 set<int>::iterator nN_p=nodes_overlap.begin();
442 for(int nN=nNodes_subdomain_new[rank];nN < nNodes_subdomain_new[rank] + int(nodes_overlap.size()); nN++)
443 {
444 int nN_global = *nN_p++;
445 nodeNumbering_subdomain2global[nN] = nN_global;
446 nodeNumbering_global2subdomain[nN_global] = nN;
447 mesh.subdomainp->nodeArray[nN*3+0] = nodeArray_new[nN_global*3+0];
448 mesh.subdomainp->nodeArray[nN*3+1] = nodeArray_new[nN_global*3+1];
449 mesh.subdomainp->nodeArray[nN*3+2] = nodeArray_new[nN_global*3+2];
450 mesh.subdomainp->nodeMaterialTypes[nN]= nodeMaterialTypes_new[nN_global];
451 }
454 valarray<int> elementNumbering_subdomain2global(mesh.subdomainp->nElements_global);
455 for (int eN=0;eN<nElements_subdomain_new[rank];eN++)
456 {
457 int eN_global = eN+elementOffsets_new[rank];
458 elementNumbering_subdomain2global[eN] = eN_global;
459 mesh.subdomainp->elementMaterialTypes[eN] = elementMaterialTypes_new[eN_global];
460 for (int nN=0;nN<mesh.subdomainp->nNodes_element;nN++)
462 nodeNumbering_global2subdomain[elementNodesArray_new[eN_global*mesh.nNodes_element + nN]];
463 }
464 set<int>::iterator eN_p=elements_overlap.begin();
465 for(int eN=nElements_subdomain_new[rank];eN < nElements_subdomain_new[rank]+int(elements_overlap.size());eN++)
466 {
467 int eN_global = *eN_p++;
468 mesh.subdomainp->elementMaterialTypes[eN] = elementMaterialTypes_new[eN_global];
469 elementNumbering_subdomain2global[eN] = eN_global;
470 for (int nN=0;nN<mesh.subdomainp->nNodes_element;nN++)
472 nodeNumbering_global2subdomain[elementNodesArray_new[eN_global*mesh.nNodes_element + nN]];
473 }
474
475 if (mesh.subdomainp->nNodes_element == 2)
476 {
480 }
481 else if (mesh.subdomainp->nNodes_element == 3)
482 {
486 }
487 else if (mesh.subdomainp->nNodes_element == 4)
488 {
492 }
493 if (mesh.elementBoundaryMaterialTypes != NULL)
494 {
495 assert(mesh.elementBoundariesArray != NULL);
496 //mwftodo need to copy over elementBoundaryMaterialTypes now
497 for (int eN=0;eN<mesh.subdomainp->nElements_global;eN++)
498 {
499 int eN_global_new = elementNumbering_subdomain2global[eN];
500 int eN_global_old = elementNumbering_global_new2old[eN_global_new];
501 for (int ebN_element = 0; ebN_element < mesh.nElementBoundaries_element; ebN_element++)
502 {
503 int ebN_global_old = mesh.elementBoundariesArray[eN_global_old*mesh.nElementBoundaries_element+ebN_element];
504 int ebN_subdomain = mesh.subdomainp->elementBoundariesArray[eN*mesh.nElementBoundaries_element+ebN_element];
505 mesh.subdomainp->elementBoundaryMaterialTypes[ebN_subdomain] = mesh.elementBoundaryMaterialTypes[ebN_global_old];
506 }
507 }
508 }
509 //now we've got the old mesh in the old ordering and the subdomain mesh in the new ordering
510 //the first chunk of nodes and elements are the owned elements so we need to know how many of those there are
511 //and the offset of the first one so we can compute subdomain2global
512 mesh.nodeOffsets_subdomain_owned = new int[size+1];
513 mesh.elementOffsets_subdomain_owned = new int[size+1];
514 for (int sdN=0;sdN<size+1;sdN++)
515 {
516 mesh.nodeOffsets_subdomain_owned[sdN] = nodeOffsets_new[sdN];
517 mesh.elementOffsets_subdomain_owned[sdN] = elementOffsets_new[sdN];
518 }
519 //we also need the subdomain 2 new global mappings
521 for (int nN=0;nN<mesh.subdomainp->nNodes_global;nN++)
522 mesh.nodeNumbering_subdomain2global[nN] = nodeNumbering_subdomain2global[nN];
524 for (int eN=0;eN<mesh.subdomainp->nElements_global;eN++)
525 mesh.elementNumbering_subdomain2global[eN] = elementNumbering_subdomain2global[eN];
526
527 ISRestoreIndices(elementNumberingIS_global_old2new,&elementNumbering_global_old2new);
528
529 ISDestroy(&elementPartitioningIS_new);
530 ISDestroy(&elementNumberingIS_subdomain_old2new);
531 ISDestroy(&elementNumberingIS_global_old2new);
532
533 ISRestoreIndices(nodeNumberingIS_global_new2old,&nodeNumbering_global_new2old);
534
535 ISDestroy(&nodeNumberingIS_new2old);
536 ISDestroy(&nodeNumberingIS_global_new2old);
537
538 return 0;
539}
540
541int partitionNodes(const MPI_Comm& PROTEUS_COMM_WORLD, Mesh& mesh, int nNodes_overlap)
542{
543 using namespace std;
544 int ierr,size,rank;
545
546 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);
547 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);
548 /***********************************************************************
549 partition domain based on nodes rather than elements, basically repeats
550 partitionElements with this one modification
551
552 right now generates equivalent of 1 layer of overlap regardless of input
553
554 1. Partition nodes in the default partition of contiguous chunks with
555 input ordering
556
557 2. Determine nodal connectivity on local processor
558
559 3. Generate new nodal partition using PETSc interface
560
561 4. Collect elements containing locally owned nodes and assign ownership
562
563 5. Generate global element numbering for new subdomain ownership
564
565 6. Create overlap (ghost) information for nodes and elements
566
567 7. March through additional layers of overlap if requested,
568
569 8. Build subdomain meshes in new numbering
570 ***********************************************************************/
571 //
572 //1. Build default nodal partition
573 //
574 //compute offsets to build processor (local) to global ordering for nodes
575 //in default partitioning
576 // printf("rank %d partitionNodes nNodes_global %d\n", rank, mesh.nNodes_global);
577 valarray<int> nodeOffsets_old(size+1);
578 nodeOffsets_old[0] = 0;
579 for (int sdN=0; sdN < size; sdN++)
580 {
581 nodeOffsets_old[sdN+1] = nodeOffsets_old[sdN] +
582 int(mesh.nNodes_global)/size + (int(mesh.nNodes_global)%size > sdN);
583 // printf("rank %d sdN %d nNodes_global %d nodeOffsets_old[%d] = %d\n", rank, sdN, mesh.nNodes_global, sdN+1, nodeOffsets_old[sdN+1]);
584 }
585 //
586 //2. Determine nodal connectivity on local processor, (local node star array)
587 //
588 int nNodes_subdomain = (nodeOffsets_old[rank+1] - nodeOffsets_old[rank]);
589 // printf("rank %d nNodes_subdomain %d\n", rank, nNodes_subdomain);
590 PetscInt *nodeNeighborsOffsets_subdomain,*nodeNeighbors_subdomain,*weights_subdomain;
591 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain+1),&nodeNeighborsOffsets_subdomain);
592 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain*mesh.max_nNodeNeighbors_node),&nodeNeighbors_subdomain);
593 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain*mesh.max_nNodeNeighbors_node),&weights_subdomain);
594 nodeNeighborsOffsets_subdomain[0] = 0;
595 for (int nN = 0,offset=0; nN < nNodes_subdomain; nN++)
596 {
597 int nN_global = nodeOffsets_old[rank] + nN;
598 // printf("rank %d nN %d nodeOffsets_old[rank] %d nNodes_subdomain %d nN_global = %d nodeStarOffset = %d\n", rank, nN, nodeOffsets_old[rank], nNodes_subdomain, nN_global, mesh.nodeStarOffsets[nN_global]);
599 for (int offset_global = mesh.nodeStarOffsets[nN_global];
600 offset_global < mesh.nodeStarOffsets[nN_global+1]; offset_global++)
601 {
602 nodeNeighbors_subdomain[offset++] = mesh.nodeStarArray[offset_global];
603 // printf("rank %d nN %d offset_global %d mesh.nodeStarOffsets[nN_global+1] %d nodeNeighbors_subdomain[offset++] = %d mesh.nodeStarArray[offset_global]\n", rank, nN, offset_global, mesh.nodeStarOffsets[nN_global+1], nodeNeighbors_subdomain[offset++], mesh.nodeStarArray[offset_global]);
604 }
605 nodeNeighborsOffsets_subdomain[nN+1]=offset;
606 sort(&nodeNeighbors_subdomain[nodeNeighborsOffsets_subdomain[nN]],&nodeNeighbors_subdomain[nodeNeighborsOffsets_subdomain[nN+1]]);
607 int weight= (nodeNeighborsOffsets_subdomain[nN+1] - nodeNeighborsOffsets_subdomain[nN]);
608 for (int k=nodeNeighborsOffsets_subdomain[nN];k<nodeNeighborsOffsets_subdomain[nN+1];k++)
609 weights_subdomain[k] = weight;
610 // printf("rank %d nodeNeighborsOffsets_subdomain[0] = %d\n", rank, nodeNeighborsOffsets_subdomain[0]);
611 }
612 //
613 //3. Generate new nodal partition using PETSc interface
614 //
615 Mat petscAdjacency;
616 // MatCreateMPIAdj(PROTEUS_COMM_WORLD,
617 // nNodes_subdomain, mesh.nNodes_global,
618 // &nodeNeighborsOffsets_subdomain[0], &nodeNeighbors_subdomain[0],
619 // &weights_subdomain[0],//PETSC_NULL,//ignore weighting for now
620 // &petscAdjacency);
621 ierr = MatCreateMPIAdj(PROTEUS_COMM_WORLD,
622 nNodes_subdomain,
623 mesh.nNodes_global,
624 nodeNeighborsOffsets_subdomain,
625 nodeNeighbors_subdomain,
626 PETSC_NULL,//weights_subdomain,
627 &petscAdjacency);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
628 MatPartitioning petscPartition;
629 MatPartitioningCreate(PROTEUS_COMM_WORLD,&petscPartition);
630 MatPartitioningSetAdjacency(petscPartition,petscAdjacency);
631 MatPartitioningSetFromOptions(petscPartition);
632
633 //get petsc index set that has the new subdomain number for each node
634 IS nodePartitioningIS_new;
635 MatPartitioningApply(petscPartition,&nodePartitioningIS_new);
636 MatPartitioningDestroy(&petscPartition); //gets petscAdjacency too I believe
637
638 //determine the number of nodes per subdomain in new partitioning
639 valarray<int> nNodes_subdomain_new(size);
640 ISPartitioningCount(nodePartitioningIS_new,size,&nNodes_subdomain_new[0]);
641
642 //need new offsets for subdomain to global numbering
643 valarray<int> nodeOffsets_new(size+1);
644 nodeOffsets_new[0] = 0;
645 for (int sdN = 0; sdN < size; sdN++)
646 nodeOffsets_new[sdN+1] = nodeOffsets_new[sdN] + nNodes_subdomain_new[sdN];
647
648 //get the new node numbers for nodes on this subdomain
649 IS nodeNumberingIS_subdomain_old2new;
650 ISPartitioningToNumbering(nodePartitioningIS_new,&nodeNumberingIS_subdomain_old2new);
651
652 //collect new node numbers for whole mesh so that subdomain reordering and renumbering
653 //can be done easily
654
655 IS nodeNumberingIS_global_old2new;
656 ISAllGather(nodeNumberingIS_subdomain_old2new,&nodeNumberingIS_global_old2new);
657 //mwf original and correct I believe
658 const PetscInt * nodeNumbering_global_old2new;//needs restore call
659 ISGetIndices(nodeNumberingIS_global_old2new,&nodeNumbering_global_old2new);
660
661 //reverse mapping for node numbers as well
662 valarray<int> nodeNumbering_global_new2old(mesh.nNodes_global);
663 for (int nN = 0; nN < mesh.nNodes_global; nN++)
664 nodeNumbering_global_new2old[nodeNumbering_global_old2new[nN]] = nN;
665
666 // //mwf debug
667 // if (rank == 0)
668 // {
669 // for (int sdN = 0; sdN < size+1; sdN++)
670 // std::cout<<"partitionNodes rank= "<<rank<<" nodeOffset["<<sdN<<"]= "<<nodeOffsets_new[sdN]<<std::endl;
671 // for (int nN = 0; nN < mesh.nNodes_global; nN++)
672 // {
673 // std::cout<<"partitionNodes rank= "<<rank<<" nN= "<<nN<<" old2new= "<<nodeNumbering_global_old2new[nN]<<" new2old= "<<nodeNumbering_global_new2old[nN]<<std::endl;
674 // }
675 // for (int sdN = 0; sdN < size; sdN++)
676 // {
677 // std::cout<<"============"<<std::endl;
678 // std::cout<<"partitionNodes rank= "<<sdN<<" nNodes_owned= "<<nodeOffsets_new[sdN+1]-nodeOffsets_new[sdN]<<" = "<<std::endl;
679 // for (int nN = nodeOffsets_new[sdN]; nN < nodeOffsets_new[sdN+1]; nN++)
680 // {
681 // std::cout<<"new number= "<<nN<<" <--> old number "<<nodeNumbering_global_new2old[nN]<<" x,y,z= "
682 // <<mesh.nodeArray[nodeNumbering_global_new2old[nN]*3+0]<<" , "
683 // <<mesh.nodeArray[nodeNumbering_global_new2old[nN]*3+1]<<" , "
684 // <<mesh.nodeArray[nodeNumbering_global_new2old[nN]*3+2]<<std::endl;
685 // }
686 // }
687
688 // }
689 //
690 //4. To build subdomain meshes, go through and collect elements containing
691 // the locally owned nodes. Assign processor ownership of elements
692 //
693 MPI_Status status;
694 PetscBT elementMask;
695 PetscBTCreate(mesh.nElements_global,&elementMask);
696 //get the owned element information
697 if (rank > 0)
698 {
699 MPI_Recv(elementMask,PetscBTLength(mesh.nElements_global),MPI_CHAR,rank-1,0,PROTEUS_COMM_WORLD,&status);
700 }
701 //mark the unmarked elements on this subdomain and store element numbers (in old numbering)
702 set<int> elements_subdomain_owned;
703 for (int nN = nodeOffsets_new[rank]; nN < nodeOffsets_new[rank+1]; nN++)
704 {
705 int nN_global_old = nodeNumbering_global_new2old[nN];
706 for (int eN_star_offset = mesh.nodeElementOffsets[nN_global_old];
707 eN_star_offset < mesh.nodeElementOffsets[nN_global_old+1]; eN_star_offset++)
708 {
709 int eN_star_old = mesh.nodeElementsArray[eN_star_offset];
710 if (!PetscBTLookupSet(elementMask,eN_star_old))
711 {
712 elements_subdomain_owned.insert(eN_star_old);
713 }
714 }
715 }
716 //mwf debug
717 // for (int nN = nodeOffsets_new[rank]; nN < nodeOffsets_new[rank+1]; nN++)
718 // {
719 // int nN_global_old = nodeNumbering_global_new2old[nN];
720 // int nElements_owned_nN =0;
721 // for (int eN_star_offset = mesh.nodeElementOffsets[nN_global_old];
722 // eN_star_offset < mesh.nodeElementOffsets[nN_global_old+1]; eN_star_offset++)
723 // {
724 // int eN_star_old = mesh.nodeElementsArray[eN_star_offset];
725 // if (elements_subdomain_owned.find(eN_star_old) != elements_subdomain_owned.end())
726 // nElements_owned_nN++;
727 // }
728
729 // if (nElements_owned_nN <= 0)
730 // {
731 // std::cout<<"Problem? proc "<<rank<<" nN_new = "<<nN<<" nN_old= "<<nN_global_old<<" nElements_owned_for_nN = "<<nElements_owned_nN<<std::endl;
732 // //find out processor owners for node neighbors
733 // for (int offset = mesh.nodeStarOffsets[nN_global_old]; offset < mesh.nodeStarOffsets[nN_global_old+1]; offset++)
734 // {
735 // int nN_neig_old = mesh.nodeStarArray[offset];
736 // std::cout<<"\t neig node old "<<nN_neig_old<<" neig node new "<<nodeNumbering_global_old2new[nN_neig_old]<<" this proc offsets= ["
737 // <<nodeOffsets_new[rank]<<","<<nodeOffsets_new[rank+1]<<"];"<<std::endl;
738 // }
739 // }
740 // }
741 //pass off newly marked info
742 if (rank < size-1)
743 MPI_Send(elementMask,PetscBTLength(mesh.nElements_global),MPI_CHAR,rank+1,0,PROTEUS_COMM_WORLD);
744 ierr = PetscBTDestroy(&elementMask);
745 if (ierr)
746 cerr<<"Error in PetscBTDestroy"<<endl;
747
748 //
749 //5. Generate global element numbering corresponding to new subdomain ownership
750 //
751 valarray<int> nElements_subdomain_new(size),
752 elementOffsets_new(size+1);
753 for (int sdN = 0; sdN < size; sdN++)
754 {
755 if (sdN == rank)
756 nElements_subdomain_new[sdN] = int(elements_subdomain_owned.size());
757 else
758 nElements_subdomain_new[sdN] = 0;
759 }
760 valarray<int> nElements_subdomain_new_send = nElements_subdomain_new;
761 MPI_Allreduce(&nElements_subdomain_new_send[0],&nElements_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
762 //new size info
763 elementOffsets_new[0] = 0;
764 for (int sdN = 0; sdN < size; sdN++)
765 elementOffsets_new[sdN+1] = elementOffsets_new[sdN] + nElements_subdomain_new[sdN];
766
767 //map to old element numbering
768 valarray<int> elementNumbering_subdomain_new2old(elements_subdomain_owned.size());
769 set<int>::iterator eN_ownedp = elements_subdomain_owned.begin();
770 for (int eN = 0; eN < int(elements_subdomain_owned.size()); eN++)
771 {
772 elementNumbering_subdomain_new2old[eN] = *eN_ownedp++;
773 }
774 //use Petsc IS to get global new2old numbering
775 IS elementNumberingIS_subdomain_new2old;
776 ISCreateGeneral(PROTEUS_COMM_WORLD,elements_subdomain_owned.size(),&elementNumbering_subdomain_new2old[0],PETSC_COPY_VALUES,
777 &elementNumberingIS_subdomain_new2old);
778 IS elementNumberingIS_global_new2old;
779 ISAllGather(elementNumberingIS_subdomain_new2old,&elementNumberingIS_global_new2old);
780
781 const PetscInt *elementNumbering_global_new2old;//needs to be restored
782 ISGetIndices(elementNumberingIS_global_new2old,&elementNumbering_global_new2old);
783 //reverse mapping
784 valarray<int> elementNumbering_global_old2new(mesh.nElements_global);
785 for (int eN = 0; eN < mesh.nElements_global; eN++)
786 {
787 elementNumbering_global_old2new[elementNumbering_global_new2old[eN]] = eN;
788 }
789
790
791
792 //4b,5b. repeat process to build global face numbering
793 //first get element --> element boundaries array for new element but old element boundary numbering
794 valarray<int> elementBoundariesArray_new(mesh.nElements_global*mesh.nElementBoundaries_element);
795 for (int eN=0; eN < mesh.nElements_global; eN++)
796 for (int ebN=0; ebN < mesh.nElementBoundaries_element; ebN++)
797 {
798 elementBoundariesArray_new[eN*mesh.nElementBoundaries_element+ebN] =
799 mesh.elementBoundariesArray[elementNumbering_global_new2old[eN]*mesh.nElementBoundaries_element+ebN];
800 // printf("rank %d eN %d ebN %d elementBoundariesArray_new[%d] = %d\n", rank, eN, ebN, eN*mesh.nElementBoundaries_element+ebN, elementBoundariesArray_new[eN*mesh.nElementBoundaries_element+ebN]);
801 }
802 MPI_Status status_elementBoundaries;
803 PetscBT elementBoundaryMask;
804 PetscBTCreate(mesh.nElementBoundaries_global,&elementBoundaryMask);
805 if (rank > 0)
806 {
807 MPI_Recv(elementBoundaryMask,PetscBTLength(mesh.nElementBoundaries_global),MPI_CHAR,rank-1,0,PROTEUS_COMM_WORLD,&status_elementBoundaries);
808 }
809 //mark the unmarked faces on this subdomain and store the global face numbers
810 //going through owned elements can pick up owned elementBoundaries on "outside" of owned nodes nodeStars
811 set<int> elementBoundaries_subdomain_owned;
812 if (mesh.nNodes_element == 8)
813 {
814
815 int lface[6][4] = {{0,1,2,3},
816 {0,1,5,4},
817 {1,2,6,5},
818 {2,3,7,6},
819 {3,0,4,7},
820 {4,5,6,7}};
821
822 for (int nN = nodeOffsets_new[rank]; nN < nodeOffsets_new[rank+1]; nN++)
823 {
824 int nN_global_old = nodeNumbering_global_new2old[nN];
825 //now get elements in node star
826 for (int offset_old = mesh.nodeElementOffsets[nN_global_old];
827 offset_old < mesh.nodeElementOffsets[nN_global_old+1]; offset_old++)
828 {
829 int eN_star_old = mesh.nodeElementsArray[offset_old];
830 int eN_star_new = elementNumbering_global_old2new[eN_star_old];
831
832 //loop through element boundaries on each element, want but want to skip
833 //the element boundary across from the owned node
834 for (int ebN=0; ebN<mesh.nElementBoundaries_element;ebN++)
835 {
836 bool foundNode = false;
837 for (int nNl=0; nNl<mesh.nNodes_elementBoundary ;nNl++)
838 {
839 int nN_global_old_across = mesh.elementNodesArray[eN_star_old*mesh.nNodes_element + lface[ebN][nNl]];
840 if (nN_global_old_across == nN_global_old) foundNode = true;
841 }
842 if (foundNode)
843 {
844 int ebN_global=elementBoundariesArray_new[eN_star_new*mesh.nElementBoundaries_element+ebN];
845 if (!PetscBTLookupSet(elementBoundaryMask,ebN_global))
846 elementBoundaries_subdomain_owned.insert(ebN_global);
847 }
848 }
849
850 }
851 }
852
853 }
854 else
855 {
856 for (int nN = nodeOffsets_new[rank]; nN < nodeOffsets_new[rank+1]; nN++)
857 {
858 int nN_global_old = nodeNumbering_global_new2old[nN];
859 //now get elements in node star
860 for (int offset_old = mesh.nodeElementOffsets[nN_global_old];
861 offset_old < mesh.nodeElementOffsets[nN_global_old+1]; offset_old++)
862 {
863 int eN_star_old = mesh.nodeElementsArray[offset_old];
864 int eN_star_new = elementNumbering_global_old2new[eN_star_old];
865
866 //loop through element boundaries on each element, want but want to skip
867 //the element boundary across from the owned node
868 for (int ebN=0; ebN<mesh.nElementBoundaries_element;ebN++)
869 {
870 int nN_global_old_across = mesh.elementNodesArray[eN_star_old*mesh.nNodes_element+ebN];
871 if (nN_global_old_across != nN_global_old)
872 {
873 int ebN_global=elementBoundariesArray_new[eN_star_new*mesh.nElementBoundaries_element+ebN];
874 if (!PetscBTLookupSet(elementBoundaryMask,ebN_global))
875 elementBoundaries_subdomain_owned.insert(ebN_global);
876 }
877 }
878 }
879 }
880 }
881
882 //ship off the mask
883 if (rank < size-1)
884 MPI_Send(elementBoundaryMask,PetscBTLength(mesh.nElementBoundaries_global),MPI_CHAR,rank+1,0,PROTEUS_COMM_WORLD);
885 ierr = PetscBTDestroy(&elementBoundaryMask);
886 if (ierr)
887 cerr<<"Error in PetscBTDestroy for elementBoundaries"<<endl;
888 //get the number of elementBoundaries on each processor
889 valarray<int> nElementBoundaries_subdomain_new(size),
890 elementBoundaryOffsets_new(size+1);
891 for (int sdN=0;sdN<size;sdN++)
892 if (sdN == rank)
893 nElementBoundaries_subdomain_new[sdN] = elementBoundaries_subdomain_owned.size();
894 else
895 nElementBoundaries_subdomain_new[sdN] = 0;
896 valarray<int> nElementBoundaries_subdomain_new_send=nElementBoundaries_subdomain_new;
897 MPI_Allreduce(&nElementBoundaries_subdomain_new_send[0],&nElementBoundaries_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
898 elementBoundaryOffsets_new[0] = 0;
899 for (int sdN=0;sdN<size;sdN++)
900 elementBoundaryOffsets_new[sdN+1] = elementBoundaryOffsets_new[sdN]+nElementBoundaries_subdomain_new[sdN];
901 //Now as with elements and nodes build a global face numbering
902 //resetting the face based information is a little different since much of this is currently built below based
903 //on the element and node information
904 //
905 valarray<int> elementBoundaryNumbering_new2old(elementBoundaries_subdomain_owned.size());
906 set<int>::iterator ebN_ownedp=elementBoundaries_subdomain_owned.begin();
907 for (int ebN=0;ebN<int(elementBoundaries_subdomain_owned.size());ebN++)
908 {
909 elementBoundaryNumbering_new2old[ebN] = *ebN_ownedp++;
910 }
911 IS elementBoundaryNumberingIS_subdomain_new2old;
912 ISCreateGeneral(PROTEUS_COMM_WORLD,elementBoundaries_subdomain_owned.size(),&elementBoundaryNumbering_new2old[0],PETSC_COPY_VALUES,&elementBoundaryNumberingIS_subdomain_new2old);
913 IS elementBoundaryNumberingIS_global_new2old;
914 ISAllGather(elementBoundaryNumberingIS_subdomain_new2old,&elementBoundaryNumberingIS_global_new2old);
915 const PetscInt *elementBoundaryNumbering_global_new2old;
916 valarray<int> elementBoundaryNumbering_old2new_global(mesh.nElementBoundaries_global);
917 ISGetIndices(elementBoundaryNumberingIS_global_new2old,&elementBoundaryNumbering_global_new2old);
918 for (int ebN=0;ebN<mesh.nElementBoundaries_global;ebN++)
919 {
920 elementBoundaryNumbering_old2new_global[elementBoundaryNumbering_global_new2old[ebN]] = ebN;
921 // printf("rank %d ebN %d old ebN %d new ebN %d \n", rank, ebN, elementBoundaryNumbering_global_new2old[ebN], elementBoundaryNumbering_old2new_global[ebN]);
922 }
923 for (int eN=0;eN < mesh.nElements_global; eN++)
924 {
925 // printf("rank %d eN %d nElementBoundaries_element %d\n", rank, eN, mesh.nElementBoundaries_element);
926 int ebN_old;
927 for (int ebN=0;ebN < mesh.nElementBoundaries_element; ebN++)
928 {
929 ebN_old = elementBoundariesArray_new[eN*mesh.nElementBoundaries_element+ebN];
930 // printf("rank %d eN %d ebN %d old ebN %d elementBoundariesArray_new %d \n", rank, eN, ebN, ebN_old, elementBoundaryNumbering_old2new_global[ebN_old]);
931 elementBoundariesArray_new[eN*mesh.nElementBoundaries_element+ebN] = elementBoundaryNumbering_old2new_global[ebN_old];
932 }
933 }
934
935 //4c,5c. Build global edge numbering as well ownership is determined by who owns the left (0) node
936 // of the edge
937 map<NodeTuple<2>, int> nodesEdgeMap_global; //new global node numbers --> original edge numbering
938 set<int> edges_subdomain_owned;
939 for (int ig = 0; ig < mesh.nEdges_global; ig++)
940 {
941 const int nN0_global_old = mesh.edgeNodesArray[2*ig];
942 const int nN1_global_old = mesh.edgeNodesArray[2*ig+1];
943 const int nN0_global = nodeNumbering_global_old2new[nN0_global_old];
944 const int nN1_global = nodeNumbering_global_old2new[nN1_global_old];
945 int nodes[2];
946 nodes[0] = nN0_global;
947 nodes[1] = nN1_global;
948 NodeTuple<2> et(nodes);
949 nodesEdgeMap_global[et] = ig;
950 if (nodeOffsets_new[rank] <= et.nodes[0] && et.nodes[0] < nodeOffsets_new[rank+1])
951 edges_subdomain_owned.insert(ig);
952 }
953 valarray<int> nEdges_subdomain_new(size),
954 edgeOffsets_new(size+1);
955
956 for (int sdN=0; sdN < size; sdN++)
957 if (sdN == rank)
958 nEdges_subdomain_new[sdN] = edges_subdomain_owned.size();
959 else
960 nEdges_subdomain_new[sdN] = 0;
961 //collect ownership info
962 valarray<int> nEdges_subdomain_new_send=nEdges_subdomain_new;
963 MPI_Allreduce(&nEdges_subdomain_new_send[0],&nEdges_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
964 edgeOffsets_new[0] = 0;
965 for (int sdN=0;sdN<size;sdN++)
966 edgeOffsets_new[sdN+1] = edgeOffsets_new[sdN]+nEdges_subdomain_new[sdN];
967
968 //build new petsc numbering and global maps from old2new and new2old
969 valarray<int> edgeNumbering_new2old(edges_subdomain_owned.size());
970 set<int>::iterator edges_ownedp = edges_subdomain_owned.begin();
971 for (int i=0; i < int(edges_subdomain_owned.size());i++)
972 edgeNumbering_new2old[i] = *edges_ownedp++;
973
974 IS edgeNumberingIS_subdomain_new2old;
975 ISCreateGeneral(PROTEUS_COMM_WORLD,edges_subdomain_owned.size(),&edgeNumbering_new2old[0],PETSC_COPY_VALUES,&edgeNumberingIS_subdomain_new2old);
976 IS edgeNumberingIS_global_new2old;
977 ISAllGather(edgeNumberingIS_subdomain_new2old,&edgeNumberingIS_global_new2old);
978 const PetscInt *edgeNumbering_global_new2old;
979 valarray<int> edgeNumbering_old2new_global(mesh.nEdges_global);
980 ISGetIndices(edgeNumberingIS_global_new2old,&edgeNumbering_global_new2old);
981 for (int ig=0;ig<mesh.nEdges_global;ig++)
982 {
983 edgeNumbering_old2new_global[edgeNumbering_global_new2old[ig]] = ig;
984 }
985
986 //create array with (new edge) --> (new node 0, new node 1)
987 //and map from (new node 0, new node 1) --> (new global edge)
988 valarray<int> edgeNodesArray_newNodesAndEdges(2*mesh.nEdges_global);
989 map<NodeTuple<2>, int > nodesEdgeMap_global_new;
990 for (int ig = 0; ig < mesh.nEdges_global; ig++)
991 {
992 const int nN0_global_old = mesh.edgeNodesArray[2*ig];
993 const int nN1_global_old = mesh.edgeNodesArray[2*ig+1];
994 const int nN0_global = nodeNumbering_global_old2new[nN0_global_old];
995 const int nN1_global = nodeNumbering_global_old2new[nN1_global_old];
996
997 const int edge_new = edgeNumbering_old2new_global[ig];
998 edgeNodesArray_newNodesAndEdges[edge_new*2+0] = nN0_global;
999 edgeNodesArray_newNodesAndEdges[edge_new*2+1] = nN1_global;
1000 int nodes[2];
1001 nodes[0] = nN0_global;
1002 nodes[1] = nN1_global;
1003 NodeTuple<2> et(nodes);
1004 nodesEdgeMap_global_new[et] = edge_new;
1005 }
1006
1007
1008
1009
1010
1011
1012 //
1013 //6. Figure out which elements are in node stars but are not locally owned, create ghost information
1014 // for these, do the same for elements
1015 set<int> elements_overlap,nodes_overlap,elementBoundaries_overlap,edges_overlap;
1016 for (int nN = nodeOffsets_new[rank]; nN < nodeOffsets_new[rank+1]; nN++)
1017 {
1018 int nN_global_old = nodeNumbering_global_new2old[nN];
1019 //nodes in node star
1020 for (int offset_old = mesh.nodeStarOffsets[nN_global_old];
1021 offset_old < mesh.nodeStarOffsets[nN_global_old+1]; offset_old++)
1022 {
1023 int nN_neig_old = mesh.nodeStarArray[offset_old];
1024 int nN_neig_new = nodeNumbering_global_old2new[nN_neig_old];
1025
1026 bool offproc = nN_neig_new >= nodeOffsets_new[rank+1] || nN_neig_new < nodeOffsets_new[rank];
1027 if (offproc)
1028 nodes_overlap.insert(nN_neig_new);
1029 }
1030 //now get elements, elementBoundaries, and edges in node star
1031 for (int offset_old = mesh.nodeElementOffsets[nN_global_old];
1032 offset_old < mesh.nodeElementOffsets[nN_global_old+1]; offset_old++)
1033 {
1034 int eN_star_old = mesh.nodeElementsArray[offset_old];
1035 int eN_star_new = elementNumbering_global_old2new[eN_star_old];
1036 bool offproc = eN_star_new >= elementOffsets_new[rank+1] || eN_star_new < elementOffsets_new[rank];
1037 if (offproc)
1038 elements_overlap.insert(eN_star_new);
1039 for (int ebN=0; ebN<mesh.nElementBoundaries_element;ebN++)
1040 {
1041 int ebN_global=elementBoundariesArray_new[eN_star_new*mesh.nElementBoundaries_element+ebN];
1042 // //mwf debug
1043 // std::cout<<"partitionNode default overlap rank= "<<rank<<" nN_new= "<<nN<<" eN_star_new= "<<eN_star_new<<" ebN= "<<ebN
1044 // <<" ebN_global= "<<ebN_global<<" ghost= "<<(ebN_global < elementBoundaryOffsets_new[rank] || ebN_global >= elementBoundaryOffsets_new[rank+1])
1045 // <<" offsets= ["<<elementBoundaryOffsets_new[rank]<<","<<elementBoundaryOffsets_new[rank+1]<<"]"<<std::endl;
1046 if (ebN_global < elementBoundaryOffsets_new[rank] || ebN_global >= elementBoundaryOffsets_new[rank+1])
1047 {
1048 elementBoundaries_overlap.insert(ebN_global);
1049 }
1050 }
1051 for (int nN0=0;nN0<mesh.nNodes_element;nN0++)
1052 for (int nN1=nN0+1; nN1<mesh.nNodes_element;nN1++)
1053 {
1054 const int nN0_global_old = mesh.elementNodesArray[eN_star_old*mesh.nNodes_element+nN0];
1055 const int nN1_global_old = mesh.elementNodesArray[eN_star_old*mesh.nNodes_element+nN1];
1056 const int nN0_global = nodeNumbering_global_old2new[nN0_global_old];
1057 const int nN1_global = nodeNumbering_global_old2new[nN1_global_old];
1058 bool foundEdge = false;
1059 int nodes[2];
1060 nodes[0] = nN0_global;
1061 nodes[1] = nN1_global;
1062 NodeTuple<2> et(nodes);
1063 const int edge_global = nodesEdgeMap_global_new[et];
1064 if (edge_global < edgeOffsets_new[rank] || edge_global >= edgeOffsets_new[rank+1])
1065 edges_overlap.insert(edge_global);
1066 }//edges
1067 }//elements in node star
1068 }//nodes on this processor
1069
1070 //
1071 //7. If we want more layers of overlap, do we have to build connectivity info in new numbering then march out
1072 // or can we just march through nodes in node_overlap and grab all of their elements that aren't owned?
1073 //
1074 int overlap_remaining = nNodes_overlap -1; //default gives 1 layer overlap
1075 //last set of overlap nodes added
1076 set<int> last_nodes_added2overlap = nodes_overlap;
1077 while (overlap_remaining > 0)
1078 {
1079 set<int> new_nodes_overlap,new_elements_overlap,new_elementBoundaries_overlap,new_edges_overlap;
1080 set<int>::iterator nN_p = last_nodes_added2overlap.begin();
1081 while (nN_p != last_nodes_added2overlap.end())
1082 {
1083 int nN_global_new = *nN_p;
1084 int nN_global_old = nodeNumbering_global_new2old[nN_global_new];//need old numbering for connectivity
1085 for (int offset_old = mesh.nodeStarOffsets[nN_global_old];
1086 offset_old < mesh.nodeStarOffsets[nN_global_old+1]; offset_old++)
1087 {
1088 int nN_neig_old = mesh.nodeStarArray[offset_old];
1089 int nN_neig_new = nodeNumbering_global_old2new[nN_neig_old];
1090 //just need to check if neighbor is offprocessor, may already be in overlap
1091 //but set merge will take care of that
1092 bool offproc = nN_neig_new >= nodeOffsets_new[rank+1] || nN_neig_new < nodeOffsets_new[rank];
1093 if (offproc)
1094 new_nodes_overlap.insert(nN_neig_new);
1095 }//node neighbor loop
1096 nN_p++;
1097 }//loop adding new nodes
1098
1099 //loop through added nodes, grab elements only check if not on processor
1100 set<int>::iterator nN_newp = last_nodes_added2overlap.begin();
1101 while (nN_newp != last_nodes_added2overlap.end())
1102 {
1103 int nN_global_new = *nN_newp;
1104 int nN_global_old = nodeNumbering_global_new2old[nN_global_new];//need old numbering for connectivity
1105 for (int offset_old = mesh.nodeElementOffsets[nN_global_old];
1106 offset_old < mesh.nodeElementOffsets[nN_global_old+1]; offset_old++)
1107 {
1108 int eN_star_old = mesh.nodeElementsArray[offset_old];
1109 int eN_star_new = elementNumbering_global_old2new[eN_star_old];
1110 bool offproc = eN_star_new >= elementOffsets_new[rank+1] || eN_star_new < elementOffsets_new[rank];
1111 if (offproc)
1112 new_elements_overlap.insert(eN_star_new);
1113 //element boundaries too
1114 for (int ebN=0; ebN<mesh.nElementBoundaries_element;ebN++)
1115 {
1116 int ebN_global=elementBoundariesArray_new[eN_star_new*mesh.nElementBoundaries_element+ebN];
1117 // //mwf debug
1118 // std::cout<<"partitionNode overlap_remaining= "<<overlap_remaining<<" rank= "<<rank<<" nN_global_new= "<<nN_global_new<<" eN_star_new= "<<eN_star_new<<" ebN= "<<ebN
1119 // <<" ebN_global= "<<ebN_global<<" ghost= "<<(ebN_global < elementBoundaryOffsets_new[rank] || ebN_global >= elementBoundaryOffsets_new[rank+1])
1120 // <<" offsets= ["<<elementBoundaryOffsets_new[rank]<<","<<elementBoundaryOffsets_new[rank+1]<<std::endl;
1121 if (ebN_global < elementBoundaryOffsets_new[rank] || ebN_global >= elementBoundaryOffsets_new[rank+1])
1122 new_elementBoundaries_overlap.insert(ebN_global);
1123 }//element boundaries
1124 //edges
1125 for (int nN0=0;nN0<mesh.nNodes_element;nN0++)
1126 for (int nN1=nN0+1; nN1<mesh.nNodes_element;nN1++)
1127 {
1128 const int nN0_global_old = mesh.elementNodesArray[eN_star_old*mesh.nNodes_element+nN0];
1129 const int nN1_global_old = mesh.elementNodesArray[eN_star_old*mesh.nNodes_element+nN1];
1130 const int nN0_global = nodeNumbering_global_old2new[nN0_global_old];
1131 const int nN1_global = nodeNumbering_global_old2new[nN1_global_old];
1132 bool foundEdge = false;
1133 int nodes[2];
1134 nodes[0] = nN0_global;
1135 nodes[1] = nN1_global;
1136 NodeTuple<2> et(nodes);
1137 const int edge_global = nodesEdgeMap_global_new[et];
1138 if (edge_global < edgeOffsets_new[rank] || edge_global >= edgeOffsets_new[rank+1])
1139 new_edges_overlap.insert(edge_global);
1140 }//edges
1141 }//elements in node star
1142 nN_newp++;
1143 }//new nodes
1144 last_nodes_added2overlap.clear();
1145 set_difference(new_nodes_overlap.begin(),new_nodes_overlap.end(),
1146 nodes_overlap.begin(),nodes_overlap.end(),
1147 std::inserter(last_nodes_added2overlap,last_nodes_added2overlap.begin()));
1148
1149 //could do a set_merge
1150 for (set<int>::iterator nN_addedp = new_nodes_overlap.begin();
1151 nN_addedp != new_nodes_overlap.end();
1152 nN_addedp++)
1153 {
1154 nodes_overlap.insert(*nN_addedp);
1155 }
1156 for (set<int>::iterator eN_addedp = new_elements_overlap.begin();
1157 eN_addedp != new_elements_overlap.end();
1158 eN_addedp++)
1159 {
1160 elements_overlap.insert(*eN_addedp);
1161 }
1162 for (set<int>::iterator ebN_addedp = new_elementBoundaries_overlap.begin();
1163 ebN_addedp != new_elementBoundaries_overlap.end();
1164 ebN_addedp++)
1165 {
1166 elementBoundaries_overlap.insert(*ebN_addedp);
1167 }
1168 for (set<int>::iterator edge_addedp = new_edges_overlap.begin();
1169 edge_addedp != new_edges_overlap.end();
1170 edge_addedp++)
1171 {
1172 edges_overlap.insert(*edge_addedp);
1173 }
1174 //example calls
1175
1176 overlap_remaining--;
1177 }//ovelap loop
1178
1179 //
1180 //8. Build subdomain meshes in new numbering, assumes memory not allocated in subdomain mesh
1181 //
1182 if (mesh.subdomainp == NULL)
1183 mesh.subdomainp = new Mesh();
1184 mesh.subdomainp->nElements_global = nElements_subdomain_new[rank] + elements_overlap.size();
1185 mesh.subdomainp->nNodes_global = nNodes_subdomain_new[rank] + nodes_overlap.size();
1186 mesh.subdomainp->nElementBoundaries_global = nElementBoundaries_subdomain_new[rank]+elementBoundaries_overlap.size();
1187 mesh.subdomainp->nEdges_global = nEdges_subdomain_new[rank]+edges_overlap.size();
1191 //subdomain 2 global mappings (including ghost info)
1192 valarray<int> nodeNumbering_subdomain2global(mesh.subdomainp->nNodes_global);
1193 valarray<int> elementNumbering_subdomain2global(mesh.subdomainp->nElements_global);
1194 valarray<int> elementBoundaryNumbering_subdomain2global(mesh.subdomainp->nElementBoundaries_global);
1195 valarray<int> edgeNumbering_subdomain2global(mesh.subdomainp->nEdges_global);
1196 map<int,int> nodeNumbering_global2subdomain;
1197 map<int,int> elementBoundaryNumbering_global2subdomain;
1198 mesh.subdomainp->nodeArray = new double[mesh.subdomainp->nNodes_global*3];
1200 //locally owned
1201 // printf("rank %d nNodes_subdomain_new = %d\n", rank, nNodes_subdomain_new[rank]);
1202 for (int nN = 0; nN < nNodes_subdomain_new[rank]; nN++)
1203 {
1204 int nN_global_new = nN + nodeOffsets_new[rank];
1205 int nN_global_old = nodeNumbering_global_new2old[nN_global_new];
1206 nodeNumbering_subdomain2global[nN] = nN_global_new;
1207 nodeNumbering_global2subdomain[nN_global_new] = nN;
1208 mesh.subdomainp->nodeArray[nN*3+0] = mesh.nodeArray[nN_global_old*3+0];
1209 mesh.subdomainp->nodeArray[nN*3+1] = mesh.nodeArray[nN_global_old*3+1];
1210 mesh.subdomainp->nodeArray[nN*3+2] = mesh.nodeArray[nN_global_old*3+2];
1211 // printf("rank %d nN %d nN_global_new %d nN_global_old %d nodeArray[%d] = (%f,%f,%f) nodeMaterialTypes[%d] = %d\n",
1212 // rank, nN, nN_global_new, nN_global_old, nN*3,
1213 // mesh.subdomainp->nodeArray[nN*3+0],
1214 // mesh.subdomainp->nodeArray[nN*3+1],
1215 // mesh.subdomainp->nodeArray[nN*3+2],
1216 // mesh.subdomainp->nodeMaterialTypes[nN]);
1217
1218 mesh.subdomainp->nodeMaterialTypes[nN] = mesh.nodeMaterialTypes[nN_global_old];
1219 }
1220 //printf("Hello 10\n");
1221 //ghost
1222 //note: sets in C++ are sorted so the overlap is laid out in
1223 //contiguous chunks corresponding to the partitions
1224 set<int>::iterator nN_p = nodes_overlap.begin();
1225 for (int nN = nNodes_subdomain_new[rank]; nN < nNodes_subdomain_new[rank] + int(nodes_overlap.size()); nN++)
1226 {
1227 int nN_global_new = *nN_p++;
1228 int nN_global_old = nodeNumbering_global_new2old[nN_global_new];
1229 nodeNumbering_subdomain2global[nN] = nN_global_new;
1230 nodeNumbering_global2subdomain[nN_global_new] = nN;
1231 mesh.subdomainp->nodeArray[nN*3+0] = mesh.nodeArray[nN_global_old*3+0];
1232 mesh.subdomainp->nodeArray[nN*3+1] = mesh.nodeArray[nN_global_old*3+1];
1233 mesh.subdomainp->nodeArray[nN*3+2] = mesh.nodeArray[nN_global_old*3+2];
1234 mesh.subdomainp->nodeMaterialTypes[nN] = mesh.nodeMaterialTypes[nN_global_old];
1235 }
1238 //locally owned
1239 for (int eN = 0; eN < nElements_subdomain_new[rank]; eN++)
1240 {
1241 int eN_global_new = elementOffsets_new[rank] + eN;
1242 int eN_global_old = elementNumbering_global_new2old[eN_global_new];
1243 elementNumbering_subdomain2global[eN] = eN_global_new;
1244 mesh.subdomainp->elementMaterialTypes[eN] = mesh.elementMaterialTypes[eN_global_old];
1245 for (int nN = 0; nN < mesh.subdomainp->nNodes_element; nN++)
1246 {
1247 int nN_global_old = mesh.elementNodesArray[eN_global_old*mesh.nNodes_element + nN];
1248 int nN_global_new = nodeNumbering_global_old2new[nN_global_old];
1249 int nN_subdomain = nodeNumbering_global2subdomain[nN_global_new];
1250 mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN]= nN_subdomain;
1251 }
1252
1253 }
1254 //ghost
1255 set<int>::iterator eN_p = elements_overlap.begin();
1256 for (int eN = nElements_subdomain_new[rank]; eN < nElements_subdomain_new[rank] + int(elements_overlap.size()); eN++)
1257 {
1258 int eN_global_new = *eN_p++;
1259 int eN_global_old = elementNumbering_global_new2old[eN_global_new];
1260 elementNumbering_subdomain2global[eN] = eN_global_new;
1261 mesh.subdomainp->elementMaterialTypes[eN] = mesh.elementMaterialTypes[eN_global_old];
1262 for (int nN = 0; nN < mesh.subdomainp->nNodes_element; nN++)
1263 {
1264 int nN_global_old = mesh.elementNodesArray[eN_global_old*mesh.nNodes_element + nN];
1265 int nN_global_new = nodeNumbering_global_old2new[nN_global_old];
1266 int nN_subdomain = nodeNumbering_global2subdomain[nN_global_new];
1267 mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN]= nN_subdomain;
1268 }
1269 }
1270 //element boundaries
1271 //locally owned
1272 //printf("Hello 11\n");
1273 for (int ebN=0; ebN < nElementBoundaries_subdomain_new[rank]; ebN++)
1274 {
1275 int ebN_global = ebN + elementBoundaryOffsets_new[rank];
1276 elementBoundaryNumbering_subdomain2global[ebN]=ebN_global;
1277 elementBoundaryNumbering_global2subdomain[ebN_global] = ebN;
1278 }
1279 //ghost
1280 set<int>::iterator ebN_p = elementBoundaries_overlap.begin();
1281 for(int ebN=nElementBoundaries_subdomain_new[rank];ebN < nElementBoundaries_subdomain_new[rank] + int(elementBoundaries_overlap.size()); ebN++)
1282 {
1283 int ebN_global = *ebN_p++;
1284 elementBoundaryNumbering_subdomain2global[ebN] = ebN_global;
1285 elementBoundaryNumbering_global2subdomain[ebN_global] = ebN;
1286 }
1287 //need elementBoundariesArray to assign consistent numbering on subdomain
1290 for (int eN=0;eN<nElements_subdomain_new[rank];eN++)
1291 {
1292 int eN_global = eN+elementOffsets_new[rank];
1293 for (int ebN=0;ebN<mesh.subdomainp->nElementBoundaries_element;ebN++)
1295 elementBoundaryNumbering_global2subdomain[elementBoundariesArray_new[eN_global*mesh.nElementBoundaries_element + ebN]];
1296}
1297//ghost elements
1298set<int>::iterator eN_p2 = elements_overlap.begin();
1299for (int eN = nElements_subdomain_new[rank]; eN < nElements_subdomain_new[rank] + int(elements_overlap.size()); eN++)
1300{
1301 int eN_global_new = *eN_p2++;
1302 for (int ebN=0;ebN<mesh.subdomainp->nElementBoundaries_element;ebN++)
1303 {
1304 // printf("rank %d eN %d ebN %d eN_global_new %d ebN_global %d\n", rank, eN, ebN, eN_global_new, elementBoundariesArray_new[eN_global_new*mesh.nElementBoundaries_element + ebN]);
1306 elementBoundaryNumbering_global2subdomain[elementBoundariesArray_new[eN_global_new*mesh.nElementBoundaries_element + ebN]];
1307 }
1308
1309}
1310
1311//printf("Hello 12\n");
1312//edges
1313mesh.subdomainp->edgeNodesArray = new int[mesh.subdomainp->nEdges_global*2];
1314//locally owned
1315for (int i=0; i < nEdges_subdomain_new[rank]; i++)
1316{
1317 const int ig = i+edgeOffsets_new[rank];
1318 const int nN0_global = edgeNodesArray_newNodesAndEdges[ig*2+0];
1319 const int nN1_global = edgeNodesArray_newNodesAndEdges[ig*2+1];
1320 //mwf todo double check can always count on having nodes on this processor
1321 const int nN0_subdomain = nodeNumbering_global2subdomain[nN0_global];
1322 const int nN1_subdomain = nodeNumbering_global2subdomain[nN1_global];
1323 mesh.subdomainp->edgeNodesArray[2*i+0]=nN0_subdomain;
1324 mesh.subdomainp->edgeNodesArray[2*i+1]=nN1_subdomain;
1325 edgeNumbering_subdomain2global[i] = ig;
1326}
1327//ghost
1328set<int>::iterator edge_p = edges_overlap.begin();
1329for (int i=nEdges_subdomain_new[rank]; i < nEdges_subdomain_new[rank] + int(edges_overlap.size()); i++)
1330{
1331 const int ig =*edge_p++;
1332 const int nN0_global = edgeNodesArray_newNodesAndEdges[ig*2+0];
1333 const int nN1_global = edgeNodesArray_newNodesAndEdges[ig*2+1];
1334 //mwf todo make sure always have nodes for the edge on this processor
1335 const int nN0_subdomain = nodeNumbering_global2subdomain[nN0_global];
1336 const int nN1_subdomain = nodeNumbering_global2subdomain[nN1_global];
1337 mesh.subdomainp->edgeNodesArray[2*i+0]=nN0_subdomain;
1338 mesh.subdomainp->edgeNodesArray[2*i+1]=nN1_subdomain;
1339 edgeNumbering_subdomain2global[i] = ig;
1340
1341}
1342
1343//now build rest of subdomain mesh connectivity information etc
1344mesh.subdomainp->px = mesh.px;
1345mesh.subdomainp->py = mesh.py;
1346mesh.subdomainp->pz = mesh.pz;
1347
1348if (mesh.subdomainp->px != 0)
1349{
1350 //constructElementBoundaryElementsArray_tetrahedron(*mesh.subdomainp);
1351 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_tetrahedron(*mesh.subdomainp);
1355}
1356else if (mesh.subdomainp->nNodes_element == 2)
1357{
1358 //constructElementBoundaryElementsArray_edge(*mesh.subdomainp);
1359 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_edge(*mesh.subdomainp);
1363}
1364else if (mesh.subdomainp->nNodes_element == 3)
1365{
1366 //constructElementBoundaryElementsArray_triangle(*mesh.subdomainp);
1367 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_triangle(*mesh.subdomainp);
1371}
1372else if (mesh.subdomainp->nNodes_element == 4 && mesh.subdomainp->nNodes_elementBoundary == 2)
1373{
1374 //constructElementBoundaryElementsArray_tetrahedron(*mesh.subdomainp);
1375 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_tetrahedron(*mesh.subdomainp);
1379}
1380else if (mesh.subdomainp->nNodes_element == 4 && mesh.subdomainp->nNodes_elementBoundary == 3)
1381{
1382 //constructElementBoundaryElementsArray_tetrahedron(*mesh.subdomainp);
1383 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_tetrahedron(*mesh.subdomainp);
1387}
1388else if (mesh.subdomainp->nNodes_element == 8)
1389{
1393}
1394else
1395{
1396 assert(false);
1397}
1398
1399if (mesh.elementBoundaryMaterialTypes != NULL)
1400{
1401 assert(mesh.elementBoundariesArray != NULL);
1402 assert(mesh.subdomainp->elementBoundariesArray != NULL);
1403 for (int eN=0;eN<mesh.subdomainp->nElements_global;eN++)
1404 {
1405 int eN_global_new = elementNumbering_subdomain2global[eN];
1406 int eN_global_old = elementNumbering_global_new2old[eN_global_new];
1407 for (int ebN_element = 0; ebN_element < mesh.nElementBoundaries_element; ebN_element++)
1408 {
1409 int ebN_global_old = mesh.elementBoundariesArray[eN_global_old*mesh.nElementBoundaries_element+ebN_element];
1410 int ebN_subdomain = mesh.subdomainp->elementBoundariesArray[eN*mesh.nElementBoundaries_element+ebN_element];
1411 // printf("ebN_global_old = %d \t ebN_subdomain = %d \t elementBoundaryMaterialType = %d mesh.subdomainp->elementBoundaryMaterialTypes = %d\n",
1412 // ebN_global_old, ebN_subdomain, mesh.elementBoundaryMaterialTypes[ebN_global_old], mesh.subdomainp->elementBoundaryMaterialTypes[ebN_subdomain]);
1413 // printf("en = %d eN_global_new %d eN_global_old %d ebN_element %d ebN_global_old %d elementBoundariesArray = %d \n",eN,eN_global_new,eN_global_old,ebN_element,ebN_global_old, mesh.elementBoundariesArray[eN_global_old*mesh.nElementBoundaries_element+ebN_element]);
1414 // printf("rank %d eN %d eN_global_new %d eN_global_old %d ebN_element %d ebN_global_old %d ebN_subdomain %d elementBoundaryMaterialType = %d\n",
1415 // rank,eN,eN_global_new,eN_global_old,ebN_element,ebN_global_old,ebN_subdomain, mesh.elementBoundaryMaterialTypes[ebN_global_old]);
1416 mesh.subdomainp->elementBoundaryMaterialTypes[ebN_subdomain] = mesh.elementBoundaryMaterialTypes[ebN_global_old];
1417 }
1418 }
1419}
1420//transfer information about owned nodes and elements to mesh
1422delete [] mesh.nodeOffsets_subdomain_owned;
1424delete [] mesh.elementOffsets_subdomain_owned;
1428 delete [] mesh.edgeOffsets_subdomain_owned;
1429 mesh.nodeOffsets_subdomain_owned = new int[size+1];
1430 mesh.elementOffsets_subdomain_owned = new int[size+1];
1431 mesh.elementBoundaryOffsets_subdomain_owned = new int[size+1];
1432 mesh.edgeOffsets_subdomain_owned = new int[size+1];
1433 for (int sdN = 0; sdN < size+1; sdN++)
1434 {
1435 mesh.nodeOffsets_subdomain_owned[sdN] = nodeOffsets_new[sdN];
1436 mesh.elementOffsets_subdomain_owned[sdN] = elementOffsets_new[sdN];
1437 mesh.elementBoundaryOffsets_subdomain_owned[sdN] = elementBoundaryOffsets_new[sdN];
1438 mesh.edgeOffsets_subdomain_owned[sdN] = edgeOffsets_new[sdN];
1439 }
1441 delete [] mesh.nodeNumbering_subdomain2global;
1443 for (int nN = 0; nN < mesh.subdomainp->nNodes_global; nN++)
1444 mesh.nodeNumbering_subdomain2global[nN] = nodeNumbering_subdomain2global[nN];
1446 delete [] mesh.elementNumbering_subdomain2global;
1448 for (int eN = 0; eN < mesh.subdomainp->nElements_global; eN++)
1449 mesh.elementNumbering_subdomain2global[eN] = elementNumbering_subdomain2global[eN];
1450 //
1454 for (int ebN = 0; ebN < mesh.subdomainp->nElementBoundaries_global; ebN++)
1455 mesh.elementBoundaryNumbering_subdomain2global[ebN] = elementBoundaryNumbering_subdomain2global[ebN];
1456 //
1458 delete [] mesh.edgeNumbering_subdomain2global;
1460 for (int i=0; i< mesh.subdomainp->nEdges_global; i++)
1461 mesh.edgeNumbering_subdomain2global[i] = edgeNumbering_subdomain2global[i];
1462
1463 //cleanup
1464 ISRestoreIndices(nodeNumberingIS_global_old2new,&nodeNumbering_global_old2new);
1465
1466 ISDestroy(&nodePartitioningIS_new);
1467 ISDestroy(&nodeNumberingIS_subdomain_old2new);
1468 ISDestroy(&nodeNumberingIS_global_old2new);
1469
1470 ISRestoreIndices(elementNumberingIS_global_new2old,&elementNumbering_global_new2old);
1471
1472 ISDestroy(&elementNumberingIS_subdomain_new2old);
1473 ISDestroy(&elementNumberingIS_global_new2old);
1474
1475 ISRestoreIndices(elementBoundaryNumberingIS_global_new2old,&elementBoundaryNumbering_global_new2old);
1476
1477 ISDestroy(&elementBoundaryNumberingIS_subdomain_new2old);
1478 ISDestroy(&elementBoundaryNumberingIS_global_new2old);
1479
1480 ISRestoreIndices(edgeNumberingIS_global_new2old,&edgeNumbering_global_new2old);
1481
1482 ISDestroy(&edgeNumberingIS_subdomain_new2old);
1483 ISDestroy(&edgeNumberingIS_global_new2old);
1484
1485 return 0;
1486}
1487
1488int partitionNodesFromTetgenFiles(const MPI_Comm& PROTEUS_COMM_WORLD, const char* filebase, int indexBase,
1489 Mesh& newMesh, int nNodes_overlap, double memHardLimit)
1490{
1491 using namespace std;
1492 PetscErrorCode ierr;
1493 PetscMPIInt size,rank;
1494
1495 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1496 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1497 //cek todo: decide whether to remove PETSc logging and just use proteus logging
1498 PetscLogStage partitioning_stage;
1499 PetscLogStageRegister("Mesh Partition",&partitioning_stage);
1500 PetscLogStagePush(partitioning_stage);
1501
1502 /***********************************************************************
1503 partition domain based on the nodes without reading in the global mesh.
1504
1505 1. Partition nodes in the default partition of contiguous chunks with
1506 input ordering
1507
1508 2. Determine nodal connectivity on local processor
1509
1510 3. Generate new nodal partition using PETSc interface
1511
1512 4. Collect subdomain elements: any that contain owned nodes; tag ownership
1513
1514 4a,b. Collect element boundaries and edges on the subdomain elements and tag ownership
1515
1516 5. Generate global element, element boundary, and edge numbering for new subdomain ownership
1517
1518 6. Create overlap (ghost) information for nodes and elements
1519
1520 7. March through additional layers of overlap if requested,
1521
1522 8. Build subdomain meshes in new numbering
1523 ***********************************************************************/
1524 //
1525 //0. Set up tetgen files. Note, tetgen should have been run with -feen to get alll the faces and elements
1526 //
1527 bool failed = false;
1528 const int simplexDim = 4;
1529 const int vertexDim = 3;
1530 using namespace IOutils;
1531 std::string vertexFileName = std::string(filebase) + ".node" ;
1532 std::string elementFileName = std::string(filebase) + ".ele" ;
1533 std::string elementBoundaryFileName = std::string(filebase) + ".face" ;
1534 std::string edgeFileName = std::string(filebase) + ".edge" ;
1535 //
1536 //1. Build default nodal partition
1537 //
1538 //compute offsets to build subdomain2global ordering for nodes
1539 //in default partitioning of the domain into subdomains. All
1540 //we need is the number of nodes in the global mesh
1541 //
1542 //read nodes for tetgen format
1543 //first just read the number of nodes and whether or not there are node tags
1544 logEvent("Building default partitioning",5);
1545 int read_elements_event;
1546 PetscLogEventRegister("Read eles",0,&read_elements_event);
1547 PetscLogEventBegin(read_elements_event,0,0,0,0);
1548 std::ifstream vertexFile(vertexFileName.c_str());
1549 if (!vertexFile.good())
1550 {
1551 std::cerr<<"cannot open Tetgen node file "
1552 <<vertexFileName<<std::endl;
1553 failed = true;
1554 return failed;
1555 }
1556 int hasVertexMarkers(0),hasVertexAttributes(0),nSpace(3),nNodes_global;
1557 //read number of vertices and whether node flags are provided
1558 vertexFile >> eatcomments >> nNodes_global >> nSpace >> hasVertexAttributes >> hasVertexMarkers >> eatline ;
1559 assert(nNodes_global > 0);
1560 assert(nSpace == 3);
1561 newMesh.nNodes_global = nNodes_global;
1562 newMesh.nNodes_element = simplexDim;
1563 newMesh.nNodes_elementBoundary = simplexDim-1;
1564 newMesh.nElementBoundaries_element = simplexDim;
1565 //cek todo: review the situation with tetgen and triangle atribs and markers
1566 if (hasVertexAttributes > 0 && rank==0)
1567 {
1568 std::cerr<<"WARNING Tetgen nodes hasAttributes= "<<hasVertexAttributes
1569 <<" > 0 will treat first value as integer id for boundary!!"<<std::endl;
1570 hasVertexMarkers = 1;
1571 }
1572 //don't need to read anymore from .nodes for now
1573 //leaving file open because we'll pick up here to read the node coordinates
1574 //after partioning, which just requires topology information
1575 //
1576 //offsets provide the lower and upper bounds for the global numbering
1577 //first we just partition the nodes among the MPI ranks, approximately equally, ignoring connectivity
1578 valarray<int> nodeOffsets_old(size+1);
1579 nodeOffsets_old[0] = 0;
1580 for (int sdN=0; sdN < size; sdN++)
1581 {
1582 nodeOffsets_old[sdN+1] = nodeOffsets_old[sdN] +
1583 int(nNodes_global)/size + (int(nNodes_global)%size > sdN);
1584 }
1585 int nNodes_subdomain_old = nodeOffsets_old[rank+1] - nodeOffsets_old[rank];
1586 int nNodes_subdomain_max = int(nNodes_global)/size + (int(nNodes_global)%size > 0);
1587 char log_buffer[100];
1588 sprintf(log_buffer,"First partitioning: Max nNodes_subdomain %d nNodes_global %d",nNodes_subdomain_max,nNodes_global);
1589 logEvent(log_buffer,5);
1590 //
1591 //2. Determine nodal connectivity (nodeStarArray) for nodes on subdomain
1592 //
1593 //connectivty commes from the topology (elements) file. We just grab the elements
1594 //that contain currently owned nodes
1595 logEvent("Determining nodal connectivity to construct new partitioning",5);
1596 std::ifstream elementFile(elementFileName.c_str());
1597 if (!elementFile.good())
1598 {
1599 std::cerr<<"cannot open Tetgen element file "
1600 <<elementFileName<<std::endl;
1601 failed = true;
1602 return failed;
1603 }
1604 //read elements
1605 int nNodesPerSimplex(simplexDim),hasElementMarkers = 0,nElements_global;
1606 elementFile >> eatcomments >> nElements_global >> nNodesPerSimplex >> hasElementMarkers >> eatline;
1607 assert(nElements_global > 0);
1608 assert(nNodesPerSimplex == simplexDim);
1609 newMesh.nElements_global = nElements_global;
1610 valarray<int> element_nodes_old(4);
1611 vector<set<int>> nodeStar(nNodes_subdomain_old);
1612 map<int,valarray<int>> elements_old;
1613 for (int ie = 0; ie < nElements_global; ie++)
1614 {
1615 int ne, nv;
1616 elementFile >> eatcomments >> ne;
1617 ne -= indexBase;
1618 assert(0 <= ne && ne < nElements_global && elementFile.good());
1619 for (int iv = 0; iv < simplexDim; iv++)
1620 {
1621 elementFile >> nv;
1622 nv -= indexBase;
1623 assert(0 <= nv && nv < nNodes_global);
1624 element_nodes_old[iv] = nv;
1625 }
1626 //for each node on the element
1627 for (int iv = 0; iv < simplexDim; iv++)
1628 {
1629 //check if the node is owned by the subdomain
1630 int nN_star = element_nodes_old[iv];
1631 bool inSubdomain=false;
1632 if (nN_star >= nodeOffsets_old[rank] && nN_star < nodeOffsets_old[rank+1])
1633 {
1634 inSubdomain = true;
1635 for (int jv = 0; jv < simplexDim; jv++)
1636 {
1637 if (iv != jv)
1638 {
1639 int nN_star_subdomain = nN_star-nodeOffsets_old[rank];
1640 nodeStar[nN_star_subdomain].insert(element_nodes_old[jv]);
1641 }
1642 }
1643 }
1644 if (inSubdomain)
1645 elements_old[ie] = element_nodes_old;
1646 }
1647 elementFile >> eatline;
1648 }//end ie
1649 elements_old.clear();
1650 elementFile.close();
1651 //cek todo: track c++ containers and put inside scope to reduce dynamic memory usage
1652 PetscLogEventEnd(read_elements_event,0,0,0,0);
1653 int repartition_nodes_event;
1654 PetscLogEventRegister("Repart nodes",0,&repartition_nodes_event);
1655 PetscLogEventBegin(repartition_nodes_event,0,0,0,0);
1656 //done reading element file for first time; will need to read again after node partitioning
1657 //build compact data structure for nodeStar, and
1658 //find maximum number of nodes in any star
1659 int max_nNodeNeighbors_node=0;
1660 for (int nN=0;nN<nNodes_subdomain_old;nN++)
1661 max_nNodeNeighbors_node=max(max_nNodeNeighbors_node,static_cast<int>(nodeStar[nN].size()));
1662 //build connectivity data structures for PETSc
1663 PetscBool isInitialized;
1664 PetscInitialized(&isInitialized);
1665 PetscInt *nodeNeighborsOffsets_subdomain,*nodeNeighbors_subdomain,*weights_subdomain,*vertex_weights_subdomain;
1666 PetscReal *partition_weights;
1667 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain_old+1),&nodeNeighborsOffsets_subdomain);
1668 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain_old*max_nNodeNeighbors_node),&nodeNeighbors_subdomain);
1669 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain_old*max_nNodeNeighbors_node),&weights_subdomain);
1670 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain_old),&vertex_weights_subdomain);
1671 PetscMalloc(sizeof(PetscReal)*(size),&partition_weights);
1672 for (int sd=0;sd<size;sd++)
1673 partition_weights[sd] = 1.0/double(size);
1674 nodeNeighborsOffsets_subdomain[0] = 0;
1675 bool test=false;
1676 for (int nN = 0,offset=0; nN < nNodes_subdomain_old; nN++)
1677 {
1678 for (auto nN_star=nodeStar[nN].begin(); nN_star!=nodeStar[nN].end(); nN_star++,offset++)
1679 {
1680 nodeNeighbors_subdomain[offset] = *nN_star;
1681 }
1682 nodeNeighborsOffsets_subdomain[nN+1]=offset;
1683 if (test)//make sure nodeNeighbors are sorted in ascending order ()
1684 {
1685 valarray<int> neighbors(nodeNeighborsOffsets_subdomain[nN+1]-nodeNeighborsOffsets_subdomain[nN]);
1686 for (int i=0;i<neighbors.size();i++)
1687 neighbors[i] = nodeNeighbors_subdomain[nodeNeighborsOffsets_subdomain[nN]+i];
1688 sort(&nodeNeighbors_subdomain[nodeNeighborsOffsets_subdomain[nN]],&nodeNeighbors_subdomain[nodeNeighborsOffsets_subdomain[nN+1]]);
1689 for (int i=0;i<neighbors.size();i++)
1690 assert(neighbors[i] == nodeNeighbors_subdomain[nodeNeighborsOffsets_subdomain[nN]+i]);
1691 }
1692 //weight nodes by size of star
1693 int weight= (nodeNeighborsOffsets_subdomain[nN+1] - nodeNeighborsOffsets_subdomain[nN]);
1694 vertex_weights_subdomain[nN] = weight;
1695 for (int k=nodeNeighborsOffsets_subdomain[nN];k<nodeNeighborsOffsets_subdomain[nN+1];k++)
1696 weights_subdomain[k] = weight;
1697 }
1698 nodeStar.clear();
1699 //
1700 //3. Generate new nodal partition using PETSc interface to graph partitioners
1701 //
1702 logEvent("Constructing new nodal partition",5);
1703 Mat petscAdjacency;
1704 ierr = MatCreateMPIAdj(PROTEUS_COMM_WORLD,
1705 nNodes_subdomain_old,
1706 nNodes_global,
1707 nodeNeighborsOffsets_subdomain,
1708 nodeNeighbors_subdomain,
1709 weights_subdomain,
1710 &petscAdjacency);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1711 const double max_rss_gb(memHardLimit/1024.0);
1712 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done allocating MPIAdj");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1713 MatPartitioning petscPartition;
1714 ierr = MatPartitioningCreate(PROTEUS_COMM_WORLD,&petscPartition);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1715 ierr = MatPartitioningSetAdjacency(petscPartition,petscAdjacency);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1716 ierr = MatPartitioningSetFromOptions(petscPartition);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1717 ierr = MatPartitioningSetVertexWeights(petscPartition,vertex_weights_subdomain);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1718 ierr = MatPartitioningSetPartitionWeights(petscPartition,partition_weights);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1719 //get petsc index set that has the new subdomain number for each node
1720 IS nodePartitioningIS_new;
1721 ierr = MatPartitioningApply(petscPartition,&nodePartitioningIS_new);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1722 ierr = MatPartitioningDestroy(&petscPartition);CHKERRABORT(PROTEUS_COMM_WORLD, ierr); //gets petscAdjacency too I believe
1723 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done applying partition");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1724
1725 //determine the number of nodes per subdomain in new partitioning
1726 valarray<int> nNodes_subdomain_new(size);
1727 ISPartitioningCount(nodePartitioningIS_new,size,&nNodes_subdomain_new[0]);
1728 //need new offsets for subdomain to global numbering
1729 valarray<int> nodeOffsets_new(size+1);
1730 nodeOffsets_new[0] = 0;
1731 nNodes_subdomain_max = 0;
1732 for (int sdN = 0; sdN < size; sdN++)
1733 {
1734 nodeOffsets_new[sdN+1] = nodeOffsets_new[sdN] + nNodes_subdomain_new[sdN];
1735 nNodes_subdomain_max=max(nNodes_subdomain_max, nNodes_subdomain_new[sdN]);
1736 }
1737 sprintf(log_buffer,"Final partitioning: Max nNodes_subdomain %d nNodes_global %d",nNodes_subdomain_max,nNodes_global);
1738 logEvent(log_buffer,5);
1739 //get the new node numbers for nodes on this subdomain
1740 IS nodeNumberingIS_subdomain_old2new;
1741 ISPartitioningToNumbering(nodePartitioningIS_new,&nodeNumberingIS_subdomain_old2new);
1742 ierr=ISDestroy(&nodePartitioningIS_new);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1743 const PetscInt* nodes_subdomain_old2new_array;
1744 ISGetIndices(nodeNumberingIS_subdomain_old2new, &nodes_subdomain_old2new_array);
1745 //
1746 // out of core creation of global old2new mapping
1747 //
1748 //create the mappings file
1749 logEvent("Writing/reading node numberings to hdf5",5);
1750 hid_t mappings_plist_id = H5Pcreate(H5P_FILE_ACCESS);
1751 H5Pset_fapl_mpio(mappings_plist_id, PROTEUS_COMM_WORLD, MPI_INFO_NULL);
1752 const char* H5FILE_NAME("mappings.h5");
1753 hid_t file_id = H5Fcreate(H5FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, mappings_plist_id);
1754 assert(file_id != H5I_INVALID_HID);
1755 H5Pclose(mappings_plist_id);
1756 //
1757 //write old2new
1758 //
1759 hsize_t nodes_global_count[]={static_cast<hsize_t>(nNodes_global)};
1760 const hsize_t ARRAY_RANK(1);
1761 hid_t nodes_old2new_filespace_id = H5Screate_simple(ARRAY_RANK, nodes_global_count, NULL);
1762 hid_t nodes_old2new_dataset_id = H5Dcreate(file_id, "nodeNumbering_old2new", H5T_NATIVE_INT,
1763 nodes_old2new_filespace_id,
1764 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1765 hsize_t nodes_subdomain_count[]={static_cast<hsize_t>(nNodes_subdomain_old)};
1766 hsize_t nodes_subdomain_offset[]={static_cast<hsize_t>(nodeOffsets_old[rank])};
1767 hid_t nodes_old2new_memspace_id = H5Screate_simple(ARRAY_RANK, nodes_subdomain_count, NULL);
1768 H5Sselect_hyperslab(nodes_old2new_filespace_id, H5S_SELECT_SET,
1769 nodes_subdomain_offset, NULL,
1770 nodes_subdomain_count, NULL);
1771 hid_t nodes_old2new_plist_id = H5Pcreate(H5P_DATASET_XFER);
1772 herr_t status = H5Pset_dxpl_mpio(nodes_old2new_plist_id, H5FD_MPIO_COLLECTIVE);
1773 status = H5Dwrite(nodes_old2new_dataset_id, H5T_NATIVE_INT,
1774 nodes_old2new_memspace_id, nodes_old2new_filespace_id,
1775 nodes_old2new_plist_id, nodes_subdomain_old2new_array);
1776 H5Pclose(nodes_old2new_plist_id);
1777 H5Dclose(nodes_old2new_dataset_id);
1778 H5Sclose(nodes_old2new_memspace_id);
1779 H5Sclose(nodes_old2new_filespace_id);
1780 //
1781 //write new2old
1782 //
1783 hid_t nodes_new2old_filespace_id = H5Screate_simple(ARRAY_RANK, nodes_global_count, NULL);
1784 hid_t nodes_new2old_dataset_id = H5Dcreate(file_id, "nodeNumbering_new2old", H5T_NATIVE_INT,
1785 nodes_new2old_filespace_id,
1786 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1787 hid_t nodes_new2old_memspace_id = H5Screate_simple(ARRAY_RANK, nodes_subdomain_count, NULL);
1788 //new2old is not a hyperslab, unlike old2new, so we have to use H5Sselect_elements
1789 //create a node list to write to for the global new2old mapping
1790 valarray<hsize_t> new_node_indices(nNodes_subdomain_old);
1791 valarray<int> old_node_indices(nNodes_subdomain_old);
1792 for (int i=0;i<nNodes_subdomain_old;i++)
1793 {
1794 new_node_indices[i] = static_cast<hsize_t>(nodes_subdomain_old2new_array[i]);//new node indices where we are writing to
1795 old_node_indices[i] = nodeOffsets_old[rank]+i;//old node numbers at those locations
1796 }
1797 status = H5Sselect_elements(nodes_new2old_filespace_id, H5S_SELECT_SET,
1798 nNodes_subdomain_old, &new_node_indices[0]);
1799 hid_t nodes_new2old_plist_id = H5Pcreate(H5P_DATASET_XFER);
1800 status = H5Pset_dxpl_mpio(nodes_new2old_plist_id, H5FD_MPIO_COLLECTIVE);
1801 status = H5Dwrite(nodes_new2old_dataset_id, H5T_NATIVE_INT,
1802 nodes_new2old_memspace_id, nodes_new2old_filespace_id,
1803 nodes_new2old_plist_id, &old_node_indices[0]);
1804 H5Pclose(nodes_new2old_plist_id);
1805 H5Dclose(nodes_new2old_dataset_id);
1806 H5Sclose(nodes_new2old_memspace_id);
1807 H5Sclose(nodes_new2old_filespace_id);
1808 H5Fclose(file_id);
1809 //
1810 //test out of core
1811 //
1812 IS nodeNumberingIS_global_old2new;
1813 const PetscInt *nodeNumbering_global_old2new;
1814 valarray<int> nodeNumbering_global_new2old;
1815 if (test)
1816 {
1817 ISAllGather(nodeNumberingIS_subdomain_old2new,&nodeNumberingIS_global_old2new);
1818 ISGetIndices(nodeNumberingIS_global_old2new,&nodeNumbering_global_old2new);
1819 nodeNumbering_global_new2old.resize(nNodes_global);
1820 for (int nN = 0; nN < nNodes_global; nN++)
1821 nodeNumbering_global_new2old[nodeNumbering_global_old2new[nN]] = nN;
1822 herr_t status;
1823 valarray<int> nodeNumbering_old2new_read(nNodes_global);
1824 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT);
1825 assert(file_id != H5I_INVALID_HID);
1826 hid_t nodeNumbering_old2new_dataset_id = H5Dopen1(file_id, "/nodeNumbering_old2new");
1827 status = H5Dread(nodeNumbering_old2new_dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
1828 &nodeNumbering_old2new_read[0]);
1829 status = H5Dclose(nodeNumbering_old2new_dataset_id);
1830 for (int i=0;i<nNodes_global;i++)
1831 {
1832 assert(nodeNumbering_global_old2new[i] == nodeNumbering_old2new_read[i]);
1833 }
1834 std::cout<<"==================out of core old2new nodes is correct!===================="<<std::endl;
1835 hid_t nodeNumbering_new2old_dataset_id = H5Dopen2(file_id, "/nodeNumbering_new2old", H5P_DEFAULT);
1836 valarray<int> nodeNumbering_new2old_read(nNodes_global);
1837 status = H5Dread(nodeNumbering_new2old_dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
1838 &nodeNumbering_new2old_read[0]);
1839 status = H5Dclose(nodeNumbering_new2old_dataset_id);
1840 H5Fclose(file_id);
1841 for (int i=0;i<nNodes_global;i++)
1842 {
1843 assert(nodeNumbering_global_new2old[i] == nodeNumbering_new2old_read[i]);
1844 }
1845 std::cout<<"==================out of core new2old nodes is correct!===================="<<std::endl;
1846 nodeNumbering_global_new2old.resize(0);
1847 }
1848 //cek todo: put this in the right place and use integers not doubles
1849 Vec nodeNumbering_old2new_petsc;
1850 ierr = VecCreateMPI(PROTEUS_COMM_WORLD, nNodes_subdomain_old, nNodes_global, &nodeNumbering_old2new_petsc);
1851 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1852 valarray<PetscInt> indices(nNodes_subdomain_old);
1853 valarray<PetscInt> ix(nNodes_subdomain_old);
1854 valarray<PetscScalar> y(nNodes_subdomain_old);
1855 for (int i=0;i<nNodes_subdomain_old;i++)
1856 {
1857 indices[i] = i+nodeOffsets_old[rank];
1858 ix[i]=i;
1859 y[i]=static_cast<PetscScalar>(nodes_subdomain_old2new_array[i]);
1860 }
1861 ISLocalToGlobalMapping mapping;
1862 PetscInt bs(1);
1863 ierr = ISLocalToGlobalMappingCreate(PROTEUS_COMM_WORLD, bs, nNodes_subdomain_old, &indices[0], PETSC_USE_POINTER, &mapping);
1864 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1865 ierr = VecSetLocalToGlobalMapping(nodeNumbering_old2new_petsc, mapping);
1866 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1867 ierr = VecSetValuesLocal(nodeNumbering_old2new_petsc, nNodes_subdomain_old, &ix[0], &y[0], INSERT_VALUES);
1868 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1869 ierr = VecAssemblyBegin(nodeNumbering_old2new_petsc);
1870 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1871 ierr = VecAssemblyEnd(nodeNumbering_old2new_petsc);
1872 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1873 if (test)
1874 {
1875 PetscScalar* test_local;
1876 VecGetArray(nodeNumbering_old2new_petsc,&test_local);
1877 for (int i=0;i<nNodes_subdomain_old;i++)
1878 {
1879 assert(test_local[i] == static_cast<PetscScalar>(nodes_subdomain_old2new_array[i]));
1880 }
1881 VecRestoreArray(nodeNumbering_old2new_petsc,&test_local);
1882 }
1883 //ISRestoreIndices(nodeNumberingIS_subdomain_old2new, &nodes_subdomain_old2new_array);
1884 //ierr=ISDestroy(&nodeNumberingIS_subdomain_old2new);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1885
1886 PetscLogEventEnd(repartition_nodes_event,0,0,0,0);
1887 int receive_element_mask_event;
1888 PetscLogEventRegister("Recv. ele mask",0,&receive_element_mask_event);
1889 PetscLogEventBegin(receive_element_mask_event,0,0,0,0);
1890 //
1891 //4. To build subdomain meshes, go through and collect elements containing
1892 // the locally owned nodes. Assign processor ownership of elements
1893 //
1894 logEvent("Collecting elements containing locally owned nodes (element support of the subdomain nodes)",5);
1895 PetscLogEventEnd(receive_element_mask_event,0,0,0,0);
1896 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done with masks");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1897 int build_subdomains_reread_elements_event;
1898 PetscLogEventRegister("Reread eles",0,&build_subdomains_reread_elements_event);
1899 PetscLogEventBegin(build_subdomains_reread_elements_event,0,0,0,0);
1900 //
1901 //mark the unmarked elements on this subdomain and store element numbers (in old numbering)
1902 //
1903 //We need to find the elements in the support of nodes in the new
1904 //partitioning, so we'll need to re-read the elements file to get
1905 //the the elements for the nodes in the new partitioning. We will be collecting OLD element numbers.
1906 std::ifstream elementFile2(elementFileName.c_str());
1907 if (!elementFile2.good())
1908 {
1909 std::cerr<<"cannot open Tetgen elements file"
1910 <<elementFileName<<std::endl;
1911 failed = true;
1912 return failed;
1913 }
1914 elementFile2 >> eatcomments >> nElements_global >> nNodesPerSimplex >> hasElementMarkers >> eatline;
1915 assert(nElements_global > 0);
1916 assert(nNodesPerSimplex == simplexDim);
1917 //cek todo: check that these are all necessary
1918 set<int> elements_subdomain_owned;
1919 valarray<int> element_nodes_new(4);
1920 vector<set<int>> nodeElementsStar(nNodes_subdomain_new[rank]);
1921 vector<set<int>> nodeStarNew(nNodes_subdomain_new[rank]);
1922 map<int,valarray<int>> elementNodesArrayMap;
1923 map<int,long int> elementMaterialTypesMap;
1924 map<NodeTuple<3>,ElementNeighbors> elementBoundaryElementsMap;
1925 map<NodeTuple<2>,set<pair<int,int>>> edgeElementsMap;
1926 set<int> node_collection;
1927 vector<valarray<int>> element_old_nodes_collection;
1928 vector<int> elements_collection;
1929 vector<double> elementId_collection;
1930 map<int, int> nodes_old2new_subdomain_map;
1931 //note any element index containers are in the old element numbering
1932 int eN_c_start = 0;//start of the collection of elements we are currently processing
1933 for (int ie = 0; ie < nElements_global; ie++)
1934 {
1935 //
1936 //Accumulate a collection of elements in the old numbering of sufficient length,
1937 //then get the new node numbers for those old nodes, renumber, take ownership of elements,
1938 //and then release the memory for the collection and continue
1939 //basic idea is to use only a part of old2new at a time.
1940 //doing with hdf5 for now, but could do with scatter
1941 //
1942 int ne, nv, elementId(0);
1943 long double elementId_double;
1944 elementFile2 >> eatcomments >> ne;
1945 ne -= indexBase;
1946 assert(0 <= ne && ne < nElements_global && elementFile.good());
1947 elements_collection.push_back(ne);
1948 for (int iv = 0; iv < simplexDim; iv++)
1949 {
1950 elementFile2 >> nv ;
1951 nv -= indexBase;
1952 assert(0 <= nv && nv < nNodes_global);
1953 node_collection.insert(nv);
1954 element_nodes_old[iv] = nv;
1955 }
1956 if (hasElementMarkers > 0)
1957 {
1958 elementFile2 >> elementId_double;
1959 elementId_collection.push_back(elementId_double);
1960 }
1961 element_old_nodes_collection.push_back(element_nodes_old);
1962 if (elements_collection.size() == nElements_global/size || ie == nElements_global-1)
1963 {
1964 //create a node list to read from old2new mapping
1965 valarray<int> nodes_old2new_subset(node_collection.size());
1966 map<int,int> nodes_old2new_subset_map;
1967 bool test_scatter=false;
1968 if (test_scatter)
1969 {
1970 Vec node_old2new_collection_petsc;
1971 ierr = VecCreateMPI(PROTEUS_COMM_WORLD, node_collection.size(), PETSC_DETERMINE,&node_old2new_collection_petsc);
1972 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1973 PetscInt collection_low, collection_high;
1974 ierr = VecGetOwnershipRange(node_old2new_collection_petsc, &collection_low, &collection_high);
1975 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1976 valarray<PetscInt> node_collection_array(node_collection.size());
1977 valarray<PetscInt> iy_collection(node_collection.size());
1978 int i_nc=0;
1979 for (auto nv=node_collection.begin();nv!=node_collection.end();nv++,i_nc++)
1980 {
1981 node_collection_array[i_nc] = static_cast<PetscInt>(*nv);
1982 iy_collection[i_nc] = i_nc + collection_low;
1983 }
1984 IS old_ix,iy;
1985 ierr = ISCreateGeneral(PROTEUS_COMM_WORLD, node_collection.size(), &node_collection_array[0],
1986 PETSC_USE_POINTER, &old_ix);
1987 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1988 ierr = ISCreateGeneral(PROTEUS_COMM_WORLD, node_collection.size(), &iy_collection[0],
1989 PETSC_USE_POINTER, &iy);
1990 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1991 VecScatter old2new_collection_scatter;
1992 ierr = VecScatterCreate(nodeNumbering_old2new_petsc, old_ix,
1993 node_old2new_collection_petsc, iy,
1994 &old2new_collection_scatter);
1995 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
1996 ierr = VecScatterBegin(old2new_collection_scatter,
1997 nodeNumbering_old2new_petsc, node_old2new_collection_petsc,
1998 INSERT_VALUES, SCATTER_FORWARD);
1999 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2000
2001 ierr = VecScatterEnd(old2new_collection_scatter,
2002 nodeNumbering_old2new_petsc, node_old2new_collection_petsc,
2003 INSERT_VALUES, SCATTER_FORWARD);
2004 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2005 PetscScalar* nodes_old2new_subset_array;
2006 ierr = VecGetArray(node_old2new_collection_petsc, &nodes_old2new_subset_array);
2007 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2008 for (int i=0;i<node_collection.size();i++)
2009 {
2010 nodes_old2new_subset[i] = nodes_old2new_subset_array[i];
2011 }
2012 ierr = VecRestoreArray(node_old2new_collection_petsc, &nodes_old2new_subset_array);
2013 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2014 ierr = VecDestroy(&node_old2new_collection_petsc);
2015 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2016 ierr = VecScatterDestroy(&old2new_collection_scatter);
2017 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2018 ierr = ISDestroy(&old_ix);
2019 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2020 ierr = ISDestroy(&iy);
2021 CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2022 for (int i=0;i<node_collection.size();i++)
2023 {
2024 nodes_old2new_subset_map[node_collection_array[i]] = nodes_old2new_subset[i];
2025 }
2026 if (test)
2027 {
2028 for (int i=0;i<node_collection.size();i++)
2029 {
2030 assert(nodes_old2new_subset_map[node_collection_array[i]] == nodeNumbering_global_old2new[node_collection_array[i]]);
2031 }
2032 }
2033 }
2034 else
2035 {
2036 herr_t status;
2037 valarray<hsize_t> node_collection_array(node_collection.size());
2038 int i_nc=0;
2039 for (auto nv=node_collection.begin();nv!=node_collection.end();nv++,i_nc++)
2040 {
2041 node_collection_array[i_nc] = static_cast<hsize_t>(*nv);
2042 }
2043 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT);
2044 assert(file_id != H5I_INVALID_HID);
2045 nodes_old2new_dataset_id = H5Dopen1(file_id,"/nodeNumbering_old2new");
2046 nodes_old2new_filespace_id = H5Dget_space(nodes_old2new_dataset_id);
2047 status = H5Sselect_elements(nodes_old2new_filespace_id, H5S_SELECT_SET,
2048 node_collection.size(), &node_collection_array[0]);
2049 hsize_t dims[] = {static_cast<hsize_t>(node_collection.size())};
2050 hid_t nodes_old2new_subset_memspace_id = H5Screate_simple(1, dims, NULL);
2051 nodes_old2new_plist_id = H5Pcreate(H5P_DATASET_XFER);
2052 status = H5Pset_dxpl_mpio(nodes_old2new_plist_id, H5FD_MPIO_COLLECTIVE);
2053 status = H5Dread(nodes_old2new_dataset_id, H5T_NATIVE_INT,
2054 nodes_old2new_subset_memspace_id, nodes_old2new_filespace_id,
2055 H5P_DEFAULT, &nodes_old2new_subset[0]);
2056 H5Pclose(nodes_old2new_plist_id);
2057 H5Sclose(nodes_old2new_subset_memspace_id);
2058 H5Sclose(nodes_old2new_filespace_id);
2059 H5Dclose(nodes_old2new_dataset_id);
2060 H5Fclose(file_id);
2061 for (int i=0;i<node_collection.size();i++)
2062 {
2063 nodes_old2new_subset_map[node_collection_array[i]] = nodes_old2new_subset[i];
2064 }
2065 if (test)
2066 {
2067 for (int i=0;i<node_collection.size();i++)
2068 {
2069 assert(nodes_old2new_subset_map[node_collection_array[i]] == nodeNumbering_global_old2new[node_collection_array[i]]);
2070 }
2071 }
2072 }
2073 for (int eN_c = eN_c_start; eN_c < ie+1;eN_c++)
2074 {
2075 ne = elements_collection[eN_c-eN_c_start];
2076 for (int iv = 0; iv < simplexDim; iv++)
2077 {
2078 element_nodes_old[iv] = element_old_nodes_collection[eN_c-eN_c_start][iv];
2079 element_nodes_new[iv] = nodes_old2new_subset_map[element_nodes_old[iv]];
2080 }
2081 NodeTuple<4> nodeTuple(&element_nodes_new[0]);
2082 for (int iv = 0; iv < simplexDim; iv++)
2083 {
2084 int nN_star_new = element_nodes_new[iv];
2085 bool inSubdomain=false;
2086 if (nN_star_new >= nodeOffsets_new[rank] && nN_star_new < nodeOffsets_new[rank+1])
2087 {
2088 inSubdomain = true;
2089 for (int iv=0; iv < simplexDim; iv++)
2090 nodes_old2new_subdomain_map[element_nodes_old[iv]] = element_nodes_new[iv];
2091 //add all the element boundaries of this element
2092 for (int ebN=0;ebN < 4 ; ebN++)
2093 {
2094 int nodes[3] = { element_nodes_new[(ebN+1) % 4],
2095 element_nodes_new[(ebN+2) % 4],
2096 element_nodes_new[(ebN+3) % 4]};
2097 NodeTuple<3> nodeTuple(nodes);
2098 if(elementBoundaryElementsMap.find(nodeTuple) != elementBoundaryElementsMap.end())
2099 {
2100 if (elementBoundaryElementsMap[nodeTuple].right == -1 && ne != elementBoundaryElementsMap[nodeTuple].left)
2101 {
2102 elementBoundaryElementsMap[nodeTuple].right=ne;
2103 elementBoundaryElementsMap[nodeTuple].right_ebN_element=ebN;
2104 }
2105 }
2106 else
2107 {
2108 elementBoundaryElementsMap[nodeTuple] = ElementNeighbors(ne,ebN);
2109 }
2110 }
2111 //add all the edges of this element
2112 for (int nNL=0,edN=0;nNL < 4 ; nNL++)
2113 for(int nNR=nNL+1;nNR < 4;nNR++,edN++)
2114 {
2115 int nodes[2] = { element_nodes_new[nNL],
2116 element_nodes_new[nNR]};
2117 NodeTuple<2> nodeTuple(nodes);
2118 edgeElementsMap[nodeTuple].insert(pair<int,int>(ne,edN));
2119 }
2120 //add all the nodes to the node star
2121 int nN_star_new_subdomain = nN_star_new - nodeOffsets_new[rank];
2122 nodeElementsStar[nN_star_new_subdomain].insert(ne);
2123 for (int jv = 0; jv < simplexDim; jv++)
2124 {
2125 if (iv != jv)
2126 {
2127 int nN_point_new = element_nodes_new[jv];
2128 nodeStarNew[nN_star_new_subdomain].insert(nN_point_new);
2129 }
2130 }
2131 }
2132 if (inSubdomain)
2133 {
2134 elementNodesArrayMap[ne] = element_nodes_new;
2135 }
2136 }
2137 //if this element contains any node owned by this subdomain, check node 1
2138 if (elementNodesArrayMap.find(ne) != elementNodesArrayMap.end())
2139 {
2140 if (nodeTuple.nodes[1] >= nodeOffsets_new[rank] && nodeTuple.nodes[1] < nodeOffsets_new[rank+1])
2141 elements_subdomain_owned.insert(ne);
2142 if (hasElementMarkers > 0)
2143 {
2144 elementId = static_cast<long int>(elementId_collection[eN_c-eN_c_start]);
2145 elementMaterialTypesMap[ne] = elementId;
2146 }
2147 }
2148 }
2149 eN_c_start = ie+1;
2150 node_collection.clear();
2151 elements_collection.clear();
2152 elementId_collection.clear();
2153 element_old_nodes_collection.clear();
2154 }
2155 elementFile2 >> eatline;
2156 }
2157 elementFile2.close();
2158 int nElements_owned_subdomain(elements_subdomain_owned.size()),
2159 nElements_owned_new=0;
2160 MPI_Allreduce(&nElements_owned_subdomain,&nElements_owned_new,1,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
2161 assert(nElements_owned_new == nElements_global);
2162 PetscLogEventEnd(build_subdomains_reread_elements_event,0,0,0,0);
2163 int build_subdomains_send_marked_elements_event;
2164 PetscLogEventRegister("Mark/send eles",0,&build_subdomains_send_marked_elements_event);
2165 PetscLogEventBegin(build_subdomains_send_marked_elements_event,0,0,0,0);
2166 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done marking elements");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2167 //cek todo: fix PETsc and memory log messages
2168 //
2169 //done with the element file
2170 //
2171 //construct compact nodeElementsArray
2172 valarray<int> nodeElementOffsets(nNodes_subdomain_new[rank]+1);
2173 nodeElementOffsets[0] = 0;
2174 for (int nN = 0; nN < nNodes_subdomain_new[rank]; nN++)
2175 nodeElementOffsets[nN+1] = nodeElementOffsets[nN]+nodeElementsStar[nN].size();
2176 valarray<int> nodeElementsArray(nodeElementOffsets[nNodes_subdomain_new[rank]]);
2177 for (int nN=0,offset=0; nN < nNodes_subdomain_new[rank]; nN++)
2178 {
2179 for (set<int>::iterator eN_star = nodeElementsStar[nN].begin(); eN_star != nodeElementsStar[nN].end();
2180 eN_star++,offset++)
2181 {
2182 nodeElementsArray[offset] = *eN_star;
2183 }
2184 }
2185 nodeElementsStar.clear();
2186 //construct compact nodeStarArray
2187 valarray<int> nodeStarOffsetsNew(nNodes_subdomain_new[rank]+1);
2188 nodeStarOffsetsNew[0] = 0;
2189 for (int nN=1;nN<nNodes_subdomain_new[rank]+1;nN++)
2190 nodeStarOffsetsNew[nN] = nodeStarOffsetsNew[nN-1] + nodeStarNew[nN-1].size();
2191 valarray<int> nodeStarArrayNew(nodeStarOffsetsNew[nNodes_subdomain_new[rank]]);
2192 for (int nN=0,offset=0;nN<nNodes_subdomain_new[rank];nN++)
2193 {
2194 for (set<int>::iterator nN_star=nodeStarNew[nN].begin();nN_star!=nodeStarNew[nN].end();nN_star++,offset++)
2195 {
2196 nodeStarArrayNew[offset] = *nN_star;
2197 }
2198 }
2199 nodeStarNew.clear();
2200 PetscLogEventEnd(build_subdomains_send_marked_elements_event,0,0,0,0);
2201 int build_subdomains_global_numbering_elements_event;
2202 PetscLogEventRegister("Global ele nmbr",0,&build_subdomains_global_numbering_elements_event);
2203 PetscLogEventBegin(build_subdomains_global_numbering_elements_event,0,0,0,0);
2204 //
2205 //5. Generate global element numbering corresponding to new subdomain ownership
2206 //
2207 logEvent("Generating global element numbering corresponding to new subdomain ownership",5);
2208 valarray<int> nElements_subdomain_new(size),
2209 elementOffsets_new(size+1);
2210 for (int sdN = 0; sdN < size; sdN++)
2211 {
2212 if (sdN == rank)
2213 nElements_subdomain_new[sdN] = int(elements_subdomain_owned.size());
2214 else
2215 nElements_subdomain_new[sdN] = 0;
2216 }
2217 valarray<int> nElements_subdomain_new_send = nElements_subdomain_new;
2218 MPI_Allreduce(&nElements_subdomain_new_send[0],&nElements_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
2219 sprintf(log_buffer,"Final partitioning: Max nElements_subdomain %d nElements_global %d",nElements_subdomain_new.max(),nElements_global);
2220 logEvent(log_buffer,5);
2221
2222 //construct new offsets for elements
2223 elementOffsets_new[0] = 0;
2224 for (int sdN = 0; sdN < size; sdN++)
2225 elementOffsets_new[sdN+1] = elementOffsets_new[sdN] + nElements_subdomain_new[sdN];
2226 //map to old element numbering
2227 valarray<int> elementNumbering_subdomain_new2old(elements_subdomain_owned.size());
2228 set<int>::iterator eN_ownedp = elements_subdomain_owned.begin();
2229 map<int, int> elementNumbering_old2new_map;
2230 for (int eN = 0; eN < int(elements_subdomain_owned.size()); eN++,eN_ownedp++)
2231 {
2232 //only for owned elements on the subdomain
2233 elementNumbering_subdomain_new2old[eN] = *eN_ownedp;
2234 elementNumbering_old2new_map[*eN_ownedp] = eN;
2235 }
2236 //
2237 //write this subdomain to the mapping file
2238 //
2239 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Writing element numberings to hdf5");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2240 logEvent("Writing element numberings to hdf5",5);
2241 mappings_plist_id = H5Pcreate(H5P_FILE_ACCESS);
2242 status = H5Pset_fapl_mpio(mappings_plist_id, PROTEUS_COMM_WORLD, MPI_INFO_NULL);
2243 assert(status >= 0);
2244 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDWR, mappings_plist_id);
2245 assert(file_id != H5I_INVALID_HID);
2246 H5Pclose(mappings_plist_id);
2247 hsize_t e_dims[]={static_cast<hsize_t>(nElements_global)};
2248 hid_t e_new2old_filespace_id = H5Screate_simple(ARRAY_RANK, e_dims, NULL);
2249 hid_t e_new2old_dataset_id = H5Dcreate(file_id, "elementNumbering_new2old", H5T_NATIVE_INT,
2250 e_new2old_filespace_id,
2251 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
2252 hsize_t e_count[]={static_cast<hsize_t>(nElements_subdomain_new[rank])};
2253 hsize_t e_offset[]={static_cast<hsize_t>(elementOffsets_new[rank])};
2254 hid_t e_new2old_memspace_id = H5Screate_simple(ARRAY_RANK, e_count, NULL);
2255 H5Sselect_hyperslab(e_new2old_filespace_id, H5S_SELECT_SET, e_offset, NULL, e_count, NULL);
2256 hid_t e_new2old_plist_id = H5Pcreate(H5P_DATASET_XFER);
2257 H5Pset_dxpl_mpio(e_new2old_plist_id, H5FD_MPIO_COLLECTIVE);
2258 status = H5Dwrite(e_new2old_dataset_id, H5T_NATIVE_INT,
2259 e_new2old_memspace_id, e_new2old_filespace_id,
2260 e_new2old_plist_id, &elementNumbering_subdomain_new2old[0]);
2261 H5Dflush(e_new2old_dataset_id);
2262 H5Pclose(e_new2old_plist_id);
2263 H5Dclose(e_new2old_dataset_id);
2264 H5Sclose(e_new2old_memspace_id);
2265 H5Sclose(e_new2old_filespace_id);
2266 valarray<hsize_t> old_element_indices(static_cast<hsize_t>(nElements_subdomain_new[rank]));
2267 valarray<int> new_element_indices(nElements_subdomain_new[rank]);
2268 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"new2old done; now old2new");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2269 //do old2new map too, can't use hyperslab
2270 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"old2new index valarrays done");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2271 for (int i=0;i<nElements_subdomain_new[rank];i++)
2272 {
2273 old_element_indices[i] = static_cast<hsize_t>(elementNumbering_subdomain_new2old[i]);
2274 new_element_indices[i] = elementOffsets_new[rank]+i;
2275 }
2276 hid_t e_old2new_filespace_id = H5Screate_simple(ARRAY_RANK, e_dims, NULL);
2277 hid_t e_old2new_dataset_id = H5Dcreate(file_id, "elementNumbering_old2new", H5T_NATIVE_INT,
2278 e_old2new_filespace_id,
2279 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
2280 hid_t e_old2new_memspace_id = H5Screate_simple(ARRAY_RANK, e_count, NULL);
2281 status = H5Sselect_elements(e_old2new_filespace_id, H5S_SELECT_SET,
2282 nElements_subdomain_new[rank], &old_element_indices[0]);
2283 hid_t e_old2new_plist_id = H5Pcreate(H5P_DATASET_XFER);
2284 H5Pset_dxpl_mpio(e_old2new_plist_id, H5FD_MPIO_COLLECTIVE);
2285 status = H5Dwrite(e_old2new_dataset_id, H5T_NATIVE_INT,
2286 e_old2new_memspace_id, e_old2new_filespace_id,
2287 e_old2new_plist_id, &new_element_indices[0]);
2288 H5Pclose(e_old2new_plist_id);
2289 H5Sclose(e_old2new_memspace_id);
2290 H5Dclose(e_old2new_dataset_id);
2291 H5Sclose(e_old2new_filespace_id);
2292 H5Fclose(file_id);
2293 //
2294 //now get maps for all the elements on the subdomain, not just owned elements
2295 //
2296 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Reading numberings from hdf5 to get subdomain map");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2297 logEvent("Reading element numberings from hdf5 to get subdomain map",5);
2298
2299 valarray<hsize_t> old_element_indices_subdomain(static_cast<hsize_t>(elementNodesArrayMap.size()));
2300 valarray<int> new_element_indices_subdomain(elementNodesArrayMap.size());
2301 int eN_old_subdomain = 0;
2302 for (auto it = elementNodesArrayMap.begin(); it != elementNodesArrayMap.end(); it++, eN_old_subdomain++)
2303 {
2304 old_element_indices_subdomain[eN_old_subdomain] = it->first;
2305 }
2306 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT);
2307 e_old2new_dataset_id = H5Dopen1(file_id, "/elementNumbering_old2new");
2308 e_old2new_filespace_id = H5Dget_space(e_old2new_dataset_id);
2309 status = H5Sselect_elements(e_old2new_filespace_id, H5S_SELECT_SET,
2310 elementNodesArrayMap.size(), &old_element_indices_subdomain[0]);
2311 hsize_t e_subdomain_count[]={static_cast<hsize_t>(elementNodesArrayMap.size())};
2312 hid_t e_old2new_subdomain_memspace_id = H5Screate_simple(ARRAY_RANK, e_subdomain_count, NULL);
2313 hid_t e_old2new_subdomain_plist_id = H5Pcreate(H5P_DATASET_XFER);
2314 status = H5Pset_dxpl_mpio(e_old2new_subdomain_plist_id, H5FD_MPIO_COLLECTIVE);
2315 status = H5Dread(e_old2new_dataset_id, H5T_NATIVE_INT,
2316 e_old2new_subdomain_memspace_id, e_old2new_filespace_id,
2317 H5P_DEFAULT, &new_element_indices_subdomain[0]);
2318 H5Pclose(e_old2new_subdomain_plist_id);
2319 H5Sclose(e_old2new_subdomain_memspace_id);
2320 H5Dclose(e_old2new_dataset_id);
2321 H5Sclose(e_old2new_filespace_id);
2322 H5Fclose(file_id);
2323 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Constructing element subdomain maps");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2324 map<int,int> elementNumbering_old2new_subdomain_map;
2325 map<int,int> elementNumbering_new2old_subdomain_map;
2326 for (int i=0;i<elementNodesArrayMap.size();i++)
2327 {
2328 elementNumbering_old2new_subdomain_map[old_element_indices_subdomain[i]] = new_element_indices_subdomain[i];
2329 elementNumbering_new2old_subdomain_map[new_element_indices_subdomain[i]] = old_element_indices_subdomain[i];
2330 }
2331 if (test)
2332 {
2333 //these were needed inside the last test section, which was in a loop, so release now
2334 ISRestoreIndices(nodeNumberingIS_global_old2new,&nodeNumbering_global_old2new);
2335 ierr=ISDestroy(&nodeNumberingIS_global_old2new);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2336 //set up global element numbering
2337 IS elementNumberingIS_subdomain_new2old;
2338 const PetscInt *elementNumbering_global_new2old;//needs to be restored
2339 valarray<int> elementNumbering_global_old2new(nElements_global);
2340 ISCreateGeneral(PROTEUS_COMM_WORLD,elements_subdomain_owned.size(),
2341 &elementNumbering_subdomain_new2old[0],PETSC_COPY_VALUES,
2342 &elementNumberingIS_subdomain_new2old);
2343 IS elementNumberingIS_global_new2old;
2344 ISAllGather(elementNumberingIS_subdomain_new2old,&elementNumberingIS_global_new2old);
2345 ISGetIndices(elementNumberingIS_global_new2old,&elementNumbering_global_new2old);
2346 //construct reverse mapping
2347 for (int eN = 0; eN < nElements_global; eN++)
2348 {
2349 elementNumbering_global_old2new[elementNumbering_global_new2old[eN]] = eN;
2350 }
2351 //check old2new
2352 valarray<int> elementNumbering_global_old2new_read(nElements_global);
2353 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT);
2354 hid_t e_old2new_dataset_id = H5Dopen1(file_id, "/elementNumbering_old2new");
2355 status = H5Dread(e_old2new_dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
2356 &elementNumbering_global_old2new_read[0]);
2357 status = H5Dclose(e_old2new_dataset_id);
2358 for (int i=0;i<nElements_global;i++)
2359 {
2360 assert(elementNumbering_global_old2new[i] == elementNumbering_global_old2new_read[i]);
2361 }
2362 std::cout<<"==================out of core elements old2new is correct!===================="<<std::endl;
2363 for (auto it = elementNodesArrayMap.begin(); it != elementNodesArrayMap.end(); it++)
2364 assert(elementNumbering_old2new_subdomain_map[it->first] ==
2365 elementNumbering_global_old2new_read[it->first]);
2366 std::cout<<"==================out of core elements old2new map is correct!===================="<<std::endl;
2367 //check new2old
2368 valarray<int> elementNumbering_global_new2old_read(nElements_global);
2369 hid_t e_new2old_dataset_id = H5Dopen1(file_id, "/elementNumbering_new2old");
2370 status = H5Dread(e_new2old_dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
2371 &elementNumbering_global_new2old_read[0]);
2372 status = H5Dclose(e_new2old_dataset_id);
2373 status = H5Fclose(file_id);
2374 for (int i=0;i<nElements_global;i++)
2375 assert(elementNumbering_global_new2old[i] == elementNumbering_global_new2old_read[i]);
2376 std::cout<<"==================out of core elements new2old is correct!===================="<<std::endl;
2377 for (size_t i=0;i< new_element_indices_subdomain.size(); i++)
2378 {
2379 int eN = new_element_indices_subdomain[i];
2380 assert(elementNumbering_new2old_subdomain_map[eN] == elementNumbering_global_new2old_read[eN]);
2381 }
2382 std::cout<<"==================out of core elements new2old map is correct!===================="<<std::endl;
2383 ISRestoreIndices(elementNumberingIS_global_new2old,&elementNumbering_global_new2old);
2384 ierr=ISDestroy(&elementNumberingIS_global_new2old);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2385 ierr=ISDestroy(&elementNumberingIS_subdomain_new2old);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2386 }
2387 PetscLogEventEnd(build_subdomains_global_numbering_elements_event,0,0,0,0);
2388 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done allocating element numbering new2old/old2new");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2389 int build_subdomains_faces_event;
2390 PetscLogEventRegister("Subd faces",0,&build_subdomains_faces_event);
2391 PetscLogEventBegin(build_subdomains_faces_event,0,0,0,0);
2392 //
2393 //4b,5b. repeat process to build global face (elementBoundary) numbering
2394 //
2395 //first read element boundaries to create nodeElementBoundariesArray
2396 //for all element boundaries on this subdomain, which we'll use to
2397 //grab element boundaries from the bit array
2398 logEvent("Generating global face numbering and ownership corresponding to new subdomain ownership",5);
2399 std::ifstream elementBoundaryFile(elementBoundaryFileName.c_str());
2400
2401 if (!elementBoundaryFile.good())
2402 {
2403 std::cerr<<"cannot open Tetgen face file "
2404 <<elementBoundaryFileName<<std::endl;
2405 failed = true;
2406 return failed;
2407 }
2408
2409 bool hasElementBoundaryMarkers = false;
2410 int nElementBoundaries_global;
2411 int ihasElementBoundaryMarkers(0);
2412 elementBoundaryFile >> eatcomments >> nElementBoundaries_global >> ihasElementBoundaryMarkers >> eatline ;
2413 assert(nElementBoundaries_global > 0);
2414 if (ihasElementBoundaryMarkers > 0)
2415 {
2416 hasElementBoundaryMarkers = true;
2417 }
2418 newMesh.nElementBoundaries_global = nElementBoundaries_global;
2419 //note, these will be in the new element numbering
2420 set<int> elementBoundaries_subdomain_owned;
2421 vector<set<int>> nodeElementBoundariesStar(nNodes_subdomain_new[rank]);
2422 map<int,int> elementBoundaryMaterialTypesMap;
2423 map<int,valarray<int>> elementBoundariesMap;
2424 set<int> supportedElementBoundaries;
2425 set<int> elementBoundaries_subdomain;
2426 for (int ieb = 0; ieb < nElementBoundaries_global; ieb++)
2427 {
2428 int neb,nn0,nn1,nn2; int ebId(0);
2429 elementBoundaryFile >> eatcomments >> neb >> nn0 >> nn1 >> nn2;
2430 if (ihasElementBoundaryMarkers > 0)
2431 elementBoundaryFile >> ebId;
2432 neb -= indexBase;
2433 nn0 -= indexBase;
2434 nn1 -= indexBase;
2435 nn2 -= indexBase;
2436 assert(0 <= neb && neb < nElementBoundaries_global && elementBoundaryFile.good());
2437 //grab the element boundaries for the node if the node is owned by the subdomain
2438 //this will miss the element boundaries on the "outside boundary" of the star, which we'll grab later
2439 //
2440 int nn0_new = -1;
2441 if (nodes_old2new_subdomain_map.find(nn0) != nodes_old2new_subdomain_map.end())
2442 nn0_new = nodes_old2new_subdomain_map[nn0];
2443 if (nn0_new >= nodeOffsets_new[rank] && nn0_new < nodeOffsets_new[rank+1])
2444 {
2445 nodeElementBoundariesStar[nn0_new-nodeOffsets_new[rank]].insert(neb);
2446 supportedElementBoundaries.insert(neb);
2447 }
2448 int nn1_new = -2;
2449 if (nodes_old2new_subdomain_map.find(nn1) != nodes_old2new_subdomain_map.end())
2450 nn1_new = nodes_old2new_subdomain_map[nn1];
2451 if (nn1_new >= nodeOffsets_new[rank] && nn1_new < nodeOffsets_new[rank+1])
2452 {
2453 nodeElementBoundariesStar[nn1_new-nodeOffsets_new[rank]].insert(neb);
2454 supportedElementBoundaries.insert(neb);
2455 }
2456 int nn2_new = -3;
2457 if (nodes_old2new_subdomain_map.find(nn2) != nodes_old2new_subdomain_map.end())
2458 nn2_new = nodes_old2new_subdomain_map[nn2];
2459 if (nn2_new >= nodeOffsets_new[rank] && nn2_new < nodeOffsets_new[rank+1])
2460 {
2461 nodeElementBoundariesStar[nn2_new-nodeOffsets_new[rank]].insert(neb);
2462 supportedElementBoundaries.insert(neb);
2463 }
2464 //if any of the new nodes is negative, then this face does not belong to an element in the subdomain
2465 //so the check on nodes[1] will always be false
2466 const int nodes[3] = {nn0_new,nn1_new,nn2_new};
2467 NodeTuple<3> nodeTuple(nodes);
2468 elementBoundaryFile >> eatline;
2469 if (elementBoundaryElementsMap.find(nodeTuple) != elementBoundaryElementsMap.end())//this element boundary is on an element in the subdomain
2470 {
2471 elementBoundaries_subdomain.insert(neb);
2472 assert(nn0_new >= 0 && nn1_new >= 0 && nn2_new >= 0);
2473 if (nodeTuple.nodes[1] >= nodeOffsets_new[rank] && nodeTuple.nodes[1] < nodeOffsets_new[rank+1])
2474 elementBoundaries_subdomain_owned.insert(neb);
2475 if (ihasElementBoundaryMarkers > 0)
2476 elementBoundaryMaterialTypesMap[neb]=ebId;
2477 int eN_left = elementNumbering_old2new_subdomain_map[elementBoundaryElementsMap[nodeTuple].left];
2478 if (elementBoundariesMap.find(eN_left) != elementBoundariesMap.end())
2479 {
2480 elementBoundariesMap[eN_left][elementBoundaryElementsMap[nodeTuple].left_ebN_element] = neb;
2481 }
2482 else
2483 {
2484 //initialize
2485 valarray<int> elementBoundaries_element(-1,4);
2486 elementBoundariesMap[eN_left] = elementBoundaries_element;
2487 //assign
2488 elementBoundariesMap[eN_left][elementBoundaryElementsMap[nodeTuple].left_ebN_element] = neb;
2489 }
2490 if (elementBoundaryElementsMap[nodeTuple].right >= 0)
2491 {
2492 int eN_right = elementNumbering_old2new_subdomain_map[elementBoundaryElementsMap[nodeTuple].right];
2493 if (elementBoundariesMap.find(eN_right) != elementBoundariesMap.end())
2494 {
2495 elementBoundariesMap[eN_right][elementBoundaryElementsMap[nodeTuple].right_ebN_element] = neb;
2496 }
2497 else
2498 {
2499 //initialize
2500 valarray<int> elementBoundaries_element(-1, 4);
2501 elementBoundariesMap[eN_right] = elementBoundaries_element;
2502 //assign
2503 elementBoundariesMap[eN_right][elementBoundaryElementsMap[nodeTuple].right_ebN_element] = neb;
2504 }
2505 }
2506 }
2507 }
2508 //done reading element boundaries
2509 elementBoundaryFile.close();
2510 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done reading element boundaries");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2511 int nElementBoundaries_owned_subdomain=elementBoundaries_subdomain_owned.size(),
2512 nElementBoundaries_owned_new=0;
2513 MPI_Allreduce(&nElementBoundaries_owned_subdomain,&nElementBoundaries_owned_new,1,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
2514 assert(nElementBoundaries_owned_new == nElementBoundaries_global);
2515 //now get the element boundaries on the outside of the star
2516 for (auto elementBoundariesp=elementBoundariesMap.begin();
2517 elementBoundariesp!=elementBoundariesMap.end();
2518 elementBoundariesp++)
2519 {
2520 //loop over the nodes of this element for the owned nodes
2521 for (int iv=0;iv<4;iv++)
2522 {
2523 //the elementNodesArrayMap is in the old element numbering while the elementBoundariesMap is in the new element numbering
2524 int nN_global = elementNodesArrayMap[elementNumbering_new2old_subdomain_map[elementBoundariesp->first]][iv];
2525 if (nN_global >= nodeOffsets_new[rank] && nN_global < nodeOffsets_new[rank+1])
2526 {
2527 //add all the faces to this node star
2528 for(int eb=0;eb<4;eb++)
2529 {
2530 nodeElementBoundariesStar[nN_global-nodeOffsets_new[rank]].insert(elementBoundariesp->second[eb]);
2531 }
2532 }
2533 }
2534 }
2535 //build compact structures for nodeElementBoundariesArray
2536 valarray<int> nodeElementBoundaryOffsets(nNodes_subdomain_new[rank]+1);
2537 nodeElementBoundaryOffsets[0] = 0;
2538 for (int nN = 0; nN < nNodes_subdomain_new[rank]; nN++)
2539 nodeElementBoundaryOffsets[nN+1] = nodeElementBoundaryOffsets[nN]+nodeElementBoundariesStar[nN].size();
2540 valarray<int> nodeElementBoundariesArray(nodeElementBoundaryOffsets[nNodes_subdomain_new[rank]]);
2541 for (int nN=0,offset=0; nN < nNodes_subdomain_new[rank]; nN++)
2542 {
2543 for (set<int>::iterator ebN_star = nodeElementBoundariesStar[nN].begin(); ebN_star != nodeElementBoundariesStar[nN].end();
2544 ebN_star++,offset++)
2545 {
2546 nodeElementBoundariesArray[offset] = *ebN_star;
2547 }
2548 }
2549
2550 //get the number of elementBoundaries owned on each processor
2551 valarray<int> nElementBoundaries_subdomain_new(size),
2552 elementBoundaryOffsets_new(size+1);
2553 for (int sdN=0;sdN<size;sdN++)
2554 if (sdN == rank)
2555 nElementBoundaries_subdomain_new[sdN] = elementBoundaries_subdomain_owned.size();
2556 else
2557 nElementBoundaries_subdomain_new[sdN] = 0;
2558 valarray<int> nElementBoundaries_subdomain_new_send=nElementBoundaries_subdomain_new;
2559 MPI_Allreduce(&nElementBoundaries_subdomain_new_send[0],&nElementBoundaries_subdomain_new[0],
2560 size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
2561 elementBoundaryOffsets_new[0] = 0;
2562 for (int sdN=0;sdN<size;sdN++)
2563 elementBoundaryOffsets_new[sdN+1] = elementBoundaryOffsets_new[sdN]+nElementBoundaries_subdomain_new[sdN];
2564 //
2565 //Now as with elements and nodes build a global face numbering
2566 //
2567 valarray<int> elementBoundaryNumbering_new2old(elementBoundaries_subdomain_owned.size());
2568 map<int,int> elementBoundaryNumbering_old2new_map;
2569 set<int>::iterator ebN_ownedp=elementBoundaries_subdomain_owned.begin();
2570 for (int ebN=0;ebN<int(elementBoundaries_subdomain_owned.size());ebN++, ebN_ownedp++)
2571 {
2572 elementBoundaryNumbering_new2old[ebN] = *ebN_ownedp;
2573 elementBoundaryNumbering_old2new_map[*ebN_ownedp] = ebN+elementBoundaryOffsets_new[rank];
2574 }
2575 //
2576 //write this subdomain to the mapping file
2577 //
2578 logEvent("Writing/reading elementBoundary (face) numberings to hdf5",5);
2579 hsize_t eb_dims[]={static_cast<hsize_t>(nElementBoundaries_global)};
2580 hid_t eb_new2old_filespace_id = H5Screate_simple(ARRAY_RANK, eb_dims, NULL);
2581 mappings_plist_id = H5Pcreate(H5P_FILE_ACCESS);
2582 H5Pset_fapl_mpio(mappings_plist_id, PROTEUS_COMM_WORLD, MPI_INFO_NULL);
2583 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDWR, mappings_plist_id);
2584 H5Pclose(mappings_plist_id);
2585 hid_t eb_new2old_dataset_id = H5Dcreate(file_id, "elementBoundaryNumbering_new2old", H5T_NATIVE_INT,
2586 eb_new2old_filespace_id,
2587 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
2588 hsize_t eb_count[] = {static_cast<hsize_t>(nElementBoundaries_subdomain_new[rank])};
2589 hsize_t eb_offset[] = {static_cast<hsize_t>(elementBoundaryOffsets_new[rank])};
2590 hid_t eb_new2old_memspace_id = H5Screate_simple(ARRAY_RANK, eb_count, NULL);
2591 H5Sselect_hyperslab(eb_new2old_filespace_id, H5S_SELECT_SET, eb_offset, NULL, eb_count, NULL);
2592 hid_t eb_new2old_plist_id = H5Pcreate(H5P_DATASET_XFER);
2593 H5Pset_dxpl_mpio(eb_new2old_plist_id, H5FD_MPIO_COLLECTIVE);
2594 status = H5Dwrite(eb_new2old_dataset_id, H5T_NATIVE_INT, eb_new2old_memspace_id, eb_new2old_filespace_id,
2595 eb_new2old_plist_id, &elementBoundaryNumbering_new2old[0]);
2596 H5Pclose(eb_new2old_plist_id);
2597 H5Sclose(eb_new2old_memspace_id);
2598 H5Sclose(eb_new2old_filespace_id);
2599 H5Dclose(eb_new2old_dataset_id);
2600 //do old2new map too, can't use hyperslab
2601 valarray<hsize_t> old_elementBoundary_indices(nElementBoundaries_subdomain_new[rank]);
2602 valarray<int> new_elementBoundary_indices(nElementBoundaries_subdomain_new[rank]);
2603 for (int i=0;i<nElementBoundaries_subdomain_new[rank];i++)
2604 {
2605 old_elementBoundary_indices[i] = elementBoundaryNumbering_new2old[i];
2606 new_elementBoundary_indices[i] = elementBoundaryOffsets_new[rank]+i;
2607 }
2608 hid_t eb_old2new_filespace_id = H5Screate_simple(ARRAY_RANK, eb_dims, NULL);
2609 hid_t eb_old2new_dataset_id = H5Dcreate(file_id, "elementBoundaryNumbering_old2new", H5T_NATIVE_INT,
2610 eb_old2new_filespace_id,
2611 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
2612 hid_t eb_old2new_memspace_id = H5Screate_simple(ARRAY_RANK, eb_count, NULL);
2613 status = H5Sselect_elements(eb_old2new_filespace_id, H5S_SELECT_SET,
2614 nElementBoundaries_subdomain_new[rank], &old_elementBoundary_indices[0]);
2615 hid_t eb_old2new_plist_id = H5Pcreate(H5P_DATASET_XFER);
2616 H5Pset_dxpl_mpio(eb_old2new_plist_id, H5FD_MPIO_COLLECTIVE);
2617 status = H5Dwrite(eb_old2new_dataset_id, H5T_NATIVE_INT,
2618 eb_old2new_memspace_id, eb_old2new_filespace_id,
2619 eb_old2new_plist_id, &new_elementBoundary_indices[0]);
2620 H5Pclose(eb_new2old_plist_id);
2621 H5Sclose(eb_old2new_memspace_id);
2622 H5Dclose(eb_old2new_dataset_id);
2623 H5Sclose(eb_old2new_filespace_id);
2624 H5Fclose(file_id);
2625 //now get maps for all the elements on the subdomain, not just owned
2626 //
2627 valarray<hsize_t> old_elementBoundary_indices_subdomain(elementBoundaries_subdomain.size());
2628 valarray<int> new_elementBoundary_indices_subdomain(elementBoundaries_subdomain.size());
2629 int ebN_subdomain = 0;
2630 for (auto it = elementBoundaries_subdomain.begin();
2631 it != elementBoundaries_subdomain.end();
2632 it++, ebN_subdomain++)
2633 {
2634 old_elementBoundary_indices_subdomain[ebN_subdomain] = static_cast<hsize_t>(*it);
2635 }
2636 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT);
2637 eb_old2new_filespace_id = H5Screate_simple(ARRAY_RANK, eb_dims, NULL);
2638 eb_old2new_dataset_id = H5Dopen1(file_id, "/elementBoundaryNumbering_old2new");
2639 status = H5Sselect_elements(eb_old2new_filespace_id, H5S_SELECT_SET,
2640 elementBoundaries_subdomain.size(),
2641 &old_elementBoundary_indices_subdomain[0]);
2642 hsize_t eb_subdomain_count[]={static_cast<hsize_t>(elementBoundaries_subdomain.size())};
2643 hid_t eb_old2new_subdomain_memspace_id = H5Screate_simple(ARRAY_RANK, eb_subdomain_count, NULL);
2644 hid_t eb_old2new_subdomain_plist_id = H5Pcreate(H5P_DATASET_XFER);
2645 H5Pset_dxpl_mpio(eb_old2new_subdomain_plist_id, H5FD_MPIO_COLLECTIVE);
2646 status = H5Dread(eb_old2new_dataset_id, H5T_NATIVE_INT,
2647 eb_old2new_subdomain_memspace_id, eb_old2new_filespace_id,
2648 H5P_DEFAULT, &new_elementBoundary_indices_subdomain[0]);
2649 H5Pclose(eb_old2new_subdomain_plist_id);
2650 H5Sclose(eb_old2new_subdomain_memspace_id);
2651 H5Sclose(eb_old2new_filespace_id);
2652 H5Dclose(eb_old2new_dataset_id);
2653 H5Fclose(file_id);
2654 map<int,int> elementBoundaryNumbering_old2new_subdomain_map;
2655 map<int,int> elementBoundaryNumbering_new2old_subdomain_map;
2656 for (int i=0;i<elementBoundaries_subdomain.size();i++)
2657 {
2658 elementBoundaryNumbering_old2new_subdomain_map[old_elementBoundary_indices_subdomain[i]] = new_elementBoundary_indices_subdomain[i];
2659 elementBoundaryNumbering_new2old_subdomain_map[new_elementBoundary_indices_subdomain[i]] = old_elementBoundary_indices_subdomain[i];
2660 }
2661 IS elementBoundaryNumberingIS_subdomain_new2old;
2662 ISCreateGeneral(PROTEUS_COMM_WORLD,elementBoundaries_subdomain_owned.size(),&elementBoundaryNumbering_new2old[0],PETSC_COPY_VALUES,&elementBoundaryNumberingIS_subdomain_new2old);
2663 if (test)
2664 {
2665 IS elementBoundaryNumberingIS_global_new2old;
2666 const PetscInt *elementBoundaryNumbering_global_new2old;
2667 valarray<int> elementBoundaryNumbering_global_old2new(nElementBoundaries_global);
2668 ISAllGather(elementBoundaryNumberingIS_subdomain_new2old,&elementBoundaryNumberingIS_global_new2old);
2669 elementBoundaryNumbering_global_old2new.resize(newMesh.nElementBoundaries_global);
2670 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Allocating elementBoudnary old2new/new2old");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2671 ISGetIndices(elementBoundaryNumberingIS_global_new2old,&elementBoundaryNumbering_global_new2old);
2672 for (int i=0;i<nElementBoundaries_global;i++)
2673 {
2674 elementBoundaryNumbering_global_old2new[elementBoundaryNumbering_global_new2old[i]]=i;
2675 }
2676
2677 herr_t status;
2678 valarray<int> elementBoundaryNumbering_old2new_read(nElementBoundaries_global);
2679 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT);
2680 eb_old2new_dataset_id = H5Dopen1(file_id, "/elementBoundaryNumbering_old2new");
2681 status = H5Dread(eb_old2new_dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
2682 &elementBoundaryNumbering_old2new_read[0]);
2683 status = H5Dclose(eb_old2new_dataset_id);
2684 for (int i=0;i<nElementBoundaries_global;i++)
2685 assert(elementBoundaryNumbering_global_old2new[i] == elementBoundaryNumbering_old2new_read[i]);
2686 std::cout<<"==================out of core old2new elementBoundaries is correct!===================="<<std::endl;
2687 hid_t eb_new2old_dataset_id = H5Dopen1(file_id, "/elementBoundaryNumbering_new2old");
2688 valarray<int> elementBoundaryNumbering_new2old_read(nElementBoundaries_global);
2689 status = H5Dread(eb_new2old_dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
2690 &elementBoundaryNumbering_new2old_read[0]);
2691 status = H5Dclose(eb_new2old_dataset_id);
2692 status = H5Fclose(file_id);
2693 for (int i=0;i<nElementBoundaries_global;i++)
2694 assert(elementBoundaryNumbering_global_new2old[i] == elementBoundaryNumbering_new2old_read[i]);
2695 std::cout<<"==================out of core new2old elementBoundaries is correct!===================="<<std::endl;
2696 for (int i=0;i<elementBoundaries_subdomain.size();i++)
2697 {
2698 int ebN = old_elementBoundary_indices_subdomain[i];
2699 assert(elementBoundaryNumbering_global_old2new[ebN] == elementBoundaryNumbering_old2new_subdomain_map[ebN]);
2700 }
2701 std::cout<<"==================out of core elementBoundaries old2new subdomain_map is correct!===================="<<std::endl;
2702 for (int i=0;i<elementBoundaries_subdomain.size();i++)
2703 {
2704 int ebN = new_elementBoundary_indices_subdomain[i];
2705 assert(elementBoundaryNumbering_global_new2old[ebN] == elementBoundaryNumbering_new2old_subdomain_map[ebN]);
2706 }
2707 std::cout<<"==================out of core elementBoundaries new2old subdomain_map is correct!===================="<<std::endl;
2708 ISRestoreIndices(elementBoundaryNumberingIS_global_new2old,&elementBoundaryNumbering_global_new2old);
2709 ierr=ISDestroy(&elementBoundaryNumberingIS_subdomain_new2old);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2710 ierr=ISDestroy(&elementBoundaryNumberingIS_global_new2old);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2711 }
2712 PetscLogEventEnd(build_subdomains_faces_event,0,0,0,0);
2713 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done allocating elementBoudnary old2new/new2old");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2714 int build_subdomains_edges_event;
2715 PetscLogEventRegister("Subd edges",0,&build_subdomains_edges_event);
2716 PetscLogEventBegin(build_subdomains_edges_event,0,0,0,0);
2717
2718 //
2719 //4c,5c. Repeate the process for edges
2720 //
2721 logEvent("Generating global edge numbering and ownership corresponding to new subdomain ownership",5);
2722 std::ifstream edgeFile(edgeFileName.c_str());
2723
2724 if (!edgeFile.good())
2725 {
2726 std::cerr<<"cannot open Tetgen edge file"
2727 <<edgeFileName<<std::endl;
2728 failed = true;
2729 return failed;
2730 }
2731
2732 bool hasEdgeMarkers = false;
2733 int nEdges_global;
2734 int ihasEdgeMarkers(0);
2735 edgeFile >> eatcomments >> nEdges_global >> eatline;// edge file doesn currently contain markers >> ihasEdgeMarkers >> eatline ;
2736 assert(nEdges_global > 0);
2737 if (ihasEdgeMarkers > 0)
2738 {
2739 hasEdgeMarkers = true;
2740 }
2741 newMesh.nEdges_global = nEdges_global;
2742 set<int> edges_subdomain_owned;
2743 vector<set<int> > nodeEdgesStar(nNodes_subdomain_new[rank]);
2744 map<int,int> edgeMaterialTypesMap;
2745 map<int,valarray<int> > elementEdgesMap;
2746 map<int,pair<int,int> > edgeNodesMap;
2747 set<int> supportedEdges;
2748 for (int ied = 0; ied < nEdges_global; ied++)
2749 {
2750 int ned,nn0,nn1; int edId(0);
2751 edgeFile >> eatcomments >> ned >> nn0 >> nn1;
2752 if (ihasEdgeMarkers > 0)
2753 edgeFile >> edId;
2754 ned -= indexBase;
2755 nn0 -= indexBase;
2756 nn1 -= indexBase;
2757 assert(0 <= ned && ned < nEdges_global && edgeFile.good());
2758 int nn0_new = -1;
2759 if (nodes_old2new_subdomain_map.find(nn0) != nodes_old2new_subdomain_map.end())
2760 nn0_new = nodes_old2new_subdomain_map[nn0];
2761 if (nn0_new >= nodeOffsets_new[rank] && nn0_new < nodeOffsets_new[rank+1])
2762 {
2763 nodeEdgesStar.at(nn0_new-nodeOffsets_new[rank]).insert(ned);
2764 supportedEdges.insert(ned);
2765 }
2766 int nn1_new = -2;
2767 if(nodes_old2new_subdomain_map.find(nn1) != nodes_old2new_subdomain_map.end())
2768 nn1_new = nodes_old2new_subdomain_map[nn1];
2769 if (nn1_new >= nodeOffsets_new[rank] && nn1_new < nodeOffsets_new[rank+1])
2770 {
2771 nodeEdgesStar.at(nn1_new-nodeOffsets_new[rank]).insert(ned);
2772 supportedEdges.insert(ned);
2773 }
2774 int nodes[2] = {nn0_new,nn1_new};
2775 NodeTuple<2> nodeTuple(nodes);
2776 edgeFile >> eatline;
2777 if (edgeElementsMap.find(nodeTuple) != edgeElementsMap.end())//this edge is on an element in the subdomain
2778 {
2779 if (nodeTuple.nodes[0] >= nodeOffsets_new[rank] && nodeTuple.nodes[0] < nodeOffsets_new[rank+1])
2780 edges_subdomain_owned.insert(ned);
2781 //pick up all the edges on the subdomain and store their nodes
2782 edgeNodesMap[ned].first = nodeTuple.nodes[0];
2783 edgeNodesMap[ned].second = nodeTuple.nodes[1];
2784 if (ihasEdgeMarkers > 0)
2785 edgeMaterialTypesMap[ned]=edId;
2786 for (auto elementp=edgeElementsMap[nodeTuple].begin();
2787 elementp != edgeElementsMap[nodeTuple].end();
2788 elementp++)
2789 {
2790 int eN = elementNumbering_old2new_subdomain_map[elementp->first];
2791 if (elementEdgesMap.find(eN) != elementEdgesMap.end())
2792 {
2793 elementEdgesMap[eN][elementp->second] = ned;
2794 }
2795 else
2796 {
2797 std::valarray<int> init(-1,6);
2798 elementEdgesMap[eN] = init;
2799 elementEdgesMap[eN][elementp->second] = ned;
2800 }
2801 }
2802 }
2803 }//end iv
2804 edgeFile.close();
2805 int nEdges_owned_subdomain=edges_subdomain_owned.size(),
2806 nEdges_owned_new=0;
2807 MPI_Allreduce(&nEdges_owned_subdomain,&nEdges_owned_new,1,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
2808 assert(nEdges_owned_new == nEdges_global);
2809 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done reading edges");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2810 //done with edge file
2811 //
2812 //just as with faces, we need to add edges along outer boundaries of star
2813 //not sure if we need to collect nodeEdges star above anymore, since we're doing this
2814 //
2815 for (auto edgesp=elementEdgesMap.begin();
2816 edgesp!=elementEdgesMap.end();
2817 edgesp++)
2818 {
2819 //loop over the nodes of this element for the owned nodes
2820 for (int iv=0;iv<4;iv++)
2821 {
2822 //the elementNodesArrayMap is in the old element numbering while the elementEdgesMap is in the new element numbering
2823 int nN_global = -1;
2824 if (elementNumbering_new2old_subdomain_map.find(edgesp->first) != elementNumbering_new2old_subdomain_map.end())
2825 nN_global = elementNodesArrayMap[elementNumbering_new2old_subdomain_map[edgesp->first]][iv];
2826 if (nN_global >= nodeOffsets_new[rank] && nN_global < nodeOffsets_new[rank+1])
2827 {
2828 //add all the edges to this node star
2829 for(int ed=0;ed<6;ed++)
2830 {
2831 nodeEdgesStar.at(nN_global-nodeOffsets_new[rank]).insert(edgesp->second[ed]);
2832 }
2833 }
2834 }
2835 }
2836 //build compact data structures for nodeEdgesArray
2837 valarray<int> nodeEdgeOffsets(nNodes_subdomain_new[rank]+1);
2838 nodeEdgeOffsets[0] = 0;
2839 for (int nN = 0; nN < nNodes_subdomain_new[rank]; nN++)
2840 nodeEdgeOffsets[nN+1] = nodeEdgeOffsets[nN]+nodeEdgesStar.at(nN).size();
2841 valarray<int> nodeEdgesArray(nodeEdgeOffsets[nNodes_subdomain_new[rank]]);
2842 for (int nN=0,offset=0; nN < nNodes_subdomain_new[rank]; nN++)
2843 {
2844 for (auto edN_star = nodeEdgesStar.at(nN).begin();
2845 edN_star != nodeEdgesStar.at(nN).end();
2846 edN_star++,offset++)
2847 {
2848 nodeEdgesArray[offset] = *edN_star;
2849 }
2850 }
2851 newMesh.subdomainp->nEdges_global = edgeNodesMap.size();
2852 //get the number of edges on each processor
2853 valarray<int> nEdges_subdomain_new(size),
2854 edgeOffsets_new(size+1);
2855 for (int sdN=0;sdN<size;sdN++)
2856 if (sdN == rank)
2857 nEdges_subdomain_new[sdN] = edges_subdomain_owned.size();
2858 else
2859 nEdges_subdomain_new[sdN] = 0;
2860 valarray<int> nEdges_subdomain_new_send=nEdges_subdomain_new;
2861 MPI_Allreduce(&nEdges_subdomain_new_send[0],&nEdges_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
2862 //
2863 //construct new offsets for owned edges
2864 //
2865 edgeOffsets_new[0] = 0;
2866 for (int sdN=0;sdN<size;sdN++)
2867 edgeOffsets_new[sdN+1] = edgeOffsets_new[sdN]+nEdges_subdomain_new[sdN];
2868 //
2869 //Now as with elementBoundaries, build a global face numbering
2870 //resetting the edge based information is a little different since much of this is currently built below based
2871 //on the element and node information
2872 //
2873 valarray<int> edgeNumbering_new2old(edges_subdomain_owned.size());
2874 map<int,int> edgeNumbering_old2new_map;
2875 set<int>::iterator edN_ownedp=edges_subdomain_owned.begin();
2876 for (int edN=0;edN<int(edges_subdomain_owned.size());edN++,edN_ownedp++)
2877 {
2878 edgeNumbering_new2old[edN] = *edN_ownedp;
2879 edgeNumbering_old2new_map[*edN_ownedp] = edN+edgeOffsets_new[rank];
2880 }
2881 //
2882 //write this subdomain to the mapping file
2883 //
2884 logEvent("Writing/reading edge numberings to hdf5",5);
2885 hsize_t ed_dims[]={static_cast<hsize_t>(nEdges_global)};
2886 hid_t ed_new2old_filespace_id = H5Screate_simple(ARRAY_RANK, ed_dims, NULL);
2887 mappings_plist_id = H5Pcreate(H5P_FILE_ACCESS);
2888 H5Pset_fapl_mpio(mappings_plist_id, PROTEUS_COMM_WORLD, MPI_INFO_NULL);
2889 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDWR, mappings_plist_id);
2890 H5Pclose(mappings_plist_id);
2891 hid_t ed_new2old_dataset_id = H5Dcreate(file_id, "edgeNumbering_new2old", H5T_NATIVE_INT,
2892 ed_new2old_filespace_id,
2893 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
2894 hsize_t ed_count[]={static_cast<hsize_t>(nEdges_subdomain_new[rank])};
2895 hsize_t ed_offset[]={static_cast<hsize_t>(edgeOffsets_new[rank])};
2896 hid_t ed_new2old_memspace_id = H5Screate_simple(ARRAY_RANK, ed_count, NULL);
2897 H5Sselect_hyperslab(ed_new2old_filespace_id, H5S_SELECT_SET, ed_offset, NULL, ed_count, NULL);
2898 hid_t ed_new2old_plist_id = H5Pcreate(H5P_DATASET_XFER);
2899 H5Pset_dxpl_mpio(ed_new2old_plist_id, H5FD_MPIO_COLLECTIVE);
2900 status = H5Dwrite(ed_new2old_dataset_id, H5T_NATIVE_INT,
2901 ed_new2old_memspace_id, ed_new2old_filespace_id,
2902 ed_new2old_plist_id, &edgeNumbering_new2old[0]);
2903 H5Pclose(ed_new2old_plist_id);
2904 H5Sclose(ed_new2old_memspace_id);
2905 H5Sclose(ed_new2old_filespace_id);
2906 H5Dclose(ed_new2old_dataset_id);
2907 //do old2new map too, can't use hyperslab
2908 valarray<hsize_t> old_edge_indices(static_cast<hsize_t>(nEdges_subdomain_new[rank]));
2909 valarray<int> new_edge_indices(nEdges_subdomain_new[rank]);
2910 for (int i=0;i<nEdges_subdomain_new[rank];i++)
2911 {
2912 old_edge_indices[i] = static_cast<hsize_t>(edgeNumbering_new2old[i]);
2913 new_edge_indices[i] = edgeOffsets_new[rank]+i;
2914 }
2915 hid_t ed_old2new_filespace_id = H5Screate_simple(ARRAY_RANK, ed_dims, NULL);
2916 hid_t ed_old2new_dataspace_id = H5Dcreate(file_id, "edgeNumbering_old2new", H5T_NATIVE_INT,
2917 ed_old2new_filespace_id,
2918 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
2919 hid_t ed_old2new_memspace_id = H5Screate_simple(ARRAY_RANK, ed_count, NULL);
2920 ed_old2new_filespace_id = H5Dget_space(ed_old2new_dataspace_id);
2921 status = H5Sselect_elements(ed_old2new_filespace_id, H5S_SELECT_SET,
2922 nEdges_subdomain_new[rank], &old_edge_indices[0]);
2923 hid_t ed_old2new_plist_id = H5Pcreate(H5P_DATASET_XFER);
2924 H5Pset_dxpl_mpio(ed_old2new_plist_id, H5FD_MPIO_COLLECTIVE);
2925 status = H5Dwrite(ed_old2new_dataspace_id, H5T_NATIVE_INT,
2926 ed_old2new_memspace_id, ed_old2new_filespace_id,
2927 ed_old2new_plist_id, &new_edge_indices[0]);
2928 H5Pclose(ed_old2new_plist_id);
2929 H5Sclose(ed_old2new_memspace_id);
2930 H5Dclose(ed_old2new_dataspace_id);
2931 H5Sclose(ed_old2new_filespace_id);
2932 H5Fclose(file_id);
2933 //
2934 //now get maps for all the edges on the subdomain, not just owned
2935 valarray<hsize_t> old_edge_indices_subdomain(edgeNodesMap.size());
2936 valarray<int> new_edge_indices_subdomain(edgeNodesMap.size());
2937 int edN_old_subdomain = 0;
2938 for (auto it = edgeNodesMap.begin(); it != edgeNodesMap.end(); it++, edN_old_subdomain++)
2939 {
2940 old_edge_indices_subdomain[edN_old_subdomain] = static_cast<hsize_t>(it->first);
2941 }
2942 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT);
2943 ed_old2new_dataspace_id = H5Dopen1(file_id, "/edgeNumbering_old2new");
2944 ed_old2new_filespace_id = H5Screate_simple(ARRAY_RANK, ed_dims, NULL);
2945 status = H5Sselect_elements(ed_old2new_filespace_id, H5S_SELECT_SET,
2946 edgeNodesMap.size(), &old_edge_indices_subdomain[0]);
2947 hsize_t ed_subdomain_count[]={static_cast<hsize_t>(edgeNodesMap.size())};
2948 hid_t ed_old2new_subdomain_memspace_id = H5Screate_simple(ARRAY_RANK, ed_subdomain_count, NULL);
2949 hid_t ed_old2new_subdomain_plist_id = H5Pcreate(H5P_DATASET_XFER);
2950 H5Pset_dxpl_mpio(ed_old2new_subdomain_plist_id, H5FD_MPIO_COLLECTIVE);
2951 status = H5Dread(ed_old2new_dataspace_id, H5T_NATIVE_INT, ed_old2new_subdomain_memspace_id,
2952 ed_old2new_filespace_id,
2953 H5P_DEFAULT, &new_edge_indices_subdomain[0]);
2954 H5Pclose(ed_old2new_subdomain_plist_id);
2955 H5Sclose(ed_old2new_subdomain_memspace_id);
2956 H5Sclose(ed_old2new_filespace_id);
2957 H5Dclose(ed_old2new_dataspace_id);
2958 H5Fclose(file_id);
2959 map<int,int> edgeNumbering_old2new_subdomain_map;
2960 map<int,int> edgeNumbering_new2old_subdomain_map;
2961 for (int i=0;i<edgeNodesMap.size();i++)
2962 {
2963 edgeNumbering_old2new_subdomain_map[old_edge_indices_subdomain[i]] = new_edge_indices_subdomain[i];
2964 edgeNumbering_new2old_subdomain_map[new_edge_indices_subdomain[i]] = old_edge_indices_subdomain[i];
2965 }
2966 if (test)
2967 {
2968 IS edgeNumberingIS_subdomain_new2old;
2969 ISCreateGeneral(PROTEUS_COMM_WORLD,edges_subdomain_owned.size(),&edgeNumbering_new2old[0],PETSC_COPY_VALUES,&edgeNumberingIS_subdomain_new2old);
2970 IS edgeNumberingIS_global_new2old;
2971 ISAllGather(edgeNumberingIS_subdomain_new2old,&edgeNumberingIS_global_new2old);
2972 const PetscInt *edgeNumbering_global_new2old;
2973 ISGetIndices(edgeNumberingIS_global_new2old,&edgeNumbering_global_new2old);
2974 valarray<int> edgeNumbering_global_old2new(newMesh.nEdges_global);
2975 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Setting edgeNumering old2new/new2old");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
2976 for (int edN=0;edN<newMesh.nEdges_global;edN++)
2977 {
2978 edgeNumbering_global_old2new[edgeNumbering_global_new2old[edN]] = edN;
2979 }
2980
2981 herr_t status;
2982 valarray<int> edgeNumbering_old2new_read(nEdges_global);
2983 file_id = H5Fopen(H5FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT);
2984 hid_t ed_old2new_dataset_id = H5Dopen1(file_id, "/edgeNumbering_old2new");
2985 status = H5Dread(ed_old2new_dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
2986 &edgeNumbering_old2new_read[0]);
2987 status = H5Dclose(ed_old2new_dataset_id);
2988 for (int i=0;i<nEdges_global;i++)
2989 assert(edgeNumbering_global_old2new[i] == edgeNumbering_old2new_read[i]);
2990 std::cout<<"==================out of core old2new edges is correct!===================="<<std::endl;
2991 hid_t ed_new2old_dataset_id = H5Dopen1(file_id, "/edgeNumbering_new2old");
2992 valarray<int> edgeNumbering_new2old_read(nEdges_global);
2993 status = H5Dread(ed_new2old_dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
2994 &edgeNumbering_new2old_read[0]);
2995 status = H5Dclose(ed_new2old_dataset_id);
2996 status = H5Fclose(file_id);
2997 for (int i=0;i<nEdges_global;i++)
2998 assert(edgeNumbering_global_new2old[i] == edgeNumbering_new2old_read[i]);
2999 std::cout<<"==================out of core new2old edges is correct!===================="<<std::endl;
3000
3001 for (auto it = edgeNodesMap.begin(); it != edgeNodesMap.end(); ++it)
3002 {
3003 assert(edgeNumbering_global_old2new[it->first] == edgeNumbering_old2new_subdomain_map[it->first]);
3004 }
3005 std::cout<<"==================out of core edgeNumbering old2new subdomain is correct!===================="<<std::endl;
3006 for (int i = 0; i < edgeNodesMap.size(); i++)
3007 {
3008 int edN = new_edge_indices_subdomain[i];
3009 assert(edgeNumbering_global_new2old[edN] == edgeNumbering_new2old_subdomain_map[edN]);
3010 }
3011 std::cout<<"==================out of core edgeNumbering new2old subdomain is correct!===================="<<std::endl;
3012 ISRestoreIndices(edgeNumberingIS_global_new2old,&edgeNumbering_global_new2old);
3013 ierr=ISDestroy(&edgeNumberingIS_subdomain_new2old);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3014 ierr=ISDestroy(&edgeNumberingIS_global_new2old);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3015 }
3016 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done allocating edgeNumering old2new/new2old");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3017 //
3018 //6. Figure out what is in the node stars but not locally owned, create ghost information
3019 //
3020 logEvent("Creating ghost information",5);
3021 set<int> elements_overlap,nodes_overlap,elementBoundaries_overlap,edges_overlap;
3022 for (int nN = 0; nN < nNodes_subdomain_new[rank]; nN++)
3023 {
3024 //nodes
3025 for (int offset = nodeStarOffsetsNew[nN];offset<nodeStarOffsetsNew[nN+1];offset++)
3026 {
3027 int nN_point_global = nodeStarArrayNew[offset];
3028 bool offproc = nN_point_global < nodeOffsets_new[rank] || nN_point_global >= nodeOffsets_new[rank+1];
3029 if (offproc)
3030 nodes_overlap.insert(nN_point_global);
3031 }
3032 //elements
3033 for (int eN_star_offset = nodeElementOffsets[nN];
3034 eN_star_offset < nodeElementOffsets[nN+1]; eN_star_offset++)
3035 {
3036 int eN_star_old = nodeElementsArray[eN_star_offset];
3037 int eN_star_new = elementNumbering_old2new_subdomain_map[eN_star_old];
3038 bool offproc = eN_star_new >= elementOffsets_new[rank+1] || eN_star_new < elementOffsets_new[rank];
3039 if (offproc)
3040 elements_overlap.insert(eN_star_new);
3041 }
3042 //element boundaries
3043 for (int ebN_star_offset = nodeElementBoundaryOffsets[nN];
3044 ebN_star_offset < nodeElementBoundaryOffsets[nN+1]; ebN_star_offset++)
3045 {
3046 int ebN_star_old = nodeElementBoundariesArray[ebN_star_offset];
3047 int ebN_star_new = elementBoundaryNumbering_old2new_subdomain_map[ebN_star_old];
3048 bool offproc = ebN_star_new >= elementBoundaryOffsets_new[rank+1] || ebN_star_new < elementBoundaryOffsets_new[rank];
3049 if (offproc)
3050 elementBoundaries_overlap.insert(ebN_star_new);
3051 }
3052 //edges in overlap
3053 for (int edN_star_offset = nodeEdgeOffsets[nN];
3054 edN_star_offset < nodeEdgeOffsets[nN+1]; edN_star_offset++)
3055 {
3056 int edN_star_old = nodeEdgesArray[edN_star_offset];
3057 int edN_star_new = edgeNumbering_old2new_subdomain_map[edN_star_old];
3058 bool offproc = edN_star_new >= edgeOffsets_new[rank+1] || edN_star_new < edgeOffsets_new[rank];
3059 if (offproc)
3060 edges_overlap.insert(edN_star_new);
3061 }
3062 }//nodes on this processor
3063 //cek debugging, edge overlap seems to be messed up. Check global node tuples of edges vs global edge numbers
3064 assert(edges_overlap.size() + nEdges_subdomain_new[rank] == edgeNodesMap.size());
3065 //
3066 //enumerate the overlap
3067 //
3068 int nN_subdomain = nNodes_subdomain_new[rank];
3069 map<int,int> nodes_overlap_global2subdomainMap;
3070 for (auto nN_globalp=nodes_overlap.begin();nN_globalp != nodes_overlap.end(); nN_globalp++,nN_subdomain++)
3071 nodes_overlap_global2subdomainMap[*nN_globalp] = nN_subdomain;
3072 //
3073 //7. add any addtional overlap, skip for now
3074 //
3075 //cek todo: re-enable additional overlap with out of core global maps
3076 assert(nNodes_overlap<2);
3077 logEvent("Skipping additiona of addtional overlap--only minimal overlap supported by this partioning function for now",5);
3078 //
3079 PetscLogEventEnd(build_subdomains_edges_event,0,0,0,0);
3080 int build_subdomains_renumber_event;
3081 PetscLogEventRegister("Subd's renumber",0,&build_subdomains_renumber_event);
3082 PetscLogEventBegin(build_subdomains_renumber_event,0,0,0,0);
3083 //
3084 //8. Build subdomain meshes in new numbering, assumes memory not allocated in subdomain mesh
3085 //
3086 logEvent("USER WARNING: You are partioning in parallel directly from Tetgen files (parun -F ...). ",5);
3087 logEvent("USER WARNING: You must use the 'f' and 'ee' flags in the triangleOptions input to avoid errors.",5);
3088 logEvent("USER WARNING: You may have done so, but the tetgen options are not stored in the Tetgen files, so we can't know.",5);
3089 logEvent("Creating final subdomain mesh data structures",5);
3090 if (newMesh.subdomainp == NULL)
3091 newMesh.subdomainp = new Mesh();
3092 newMesh.subdomainp->nElements_global = nElements_subdomain_new[rank] + elements_overlap.size();
3093 newMesh.subdomainp->nNodes_global = nNodes_subdomain_new[rank] + nodes_overlap.size();
3094 newMesh.subdomainp->nElementBoundaries_global = nElementBoundaries_subdomain_new[rank]+elementBoundaries_overlap.size();
3095 assert(int(edges_subdomain_owned.size()+edges_overlap.size()) == newMesh.subdomainp->nEdges_global);
3096 //newMesh.subdomainp->nEdges_global = edges_subdomain_owned.size()+edges_overlap.size();
3097 newMesh.subdomainp->nNodes_element = newMesh.nNodes_element;
3100 //subdomain 2 global mappings (including ghost info)
3101 valarray<int> nodeNumbering_subdomain2global(newMesh.subdomainp->nNodes_global);
3102 valarray<int> elementNumbering_subdomain2global(newMesh.subdomainp->nElements_global);
3103 valarray<int> elementBoundaryNumbering_subdomain2global(newMesh.subdomainp->nElementBoundaries_global);
3104 valarray<int> edgeNumbering_subdomain2global(newMesh.subdomainp->nEdges_global);
3105 map<int,int> nodeNumbering_global2subdomainMap;
3106 map<int,int> elementBoundaryNumbering_global2subdomainMap;
3107 map<int,int> edgeNumbering_global2subdomainMap;
3108 newMesh.subdomainp->nodeArray = new double[newMesh.subdomainp->nNodes_global*3];
3109 newMesh.subdomainp->nodeMaterialTypes = new int[newMesh.subdomainp->nNodes_global];
3110 //
3111 //now finally finish reading node coordinates and node flags
3112 //
3113 for (int iv = 0; iv < nNodes_global; iv++)
3114 {
3115 int nv; double x,y,z; int nodeId(0);
3116 vertexFile >> eatcomments >> nv >> x >> y >> z;
3117 if (hasVertexMarkers > 0)
3118 vertexFile >> nodeId;
3119 nv -= indexBase;
3120 assert(0 <= nv && nv < nNodes_global && vertexFile.good());
3121 int nN_global_new = -1;
3122 if (nodes_old2new_subdomain_map.find(nv) != nodes_old2new_subdomain_map.end())
3123 nN_global_new = nodes_old2new_subdomain_map[nv];
3124 //local
3125 if (nN_global_new >= nodeOffsets_new[rank] && nN_global_new < nodeOffsets_new[rank+1])
3126 {
3127 int nv_subdomain_new = nN_global_new - nodeOffsets_new[rank];
3128 nodeNumbering_subdomain2global[nv_subdomain_new] = nN_global_new;
3129 nodeNumbering_global2subdomainMap[nN_global_new] = nv_subdomain_new;
3130 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 0] = x;
3131 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 1] = y;
3132 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 2] = z;
3133 if (hasVertexMarkers > 0)
3134 newMesh.subdomainp->nodeMaterialTypes[nv_subdomain_new] = nodeId;
3135 }
3136 //overlap
3137 if (nodes_overlap.count(nN_global_new) == 1)
3138 {
3139 int nv_subdomain_new = nodes_overlap_global2subdomainMap[nN_global_new];
3140 nodeNumbering_subdomain2global[nv_subdomain_new] = nN_global_new;
3141 nodeNumbering_global2subdomainMap[nN_global_new] = nv_subdomain_new;
3142 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 0] = x;
3143 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 1] = y;
3144 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 2] = z;
3145 if (hasVertexMarkers > 0)
3146 newMesh.subdomainp->nodeMaterialTypes[nv_subdomain_new] = nodeId;
3147 }
3148 vertexFile >> eatline;
3149 }//end iv
3150 vertexFile.close();
3151 //done with vertex file (and all file reads at this point)
3152 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done reading vertices");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3153
3155 newMesh.subdomainp->elementMaterialTypes = new int[newMesh.subdomainp->nElements_global];
3156 //
3157 //elements
3158 //
3159 //locally owned
3160 //
3161 for (int eN = 0; eN < nElements_subdomain_new[rank]; eN++)
3162 {
3163 int eN_global_new = elementOffsets_new[rank] + eN;
3164 int eN_global_old = elementNumbering_subdomain_new2old[eN];
3165 elementNumbering_subdomain2global[eN] = eN_global_new;
3166 newMesh.subdomainp->elementMaterialTypes[eN] = elementMaterialTypesMap[eN_global_old];
3167 for (int nN = 0; nN < newMesh.subdomainp->nNodes_element; nN++)
3168 {
3169 int nN_global_new = elementNodesArrayMap[eN_global_old][nN];
3170 int nN_subdomain = nodeNumbering_global2subdomainMap[nN_global_new];
3171 newMesh.subdomainp->elementNodesArray[eN*newMesh.subdomainp->nNodes_element + nN]= nN_subdomain;
3172 }
3173 }
3174 //
3175 //ghost
3176 //
3177 set<int>::iterator eN_p = elements_overlap.begin();
3178 for (int eN = nElements_subdomain_new[rank]; eN < nElements_subdomain_new[rank] + int(elements_overlap.size()); eN++,eN_p++)
3179 {
3180 int eN_global_new = *eN_p;
3181 int eN_global_old = elementNumbering_new2old_subdomain_map[eN_global_new];
3182 elementNumbering_subdomain2global[eN] = eN_global_new;
3183 newMesh.subdomainp->elementMaterialTypes[eN] = elementMaterialTypesMap[eN_global_old];
3184 for (int nN = 0; nN < newMesh.subdomainp->nNodes_element; nN++)
3185 {
3186 int nN_global_new = elementNodesArrayMap[eN_global_old][nN];
3187 int nN_subdomain = nodeNumbering_global2subdomainMap[nN_global_new];
3188 newMesh.subdomainp->elementNodesArray[eN*newMesh.subdomainp->nNodes_element + nN]= nN_subdomain;
3189 }
3190 }
3191 //
3192 //element boundaries
3193 //
3194 //owned
3195 //
3196 for (int ebN=0; ebN < nElementBoundaries_subdomain_new[rank]; ebN++)
3197 {
3198 int ebN_global = ebN + elementBoundaryOffsets_new[rank];
3199 elementBoundaryNumbering_subdomain2global[ebN]=ebN_global;
3200 elementBoundaryNumbering_global2subdomainMap[ebN_global] = ebN;
3201 }
3202 //
3203 //ghost
3204 //
3205 set<int>::iterator ebN_p = elementBoundaries_overlap.begin();
3206 for(int ebN=nElementBoundaries_subdomain_new[rank];ebN < nElementBoundaries_subdomain_new[rank] + int(elementBoundaries_overlap.size()); ebN++,ebN_p++)
3207 {
3208 int ebN_global = *ebN_p;
3209 elementBoundaryNumbering_subdomain2global[ebN] = ebN_global;
3210 elementBoundaryNumbering_global2subdomainMap[ebN_global] = ebN;
3211 }
3212 //
3213 //need elementBoundariesArray to assign consistent numbering on subdomain
3214 //
3215 //local
3216 //
3219 for (int eN=0;eN<nElements_subdomain_new[rank];eN++)
3220 {
3221 int eN_global = eN+elementOffsets_new[rank];
3222 for (int ebN=0;ebN<newMesh.subdomainp->nElementBoundaries_element;ebN++)
3223 {
3225 elementBoundaryNumbering_global2subdomainMap[elementBoundaryNumbering_old2new_subdomain_map[elementBoundariesMap[eN_global][ebN]]];
3226 }
3227 }
3228 //
3229 //ghost elements
3230 //
3231 eN_p = elements_overlap.begin();
3232 for (int eN = nElements_subdomain_new[rank]; eN < nElements_subdomain_new[rank] + int(elements_overlap.size()); eN++,eN_p++)
3233 {
3234 int eN_global_new = *eN_p;
3235 for (int ebN=0;ebN<newMesh.subdomainp->nElementBoundaries_element;ebN++)
3236 {
3238 elementBoundaryNumbering_global2subdomainMap[elementBoundaryNumbering_old2new_subdomain_map[elementBoundariesMap[eN_global_new][ebN]]];
3239 }
3240 }
3241 //
3242 //edges
3243 //
3244 //local
3245 //
3246 for (int edN=0; edN < nEdges_subdomain_new[rank]; edN++)
3247 {
3248 int edN_global = edN + edgeOffsets_new[rank];
3249 edgeNumbering_subdomain2global[edN]=edN_global;
3250 edgeNumbering_global2subdomainMap[edN_global] = edN;
3251 }
3252 //
3253 //ghost
3254 //
3255 set<int>::iterator edN_p = edges_overlap.begin();
3256 for(int edN=nEdges_subdomain_new[rank];edN < nEdges_subdomain_new[rank] + int(edges_overlap.size()); edN++,edN_p++)
3257 {
3258 int edN_global = *edN_p;
3259 edgeNumbering_subdomain2global[edN] = edN_global;
3260 edgeNumbering_global2subdomainMap[edN_global] = edN;
3261 }
3262 //
3263 //now build edgeNodes array in new numberings
3264 //
3265 newMesh.subdomainp->edgeNodesArray = new int[newMesh.subdomainp->nEdges_global*2];
3266 for (int i=0;i<newMesh.subdomainp->nEdges_global*2;i++)
3267 newMesh.subdomainp->edgeNodesArray[i] = -1;
3268 for (map<int,pair<int,int> >::iterator edgep=edgeNodesMap.begin();
3269 edgep!=edgeNodesMap.end();
3270 edgep++)
3271 {
3272 int edN_global_old = edgep->first;
3273 int edN_global_new = edgeNumbering_old2new_subdomain_map[edN_global_old];
3274 assert(edgeNumbering_global2subdomainMap.find(edN_global_new) != edgeNumbering_global2subdomainMap.end());
3275 int edN_subdomain = edgeNumbering_global2subdomainMap[edN_global_new];
3276 newMesh.subdomainp->edgeNodesArray[edN_subdomain*2+0] = nodeNumbering_global2subdomainMap[edgep->second.first];
3277 newMesh.subdomainp->edgeNodesArray[edN_subdomain*2+1] = nodeNumbering_global2subdomainMap[edgep->second.second];
3278 }
3279 //
3280 //end edges
3281 //
3282
3283 //now build rest of subdomain mesh connectivity information etc
3285 //build local geometric info
3288 if (hasElementBoundaryMarkers)
3289 {
3290 assert(newMesh.subdomainp->elementBoundariesArray != NULL);
3291 for (auto ebmp = elementBoundaryMaterialTypesMap.begin(); ebmp != elementBoundaryMaterialTypesMap.end();ebmp++)
3292 {
3293 int ebN_global_new = elementBoundaryNumbering_old2new_subdomain_map[ebmp->first];
3294 assert(elementBoundaryNumbering_global2subdomainMap.find(ebN_global_new) != elementBoundaryNumbering_global2subdomainMap.end());
3295 int ebN_subdomain = elementBoundaryNumbering_global2subdomainMap[ebN_global_new];
3296 newMesh.subdomainp->elementBoundaryMaterialTypes[ebN_subdomain] = ebmp->second;
3297 }
3298 if (!hasVertexMarkers)
3299 for (int ebNE = 0; ebNE < newMesh.subdomainp->nExteriorElementBoundaries_global; ebNE++)
3300 {
3301 int ebN = newMesh.subdomainp->exteriorElementBoundariesArray[ebNE];
3302 for (int nN_local = 0; nN_local < newMesh.subdomainp->nNodes_elementBoundary; nN_local++)
3303 {
3304 int nN = newMesh.subdomainp->elementBoundaryNodesArray[ebN*newMesh.subdomainp->nNodes_elementBoundary+nN_local];
3306 }
3307 }
3308 }
3309 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done with material types");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3310 PetscLogEventEnd(build_subdomains_renumber_event,0,0,0,0);
3311 int build_subdomains_cleanup_event;
3312 PetscLogEventRegister("Cleanup",0,&build_subdomains_cleanup_event);
3313 PetscLogEventBegin(build_subdomains_cleanup_event,0,0,0,0);
3314 //transfer information about owned nodes and elements to mesh
3315 logEvent("Cleaning up after partitioning",5);
3316 if (newMesh.nodeOffsets_subdomain_owned)
3317 delete [] newMesh.nodeOffsets_subdomain_owned;
3319 delete [] newMesh.elementOffsets_subdomain_owned;
3322 if (newMesh.edgeOffsets_subdomain_owned)
3323 delete [] newMesh.edgeOffsets_subdomain_owned;
3324 newMesh.nodeOffsets_subdomain_owned = new int[size+1];
3325 newMesh.elementOffsets_subdomain_owned = new int[size+1];
3326 newMesh.elementBoundaryOffsets_subdomain_owned = new int[size+1];
3327 newMesh.edgeOffsets_subdomain_owned = new int[size+1];
3328 for (int sdN = 0; sdN < size+1; sdN++)
3329 {
3330 newMesh.nodeOffsets_subdomain_owned[sdN] = nodeOffsets_new[sdN];
3331 newMesh.elementOffsets_subdomain_owned[sdN] = elementOffsets_new[sdN];
3332 newMesh.elementBoundaryOffsets_subdomain_owned[sdN] = elementBoundaryOffsets_new[sdN];
3333 newMesh.edgeOffsets_subdomain_owned[sdN] = edgeOffsets_new[sdN];
3334 }
3336 delete [] newMesh.nodeNumbering_subdomain2global;
3337 newMesh.nodeNumbering_subdomain2global = new int[newMesh.subdomainp->nNodes_global];
3338 for (int nN = 0; nN < newMesh.subdomainp->nNodes_global; nN++)
3339 newMesh.nodeNumbering_subdomain2global[nN] = nodeNumbering_subdomain2global[nN];
3341 delete [] newMesh.elementNumbering_subdomain2global;
3343 for (int eN = 0; eN < newMesh.subdomainp->nElements_global; eN++)
3344 newMesh.elementNumbering_subdomain2global[eN] = elementNumbering_subdomain2global[eN];
3345 //
3349 for (int ebN = 0; ebN < newMesh.subdomainp->nElementBoundaries_global; ebN++)
3350 newMesh.elementBoundaryNumbering_subdomain2global[ebN] = elementBoundaryNumbering_subdomain2global[ebN];
3351 //
3353 delete [] newMesh.edgeNumbering_subdomain2global;
3354 newMesh.edgeNumbering_subdomain2global = new int[newMesh.subdomainp->nEdges_global];
3355 for (int i=0; i< newMesh.subdomainp->nEdges_global; i++)
3356 newMesh.edgeNumbering_subdomain2global[i] = edgeNumbering_subdomain2global[i];
3357 //cleanup
3358 PetscLogEventEnd(build_subdomains_cleanup_event,0,0,0,0);
3359 PetscLogStagePop();
3360 PetscLogView(PETSC_VIEWER_STDOUT_WORLD);
3361 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done with partitioning!");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3362 return 0;
3363}
3364int partitionNodesFromTriangleFiles(const MPI_Comm& PROTEUS_COMM_WORLD, const char* filebase, int indexBase, Mesh& newMesh, int nNodes_overlap)
3365{
3366 using namespace std;
3367 PetscErrorCode ierr;
3368 PetscMPIInt size,rank;
3369
3370 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3371 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3372 PetscLogStage partitioning_stage;
3373 PetscLogStageRegister("Mesh Partition",&partitioning_stage);
3374 PetscLogStagePush(partitioning_stage);
3375
3376 /***********************************************************************
3377 partition domain based on the nodes without reading in the global mesh.
3378
3379 1. Partition nodes in the default partition of contiguous chunks with
3380 input ordering
3381
3382 2. Determine nodal connectivity on local processor
3383
3384 3. Generate new nodal partition using PETSc interface
3385
3386 4. Collect subdomain elements: any that contain owned nodes; tag ownership
3387
3388 4a,b. Collect element boundaries and edges on the subdomain elements and tag ownership
3389
3390 5. Generate global element and edge numbering for new subdomain ownership
3391
3392 6. Create overlap (ghost) information for nodes and elements
3393
3394 7. March through additional layers of overlap if requested,
3395
3396 8. Build subdomain meshes in new numbering
3397 ***********************************************************************/
3398 //
3399 //0. Set up triangle files. Note, triangle should have been run with -en to get all edges and neighbors
3400 //
3401 bool failed = false;
3402 const int simplexDim = 3;
3403 const int vertexDim = 3;
3404 using namespace IOutils;
3405 std::string vertexFileName = std::string(filebase) + ".node" ;
3406 std::string elementFileName = std::string(filebase) + ".ele" ;
3407 std::string elementBoundaryFileName = std::string(filebase) + ".edge" ;
3408 std::string edgeFileName = std::string(filebase) + ".edge" ;
3409
3410 //
3411 //1. Build default nodal partition
3412 //
3413 //compute offsets to build subdomain2global ordering for nodes
3414 //in default partitioning of the domain into subdomains. All
3415 //we need is the number of nodes in the global mesh
3416 //
3417 //read nodes for triangle format
3418 //first just read the number of nodes and whether or not there are node tags
3419 int read_elements_event;
3420 PetscLogEventRegister("Read eles",0,&read_elements_event);
3421 PetscLogEventBegin(read_elements_event,0,0,0,0);
3422 std::ifstream vertexFile(vertexFileName.c_str());
3423 if (!vertexFile.good())
3424 {
3425 std::cerr<<"cannot open triangle node file "
3426 <<vertexFileName<<std::endl;
3427 failed = true;
3428 return failed;
3429 }
3430 int hasVertexMarkers(0),hasVertexAttributes(0),nSpace(2),nNodes_global;
3431 //read number of vertices and whether node flags are provided
3432 vertexFile >> eatcomments >> nNodes_global >> nSpace >> hasVertexAttributes >> hasVertexMarkers >> eatline ;
3433 assert(nNodes_global > 0);
3434 assert(nSpace == 2);
3435 newMesh.nNodes_global = nNodes_global;
3436 newMesh.nNodes_element = simplexDim;
3437 newMesh.nNodes_elementBoundary = simplexDim-1;
3438 newMesh.nElementBoundaries_element = simplexDim;
3439 if (hasVertexAttributes > 0)
3440 {
3441 std::cerr<<"WARNING triangle nodes hasAttributes= "<<hasVertexAttributes
3442 <<" > 0 will treat first value as integer id for boundary!!"<<std::endl;
3443 hasVertexMarkers = 1;
3444 }
3445 //don't need to read anymore from nodes for now
3446
3447 //offsets provide the lower and upper bounds for the global numbering
3448 //first we just partition the nodes approximately equally ignoring connectivity
3449 valarray<int> nodeOffsets_old(size+1);
3450 nodeOffsets_old[0] = 0;
3451 for (int sdN=0; sdN < size; sdN++)
3452 {
3453 nodeOffsets_old[sdN+1] = nodeOffsets_old[sdN] +
3454 int(nNodes_global)/size + (int(nNodes_global)%size > sdN);
3455 }
3456 int nNodes_subdomain_old = nodeOffsets_old[rank+1] - nodeOffsets_old[rank];
3457
3458 //
3459 //2. Determine nodal connectivity (nodeStarArray) for nodes on subdomain
3460 //
3461 //connectivty commes from the topology (elements) file. We just grab the elements
3462 //that contain currently owned nodes
3463 std::ifstream elementFile(elementFileName.c_str());
3464 if (!elementFile.good())
3465 {
3466 std::cerr<<"cannot open triangle element file "
3467 <<elementFileName<<std::endl;
3468 failed = true;
3469 return failed;
3470 }
3471 //read elements
3472 int nNodesPerSimplex(simplexDim),hasElementMarkers = 0,nElements_global;
3473 elementFile >> eatcomments >> nElements_global >> nNodesPerSimplex >> hasElementMarkers >> eatline;
3474 assert(nElements_global > 0);
3475 assert(nNodesPerSimplex == simplexDim);
3476 newMesh.nElements_global = nElements_global;
3477 vector<int> element_nodes_old(3);
3478 vector<set<int> > nodeStar(nNodes_subdomain_old);
3479 map<int,vector<int> > elements_old;//elementNodesMap_old
3480 for (int ie = 0; ie < nElements_global; ie++)
3481 {
3482 int ne, nv;
3483 elementFile >> eatcomments >> ne;
3484 ne -= indexBase;
3485 assert(0 <= ne && ne < nElements_global && elementFile.good());
3486 for (int iv = 0; iv < simplexDim; iv++)
3487 {
3488 elementFile >> nv;
3489 nv -= indexBase;
3490 assert(0 <= nv && nv < nNodes_global);
3491 element_nodes_old[iv] = nv;
3492 }
3493 //for each node on the element
3494 for (int iv = 0; iv < simplexDim; iv++)
3495 {
3496 //check if the node is owned by the subdomain
3497 int nN_star = element_nodes_old[iv];
3498 bool inSubdomain=false;
3499 if (nN_star >= nodeOffsets_old[rank] && nN_star < nodeOffsets_old[rank+1])
3500 {
3501 //this node is owned by the subdomain so
3502 inSubdomain = true;
3503 for (int jv = 0; jv < simplexDim; jv++)
3504 {
3505 if (iv != jv)
3506 {
3507 int nN_star_subdomain = nN_star-nodeOffsets_old[rank];
3508 nodeStar[nN_star_subdomain].insert(element_nodes_old[jv]);
3509 }
3510 }
3511 }
3512 if (inSubdomain)
3513 elements_old[ie] = element_nodes_old;
3514 }
3515 elementFile >> eatline;
3516 }//end ie
3517 elementFile.close();
3518 PetscLogEventEnd(read_elements_event,0,0,0,0);
3519 int repartition_nodes_event;
3520 PetscLogEventRegister("Repart nodes",0,&repartition_nodes_event);
3521 PetscLogEventBegin(repartition_nodes_event,0,0,0,0);
3522 //done reading element file for first time; will need to read again after node partitioning
3523 //build compact data structure for nodeStar
3524 valarray<int> nodeStarOffsets(nNodes_subdomain_old+1);
3525 nodeStarOffsets[0] = 0;
3526 for (int nN=1;nN<nNodes_subdomain_old+1;nN++)
3527 nodeStarOffsets[nN] = nodeStarOffsets[nN-1] + nodeStar[nN-1].size();
3528 valarray<int> nodeStarArray(nodeStarOffsets[nNodes_subdomain_old]);
3529 for (int nN=0,offset=0;nN<nNodes_subdomain_old;nN++)
3530 for (set<int>::iterator nN_star=nodeStar[nN].begin();nN_star!=nodeStar[nN].end();nN_star++,offset++)
3531 nodeStarArray[offset] = *nN_star;
3532 //find maximum number of nodes in any star
3533 int max_nNodeNeighbors_node=0;
3534 for (int nN=0;nN<nNodes_subdomain_old;nN++)
3535 max_nNodeNeighbors_node=max(max_nNodeNeighbors_node,nodeStarOffsets[nN+1]-nodeStarOffsets[nN]);
3536 //build connectivity data structures for PETSc
3537 PetscBool isInitialized;
3538 PetscInitialized(&isInitialized);
3539 PetscInt *nodeNeighborsOffsets_subdomain,*nodeNeighbors_subdomain,*weights_subdomain,*vertex_weights_subdomain;
3540 PetscReal *partition_weights;
3541 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain_old+1),&nodeNeighborsOffsets_subdomain);
3542 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain_old*max_nNodeNeighbors_node),&nodeNeighbors_subdomain);
3543 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain_old*max_nNodeNeighbors_node),&weights_subdomain);
3544 PetscMalloc(sizeof(PetscInt)*(nNodes_subdomain_old),&vertex_weights_subdomain);
3545 PetscMalloc(sizeof(PetscReal)*(size),&partition_weights);
3546 for (int sd=0;sd<size;sd++)
3547 partition_weights[sd] = 1.0/double(size);
3548 nodeNeighborsOffsets_subdomain[0] = 0;
3549 //I think we can simplify this now that nodeStarArray is local to the subdomain, could just use nodeStar instead of nodeStarArray
3550 for (int nN = 0,offset=0; nN < nNodes_subdomain_old; nN++)
3551 {
3552 for (int offset_subdomain = nodeStarOffsets[nN];
3553 offset_subdomain < nodeStarOffsets[nN+1];
3554 offset_subdomain++)
3555 {
3556 nodeNeighbors_subdomain[offset++] = nodeStarArray[offset_subdomain];
3557 }
3558 nodeNeighborsOffsets_subdomain[nN+1]=offset;
3559 sort(&nodeNeighbors_subdomain[nodeNeighborsOffsets_subdomain[nN]],&nodeNeighbors_subdomain[nodeNeighborsOffsets_subdomain[nN+1]]);
3560 //weight nodes by size of star
3561 int weight= (nodeNeighborsOffsets_subdomain[nN+1] - nodeNeighborsOffsets_subdomain[nN]);
3562 vertex_weights_subdomain[nN] = weight;
3563 for (int k=nodeNeighborsOffsets_subdomain[nN];k<nodeNeighborsOffsets_subdomain[nN+1];k++)
3564 weights_subdomain[k] = weight;
3565 }
3566 //
3567 //3. Generate new nodal partition using PETSc interface
3568 //
3569 Mat petscAdjacency;
3570 int nNodes_subdomain_max=0;
3571 MPI_Allreduce(&nNodes_subdomain_old,
3572 &nNodes_subdomain_max,
3573 1,
3574 MPI_INT,
3575 MPI_MAX,
3576 PROTEUS_COMM_WORLD);
3577 if (rank == 0)
3578 std::cout<<"Max nNodes_subdomain "<<nNodes_subdomain_max<<" nNodes_global "<<nNodes_global<<std::endl;
3579 ierr = MatCreateMPIAdj(PROTEUS_COMM_WORLD,
3580 nNodes_subdomain_old,
3581 nNodes_global,
3582 nodeNeighborsOffsets_subdomain,
3583 nodeNeighbors_subdomain,
3584 weights_subdomain,
3585 &petscAdjacency);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3586 //const double max_rss_gb(0.75*3.25);//half max mem per core on topaz
3587 const double max_rss_gb(10.0);
3588 ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done allocating MPIAdj");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3589 MatPartitioning petscPartition;
3590 ierr = MatPartitioningCreate(PROTEUS_COMM_WORLD,&petscPartition);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3591 ierr = MatPartitioningSetAdjacency(petscPartition,petscAdjacency);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3592 ierr = MatPartitioningSetFromOptions(petscPartition);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3593 ierr = MatPartitioningSetVertexWeights(petscPartition,vertex_weights_subdomain);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3594 ierr = MatPartitioningSetPartitionWeights(petscPartition,partition_weights);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3595 //get petsc index set that has the new subdomain number for each node
3596 IS nodePartitioningIS_new;
3597 ierr = MatPartitioningApply(petscPartition,&nodePartitioningIS_new);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3598 ierr = MatPartitioningDestroy(&petscPartition);CHKERRABORT(PROTEUS_COMM_WORLD, ierr); //gets petscAdjacency too I believe
3599 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done applying partition");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3600
3601 //determine the number of nodes per subdomain in new partitioning
3602 valarray<int> nNodes_subdomain_new(size);
3603 ISPartitioningCount(nodePartitioningIS_new,size,&nNodes_subdomain_new[0]);
3604
3605 //need new offsets for subdomain to global numbering
3606 valarray<int> nodeOffsets_new(size+1);
3607 nodeOffsets_new[0] = 0;
3608 for (int sdN = 0; sdN < size; sdN++)
3609 {
3610 nodeOffsets_new[sdN+1] = nodeOffsets_new[sdN] + nNodes_subdomain_new[sdN];
3611 }
3612
3613 //get the new node numbers for nodes on this subdomain
3614 IS nodeNumberingIS_subdomain_old2new;
3615 ISPartitioningToNumbering(nodePartitioningIS_new,&nodeNumberingIS_subdomain_old2new);
3616 //
3617 //try out of core
3618 //
3619 /*
3620 * Set up file access property list with parallel I/O access
3621 */
3622 hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS);
3623#ifdef H5_HAVE_PARALLEL
3624 H5Pset_fapl_mpio(plist_id, PROTEUS_COMM_WORLD, MPI_INFO_NULL);
3625#endif
3626
3627 /*
3628 * Create a new file collectively and release property list identifier.
3629 */
3630 const char* H5FILE_NAME("mappings.h5");
3631 hid_t file_id = H5Fcreate(H5FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, plist_id);
3632 H5Pclose(plist_id);
3633
3634
3635 /*
3636 * Create the dataspace for the dataset.
3637 */
3638 hsize_t dimsf[1];
3639 dimsf[0] = nNodes_global;
3640#define RANK 1
3641 hid_t filespace = H5Screate_simple(RANK, dimsf, NULL);
3642
3643 /*
3644 * Create the dataset with default properties and close filespace.
3645 */
3646 hid_t dset_id = H5Dcreate(file_id, "nodeNumbering_old2new", H5T_NATIVE_INT, filespace,
3647 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
3648 H5Sclose(filespace);
3649
3650 /*
3651 * Each process defines dataset in memory and writes it to the hyperslab
3652 * in the file.
3653 */
3654 hsize_t count[1]; /* hyperslab selection parameters */
3655 hsize_t offset[1];
3656 count[0] = nNodes_subdomain_old;
3657 offset[0] = nodeOffsets_old[rank];
3658 hid_t memspace = H5Screate_simple(RANK, count, NULL);
3659
3660 /*
3661 * Select hyperslab in the file.
3662 */
3663 filespace = H5Dget_space(dset_id);
3664 H5Sselect_hyperslab(filespace, H5S_SELECT_SET, offset, NULL, count, NULL);
3665
3666 /*
3667 * Initialize data buffer
3668 */
3669 // data = (int *) malloc(sizeof(int)*count[0]*count[1]);
3670 // for (i=0; i < count[0]*count[1]; i++) {
3671 // data[i] = mpi_rank + 10;
3672 // }
3673 const PetscInt* data;
3674 ISGetIndices(nodeNumberingIS_subdomain_old2new, &data);
3675
3676 /*
3677 * Create property list for collective dataset write.
3678 */
3679 plist_id = H5Pcreate(H5P_DATASET_XFER);
3680#ifdef H5_HAVE_PARALLEL
3681 H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);
3682#endif
3683
3684 herr_t status = H5Dwrite(dset_id, H5T_NATIVE_INT, memspace, filespace,
3685 plist_id, data);
3686 //free(data);
3687 ISRestoreIndices(nodeNumberingIS_subdomain_old2new, &data);
3688 /*
3689 * Close/release resources.
3690 */
3691 H5Dclose(dset_id);
3692 //
3693 //end try out of core
3694 //
3695 //collect new node numbers for whole mesh so that subdomain reordering and renumbering
3696 //can be done easily
3697
3698 IS nodeNumberingIS_global_old2new;
3699 ISAllGather(nodeNumberingIS_subdomain_old2new,&nodeNumberingIS_global_old2new);
3700 const PetscInt * nodeNumbering_global_old2new;//needs restore call
3701 ISGetIndices(nodeNumberingIS_global_old2new,&nodeNumbering_global_old2new);
3702 //
3703 //test out of core
3704 //
3705 if (rank == 0)
3706 {
3707 hid_t dataset_id; /* identifiers */
3708 herr_t status;
3709 int dset_data[nNodes_global];
3710
3711 /* Open an existing file. */
3712 //file_id = H5Fopen("mappings.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
3713
3714 /* Open an existing dataset. */
3715 dataset_id = H5Dopen2(file_id, "/nodeNumbering_old2new", H5P_DEFAULT);
3716
3717 status = H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
3718 dset_data);
3719
3720 /* Close the dataset. */
3721 status = H5Dclose(dataset_id);
3722
3723 for (int i=0;i<nNodes_global;i++)
3724 assert(nodeNumbering_global_old2new[i] == dset_data[i]);
3725 std::cout<<"==================out of core old2new is correct!===================="<<std::endl;
3726 }
3727 //
3728 //end test out of core
3729 //
3730 //reverse mapping for node numbers too
3731 //cek hack, not needed
3732 /*
3733 valarray<int> nodeNumbering_global_new2old(nNodes_global);
3734 for (int nN = 0; nN < nNodes_global; nN++)
3735 nodeNumbering_global_new2old[nodeNumbering_global_old2new[nN]] = nN;
3736 */
3737 PetscLogEventEnd(repartition_nodes_event,0,0,0,0);
3738 int receive_element_mask_event;
3739 PetscLogEventRegister("Recv. ele mask",0,&receive_element_mask_event);
3740 PetscLogEventBegin(receive_element_mask_event,0,0,0,0);
3741 //
3742 //4. To build subdomain meshes, go through and collect elements containing
3743 // the locally owned nodes. Assign processor ownership of elements
3744 //
3745 PetscLogEventEnd(receive_element_mask_event,0,0,0,0);
3746 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done with masks");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3747 int build_subdomains_reread_elements_event;
3748 PetscLogEventRegister("Reread eles",0,&build_subdomains_reread_elements_event);
3749 PetscLogEventBegin(build_subdomains_reread_elements_event,0,0,0,0);
3750 //
3751 //mark the unmarked elements on this subdomain and store element numbers (in old numbering)
3752 //
3753 //We need to find the elements in the support of nodes in the new
3754 //partitioning, so we'll need to re-read the elements file to get
3755 //the the elements for the nodes in the new partitioning. We will be collecting OLD element numbers.
3756 std::ifstream elementFile2(elementFileName.c_str());
3757
3758 if (!elementFile2.good())
3759 {
3760 std::cerr<<"cannot open triangle elements file"
3761 <<elementFileName<<std::endl;
3762 failed = true;
3763 return failed;
3764 }
3765 elementFile2 >> eatcomments >> nElements_global >> nNodesPerSimplex >> hasElementMarkers >> eatline;
3766 assert(nElements_global > 0);
3767 assert(nNodesPerSimplex == simplexDim);
3768 set<int> elements_subdomain_owned;
3769 vector<int> element_nodes_new(3);
3770 int element_nodes_new_array[3];
3771 vector<set<int> > nodeElementsStar(nNodes_subdomain_new[rank]);
3772 vector<set<int> > nodeStarNew(nNodes_subdomain_new[rank]);
3773 map<int,vector<int> > elementNodesArrayMap;
3774 map<int,long int> elementMaterialTypesMap;
3775 map<NodeTuple<2>,ElementNeighbors> elementBoundaryElementsMap;
3776 map<NodeTuple<2>,set<pair<int,int> > > edgeElementsMap;
3777
3778 //note any element index containers are in the old element numbering
3779 for (int ie = 0; ie < nElements_global; ie++)
3780 {
3781 int ne, nv, elementId(0);
3782 long double elementId_double;
3783 elementFile2 >> eatcomments >> ne;
3784 ne -= indexBase;
3785 assert(0 <= ne && ne < nElements_global && elementFile.good());
3786 for (int iv = 0; iv < simplexDim; iv++)
3787 {
3788 elementFile2 >> nv ;
3789 nv -= indexBase;
3790 assert(0 <= nv && nv < nNodes_global);
3791 element_nodes_old[iv] = nv;
3792 element_nodes_new[iv] = nodeNumbering_global_old2new[nv];
3793 element_nodes_new_array[iv] = element_nodes_new[iv];
3794 }
3795 NodeTuple<simplexDim> nodeTuple(element_nodes_new_array);
3796 for (int iv = 0; iv < simplexDim; iv++)
3797 {
3798 int nN_star_new = element_nodes_new[iv];
3799 bool inSubdomain=false;
3800 if (nN_star_new >= nodeOffsets_new[rank] && nN_star_new < nodeOffsets_new[rank+1])
3801 {
3802 inSubdomain = true;
3803 //add all the element boundaries of this element
3804 for (int ebN=0;ebN < simplexDim ; ebN++)
3805 {
3806 int nodes[simplexDim-1] = { element_nodes_new[(ebN+1) % simplexDim],
3807 element_nodes_new[(ebN+2) % simplexDim]};
3808 NodeTuple<simplexDim-1> nodeTuple(nodes);
3809 if(elementBoundaryElementsMap.find(nodeTuple) != elementBoundaryElementsMap.end())
3810 {
3811 if (elementBoundaryElementsMap[nodeTuple].right == -1 && ne != elementBoundaryElementsMap[nodeTuple].left)
3812 {
3813 elementBoundaryElementsMap[nodeTuple].right=ne;
3814 elementBoundaryElementsMap[nodeTuple].right_ebN_element=ebN;
3815 }
3816 }
3817 else
3818 {
3819 elementBoundaryElementsMap[nodeTuple] = ElementNeighbors(ne,ebN);
3820 }
3821 }
3822 //add all the edges of this element
3823 for (int nNL=0,edN=0;nNL < simplexDim ; nNL++)
3824 for(int nNR=nNL+1;nNR < simplexDim;nNR++,edN++)
3825 {
3826 int nodes[2] = { element_nodes_new[nNL],
3827 element_nodes_new[nNR]};
3828 NodeTuple<2> nodeTuple(nodes);
3829 edgeElementsMap[nodeTuple].insert(pair<int,int>(ne,edN));
3830 }
3831 //add all the nodes to the node star
3832 int nN_star_new_subdomain = nN_star_new - nodeOffsets_new[rank];
3833 nodeElementsStar[nN_star_new_subdomain].insert(ne);
3834 for (int jv = 0; jv < simplexDim; jv++)
3835 {
3836 if (iv != jv)
3837 {
3838 int nN_point_new = element_nodes_new[jv];
3839 nodeStarNew[nN_star_new_subdomain].insert(nN_point_new);
3840 }
3841 }
3842 }
3843 if (inSubdomain)
3844 {
3845 elementNodesArrayMap[ne] = element_nodes_new;
3846 }
3847 }
3848 if (elementNodesArrayMap.find(ne) != elementNodesArrayMap.end())//this element contains a node owned by this subdomain
3849 {
3850 if (nodeTuple.nodes[1] >= nodeOffsets_new[rank] && nodeTuple.nodes[1] < nodeOffsets_new[rank+1])
3851 elements_subdomain_owned.insert(ne);
3852 if (hasElementMarkers > 0)
3853 {
3854 elementFile2 >> elementId_double;
3855 elementId = static_cast<long int>(elementId_double);
3856 elementMaterialTypesMap[ne] = elementId;
3857 }
3858 }
3859 elementFile2 >> eatline;
3860 }
3861 elementFile2.close();
3862 int nElements_owned_subdomain(elements_subdomain_owned.size()),
3863 nElements_owned_new=0;
3864 MPI_Allreduce(&nElements_owned_subdomain,&nElements_owned_new,1,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
3865 assert(nElements_owned_new == nElements_global);
3866 PetscLogEventEnd(build_subdomains_reread_elements_event,0,0,0,0);
3867 int build_subdomains_send_marked_elements_event;
3868 PetscLogEventRegister("Mark/send eles",0,&build_subdomains_send_marked_elements_event);
3869 PetscLogEventBegin(build_subdomains_send_marked_elements_event,0,0,0,0);
3870 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done marking elements");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3871 //
3872 //done with the element file
3873 //
3874 //construct compact nodeElementsArray
3875 valarray<int> nodeElementOffsets(nNodes_subdomain_new[rank]+1);
3876 nodeElementOffsets[0] = 0;
3877 for (int nN = 0; nN < nNodes_subdomain_new[rank]; nN++)
3878 nodeElementOffsets[nN+1] = nodeElementOffsets[nN]+nodeElementsStar[nN].size();
3879 valarray<int> nodeElementsArray(nodeElementOffsets[nNodes_subdomain_new[rank]]);
3880 for (int nN=0,offset=0; nN < nNodes_subdomain_new[rank]; nN++)
3881 {
3882 for (set<int>::iterator eN_star = nodeElementsStar[nN].begin(); eN_star != nodeElementsStar[nN].end();
3883 eN_star++,offset++)
3884 {
3885 nodeElementsArray[offset] = *eN_star;
3886 }
3887 }
3888 //construct compact nodeStarArray
3889 valarray<int> nodeStarOffsetsNew(nNodes_subdomain_new[rank]+1);
3890 nodeStarOffsetsNew[0] = 0;
3891 for (int nN=1;nN<nNodes_subdomain_new[rank]+1;nN++)
3892 nodeStarOffsetsNew[nN] = nodeStarOffsetsNew[nN-1] + nodeStarNew[nN-1].size();
3893 valarray<int> nodeStarArrayNew(nodeStarOffsetsNew[nNodes_subdomain_new[rank]]);
3894 for (int nN=0,offset=0;nN<nNodes_subdomain_new[rank];nN++)
3895 {
3896 for (set<int>::iterator nN_star=nodeStarNew[nN].begin();nN_star!=nodeStarNew[nN].end();nN_star++,offset++)
3897 {
3898 nodeStarArrayNew[offset] = *nN_star;
3899 }
3900 }
3901 PetscLogEventEnd(build_subdomains_send_marked_elements_event,0,0,0,0);
3902 int build_subdomains_global_numbering_elements_event;
3903 PetscLogEventRegister("Global ele nmbr",0,&build_subdomains_global_numbering_elements_event);
3904 PetscLogEventBegin(build_subdomains_global_numbering_elements_event,0,0,0,0);
3905 //
3906 //5. Generate global element numbering corresponding to new subdomain ownership
3907 //
3908 valarray<int> nElements_subdomain_new(size),
3909 elementOffsets_new(size+1);
3910 for (int sdN = 0; sdN < size; sdN++)
3911 {
3912 if (sdN == rank)
3913 nElements_subdomain_new[sdN] = int(elements_subdomain_owned.size());
3914 else
3915 nElements_subdomain_new[sdN] = 0;
3916 }
3917 valarray<int> nElements_subdomain_new_send = nElements_subdomain_new;
3918 MPI_Allreduce(&nElements_subdomain_new_send[0],&nElements_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
3919 //construct new offsets for elements
3920 elementOffsets_new[0] = 0;
3921 for (int sdN = 0; sdN < size; sdN++)
3922 elementOffsets_new[sdN+1] = elementOffsets_new[sdN] + nElements_subdomain_new[sdN];
3923 //map to old element numbering
3924 valarray<int> elementNumbering_subdomain_new2old(elements_subdomain_owned.size());
3925 set<int>::iterator eN_ownedp = elements_subdomain_owned.begin();
3926 for (int eN = 0; eN < int(elements_subdomain_owned.size()); eN++,eN_ownedp++)
3927 {
3928 elementNumbering_subdomain_new2old[eN] = *eN_ownedp;
3929 }
3930 //use Petsc IS to get global new2old numbering
3931 IS elementNumberingIS_subdomain_new2old;
3932 ISCreateGeneral(PROTEUS_COMM_WORLD,elements_subdomain_owned.size(),&elementNumbering_subdomain_new2old[0],PETSC_COPY_VALUES,
3933 &elementNumberingIS_subdomain_new2old);
3934 IS elementNumberingIS_global_new2old;
3935 ISAllGather(elementNumberingIS_subdomain_new2old,&elementNumberingIS_global_new2old);
3936
3937 const PetscInt *elementNumbering_global_new2old;//needs to be restored
3938 ISGetIndices(elementNumberingIS_global_new2old,&elementNumbering_global_new2old);
3939 //construct reverse mapping
3940 valarray<int> elementNumbering_global_old2new(nElements_global);
3941 for (int eN = 0; eN < nElements_global; eN++)
3942 {
3943 elementNumbering_global_old2new[elementNumbering_global_new2old[eN]] = eN;
3944 }
3945 PetscLogEventEnd(build_subdomains_global_numbering_elements_event,0,0,0,0);
3946 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done allocating element numbering new2old/old2new");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
3947 int build_subdomains_faces_event;
3948 PetscLogEventRegister("Subd faces",0,&build_subdomains_faces_event);
3949 PetscLogEventBegin(build_subdomains_faces_event,0,0,0,0);
3950 //
3951 //4b,5b. repeat process to build global face (elementBoundary) numbering
3952 //
3953 //first read element boundaries to create nodeElementBoundariesArray
3954 //for all element boundaries on this subdomain, which we'll use to
3955 //grab element boundaries from the bit array
3956
3957
3958 //In 2D, the element boundaries are edges and not faces.
3959 //nodeElementBoundariesArray maps an element
3960
3961 std::ifstream elementBoundaryFile(elementBoundaryFileName.c_str());
3962
3963 if (!elementBoundaryFile.good())
3964 {
3965 std::cerr<<"cannot open triangle edge file "
3966 <<elementBoundaryFileName<<std::endl;
3967 failed = true;
3968 return failed;
3969 }
3970
3971 bool hasElementBoundaryMarkers = false;
3972 int nElementBoundaries_global;
3973 int ihasElementBoundaryMarkers(0);
3974
3975 elementBoundaryFile >> eatcomments >> nElementBoundaries_global >>ihasElementBoundaryMarkers >> eatline ;
3976 assert(nElementBoundaries_global > 0);
3977 if (ihasElementBoundaryMarkers > 0)
3978 {
3979 hasElementBoundaryMarkers = true;
3980 }
3981 newMesh.nElementBoundaries_global = nElementBoundaries_global;
3982 //note, these will be in the new element numbering
3983 set<int> elementBoundaries_subdomain_owned;
3984 vector<set<int> > nodeElementBoundariesStar(nNodes_subdomain_new[rank]);
3985 map<int,int> elementBoundaryMaterialTypesMap;
3986 map<int,vector<int> > elementBoundariesMap;
3987 set<int> supportedElementBoundaries;
3988 for (int ieb = 0; ieb < nElementBoundaries_global; ieb++)
3989 {
3990 int neb,nn0,nn1; int ebId(0);
3991 elementBoundaryFile >> eatcomments >> neb >> nn0 >> nn1;
3992 if (ihasElementBoundaryMarkers > 0)
3993 elementBoundaryFile >> ebId;
3994 neb -= indexBase;
3995 nn0 -= indexBase;
3996 nn1 -= indexBase;
3997 assert(0 <= neb && neb < nElementBoundaries_global && elementBoundaryFile.good());
3998 //grab the element boundaries for the node if the node is owned by the subdomain
3999 //this will miss the element boundaries on the "outside boundary" of the star, which will grab later
4000 int nn0_new = nodeNumbering_global_old2new[nn0];
4001 if (nn0_new >= nodeOffsets_new[rank] && nn0_new < nodeOffsets_new[rank+1])
4002 {
4003 nodeElementBoundariesStar[nn0_new-nodeOffsets_new[rank]].insert(neb);
4004 supportedElementBoundaries.insert(neb);
4005 }
4006 int nn1_new = nodeNumbering_global_old2new[nn1];
4007 if (nn1_new >= nodeOffsets_new[rank] && nn1_new < nodeOffsets_new[rank+1])
4008 {
4009 nodeElementBoundariesStar[nn1_new-nodeOffsets_new[rank]].insert(neb);
4010 supportedElementBoundaries.insert(neb);
4011 }
4012 int nodes[2] = {nn0_new,nn1_new};
4013 NodeTuple<2> nodeTuple(nodes);
4014 elementBoundaryFile >> eatline;
4015 if (elementBoundaryElementsMap.find(nodeTuple) != elementBoundaryElementsMap.end())//this element boundary is on an element in the subdomain
4016 {
4017 if (nodeTuple.nodes[1] >= nodeOffsets_new[rank] && nodeTuple.nodes[1] < nodeOffsets_new[rank+1])
4018 elementBoundaries_subdomain_owned.insert(neb);
4019 if (ihasElementBoundaryMarkers > 0)
4020 elementBoundaryMaterialTypesMap[neb]=ebId;
4021 int eN_left = elementNumbering_global_old2new[elementBoundaryElementsMap[nodeTuple].left];
4022 if (elementBoundariesMap.find(eN_left) != elementBoundariesMap.end())
4023 {
4024 elementBoundariesMap[eN_left][elementBoundaryElementsMap[nodeTuple].left_ebN_element] = neb;
4025 }
4026 else
4027 {
4028 //initialize
4029 vector<int> elementBoundaries_element(3,-1);
4030 elementBoundariesMap[eN_left] = elementBoundaries_element;
4031 //assign
4032 elementBoundariesMap[eN_left][elementBoundaryElementsMap[nodeTuple].left_ebN_element] = neb;
4033 }
4034 if (elementBoundaryElementsMap[nodeTuple].right >= 0)
4035 {
4036 int eN_right = elementNumbering_global_old2new[elementBoundaryElementsMap[nodeTuple].right];
4037 if (elementBoundariesMap.find(eN_right) != elementBoundariesMap.end())
4038 {
4039 elementBoundariesMap[eN_right][elementBoundaryElementsMap[nodeTuple].right_ebN_element] = neb;
4040 }
4041 else
4042 {
4043 //initialize
4044 vector<int> elementBoundaries_element(3,-1);
4045 elementBoundariesMap[eN_right] = elementBoundaries_element;
4046 //assign
4047 elementBoundariesMap[eN_right][elementBoundaryElementsMap[nodeTuple].right_ebN_element] = neb;
4048 }
4049 }
4050 }
4051 }
4052 elementBoundaryElementsMap.clear();
4053 //done reading element boundaries
4054 elementBoundaryFile.close();
4055 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done reading element boundaries");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4056 int nElementBoundaries_owned_subdomain=elementBoundaries_subdomain_owned.size(),
4057 nElementBoundaries_owned_new=0;
4058 MPI_Allreduce(&nElementBoundaries_owned_subdomain,&nElementBoundaries_owned_new,1,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
4059 assert(nElementBoundaries_owned_new == nElementBoundaries_global);
4060
4061 //now get the element boundaries on the outside of the star
4062 for (map<int,vector<int> >::iterator elementBoundariesp=elementBoundariesMap.begin();
4063 elementBoundariesp!=elementBoundariesMap.end();
4064 elementBoundariesp++)
4065 {
4066 //loop over the nodes of this element for the owned nodes
4067 for (int iv=0;iv<simplexDim;iv++)
4068 {
4069 //the elementNodesArrayMap is in the old element numbering while the elementBoundariesMap is in the new element numbering
4070 int nN_global = elementNodesArrayMap[elementNumbering_global_new2old[elementBoundariesp->first]][iv];
4071 if (nN_global >= nodeOffsets_new[rank] && nN_global < nodeOffsets_new[rank+1])
4072 {
4073 //add all the faces to this node star
4074 for(int eb=0;eb<simplexDim;eb++)
4075 {
4076 nodeElementBoundariesStar[nN_global-nodeOffsets_new[rank]].insert(elementBoundariesp->second[eb]);
4077 }
4078 }
4079 }
4080 }
4081 //build compact structures for nodeElementBoundariesArray
4082 valarray<int> nodeElementBoundaryOffsets(nNodes_subdomain_new[rank]+1);
4083 nodeElementBoundaryOffsets[0] = 0;
4084 for (int nN = 0; nN < nNodes_subdomain_new[rank]; nN++)
4085 nodeElementBoundaryOffsets[nN+1] = nodeElementBoundaryOffsets[nN]+nodeElementBoundariesStar[nN].size();
4086 valarray<int> nodeElementBoundariesArray(nodeElementBoundaryOffsets[nNodes_subdomain_new[rank]]);
4087 for (int nN=0,offset=0; nN < nNodes_subdomain_new[rank]; nN++)
4088 {
4089 for (set<int>::iterator ebN_star = nodeElementBoundariesStar[nN].begin(); ebN_star != nodeElementBoundariesStar[nN].end();
4090 ebN_star++,offset++)
4091 {
4092 nodeElementBoundariesArray[offset] = *ebN_star;
4093 }
4094 }
4095
4096 //get the number of elementBoundaries owned on each processor
4097 valarray<int> nElementBoundaries_subdomain_new(size),
4098 elementBoundaryOffsets_new(size+1);
4099 for (int sdN=0;sdN<size;sdN++)
4100 if (sdN == rank)
4101 nElementBoundaries_subdomain_new[sdN] = elementBoundaries_subdomain_owned.size();
4102 else
4103 nElementBoundaries_subdomain_new[sdN] = 0;
4104 valarray<int> nElementBoundaries_subdomain_new_send=nElementBoundaries_subdomain_new;
4105 MPI_Allreduce(&nElementBoundaries_subdomain_new_send[0],&nElementBoundaries_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
4106 elementBoundaryOffsets_new[0] = 0;
4107 for (int sdN=0;sdN<size;sdN++)
4108 elementBoundaryOffsets_new[sdN+1] = elementBoundaryOffsets_new[sdN]+nElementBoundaries_subdomain_new[sdN];
4109 //
4110 //Now as with elements and nodes build a global face numbering
4111 //resetting the face-based information is a little different since much of this is currently built below based
4112 //on the element and node information
4113 //
4114 valarray<int> elementBoundaryNumbering_new2old(elementBoundaries_subdomain_owned.size());
4115 set<int>::iterator ebN_ownedp=elementBoundaries_subdomain_owned.begin();
4116 for (int ebN=0;ebN<int(elementBoundaries_subdomain_owned.size());ebN++)
4117 {
4118 elementBoundaryNumbering_new2old[ebN] = *ebN_ownedp++;
4119 }
4120 IS elementBoundaryNumberingIS_subdomain_new2old;
4121 ISCreateGeneral(PROTEUS_COMM_WORLD,elementBoundaries_subdomain_owned.size(),&elementBoundaryNumbering_new2old[0],PETSC_COPY_VALUES,&elementBoundaryNumberingIS_subdomain_new2old);
4122 IS elementBoundaryNumberingIS_global_new2old;
4123 ISAllGather(elementBoundaryNumberingIS_subdomain_new2old,&elementBoundaryNumberingIS_global_new2old);
4124 const PetscInt *elementBoundaryNumbering_global_new2old;
4125 valarray<int> elementBoundaryNumbering_global_old2new(newMesh.nElementBoundaries_global);
4126 ISGetIndices(elementBoundaryNumberingIS_global_new2old,&elementBoundaryNumbering_global_new2old);
4127 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Allocating elementBoudnary old2new/new2old");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4128 for (int ebN=0;ebN<newMesh.nElementBoundaries_global;ebN++)
4129 {
4130 elementBoundaryNumbering_global_old2new[elementBoundaryNumbering_global_new2old[ebN]] = ebN;
4131 }
4132 ISRestoreIndices(elementBoundaryNumberingIS_global_new2old,&elementBoundaryNumbering_global_new2old);
4133 ISDestroy(&elementBoundaryNumberingIS_subdomain_new2old);
4134 ISDestroy(&elementBoundaryNumberingIS_global_new2old);
4135 PetscLogEventEnd(build_subdomains_faces_event,0,0,0,0);
4136 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done allocating elementBoudnary old2new/new2old");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4137 int build_subdomains_edges_event;
4138 PetscLogEventRegister("Subd edges",0,&build_subdomains_edges_event);
4139 PetscLogEventBegin(build_subdomains_edges_event,0,0,0,0);
4140
4141 //
4142 //4c,5c. Repeate the process for edges
4143 //
4144 std::ifstream edgeFile(edgeFileName.c_str());
4145
4146 if (!edgeFile.good())
4147 {
4148 std::cerr<<"cannot open Triangle edge file"
4149 <<edgeFileName<<std::endl;
4150 failed = true;
4151 return failed;
4152 }
4153
4154 bool hasEdgeMarkers = false;
4155 int nEdges_global;
4156 int ihasEdgeMarkers(0);
4157 edgeFile >> eatcomments >> nEdges_global >> eatline;// edge file doesn currently contain markers >> ihasEdgeMarkers >> eatline ;
4158 assert(nEdges_global > 0);
4159 if (ihasEdgeMarkers > 0)
4160 {
4161 hasEdgeMarkers = true;
4162 }
4163
4164 newMesh.nEdges_global = nEdges_global;
4165 set<int> edges_subdomain_owned;
4166 vector<set<int> > nodeEdgesStar(nNodes_subdomain_new[rank]);
4167 map<int,int> edgeMaterialTypesMap;
4168 map<int,vector<int> > elementEdgesMap;
4169 map<int,pair<int,int> > edgeNodesMap;
4170 set<int> supportedEdges;
4171 for (int ied = 0; ied < nEdges_global; ied++)
4172 {
4173 int ned,nn0,nn1; int edId(0);
4174 edgeFile >> eatcomments >> ned >> nn0 >> nn1;
4175 if (ihasEdgeMarkers > 0)
4176 edgeFile >> edId;
4177 ned -= indexBase;
4178 nn0 -= indexBase;
4179 nn1 -= indexBase;
4180 assert(0 <= ned && ned < nEdges_global && edgeFile.good());
4181 int nn0_new = nodeNumbering_global_old2new[nn0];
4182 if (nn0_new >= nodeOffsets_new[rank] && nn0_new < nodeOffsets_new[rank+1])
4183 {
4184 nodeEdgesStar.at(nn0_new-nodeOffsets_new[rank]).insert(ned);
4185 supportedEdges.insert(ned);
4186 }
4187 int nn1_new = nodeNumbering_global_old2new[nn1];
4188 if (nn1_new >= nodeOffsets_new[rank] && nn1_new < nodeOffsets_new[rank+1])
4189 {
4190 nodeEdgesStar.at(nn1_new-nodeOffsets_new[rank]).insert(ned);
4191 supportedEdges.insert(ned);
4192 }
4193 int nodes[2] = {nn0_new,nn1_new};
4194 NodeTuple<2> nodeTuple(nodes);
4195 edgeFile >> eatline;
4196 if (edgeElementsMap.find(nodeTuple) != edgeElementsMap.end())//this edge is on an element in the subdomain
4197 {
4198 if (nodeTuple.nodes[0] >= nodeOffsets_new[rank] && nodeTuple.nodes[0] < nodeOffsets_new[rank+1])
4199 edges_subdomain_owned.insert(ned);
4200 //pick up all the edges on the subdomain and store their nodes
4201 edgeNodesMap[ned].first = nodeTuple.nodes[0];
4202 edgeNodesMap[ned].second = nodeTuple.nodes[1];
4203 if (ihasEdgeMarkers > 0)
4204 edgeMaterialTypesMap[ned]=edId;
4205 for (set<pair<int,int> >::iterator elementp=edgeElementsMap[nodeTuple].begin();
4206 elementp != edgeElementsMap[nodeTuple].end();
4207 elementp++)
4208 {
4209 int eN = elementNumbering_global_old2new[elementp->first];
4210 if (elementEdgesMap.find(eN) != elementEdgesMap.end())
4211 {
4212 elementEdgesMap[eN][elementp->second] = ned;
4213 }
4214 else
4215 {
4216 std::vector<int> init(3,-1);
4217 elementEdgesMap[eN] = init;
4218 elementEdgesMap[eN][elementp->second] = ned;
4219 }
4220 }
4221 }
4222 }//end iv
4223 edgeElementsMap.clear();
4224 edgeFile.close();
4225 int nEdges_owned_subdomain=edges_subdomain_owned.size(),
4226 nEdges_owned_new=0;
4227 MPI_Allreduce(&nEdges_owned_subdomain,&nEdges_owned_new,1,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
4228 assert(nEdges_owned_new == nEdges_global);
4229 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done reading edges");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4230 //done with edge file
4231 //
4232 //just as with faces, we need to add edges along outer boundaries of star
4233 //not sure if we need to collect nodeEdges star above anymore, since we're doing this
4234 //
4235 for (map<int,vector<int> >::iterator edgesp=elementEdgesMap.begin();
4236 edgesp!=elementEdgesMap.end();
4237 edgesp++)
4238 {
4239 //loop over the nodes of this element for the owned nodes
4240 for (int iv=0;iv<simplexDim;iv++)
4241 {
4242 //the elementNodesArrayMap is in the old elemetn numbering while the elementEdgesMap is in the new element numbering
4243 int nN_global = elementNodesArrayMap[elementNumbering_global_new2old[edgesp->first]][iv];
4244 if (nN_global >= nodeOffsets_new[rank] && nN_global < nodeOffsets_new[rank+1])
4245 {
4246 //add all the edges to this node star
4247 for(int ed=0;ed<3;ed++)
4248 {
4249 nodeEdgesStar.at(nN_global-nodeOffsets_new[rank]).insert(edgesp->second[ed]);
4250 }
4251 }
4252 }
4253 }
4254 //build compact data structures for nodeEdgesArray
4255 valarray<int> nodeEdgeOffsets(nNodes_subdomain_new[rank]+1);
4256 nodeEdgeOffsets[0] = 0;
4257 for (int nN = 0; nN < nNodes_subdomain_new[rank]; nN++)
4258 nodeEdgeOffsets[nN+1] = nodeEdgeOffsets[nN]+nodeEdgesStar.at(nN).size();
4259 valarray<int> nodeEdgesArray(nodeEdgeOffsets[nNodes_subdomain_new[rank]]);
4260 for (int nN=0,offset=0; nN < nNodes_subdomain_new[rank]; nN++)
4261 {
4262 for (set<int>::iterator edN_star = nodeEdgesStar.at(nN).begin();
4263 edN_star != nodeEdgesStar.at(nN).end();
4264 edN_star++,offset++)
4265 {
4266 nodeEdgesArray[offset] = *edN_star;
4267 }
4268 }
4269 newMesh.subdomainp->nEdges_global = edgeNodesMap.size();
4270 //get the number of edges on each processor
4271 valarray<int> nEdges_subdomain_new(size),
4272 edgeOffsets_new(size+1);
4273 for (int sdN=0;sdN<size;sdN++)
4274 if (sdN == rank)
4275 nEdges_subdomain_new[sdN] = edges_subdomain_owned.size();
4276 else
4277 nEdges_subdomain_new[sdN] = 0;
4278 valarray<int> nEdges_subdomain_new_send=nEdges_subdomain_new;
4279 MPI_Allreduce(&nEdges_subdomain_new_send[0],&nEdges_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
4280 //
4281 //construct new offsets for owned edges
4282 //
4283 edgeOffsets_new[0] = 0;
4284 for (int sdN=0;sdN<size;sdN++)
4285 edgeOffsets_new[sdN+1] = edgeOffsets_new[sdN]+nEdges_subdomain_new[sdN];
4286 //
4287 //Now as with elementBoundaries, build a global face numbering
4288 //resetting the edge based information is a little different since much of this is currently built below based
4289 //on the element and node information
4290 //
4291 valarray<int> edgeNumbering_new2old(edges_subdomain_owned.size());
4292 set<int>::iterator edN_ownedp=edges_subdomain_owned.begin();
4293 for (int edN=0;edN<int(edges_subdomain_owned.size());edN++,edN_ownedp++)
4294 {
4295 edgeNumbering_new2old[edN] = *edN_ownedp;
4296 }
4297 IS edgeNumberingIS_subdomain_new2old;
4298 ISCreateGeneral(PROTEUS_COMM_WORLD,edges_subdomain_owned.size(),&edgeNumbering_new2old[0],PETSC_COPY_VALUES,&edgeNumberingIS_subdomain_new2old);
4299 IS edgeNumberingIS_global_new2old;
4300 ISAllGather(edgeNumberingIS_subdomain_new2old,&edgeNumberingIS_global_new2old);
4301 const PetscInt *edgeNumbering_global_new2old;
4302 valarray<int> edgeNumbering_global_old2new(newMesh.nEdges_global);
4303 ISGetIndices(edgeNumberingIS_global_new2old,&edgeNumbering_global_new2old);
4304 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Setting edgeNumering old2new/new2old");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4305 for (int edN=0;edN<newMesh.nEdges_global;edN++)
4306 {
4307 edgeNumbering_global_old2new[edgeNumbering_global_new2old[edN]] = edN;
4308 }
4309 ISRestoreIndices(edgeNumberingIS_global_new2old,&edgeNumbering_global_new2old);
4310 ISDestroy(&edgeNumberingIS_subdomain_new2old);
4311 ISDestroy(&edgeNumberingIS_global_new2old);
4312 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done allocating edgeNumering old2new/new2old");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4313 //
4314 //6. Figure out what is in the node stars but not locally owned, create ghost information
4315 //
4316
4317 set<int> elements_overlap,nodes_overlap,elementBoundaries_overlap,edges_overlap;
4318 for (int nN = 0; nN < nNodes_subdomain_new[rank]; nN++)
4319 {
4320 //nodes
4321 for (int offset = nodeStarOffsetsNew[nN];offset<nodeStarOffsetsNew[nN+1];offset++)
4322 {
4323 int nN_point_global = nodeStarArrayNew[offset];
4324 bool offproc = nN_point_global < nodeOffsets_new[rank] || nN_point_global >= nodeOffsets_new[rank+1];
4325 if (offproc)
4326 nodes_overlap.insert(nN_point_global);
4327 }
4328 //elements
4329 for (int eN_star_offset = nodeElementOffsets[nN];
4330 eN_star_offset < nodeElementOffsets[nN+1]; eN_star_offset++)
4331 {
4332 int eN_star_old = nodeElementsArray[eN_star_offset];
4333 int eN_star_new = elementNumbering_global_old2new[eN_star_old];
4334 bool offproc = eN_star_new >= elementOffsets_new[rank+1] || eN_star_new < elementOffsets_new[rank];
4335 if (offproc)
4336 elements_overlap.insert(eN_star_new);
4337 }
4338 //element boundaries
4339 for (int ebN_star_offset = nodeElementBoundaryOffsets[nN];
4340 ebN_star_offset < nodeElementBoundaryOffsets[nN+1]; ebN_star_offset++)
4341 {
4342 int ebN_star_old = nodeElementBoundariesArray[ebN_star_offset];
4343 int ebN_star_new = elementBoundaryNumbering_global_old2new[ebN_star_old];
4344 bool offproc = ebN_star_new >= elementBoundaryOffsets_new[rank+1] || ebN_star_new < elementBoundaryOffsets_new[rank];
4345 if (offproc)
4346 elementBoundaries_overlap.insert(ebN_star_new);
4347 }
4348 //edges in overlap
4349 for (int edN_star_offset = nodeEdgeOffsets[nN];
4350 edN_star_offset < nodeEdgeOffsets[nN+1]; edN_star_offset++)
4351 {
4352 int edN_star_old = nodeEdgesArray[edN_star_offset];
4353 int edN_star_new = edgeNumbering_global_old2new[edN_star_old];
4354 bool offproc = edN_star_new >= edgeOffsets_new[rank+1] || edN_star_new < edgeOffsets_new[rank];
4355 if (offproc)
4356 edges_overlap.insert(edN_star_new);
4357 }
4358 }//nodes on this processor
4359 elementNumbering_global_old2new.resize(0);
4360 MPI_Barrier(PROTEUS_COMM_WORLD);
4361 assert(edges_overlap.size() + nEdges_subdomain_new[rank] == edgeNodesMap.size());
4362 //
4363 //enumerate the overlap
4364 //
4365 int nN_subdomain = nNodes_subdomain_new[rank];
4366 map<int,int> nodes_overlap_global2subdomainMap;
4367 for (set<int>::iterator nN_globalp=nodes_overlap.begin();nN_globalp != nodes_overlap.end(); nN_globalp++,nN_subdomain++)
4368 nodes_overlap_global2subdomainMap[*nN_globalp] = nN_subdomain;
4369
4370 // map<int,int> elements_overlap_global2subdomainMap;
4371 // for (set<int>::iterator eN_globalp=elements_overlap.begin();eN_globalp != elements_overlap.end(); eN_globalp++,eN_subdomain++)
4372 // elements_overlap_global2subdomainMap[*eN_globalp] = eN_subdomain;
4373
4374 // int ebN_subdomain = nElementBoundaries_subdomain_new[rank];
4375 // map<int,int> elementBoundaries_overlap_global2subdomainMap;
4376 // for (set<int>::iterator ebN_globalp=elementBoundaries_overlap.begin();ebN_globalp != elementBoundaries_overlap.end(); ebN_globalp++,ebN_subdomain++)
4377 // elementBoundaries_overlap_global2subdomainMap[*ebN_globalp] = ebN_subdomain;
4378
4379 // int edN_subdomain = nEdges_subdomain_new[rank];
4380 // map<int,int> edges_overlap_global2subdomainMap;
4381 // for (set<int>::iterator edN_globalp=edges_overlap.begin();edN_globalp != edges_overlap.end(); edN_globalp++,edN_subdomain++)
4382 // edges_overlap_global2subdomainMap[*edN_globalp] = edN_subdomain;
4383 //
4384 //7. add any addtional overlap, skip for now
4385 //
4386
4387 PetscLogEventEnd(build_subdomains_edges_event,0,0,0,0);
4388 int build_subdomains_renumber_event;
4389 PetscLogEventRegister("Subd's renumber",0,&build_subdomains_renumber_event);
4390 PetscLogEventBegin(build_subdomains_renumber_event,0,0,0,0);
4391 //
4392 //8. Build subdomain meshes in new numbering, assumes memory not allocated in subdomain mesh
4393 //
4394 if(rank==0){
4395 std::cerr<<"USER WARNING: In order to avoid a segmentation fault, you need to have supplied the 'f' flag to the triangleOptions input."<<std::endl;
4396 std::cerr<<"USER WARNING: In order to avoid an edge assertion error, you need to have supplied the 'ee' flag to the triangleOptions input."<<std::endl;
4397 }
4398
4399 if (newMesh.subdomainp == NULL)
4400 newMesh.subdomainp = new Mesh();
4401 newMesh.subdomainp->nElements_global = nElements_subdomain_new[rank] + elements_overlap.size();
4402 newMesh.subdomainp->nNodes_global = nNodes_subdomain_new[rank] + nodes_overlap.size();
4403 newMesh.subdomainp->nElementBoundaries_global = nElementBoundaries_subdomain_new[rank]+elementBoundaries_overlap.size();
4404 assert(int(edges_subdomain_owned.size()+edges_overlap.size()) == newMesh.subdomainp->nEdges_global);
4405 //newMesh.subdomainp->nEdges_global = edges_subdomain_owned.size()+edges_overlap.size();
4406 newMesh.subdomainp->nNodes_element = newMesh.nNodes_element;
4409 //subdomain 2 global mappings (including ghost info)
4410 valarray<int> nodeNumbering_subdomain2global(newMesh.subdomainp->nNodes_global);
4411 valarray<int> elementNumbering_subdomain2global(newMesh.subdomainp->nElements_global);
4412 valarray<int> elementBoundaryNumbering_subdomain2global(newMesh.subdomainp->nElementBoundaries_global);
4413 valarray<int> edgeNumbering_subdomain2global(newMesh.subdomainp->nEdges_global);
4414 map<int,int> nodeNumbering_global2subdomainMap;
4415 map<int,int> elementBoundaryNumbering_global2subdomainMap;
4416 map<int,int> edgeNumbering_global2subdomainMap;
4417 newMesh.subdomainp->nodeArray = new double[newMesh.subdomainp->nNodes_global*3];
4418 newMesh.subdomainp->nodeMaterialTypes = new int[newMesh.subdomainp->nNodes_global];
4419 //
4420 //now finally finish reading node coordinates and node flags
4421 //
4422 for (int iv = 0; iv < nNodes_global; iv++)
4423 {
4424 int nv; double x,y; int nodeId(0);
4425 vertexFile >> eatcomments >> nv >> x >> y;
4426 if (hasVertexMarkers > 0)
4427 vertexFile >> nodeId;
4428 nv -= indexBase;
4429 assert(0 <= nv && nv < nNodes_global && vertexFile.good());
4430 int nN_global_new = nodeNumbering_global_old2new[nv];
4431 //local
4432 if (nN_global_new >= nodeOffsets_new[rank] && nN_global_new < nodeOffsets_new[rank+1])
4433 {
4434 int nv_subdomain_new = nN_global_new - nodeOffsets_new[rank];
4435 nodeNumbering_subdomain2global[nv_subdomain_new] = nN_global_new;
4436 nodeNumbering_global2subdomainMap[nN_global_new] = nv_subdomain_new;
4437 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 0] = x;
4438 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 1] = y;
4439 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 2] = 0.0;
4440 if (hasVertexMarkers > 0)
4441 newMesh.subdomainp->nodeMaterialTypes[nv_subdomain_new] = nodeId;
4442 }
4443 //overlap
4444 if (nodes_overlap.count(nN_global_new) == 1)
4445 {
4446 int nv_subdomain_new = nodes_overlap_global2subdomainMap[nN_global_new];
4447 nodeNumbering_subdomain2global[nv_subdomain_new] = nN_global_new;
4448 nodeNumbering_global2subdomainMap[nN_global_new] = nv_subdomain_new;
4449 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 0] = x;
4450 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 1] = y;
4451 newMesh.subdomainp->nodeArray[vertexDim*nv_subdomain_new + 2] = 0.0;
4452 if (hasVertexMarkers > 0)
4453 newMesh.subdomainp->nodeMaterialTypes[nv_subdomain_new] = nodeId;
4454 }
4455 vertexFile >> eatline;
4456 }//end iv
4457 vertexFile.close();
4458 ISRestoreIndices(nodeNumberingIS_global_old2new,&nodeNumbering_global_old2new);
4459 ISDestroy(&nodePartitioningIS_new);
4460 ISDestroy(&nodeNumberingIS_subdomain_old2new);
4461 ISDestroy(&nodeNumberingIS_global_old2new);
4462 //done with vertex file (and all file reads at this point)
4463 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done reading vertices");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4464
4466 newMesh.subdomainp->elementMaterialTypes = new int[newMesh.subdomainp->nElements_global];
4467 //
4468 //elements
4469 //
4470 //locally owned
4471 //
4472 for (int eN = 0; eN < nElements_subdomain_new[rank]; eN++)
4473 {
4474 int eN_global_new = elementOffsets_new[rank] + eN;
4475 int eN_global_old = elementNumbering_global_new2old[eN_global_new];
4476 elementNumbering_subdomain2global[eN] = eN_global_new;
4477 newMesh.subdomainp->elementMaterialTypes[eN] = elementMaterialTypesMap[eN_global_old];
4478 for (int nN = 0; nN < newMesh.subdomainp->nNodes_element; nN++)
4479 {
4480 int nN_global_new = elementNodesArrayMap[eN_global_old][nN];
4481 int nN_subdomain = nodeNumbering_global2subdomainMap[nN_global_new];
4482 newMesh.subdomainp->elementNodesArray[eN*newMesh.subdomainp->nNodes_element + nN]= nN_subdomain;
4483 }
4484 }
4485 //
4486 //ghost
4487 //
4488 set<int>::iterator eN_p = elements_overlap.begin();
4489 for (int eN = nElements_subdomain_new[rank]; eN < nElements_subdomain_new[rank] + int(elements_overlap.size()); eN++,eN_p++)
4490 {
4491 int eN_global_new = *eN_p;
4492 int eN_global_old = elementNumbering_global_new2old[eN_global_new];
4493 elementNumbering_subdomain2global[eN] = eN_global_new;
4494 newMesh.subdomainp->elementMaterialTypes[eN] = elementMaterialTypesMap[eN_global_old];
4495 for (int nN = 0; nN < newMesh.subdomainp->nNodes_element; nN++)
4496 {
4497 int nN_global_new = elementNodesArrayMap[eN_global_old][nN];
4498 int nN_subdomain = nodeNumbering_global2subdomainMap[nN_global_new];
4499 newMesh.subdomainp->elementNodesArray[eN*newMesh.subdomainp->nNodes_element + nN]= nN_subdomain;
4500 }
4501 }
4502 elementNodesArrayMap.clear();
4503 elementMaterialTypesMap.clear();
4504 ISRestoreIndices(elementNumberingIS_global_new2old,&elementNumbering_global_new2old);
4505 ISDestroy(&elementNumberingIS_subdomain_new2old);
4506 ISDestroy(&elementNumberingIS_global_new2old);
4507 //
4508 //element boundaries
4509 //
4510 //owned
4511 //
4512 for (int ebN=0; ebN < nElementBoundaries_subdomain_new[rank]; ebN++)
4513 {
4514 int ebN_global = ebN + elementBoundaryOffsets_new[rank];
4515 elementBoundaryNumbering_subdomain2global[ebN]=ebN_global;
4516 elementBoundaryNumbering_global2subdomainMap[ebN_global] = ebN;
4517 }
4518 //
4519 //ghost
4520 //
4521 set<int>::iterator ebN_p = elementBoundaries_overlap.begin();
4522 for(int ebN=nElementBoundaries_subdomain_new[rank];ebN < nElementBoundaries_subdomain_new[rank] + int(elementBoundaries_overlap.size()); ebN++,ebN_p++)
4523 {
4524 int ebN_global = *ebN_p;
4525 elementBoundaryNumbering_subdomain2global[ebN] = ebN_global;
4526 elementBoundaryNumbering_global2subdomainMap[ebN_global] = ebN;
4527 }
4528 //
4529 //need elementBoundariesArray to assign consistent numbering on subdomain
4530 //
4531 //local
4532 //
4535 for (int eN=0;eN<nElements_subdomain_new[rank];eN++)
4536 {
4537 int eN_global = eN+elementOffsets_new[rank];
4538 for (int ebN=0;ebN<newMesh.subdomainp->nElementBoundaries_element;ebN++)
4539 {
4541 elementBoundaryNumbering_global2subdomainMap[elementBoundaryNumbering_global_old2new[elementBoundariesMap[eN_global][ebN]]];
4542 }
4543 }
4544 //
4545 //ghost elements
4546 //
4547 eN_p = elements_overlap.begin();
4548 for (int eN = nElements_subdomain_new[rank]; eN < nElements_subdomain_new[rank] + int(elements_overlap.size()); eN++,eN_p++)
4549 {
4550 int eN_global_new = *eN_p;
4551 for (int ebN=0;ebN<newMesh.subdomainp->nElementBoundaries_element;ebN++)
4552 {
4554 elementBoundaryNumbering_global2subdomainMap[elementBoundaryNumbering_global_old2new[elementBoundariesMap[eN_global_new][ebN]]];
4555 }
4556 }
4557 //
4558 //edges
4559 //
4560 //local
4561 //
4562 for (int edN=0; edN < nEdges_subdomain_new[rank]; edN++)
4563 {
4564 int edN_global = edN + edgeOffsets_new[rank];
4565 edgeNumbering_subdomain2global[edN]=edN_global;
4566 edgeNumbering_global2subdomainMap[edN_global] = edN;
4567 }
4568 //
4569 //ghost
4570 //
4571 set<int>::iterator edN_p = edges_overlap.begin();
4572 for(int edN=nEdges_subdomain_new[rank];edN < nEdges_subdomain_new[rank] + int(edges_overlap.size()); edN++,edN_p++)
4573 {
4574 int edN_global = *edN_p;
4575 edgeNumbering_subdomain2global[edN] = edN_global;
4576 edgeNumbering_global2subdomainMap[edN_global] = edN;
4577 }
4578 //
4579 //now build edgeNodes array in new numberings
4580 //
4581 newMesh.subdomainp->edgeNodesArray = new int[newMesh.subdomainp->nEdges_global*2];
4582 for (int i=0;i<newMesh.subdomainp->nEdges_global*2;i++)
4583 newMesh.subdomainp->edgeNodesArray[i] = -1;
4584 for (map<int,pair<int,int> >::iterator edgep=edgeNodesMap.begin();
4585 edgep!=edgeNodesMap.end();
4586 edgep++)
4587 {
4588 int edN_global_old = edgep->first;
4589 int edN_global_new = edgeNumbering_global_old2new[edN_global_old];
4590 assert(edgeNumbering_global2subdomainMap.find(edN_global_new) != edgeNumbering_global2subdomainMap.end());
4591 int edN_subdomain = edgeNumbering_global2subdomainMap[edN_global_new];
4592 newMesh.subdomainp->edgeNodesArray[edN_subdomain*2+0] = nodeNumbering_global2subdomainMap[edgep->second.first];
4593 newMesh.subdomainp->edgeNodesArray[edN_subdomain*2+1] = nodeNumbering_global2subdomainMap[edgep->second.second];
4594 }
4595 edgeNumbering_global_old2new.resize(0);
4596 //
4597 //end edges
4598 //
4599
4600 //now build rest of subdomain mesh connectivity information etc
4601 bool callOld=true;
4602 if(callOld)
4604 else
4605 {
4606 //const int DEFAULT_ELEMENT_MATERIAL=0;
4607 const int DEFAULT_NODE_MATERIAL=-1;
4608 const int INTERIOR_NODE_MATERIAL=0;
4609 const int EXTERIOR_NODE_MATERIAL=1;
4612
4615 assert(newMesh.subdomainp->elementBoundariesArray);
4616 using namespace std;
4617 //double start,stop;
4618 map<NodeTuple<3>,
4619 ElementNeighbors> elementBoundaryElements;
4620 map<NodeTuple<3>,
4621 int> elementBoundaryIds;
4622 //start=CurrentTime();
4623 //cout<<"Extracting boundary elements"<<endl;
4624 for(int eN=0;eN<newMesh.subdomainp->nElements_global;eN++)
4625 for(int ebN=0;ebN<newMesh.subdomainp->nElementBoundaries_element;ebN++)
4626 {
4627 int ebN_global = newMesh.subdomainp->elementBoundariesArray[eN*newMesh.subdomainp->nElementBoundaries_element+ebN];
4628 int nodes[3];
4629 nodes[0] = newMesh.subdomainp->elementNodesArray[eN*4+((ebN+1)%4)];
4630 nodes[1] = newMesh.subdomainp->elementNodesArray[eN*4+((ebN+2)%4)];
4631 nodes[2] = newMesh.subdomainp->elementNodesArray[eN*4+((ebN+3)%4)];
4632 NodeTuple<3> ebt(nodes);
4633 if(elementBoundaryElements.find(ebt) != elementBoundaryElements.end())
4634 {
4635 elementBoundaryElements[ebt].right=eN;
4636 elementBoundaryElements[ebt].right_ebN_element=ebN;
4637 assert(elementBoundaryIds[ebt] == ebN_global);
4638 }
4639 else
4640 {
4641 elementBoundaryElements.insert(elementBoundaryElements.end(),make_pair(ebt,ElementNeighbors(eN,ebN)));
4642 elementBoundaryIds.insert(elementBoundaryIds.end(),make_pair(ebt,ebN_global));
4643 }
4644 }
4645 //stop = CurrentTime();
4646 //cout<<"Elapsed time for building element boundary elements map= "<<(stop-start)<<"s"<<endl;
4647 newMesh.subdomainp->nElementBoundaries_global = elementBoundaryElements.size();
4648 //cout<<"nElementBoundaries_global = "<<newMesh.subdomainp->nElementBoundaries_global<<endl;
4649
4650 //cout<<"Allocating Arrays"<<endl;
4651 //start = CurrentTime();
4652 set<int> interiorElementBoundaries,exteriorElementBoundaries;
4657 //stop = CurrentTime();
4658 //cout<<"Elapsed time for allocating arrays = "<<(stop-start)<<"s"<<endl;
4659
4660 //cout<<"Generating elementBoundaryElementsArray and elementBoundaryNodesArray"<<endl;
4661 //start = CurrentTime();
4662 for(map<NodeTuple<3>,ElementNeighbors>::iterator eb=elementBoundaryElements.begin();
4663 eb != elementBoundaryElements.end();
4664 eb++)
4665 {
4666 int ebN = elementBoundaryIds[eb->first];
4667 newMesh.subdomainp->elementBoundaryNodesArray[ebN*3 + 0] = eb->first.nodes[0];
4668 newMesh.subdomainp->elementBoundaryNodesArray[ebN*3 + 1] = eb->first.nodes[1];
4669 newMesh.subdomainp->elementBoundaryNodesArray[ebN*3 + 2] = eb->first.nodes[2];
4670
4671 newMesh.subdomainp->elementBoundaryElementsArray[ebN*2 + 0] = eb->second.left;
4672 newMesh.subdomainp->elementBoundaryLocalElementBoundariesArray[ebN*2 + 0] = eb->second.left_ebN_element;
4673 newMesh.subdomainp->elementBoundaryElementsArray[ebN*2 + 1] = eb->second.right;
4674 newMesh.subdomainp->elementBoundaryLocalElementBoundariesArray[ebN*2 + 1] = eb->second.right_ebN_element;
4675 newMesh.subdomainp->elementNeighborsArray[eb->second.left*newMesh.subdomainp->nElementBoundaries_element + eb->second.left_ebN_element] = eb->second.right;
4676 if(eb->second.right != -1)
4677 {
4678 interiorElementBoundaries.insert(ebN);
4679 newMesh.subdomainp->elementNeighborsArray[eb->second.right*newMesh.subdomainp->nElementBoundaries_element + eb->second.right_ebN_element] = eb->second.left;
4680 }
4681 else
4682 exteriorElementBoundaries.insert(ebN);
4683 assert(newMesh.subdomainp->elementBoundariesArray[eb->second.left*newMesh.subdomainp->nElementBoundaries_element + eb->second.left_ebN_element] == ebN);
4684 if (eb->second.right != -1)
4685 {
4686 assert(newMesh.subdomainp->elementBoundariesArray[eb->second.right*newMesh.subdomainp->nElementBoundaries_element + eb->second.right_ebN_element] == ebN);
4687 }
4688 }
4689 newMesh.subdomainp->nInteriorElementBoundaries_global = interiorElementBoundaries.size();
4691 newMesh.subdomainp->nExteriorElementBoundaries_global = exteriorElementBoundaries.size();
4693 int ebNI=0,ebNE=0;
4694 for (set<int>::iterator ebN=interiorElementBoundaries.begin();ebN != interiorElementBoundaries.end(); ebN++,ebNI++)
4695 newMesh.subdomainp->interiorElementBoundariesArray[ebNI] = *ebN;
4696 for (set<int>::iterator ebN=exteriorElementBoundaries.begin();ebN != exteriorElementBoundaries.end(); ebN++,ebNE++)
4697 newMesh.subdomainp->exteriorElementBoundariesArray[ebNE] = *ebN;
4698 set<NodeTuple<2> > edges;
4699 for (int eN=0;eN<newMesh.subdomainp->nElements_global;eN++)
4700 {
4701 int nodes[2];
4702 for (int nN_L=0;nN_L<newMesh.subdomainp->nNodes_element;nN_L++)
4703 for (int nN_R=nN_L+1;nN_R<newMesh.subdomainp->nNodes_element;nN_R++)
4704 {
4705 nodes[0] = newMesh.subdomainp->elementNodesArray[eN*4+nN_L];
4706 nodes[1] = newMesh.subdomainp->elementNodesArray[eN*4+nN_R];
4707 edges.insert(NodeTuple<2>(nodes));
4708 }
4709 }
4710 assert(newMesh.subdomainp->nEdges_global == int(edges.size()));
4711 vector<set<int> > nodeStar(newMesh.subdomainp->nNodes_global);
4712 for (int edgeN=0;edgeN<newMesh.subdomainp->nEdges_global;edgeN++)
4713 {
4714 nodeStar[newMesh.subdomainp->edgeNodesArray[edgeN*2+0]].insert(newMesh.subdomainp->edgeNodesArray[edgeN*2+1]);
4715 nodeStar[newMesh.subdomainp->edgeNodesArray[edgeN*2+1]].insert(newMesh.subdomainp->edgeNodesArray[edgeN*2+0]);
4716 }
4717 newMesh.subdomainp->nodeStarOffsets = new int[newMesh.subdomainp->nNodes_global+1];
4718 newMesh.subdomainp->nodeStarOffsets[0] = 0;
4719 for (int nN=1;nN<newMesh.subdomainp->nNodes_global+1;nN++)
4720 newMesh.subdomainp->nodeStarOffsets[nN] = newMesh.subdomainp->nodeStarOffsets[nN-1] + nodeStar[nN-1].size();
4721 newMesh.subdomainp->nodeStarArray = new int[newMesh.subdomainp->nodeStarOffsets[newMesh.subdomainp->nNodes_global]];
4722 for (int nN=0,offset=0;nN<newMesh.subdomainp->nNodes_global;nN++)
4723 for (set<int>::iterator nN_star=nodeStar[nN].begin();nN_star!=nodeStar[nN].end();nN_star++,offset++)
4724 newMesh.subdomainp->nodeStarArray[offset] = *nN_star;
4725 //stop = CurrentTime();
4727 for (int nN=0;nN<newMesh.subdomainp->nNodes_global;nN++)
4729 //mwf repeat for node-->elements arrays
4730 vector<set<int> > nodeElementsStar(newMesh.subdomainp->nNodes_global);
4731 for (int eN = 0; eN < newMesh.subdomainp->nElements_global; eN++)
4732 {
4733 for (int nN = 0; nN < newMesh.subdomainp->nNodes_element; nN++)
4734 nodeElementsStar[newMesh.subdomainp->elementNodesArray[eN*newMesh.subdomainp->nNodes_element+nN]].insert(eN);
4735 }
4736 newMesh.subdomainp->nodeElementOffsets = new int[newMesh.subdomainp->nNodes_global+1];
4737 newMesh.subdomainp->nodeElementOffsets[0] = 0;
4738 for (int nN = 0; nN < newMesh.subdomainp->nNodes_global; nN++)
4739 newMesh.subdomainp->nodeElementOffsets[nN+1] = newMesh.subdomainp->nodeElementOffsets[nN]+nodeElementsStar[nN].size();
4741 for (int nN=0,offset=0; nN < newMesh.subdomainp->nNodes_global; nN++)
4742 {
4743 for (set<int>::iterator eN_star = nodeElementsStar[nN].begin(); eN_star != nodeElementsStar[nN].end();
4744 eN_star++,offset++)
4745 {
4746 newMesh.subdomainp->nodeElementsArray[offset] = *eN_star;
4747 }
4748 }
4749 //mwf end node-->elements construction
4751 //if nodeMaterial is DEFAULT, go ahead and set to interior or exterior
4752 //depending on which boundary node belongs to.
4753 //If node on at least one exterior boundary then it's exterior
4754 for (int ebNE = 0; ebNE < newMesh.subdomainp->nExteriorElementBoundaries_global; ebNE++)
4755 {
4756 int ebN = newMesh.subdomainp->exteriorElementBoundariesArray[ebNE];
4758 for (int nN_local = 0; nN_local < newMesh.subdomainp->nNodes_elementBoundary; nN_local++)
4759 {
4760 int nN = newMesh.subdomainp->elementBoundaryNodesArray[ebN*newMesh.subdomainp->nNodes_elementBoundary+nN_local];
4763 }
4764 }
4765 for (int ebNI = 0; ebNI < newMesh.subdomainp->nInteriorElementBoundaries_global; ebNI++)
4766 {
4767 int ebN = newMesh.subdomainp->interiorElementBoundariesArray[ebNI];
4769 for (int nN_local = 0; nN_local < newMesh.subdomainp->nNodes_elementBoundary; nN_local++)
4770 {
4771 int nN = newMesh.subdomainp->elementBoundaryNodesArray[ebN*newMesh.subdomainp->nNodes_elementBoundary+nN_local];
4774 }
4775 }
4776 //cout<<"Elapsed time for populating arrays = "<<(stop-start)<<"s"<<endl;
4777 }
4778 //build local geometric info
4781
4782 if (hasElementBoundaryMarkers)
4783 {
4784 assert(newMesh.subdomainp->elementBoundariesArray != NULL);
4785 for (map<int,int>::iterator ebmp = elementBoundaryMaterialTypesMap.begin(); ebmp != elementBoundaryMaterialTypesMap.end();ebmp++)
4786 {
4787 int ebN_global_new = elementBoundaryNumbering_global_old2new[ebmp->first];
4788 assert(elementBoundaryNumbering_global2subdomainMap.find(ebN_global_new) != elementBoundaryNumbering_global2subdomainMap.end());
4789 int ebN_subdomain = elementBoundaryNumbering_global2subdomainMap[ebN_global_new];
4790 newMesh.subdomainp->elementBoundaryMaterialTypes[ebN_subdomain] = ebmp->second;
4791 }
4792 if (!hasVertexMarkers)
4793 for (int ebNE = 0; ebNE < newMesh.subdomainp->nExteriorElementBoundaries_global; ebNE++)
4794 {
4795 int ebN = newMesh.subdomainp->exteriorElementBoundariesArray[ebNE];
4796 for (int nN_local = 0; nN_local < newMesh.subdomainp->nNodes_elementBoundary; nN_local++)
4797 {
4798 int nN = newMesh.subdomainp->elementBoundaryNodesArray[ebN*newMesh.subdomainp->nNodes_elementBoundary+nN_local];
4800 }
4801 }
4802 }
4803 elementBoundaryNumbering_global_old2new.resize(0);
4804 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done with material types");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4805 PetscLogEventEnd(build_subdomains_renumber_event,0,0,0,0);
4806 int build_subdomains_cleanup_event;
4807 PetscLogEventRegister("Cleanup",0,&build_subdomains_cleanup_event);
4808 PetscLogEventBegin(build_subdomains_cleanup_event,0,0,0,0);
4809 //transfer information about owned nodes and elements to mesh
4810 if (newMesh.nodeOffsets_subdomain_owned)
4811 delete [] newMesh.nodeOffsets_subdomain_owned;
4813 delete [] newMesh.elementOffsets_subdomain_owned;
4816 if (newMesh.edgeOffsets_subdomain_owned)
4817 delete [] newMesh.edgeOffsets_subdomain_owned;
4818 newMesh.nodeOffsets_subdomain_owned = new int[size+1];
4819 newMesh.elementOffsets_subdomain_owned = new int[size+1];
4820 newMesh.elementBoundaryOffsets_subdomain_owned = new int[size+1];
4821 newMesh.edgeOffsets_subdomain_owned = new int[size+1];
4822 for (int sdN = 0; sdN < size+1; sdN++)
4823 {
4824 newMesh.nodeOffsets_subdomain_owned[sdN] = nodeOffsets_new[sdN];
4825 newMesh.elementOffsets_subdomain_owned[sdN] = elementOffsets_new[sdN];
4826 newMesh.elementBoundaryOffsets_subdomain_owned[sdN] = elementBoundaryOffsets_new[sdN];
4827 newMesh.edgeOffsets_subdomain_owned[sdN] = edgeOffsets_new[sdN];
4828 }
4830 delete [] newMesh.nodeNumbering_subdomain2global;
4831 newMesh.nodeNumbering_subdomain2global = new int[newMesh.subdomainp->nNodes_global];
4832 for (int nN = 0; nN < newMesh.subdomainp->nNodes_global; nN++)
4833 newMesh.nodeNumbering_subdomain2global[nN] = nodeNumbering_subdomain2global[nN];
4835 delete [] newMesh.elementNumbering_subdomain2global;
4837 for (int eN = 0; eN < newMesh.subdomainp->nElements_global; eN++)
4838 newMesh.elementNumbering_subdomain2global[eN] = elementNumbering_subdomain2global[eN];
4839 //
4843 for (int ebN = 0; ebN < newMesh.subdomainp->nElementBoundaries_global; ebN++)
4844 newMesh.elementBoundaryNumbering_subdomain2global[ebN] = elementBoundaryNumbering_subdomain2global[ebN];
4845 //
4847 delete [] newMesh.edgeNumbering_subdomain2global;
4848 newMesh.edgeNumbering_subdomain2global = new int[newMesh.subdomainp->nEdges_global];
4849 for (int i=0; i< newMesh.subdomainp->nEdges_global; i++)
4850 newMesh.edgeNumbering_subdomain2global[i] = edgeNumbering_subdomain2global[i];
4851 //cleanup
4852 /* out of core*/
4853 H5Sclose(filespace);
4854 H5Sclose(memspace);
4855 H5Pclose(plist_id);
4856 H5Fclose(file_id);
4857 /* out of core */
4858 PetscLogEventEnd(build_subdomains_cleanup_event,0,0,0,0);
4859 PetscLogStagePop();
4860 PetscLogView(PETSC_VIEWER_STDOUT_WORLD);
4861 //ierr = enforceMemoryLimit(PROTEUS_COMM_WORLD, rank, max_rss_gb,"Done with partitioning!");CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4862 return 0;
4863}
4864//todo add overlap for element based partitions
4865int partitionElements(const MPI_Comm& PROTEUS_COMM_WORLD, Mesh& mesh, int nElements_overlap)
4866{
4867 using namespace std;
4868 int ierr,size,rank;
4869
4870 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);
4871 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);
4872
4873 //Contents
4874 //
4875 //1. Partition the elements in the "default" partition (contiguous
4876 //chunks in given ordering)
4877 //
4878 //2. Partition the elementNeighbors based on this partition
4879 //
4880 //3. Pass to Parmetis to build a better partition of the elements
4881 //
4882 //4. Tag a subset of the nodes and faces on the subdomain elements as owned
4883 //using a mark and pass approach.**
4884 //
4885 //5. Extract the nodes and faces in the
4886 //overlapping elements.**
4887 //
4888 //6. Build the subdomain mesh from the
4889 //subdomain elements
4890 //
4891 //**To be more general we could get all the support (i.e. faces
4892 //and edges) and partitiong them, but the main reason for
4893 //partitioning is to keep track of a global numbering for degrees
4894 //of freedom that live on each type of geometric entity. We only
4895 //have node and element based DOFs so I just rebuild the other
4896 //information once we have elements and nodes partitioned.
4897 //
4898 // \todo check that I restore all data that PETSc expects to have
4899 // back, add PETSc error checking macros
4900 //
4901 //1. Build default partitioning
4902 //
4903 //get offsets so we can calculate the processor to global mapping
4904 //for elements in the old (default) partitioning
4905 valarray<int> elementOffsets_old(size+1);
4906 elementOffsets_old[0] = 0;
4907 for(int sdN=0;sdN<size;sdN++)
4908 elementOffsets_old[sdN+1] = elementOffsets_old[sdN] +
4909 int(mesh.nElements_global)/size +
4910 (int(mesh.nElements_global)%size > sdN);
4911
4912 //2. Extract subdomain element adjacency information could read
4913 //only the required portion from a file
4914 int nElements_subdomain = (elementOffsets_old[rank+1] - elementOffsets_old[rank]);
4915 PetscInt *elementNeighborsOffsets_subdomain,*elementNeighbors_subdomain,*weights_subdomain;
4916 PetscMalloc(sizeof(PetscInt)*(nElements_subdomain+1),&elementNeighborsOffsets_subdomain);
4917 PetscMalloc(sizeof(PetscInt)*(nElements_subdomain*mesh.nElementBoundaries_element),&elementNeighbors_subdomain);
4918 PetscMalloc(sizeof(PetscInt)*(nElements_subdomain*mesh.nElementBoundaries_element),&weights_subdomain);
4919 //this wastes a little space
4920 elementNeighborsOffsets_subdomain[0] = 0;
4921 for (int eN=0,offset=0; eN < nElements_subdomain; eN++)
4922 {
4923 int eN_global = elementOffsets_old[rank] + eN;
4924 int offsetStart=offset;
4925 for (int ebN=0; ebN< mesh.nElementBoundaries_element;ebN++)
4926 {
4927 int eN_neighbor_global = mesh.elementNeighborsArray[eN_global*mesh.nElementBoundaries_element + ebN];
4928 if (eN_neighbor_global >= 0 )
4929 elementNeighbors_subdomain[offset++] = eN_neighbor_global;
4930 }
4931 elementNeighborsOffsets_subdomain[eN+1]=offset;
4932 sort(&elementNeighbors_subdomain[offsetStart],&elementNeighbors_subdomain[offset]);
4933 int weight = (elementNeighborsOffsets_subdomain[eN+1] - elementNeighborsOffsets_subdomain[eN]);
4934 for (int k=elementNeighborsOffsets_subdomain[eN];k<elementNeighborsOffsets_subdomain[eN+1];k++)
4935 weights_subdomain[k] = weight;
4936 }
4937 //3. Generate the new partitiong using PETSc, this is done in parallel using parmetis
4938 Mat petscAdjacency;
4939 // MatCreateMPIAdj(PROTEUS_COMM_WORLD,
4940 // nElements_subdomain, mesh.nElements_global,
4941 // &elementNeighborsOffsets_subdomain[0], &elementNeighbors_subdomain[0],
4942 // &weights_subdomain[0],//PETSC_NULL,
4943 // &petscAdjacency);
4944 ierr = MatCreateMPIAdj(PROTEUS_COMM_WORLD,
4945 nElements_subdomain,
4946 mesh.nElements_global,
4947 elementNeighborsOffsets_subdomain,
4948 elementNeighbors_subdomain,
4949 PETSC_NULL,//weights_subdomain,
4950 &petscAdjacency);CHKERRABORT(PROTEUS_COMM_WORLD, ierr);
4951 PetscFree(weights_subdomain);
4952 MatPartitioning petscPartition;
4953 MatPartitioningCreate(PROTEUS_COMM_WORLD,&petscPartition);
4954 MatPartitioningSetAdjacency(petscPartition,petscAdjacency);
4955 MatPartitioningSetFromOptions(petscPartition);
4956
4957 //get a petsc index set that has the new submdomain number for each element
4958 IS elementPartitioningIS_new;
4959 MatPartitioningApply(petscPartition,&elementPartitioningIS_new);
4960 MatPartitioningDestroy(&petscPartition);
4961 MatDestroy(&petscAdjacency);
4962 //ISView(elementPartitioningIS_new,PETSC_VIEWER_STDOUT_WORLD);
4963
4964 //experiment with metis
4965 //mwf set some defaults and not call if size == 1 since metis crashes
4966 //cek commenting out for now
4967 //int etype=1,edgecut=0,base=0;
4968 //epart assign everything to processor zero by default
4969 //valarray<int> epart(0,mesh.nElements_global),npart(mesh.nNodes_global);
4970 //if (size > 1)
4971 // METIS_PartMeshNodal(&mesh.nElements_global,&mesh.nNodes_global,mesh.elementNodesArray,&etype,&base,&size,&edgecut,&epart[0],&npart[0]);
4972 //ISCreateGeneralWithArray(PETSC_COMM_SELF,mesh.nElements_global,&epart[0],&elementPartitioningIS_new);
4973 //write mesh to view with showme
4974 // std::ofstream nodeout("mesh.node"),eleout("mesh.ele"),partout("mesh.part");
4975 // eleout<<mesh.nElements_global<<" 3 0"<<std::endl;
4976 // partout<<mesh.nElements_global<<"\t"<<size<<std::endl;
4977 // for (int eN=0;eN<mesh.nElements_global;eN++)
4978 // {
4979 // partout<<(eN+1)<<"\t"<<(1+epart[eN])<<std::endl;
4980 // eleout<<(eN+1)<<"\t"<<(1+mesh.elementNodesArray[eN*3+0])
4981 // <<"\t"<<(1+mesh.elementNodesArray[eN*3+1])
4982 // <<"\t"<<(1+mesh.elementNodesArray[eN*3+2])
4983 // <<std::endl;
4984 // }
4985 // nodeout<<mesh.nNodes_global<<" 2 0 0"<<std::endl;
4986 // for (int nN=0;nN<mesh.nNodes_global;nN++)
4987 // {
4988 // nodeout<<(nN+1)<<"\t"<<mesh.nodeArray[nN*3+0]<<"\t"<<mesh.nodeArray[nN*3+1]<<std::endl;
4989 // }
4990 // eleout.close();
4991 // partout.close();
4992 //count the new number of elements on each subdomain
4993 valarray<int> nElements_subdomain_new(size);
4994 ISPartitioningCount(elementPartitioningIS_new,size,&nElements_subdomain_new[0]);
4995
4996 //get the new offsets for the subdomain to global numbering
4997 valarray<int> elementOffsets_new(size+1);
4998 elementOffsets_new[0] = 0;
4999 for (int sdN=0;sdN<size;sdN++)
5000 elementOffsets_new[sdN+1] = elementOffsets_new[sdN] + nElements_subdomain_new[sdN];
5001
5002 //get the new element numbers for the elements on this subdomain
5003 IS elementNumberingIS_subdomain_old2new;
5004 ISPartitioningToNumbering(elementPartitioningIS_new,&elementNumberingIS_subdomain_old2new);
5005
5006 //now get the new element numbers for the whole mesh so that we
5007 //can just read this processors elements, reorder, and renumber**
5008 //
5009 //**We could do this in parallel by scattering all the element
5010 //information
5011 IS elementNumberingIS_global_old2new;
5012 ISAllGather(elementNumberingIS_subdomain_old2new,&elementNumberingIS_global_old2new);
5013 const PetscInt *elementNumbering_global_old2new;
5014 ISGetIndices(elementNumberingIS_global_old2new,&elementNumbering_global_old2new);
5015 valarray<int> elementNumbering_global_new2old(mesh.nElements_global);
5016 for(int eN=0;eN<mesh.nElements_global;eN++)
5017 elementNumbering_global_new2old[elementNumbering_global_old2new[eN]] = eN;
5018
5019 //Sort element based arrays, maybe I don't need to do this, maybe
5020 //I just need to start writing into the subdomain mesh here and
5021 //preserve subdomain2old and subdomain2global mappings
5022 valarray<int> elementNodesArray_new(mesh.nElements_global*mesh.nNodes_element),
5023 elementNeighborsArray_new(mesh.nElements_global*mesh.nElementBoundaries_element),
5024 elementMaterialTypes_new(mesh.nElements_global),
5025 elementBoundariesArray_new(mesh.nElements_global*mesh.nElementBoundaries_element),
5026 elementBoundaryElementsArray_new(mesh.nElementBoundaries_global*2),
5027 elementBoundaryLocalElementBoundariesArray_new(mesh.nElementBoundaries_global*2),
5028 elementBoundaryNodesArray_new(mesh.nElementBoundaries_global*mesh.nNodes_elementBoundary),
5029 edgeNodesArray_new(mesh.nEdges_global*2);
5030 valarray<int> elementBoundaryMaterialTypes_new(mesh.nElementBoundaries_global);
5031 for (int eN=0;eN<mesh.nElements_global;eN++)
5032 {
5033 for (int nN=0;nN<mesh.nNodes_element;nN++)
5034 elementNodesArray_new[eN*mesh.nNodes_element + nN] =
5035 mesh.elementNodesArray[elementNumbering_global_new2old[eN]*mesh.nNodes_element+nN];
5036 for (int ebN=0;ebN<mesh.nElementBoundaries_element;ebN++)
5037 {
5038 elementNeighborsArray_new[eN*mesh.nElementBoundaries_element+ebN] =
5039 mesh.elementNeighborsArray[elementNumbering_global_new2old[eN]*mesh.nElementBoundaries_element+ebN];
5040 //need new elements --> old element boundary numbers for now
5041 elementBoundariesArray_new[eN*mesh.nElementBoundaries_element+ebN] =
5042 mesh.elementBoundariesArray[elementNumbering_global_new2old[eN]*mesh.nElementBoundaries_element+ebN];
5043 }
5044 elementMaterialTypes_new[eN] = mesh.elementMaterialTypes[elementNumbering_global_new2old[eN]];
5045
5046 }
5047 //renumber references to element numbers
5048 for (int eN=0;eN<mesh.nElements_global;eN++)
5049 {
5050 for (int ebN=0;ebN<mesh.nElementBoundaries_element;ebN++)
5051 {
5052 int eN_ebN = elementNeighborsArray_new[eN*mesh.nElementBoundaries_element+ebN];
5053 if (eN_ebN >= 0)
5054 elementNeighborsArray_new[eN*mesh.nElementBoundaries_element+ebN] =
5055 elementNumbering_global_old2new[eN_ebN];
5056 }
5057 }
5058 //4. now we need to build a new node ordering with better data locality for C0 finite elements
5059 //otherwise we could just grab the nodes on the subdomain and not worry about ownership
5060 //in the long run it wouldn't be bad to do a global repartition of faces and edges for mixed hybrid
5061 //and non-conforming finite elements
5062 MPI_Status status;
5063 PetscBT nodeMask;
5064 PetscBTCreate(mesh.nNodes_global,&nodeMask);
5065 if (rank > 0)
5066 {
5067 MPI_Recv(nodeMask,PetscBTLength(mesh.nNodes_global),MPI_CHAR,rank-1,0,PROTEUS_COMM_WORLD,&status);
5068 }
5069 //mark the unmarked nodes on this subdomain and store the node numbers
5070 set<int> nodes_subdomain_owned;
5071 for(int eN=elementOffsets_new[rank];eN<elementOffsets_new[rank+1];eN++)
5072 for(int nN=0;nN<mesh.nNodes_element;nN++)
5073 {
5074 int nN_global = elementNodesArray_new[eN*mesh.nNodes_element+nN];
5075 if (!PetscBTLookupSet(nodeMask,nN_global))
5076 nodes_subdomain_owned.insert(nN_global);
5077 }
5078 //ship off the mask
5079 if (rank < size-1)
5080 MPI_Send(nodeMask,PetscBTLength(mesh.nNodes_global),MPI_CHAR,rank+1,0,PROTEUS_COMM_WORLD);
5081 ierr = PetscBTDestroy(&nodeMask);
5082 if (ierr)
5083 cerr<<"Error in PetscBTDestroy"<<endl;
5084 //get the number of nodes on each processor
5085 valarray<int> nNodes_subdomain_new(size),
5086 nodeOffsets_new(size+1);
5087 for (int sdN=0;sdN<size;sdN++)
5088 if (sdN == rank)
5089 nNodes_subdomain_new[sdN] = nodes_subdomain_owned.size();
5090 else
5091 nNodes_subdomain_new[sdN] = 0;
5092 valarray<int> nNodes_subdomain_new_send=nNodes_subdomain_new;
5093 MPI_Allreduce(&nNodes_subdomain_new_send[0],&nNodes_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
5094 nodeOffsets_new[0] = 0;
5095 for (int sdN=0;sdN<size;sdN++)
5096 nodeOffsets_new[sdN+1] = nodeOffsets_new[sdN]+nNodes_subdomain_new[sdN];
5097
5098 assert(nodeOffsets_new[size]==mesh.nNodes_global);
5099
5100 //Now as with elements build a global node numbering, sort node
5101 //based information, and renumber references to node numbers
5102 valarray<int> nodeNumbering_new2old(nodes_subdomain_owned.size());
5103 set<int>::iterator nN_ownedp=nodes_subdomain_owned.begin();
5104 for (int nN=0;nN<int(nodes_subdomain_owned.size());nN++)
5105 {
5106 nodeNumbering_new2old[nN] = *nN_ownedp++;
5107 }
5108 IS nodeNumberingIS_new2old;
5109 ISCreateGeneral(PROTEUS_COMM_WORLD,nodes_subdomain_owned.size(),&nodeNumbering_new2old[0],PETSC_COPY_VALUES,&nodeNumberingIS_new2old);
5110 IS nodeNumberingIS_global_new2old;
5111 ISAllGather(nodeNumberingIS_new2old,&nodeNumberingIS_global_new2old);
5112 const PetscInt *nodeNumbering_global_new2old;
5113 valarray<int> nodeNumbering_old2new_global(mesh.nNodes_global);
5114 ISGetIndices(nodeNumberingIS_global_new2old,&nodeNumbering_global_new2old);
5115 for (int nN=0;nN<mesh.nNodes_global;nN++)
5116 {
5117 nodeNumbering_old2new_global[nodeNumbering_global_new2old[nN]] = nN;
5118 }
5119 for (int eN=0;eN < mesh.nElements_global; eN++)
5120 {
5121 int nN_old;
5122 for (int nN=0;nN < mesh.nNodes_element; nN++)
5123 {
5124 nN_old = elementNodesArray_new[eN*mesh.nNodes_element+nN];
5125 elementNodesArray_new[eN*mesh.nNodes_element+nN] = nodeNumbering_old2new_global[nN_old];
5126 }
5127 }
5128 //mwf postpone until after element boundary renumbering
5129 // for (int i=0;i<mesh.nElementBoundaries_global*mesh.nNodes_elementBoundary;i++)
5130 // {
5131 // int nN_old = mesh.elementBoundaryNodesArray[i];
5132 // elementBoundaryNodesArray_new[i] = nodeNumbering_old2new_global[nN_old];
5133 // }
5134 for (int i=0;i<mesh.nEdges_global*2;i++)
5135 {
5136 int nN_old = mesh.edgeNodesArray[i];
5137 edgeNodesArray_new[i] = nodeNumbering_old2new_global[nN_old];
5138 }
5139 valarray<int> nodeStarArray_new(mesh.nodeStarOffsets[mesh.nNodes_global]);
5140 for (int i=0;i<mesh.nodeStarOffsets[mesh.nNodes_global];i++)
5141 {
5142 int nN_old = mesh.nodeStarArray[i];
5143 nodeStarArray_new[i] = nodeNumbering_old2new_global[nN_old];
5144 }
5145 valarray<double> nodeArray_new(mesh.nNodes_global*3);
5146 valarray<int> nodeMaterialTypes_new(mesh.nNodes_global);
5147 for (int nN=0;nN<mesh.nNodes_global;nN++)
5148 {
5149 int nN_new = nodeNumbering_old2new_global[nN];
5150 nodeArray_new[nN_new*3+0] = mesh.nodeArray[nN*3+0];
5151 nodeArray_new[nN_new*3+1] = mesh.nodeArray[nN*3+1];
5152 nodeArray_new[nN_new*3+2] = mesh.nodeArray[nN*3+2];
5153 nodeMaterialTypes_new[nN_new] = mesh.nodeMaterialTypes[nN];
5154 }
5155
5156 //4b. repeat process to build global face numbering
5157 MPI_Status status_elementBoundaries;
5158 PetscBT elementBoundaryMask;
5159 PetscBTCreate(mesh.nElementBoundaries_global,&elementBoundaryMask);
5160 if (rank > 0)
5161 {
5162 MPI_Recv(elementBoundaryMask,PetscBTLength(mesh.nElementBoundaries_global),MPI_CHAR,rank-1,0,PROTEUS_COMM_WORLD,&status_elementBoundaries);
5163 }
5164 //mark the unmarked faces on this subdomain and store the global face numbers
5165 set<int> elementBoundaries_subdomain_owned;
5166 for(int eN=elementOffsets_new[rank];eN<elementOffsets_new[rank+1];eN++)
5167 for(int ebN=0;ebN<mesh.nElementBoundaries_element;ebN++)
5168 {
5169 int ebN_global = elementBoundariesArray_new[eN*mesh.nElementBoundaries_element+ebN];
5170 if(!PetscBTLookup(elementBoundaryMask,ebN_global))
5171 {
5172 bool notFound=true;
5173 for(int nN=0;nN<mesh.nNodes_elementBoundary;nN++)
5174 {
5175 int nN_global_old = mesh.elementBoundaryNodesArray[ebN_global*mesh.nNodes_elementBoundary+nN];
5176 if (nodes_subdomain_owned.count(nN_global_old) > 0)
5177 {
5178 notFound=false;
5179 }
5180 }
5181 if (notFound)
5182 {
5183 //std::cout<<"=========================Face has no owned nodes"<<std::endl;
5184 PetscBTSet(elementBoundaryMask,ebN_global);
5185 elementBoundaries_subdomain_owned.insert(ebN_global);
5186 }
5187 else
5188 {
5189 PetscBTSet(elementBoundaryMask,ebN_global);
5190 elementBoundaries_subdomain_owned.insert(ebN_global);
5191 }
5192 }
5193 }
5194 //std::cout<<"Done marking element boundares "<<elementBoundaries_subdomain_owned.size()<<std::endl;
5195 //ship off the mask
5196 if (rank < size-1)
5197 MPI_Send(elementBoundaryMask,PetscBTLength(mesh.nElementBoundaries_global),MPI_CHAR,rank+1,0,PROTEUS_COMM_WORLD);
5198 ierr = PetscBTDestroy(&elementBoundaryMask);
5199 if (ierr)
5200 cerr<<"Error in PetscBTDestroy for elementBoundaries"<<endl;
5201 //get the number of elementBoundaries on each processor
5202 valarray<int> nElementBoundaries_subdomain_new(size),
5203 elementBoundaryOffsets_new(size+1);
5204 for (int sdN=0;sdN<size;sdN++)
5205 if (sdN == rank)
5206 nElementBoundaries_subdomain_new[sdN] = elementBoundaries_subdomain_owned.size();
5207 else
5208 nElementBoundaries_subdomain_new[sdN] = 0;
5209 valarray<int> nElementBoundaries_subdomain_new_send=nElementBoundaries_subdomain_new;
5210 MPI_Allreduce(&nElementBoundaries_subdomain_new_send[0],&nElementBoundaries_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
5211 elementBoundaryOffsets_new[0] = 0;
5212 for (int sdN=0;sdN<size;sdN++)
5213 elementBoundaryOffsets_new[sdN+1] = elementBoundaryOffsets_new[sdN]+nElementBoundaries_subdomain_new[sdN];
5214 //Now as with elements and nodes build a global face numbering
5215 //resetting the face based information is a little different since much of this is currently built below based
5216 //on the element and node information
5217 //
5218 valarray<int> elementBoundaryNumbering_new2old(elementBoundaries_subdomain_owned.size());
5219 set<int>::iterator ebN_ownedp=elementBoundaries_subdomain_owned.begin();
5220 for (int ebN=0;ebN<int(elementBoundaries_subdomain_owned.size());ebN++)
5221 {
5222 elementBoundaryNumbering_new2old[ebN] = *ebN_ownedp++;
5223 }
5224 IS elementBoundaryNumberingIS_new2old;
5225 ISCreateGeneral(PROTEUS_COMM_WORLD,elementBoundaries_subdomain_owned.size(),&elementBoundaryNumbering_new2old[0],PETSC_COPY_VALUES,&elementBoundaryNumberingIS_new2old);
5226 IS elementBoundaryNumberingIS_global_new2old;
5227 ISAllGather(elementBoundaryNumberingIS_new2old,&elementBoundaryNumberingIS_global_new2old);
5228 const PetscInt *elementBoundaryNumbering_global_new2old;
5229 valarray<int> elementBoundaryNumbering_old2new_global(mesh.nElementBoundaries_global);
5230 ISGetIndices(elementBoundaryNumberingIS_global_new2old,&elementBoundaryNumbering_global_new2old);
5231 for (int ebN=0;ebN<mesh.nElementBoundaries_global;ebN++)
5232 {
5233 elementBoundaryNumbering_old2new_global[elementBoundaryNumbering_global_new2old[ebN]] = ebN;
5234 }
5235 for (int eN=0;eN < mesh.nElements_global; eN++)
5236 {
5237 int ebN_old;
5238 for (int ebN=0;ebN < mesh.nElementBoundaries_element; ebN++)
5239 {
5240 ebN_old = elementBoundariesArray_new[eN*mesh.nElementBoundaries_element+ebN];
5241 elementBoundariesArray_new[eN*mesh.nElementBoundaries_element+ebN] = elementBoundaryNumbering_old2new_global[ebN_old];
5242 }
5243 }
5244 //redo
5245 for (int ebN=0;ebN<mesh.nElementBoundaries_global;ebN++)
5246 {
5247 int ebN_old=elementBoundaryNumbering_global_new2old[ebN];
5248 for (int nN=0; nN<mesh.nNodes_elementBoundary; nN++)
5249 {
5250 int nN_old = mesh.elementBoundaryNodesArray[ebN_old*mesh.nNodes_elementBoundary+nN];
5251 elementBoundaryNodesArray_new[ebN*mesh.nNodes_elementBoundary+nN]=nodeNumbering_old2new_global[nN_old];
5252 }
5253 int eN_L_old = mesh.elementBoundaryElementsArray[ebN_old*2+0],
5254 eN_R_old = mesh.elementBoundaryElementsArray[ebN_old*2+1];
5255 elementBoundaryElementsArray_new[ebN*2+0] = elementNumbering_global_old2new[eN_L_old];
5256 if(eN_R_old >= 0)
5257 elementBoundaryElementsArray_new[ebN*2+1] = elementNumbering_global_old2new[eN_R_old];
5258
5259 elementBoundaryMaterialTypes_new[ebN] = mesh.elementBoundaryMaterialTypes[ebN_old];
5260 }
5261 // //mwf debug check constistency
5262 // for (int ebN=0; ebN<mesh.nElementBoundaries_global;ebN++)
5263 // {
5264 // int eN_left=elementBoundaryElementsArray_new[ebN*2+0];
5265 // int eN_right=elementBoundaryElementsArray_new[ebN*2+1];
5266 // assert(eN_left>=0);
5267 // bool found_ebN_left=false;
5268 // for (int ebN_element=0; ebN_element<mesh.nElementBoundaries_element; ebN_element++)
5269 // {
5270 // if (ebN == elementBoundariesArray_new[eN_left*mesh.nElementBoundaries_element+ebN_element])
5271 // {
5272 // assert(ebN_element==elementBoundaryLocalElementBoundariesArray_new[ebN*2+0]);
5273 // found_ebN_left=true;
5274 // }
5275 // }
5276 // assert(found_ebN_left);
5277 // if (eN_right>=0)
5278 // {
5279 // bool found_ebN_right=false;
5280 // for (int ebN_element=0; ebN_element<mesh.nElementBoundaries_element; ebN_element++)
5281 // {
5282 // if (ebN == elementBoundariesArray_new[eN_right*mesh.nElementBoundaries_element+ebN_element])
5283 // {
5284 // assert(ebN_element==elementBoundaryLocalElementBoundariesArray_new[ebN*2+1]);
5285 // found_ebN_right=true;
5286 // }
5287 // }
5288 // assert(found_ebN_right);
5289 // }
5290 // }
5291
5292 //do not renumber interior and exterior element boundary arrays yet
5293
5294 //write partitioned mesh to view with "showme"
5295 // std::ofstream nodeout("mesh.node"),eleout("mesh.ele"),partout("mesh.part");
5296 // eleout<<mesh.nElements_global<<" 3 0"<<std::endl;
5297 // partout<<mesh.nElements_global<<"\t"<<size<<std::endl;
5298 // for (int eN=0;eN<mesh.nElements_global;eN++)
5299 // {
5300 // partout<<(eN+1)<<"\t"<<(1+epart[elementNumbering_global_new2old[eN]])<<std::endl;
5301 // //partout<<(eN+1)<<"\t"<<(1+epart[eN])<<std::endl;
5302 // eleout<<(eN+1)<<"\t"<<(1+elementNodesArray_new[eN*3+0])
5303 // <<"\t"<<(1+elementNodesArray_new[eN*3+1])
5304 // <<"\t"<<(1+elementNodesArray_new[eN*3+2])
5305 // <<std::endl;
5306 // }
5307 // nodeout<<mesh.nNodes_global<<" 2 0 0"<<std::endl;
5308 // for (int nN=0;nN<mesh.nNodes_global;nN++)
5309 // {
5310 // nodeout<<(nN+1)<<"\t"<<nodeArray_new[nN*3+0]<<"\t"<<nodeArray_new[nN*3+1]<<std::endl;
5311 // }
5312 // eleout.close();
5313 // partout.close();
5314
5315 //4c. Build global edge numbering as well
5316 // ownership is determined by the edges on owned elements, then
5317 // who owns the left (0) node of the edge
5318 MPI_Status status_edges;
5319 PetscBT edgesMask;
5320 PetscBTCreate(mesh.nEdges_global,&edgesMask);
5321 if (rank > 0)
5322 {
5323 MPI_Recv(edgesMask,PetscBTLength(mesh.nEdges_global),MPI_CHAR,rank-1,0,PROTEUS_COMM_WORLD,&status_edges);
5324 }
5325 //mark the unmarked faces on this subdomain and store the global face numbers
5326 map<NodeTuple<2>, int> nodesEdgeMap_global; //new global node numbers --> original edge numbering
5327 set<int> edges_subdomain_owned;
5328 for (int ig = 0; ig < mesh.nEdges_global; ig++)
5329 {
5330 int nodes[2];
5331 nodes[0] = edgeNodesArray_new[2*ig];
5332 nodes[1] = edgeNodesArray_new[2*ig+1];
5333 NodeTuple<2> et(nodes);
5334 nodesEdgeMap_global[et] = ig;
5335 }
5336 for(int eN=elementOffsets_new[rank];eN<elementOffsets_new[rank+1];eN++)
5337 {
5338 for (int nN0=0;nN0<mesh.nNodes_element;nN0++)//assume all nodes in element may be edges
5339 for (int nN1=nN0+1; nN1<mesh.nNodes_element;nN1++)
5340 {
5341 int nodes[2];
5342 nodes[0] = elementNodesArray_new[eN*mesh.nNodes_element+nN0];
5343 nodes[1] = elementNodesArray_new[eN*mesh.nNodes_element+nN1];
5344 NodeTuple<2> et(nodes);
5345 if (nodesEdgeMap_global.find(et) != nodesEdgeMap_global.end())
5346 {
5347 int edge_global = nodesEdgeMap_global[et];
5348 if(!PetscBTLookup(edgesMask,edge_global))
5349 {
5350 PetscBTSet(edgesMask,edge_global);
5351 edges_subdomain_owned.insert(nodesEdgeMap_global[et]);
5352 }
5353 }
5354 }
5355 }
5356 if (rank < size-1)
5357 MPI_Send(edgesMask,PetscBTLength(mesh.nEdges_global),MPI_CHAR,rank+1,0,PROTEUS_COMM_WORLD);
5358 ierr = PetscBTDestroy(&edgesMask);
5359 if (ierr)
5360 cerr<<"Error in PetscBTDestroy for edges"<<endl;
5361
5362 valarray<int> nEdges_subdomain_new(size),
5363 edgeOffsets_new(size+1);
5364
5365 for (int sdN=0; sdN < size; sdN++)
5366 {
5367 if (sdN == rank)
5368 nEdges_subdomain_new[sdN] = edges_subdomain_owned.size();
5369 else
5370 nEdges_subdomain_new[sdN] = 0;
5371 }
5372 //collect ownership info
5373 valarray<int> nEdges_subdomain_new_send=nEdges_subdomain_new;
5374 MPI_Allreduce(&nEdges_subdomain_new_send[0],&nEdges_subdomain_new[0],size,MPI_INT,MPI_SUM,PROTEUS_COMM_WORLD);
5375 edgeOffsets_new[0] = 0;
5376 for (int sdN=0;sdN<size;sdN++)
5377 edgeOffsets_new[sdN+1] = edgeOffsets_new[sdN]+nEdges_subdomain_new[sdN];
5378
5379 //build new petsc numbering and global maps from old2new and new2old
5380 valarray<int> edgeNumbering_new2old(edges_subdomain_owned.size());
5381 set<int>::iterator edges_ownedp = edges_subdomain_owned.begin();
5382 for (int i=0; i < int(edges_subdomain_owned.size());i++)
5383 edgeNumbering_new2old[i] = *edges_ownedp++;
5384
5385 IS edgeNumberingIS_new2old;
5386 ISCreateGeneral(PROTEUS_COMM_WORLD,edges_subdomain_owned.size(),&edgeNumbering_new2old[0],PETSC_COPY_VALUES,&edgeNumberingIS_new2old);
5387 IS edgeNumberingIS_global_new2old;
5388 ISAllGather(edgeNumberingIS_new2old,&edgeNumberingIS_global_new2old);
5389 const PetscInt *edgeNumbering_global_new2old;
5390
5391
5392 valarray<int> edgeNumbering_old2new_global(mesh.nEdges_global);
5393 ISGetIndices(edgeNumberingIS_global_new2old,&edgeNumbering_global_new2old);
5394 for (int ig=0;ig<mesh.nEdges_global;ig++)
5395 {
5396 edgeNumbering_old2new_global[edgeNumbering_global_new2old[ig]] = ig;
5397 }
5398
5399 //create array with (new edge) --> (new node 0, new node 1)
5400 //and map from (new node 0, new node 1) --> (new global edge)
5401 valarray<int> edgeNodesArray_newNodesAndEdges(2*mesh.nEdges_global);
5402 map<NodeTuple<2>,int > nodesEdgeMap_global_new;
5403 for (int ig = 0; ig < mesh.nEdges_global; ig++)
5404 {
5405 int nodes[2];
5406 const int edge_old = edgeNumbering_global_new2old[ig];
5407 nodes[0] = edgeNodesArray_new[edge_old*2+0];
5408 nodes[1] = edgeNodesArray_new[edge_old*2+1];
5409 NodeTuple<2> et(nodes);
5410 edgeNodesArray_newNodesAndEdges[ig*2+0] = edgeNodesArray_new[edge_old*2+0];
5411 edgeNodesArray_newNodesAndEdges[ig*2+1] = edgeNodesArray_new[edge_old*2+1];
5412 assert(nodesEdgeMap_global_new.find(et) == nodesEdgeMap_global_new.end());
5413 nodesEdgeMap_global_new[et] = ig;
5414 }
5415
5416 //5. At this point we have new, renumbered and sorted the global element, and node based information, and
5417 //we have it all on each processor so we can add overlap
5418 set<int> elements_overlap,nodes_overlap,elementBoundaries_overlap,edges_overlap;
5419 for(int eN=elementOffsets_new[rank];eN<elementOffsets_new[rank+1];eN++)
5420 {
5421 for (int nN=0;nN<mesh.nNodes_element;nN++)
5422 {
5423 int nN_global = elementNodesArray_new[eN*mesh.nNodes_element+nN];
5424 if (nN_global < nodeOffsets_new[rank] || nN_global >= nodeOffsets_new[rank+1])
5425 nodes_overlap.insert(nN_global);
5426 }
5427 for (int ebN=0; ebN<mesh.nElementBoundaries_element;ebN++)
5428 {
5429 int ebN_global=elementBoundariesArray_new[eN*mesh.nElementBoundaries_element+ebN];
5430 if (ebN_global < elementBoundaryOffsets_new[rank] || ebN_global >= elementBoundaryOffsets_new[rank+1])
5431 elementBoundaries_overlap.insert(ebN_global);
5432 }
5433 for (int nN0=0;nN0<mesh.nNodes_element;nN0++)//assume all nodes in element may be edges
5434 for (int nN1=nN0+1; nN1<mesh.nNodes_element;nN1++)
5435 {
5436 int nodes[2];
5437 nodes[0] = elementNodesArray_new[eN*mesh.nNodes_element+nN0];
5438 nodes[1] = elementNodesArray_new[eN*mesh.nNodes_element+nN1];
5439 NodeTuple<2> et(nodes);
5440 const int nN0_global = elementNodesArray_new[eN*mesh.nNodes_element+nN0];
5441 const int nN1_global = elementNodesArray_new[eN*mesh.nNodes_element+nN1];
5442 if (nN0_global < nodeOffsets_new[rank] || nN0_global >= nodeOffsets_new[rank+1])
5443 assert(nodes_overlap.find(nN0_global) != nodes_overlap.end());
5444 if (nN1_global < nodeOffsets_new[rank] || nN1_global >= nodeOffsets_new[rank+1])
5445 assert(nodes_overlap.find(nN1_global) != nodes_overlap.end());
5446 if (nodesEdgeMap_global_new.find(et) != nodesEdgeMap_global_new.end())
5447 {
5448 const int edge_global = nodesEdgeMap_global_new[et];
5449 if (edge_global < edgeOffsets_new[rank] || edge_global >= edgeOffsets_new[rank+1])
5450 edges_overlap.insert(edge_global);
5451 }
5452 }//edges
5453 }
5454
5455 if (nElements_overlap > 0)
5456 {
5457 //get all elements in the node stars and their nodes
5458 // for (int nN_new=nodeOffsets_new[rank]; nN_new < nodeOffsets_new[rank+1]; nN_new++)
5459 // {
5460 // int nN = nodeNumbering_global_new2old[nN_new];
5461 // for (int offset =mesh.nodeElementOffsets[nN];offset<mesh.nodeElementOffsets[nN+1];offset++)
5462 // {
5463 // int eN = mesh.nodeElementsArray[offset];
5464 // int eN_new = elementNumbering_global_old2new[eN];
5465 // if (eN_new < elementOffsets_new[rank] or eN_new >= elementOffsets_new[rank+1])
5466 // {
5467 // elements_overlap.insert(eN_new);
5468 // for (int nN_element=0;nN_element<mesh.nNodes_element;nN_element++)
5469 // {
5470 // int nN_global = elementNodesArray_new[eN_new*mesh.nNodes_element+nN_element];
5471 // if (nN_global < nodeOffsets_new[rank] or nN_global >= nodeOffsets_new[rank+1])
5472 // nodes_overlap.insert(nN_global);
5473 // }
5474 // }
5475 // }
5476 // }
5477 //get all elements in the node stars of owned nodes and those elements' nodes and faces and edges
5478 for (set<int>::iterator nN=nodes_subdomain_owned.begin();nN != nodes_subdomain_owned.end();nN++)
5479 {
5480 for (int offset =mesh.nodeElementOffsets[*nN];offset<mesh.nodeElementOffsets[(*nN)+1];offset++)
5481 {
5482 int eN = mesh.nodeElementsArray[offset];
5483 int eN_new = elementNumbering_global_old2new[eN];
5484 if (eN_new < elementOffsets_new[rank] or eN_new >= elementOffsets_new[rank+1])
5485 {
5486 elements_overlap.insert(eN_new);
5487 for (int nN_element=0;nN_element<mesh.nNodes_element;nN_element++)
5488 {
5489 int nN_global = elementNodesArray_new[eN_new*mesh.nNodes_element+nN_element];
5490 if (nN_global < nodeOffsets_new[rank] or nN_global >= nodeOffsets_new[rank+1])
5491 nodes_overlap.insert(nN_global);
5492 }
5493 for (int ebN=0; ebN<mesh.nElementBoundaries_element;ebN++)
5494 {
5495 int ebN_global=elementBoundariesArray_new[eN_new*mesh.nElementBoundaries_element+ebN];
5496 if (ebN_global < elementBoundaryOffsets_new[rank] || ebN_global >= elementBoundaryOffsets_new[rank+1])
5497 elementBoundaries_overlap.insert(ebN_global);
5498 }
5499 //edges too
5500 for (int nN0=0;nN0<mesh.nNodes_element;nN0++)
5501 for (int nN1=nN0+1; nN1<mesh.nNodes_element;nN1++)
5502 {
5503 int nodes[2];
5504 nodes[0] = elementNodesArray_new[eN_new*mesh.nNodes_element+nN0];
5505 nodes[1] = elementNodesArray_new[eN_new*mesh.nNodes_element+nN1];
5506 NodeTuple<2> et(nodes);
5507 const int nN0_global = elementNodesArray_new[eN_new*mesh.nNodes_element+nN0];
5508 const int nN1_global = elementNodesArray_new[eN_new*mesh.nNodes_element+nN1];
5509 if (nodesEdgeMap_global_new.find(et) != nodesEdgeMap_global_new.end())
5510 {
5511 const int edge_global = nodesEdgeMap_global_new[et];
5512 if (edge_global < edgeOffsets_new[rank] || edge_global >= edgeOffsets_new[rank+1])
5513 edges_overlap.insert(edge_global);
5514 }
5515 }//edges
5516 }
5517 }
5518 }
5519 //get all the element neighbors
5520 for(int eN=elementOffsets_new[rank];eN<elementOffsets_new[rank+1];eN++)
5521 for(int ebN=0;ebN<mesh.nElementBoundaries_element;ebN++)
5522 {
5523 int eN_ebN = elementNeighborsArray_new[eN*mesh.nElementBoundaries_element+ebN];
5524 if (eN_ebN >= 0 &&
5525 (eN_ebN < elementOffsets_new[rank] || eN_ebN >= elementOffsets_new[rank+1]))
5526 {
5527 elements_overlap.insert(eN_ebN);
5528 for (int nN=0;nN<mesh.nNodes_element;nN++)
5529 {
5530 int nN_global = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN];
5531 if (nN_global < nodeOffsets_new[rank] || nN_global >= nodeOffsets_new[rank+1])
5532 nodes_overlap.insert(nN_global);
5533 }
5534 for (int ebN_element=0; ebN_element<mesh.nElementBoundaries_element;ebN_element++)
5535 {
5536 int ebN_global=elementBoundariesArray_new[eN_ebN*mesh.nElementBoundaries_element+ebN_element];
5537 if (ebN_global < elementBoundaryOffsets_new[rank] || ebN_global >= elementBoundaryOffsets_new[rank+1])
5538 elementBoundaries_overlap.insert(ebN_global);
5539 }
5540 //edges too
5541 for (int nN0=0;nN0<mesh.nNodes_element;nN0++)
5542 for (int nN1=nN0+1; nN1<mesh.nNodes_element;nN1++)
5543 {
5544 int nodes[2];
5545 nodes[0] = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN0];
5546 nodes[1] = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN1];
5547 NodeTuple<2> et(nodes);
5548 const int nN0_global = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN0];
5549 const int nN1_global = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN1];
5550 bool foundEdge = false;
5551 const int edge_global = nodesEdgeMap_global_new[et];
5552 if (edge_global < edgeOffsets_new[rank] || edge_global >= edgeOffsets_new[rank+1])
5553 edges_overlap.insert(edge_global);
5554 }//edges
5555 }
5556 }
5557 }
5558 for (int layer=1;layer<nElements_overlap;layer++)
5559 {
5560 for (set<int>::iterator eN_p=elements_overlap.begin();eN_p != elements_overlap.end();eN_p++)
5561 {
5562 int eN_global = *eN_p;
5563 for(int ebN=0;ebN<mesh.nElementBoundaries_element;ebN++)
5564 {
5565 int eN_ebN = elementNeighborsArray_new[eN_global*mesh.nElementBoundaries_element+ebN];
5566 if (eN_ebN >= 0 &&
5567 (eN_ebN < elementOffsets_new[rank] || eN_ebN >= elementOffsets_new[rank+1]))
5568 {
5569 elements_overlap.insert(eN_ebN);
5570 for (int nN=0;nN<mesh.nNodes_element;nN++)
5571 {
5572 int nN_global = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN];
5573 if (nN_global < nodeOffsets_new[rank] || nN_global >= nodeOffsets_new[rank+1])
5574 nodes_overlap.insert(nN_global);
5575 }
5576 for (int ebN_element=0; ebN_element<mesh.nElementBoundaries_element;ebN_element++)
5577 {
5578 int ebN_global=elementBoundariesArray_new[eN_ebN*mesh.nElementBoundaries_element+ebN_element];
5579 if (ebN_global < elementBoundaryOffsets_new[rank] || ebN_global >= elementBoundaryOffsets_new[rank+1])
5580 elementBoundaries_overlap.insert(ebN_global);
5581 }
5582 //edges too
5583 for (int nN0=0;nN0<mesh.nNodes_element;nN0++)
5584 for (int nN1=nN0+1; nN1<mesh.nNodes_element;nN1++)
5585 {
5586 int nodes[2];
5587 nodes[0] = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN0];
5588 nodes[1] = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN1];
5589 NodeTuple<2> et(nodes);
5590 const int nN0_global = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN0];
5591 const int nN1_global = elementNodesArray_new[eN_ebN*mesh.nNodes_element+nN1];
5592 bool foundEdge = false;
5593 if (nodesEdgeMap_global_new.find(et) != nodesEdgeMap_global_new.end())
5594 {
5595 const int edge_global = nodesEdgeMap_global_new[et];
5596 if (edge_global < edgeOffsets_new[rank] || edge_global >= edgeOffsets_new[rank+1])
5597 edges_overlap.insert(edge_global);
5598 }
5599 }//edges
5600 }
5601 }
5602 }
5603 }
5604 //
5605 //6. Now build subdomain mesh
5606 //
5607 //set what we know
5608 if (mesh.subdomainp == NULL)
5609 mesh.subdomainp = new Mesh();
5610 mesh.subdomainp->nElements_global = nElements_subdomain_new[rank] + elements_overlap.size();
5611 mesh.subdomainp->nNodes_global = nNodes_subdomain_new[rank] + nodes_overlap.size();
5612 //better be true ... check below
5613 mesh.subdomainp->nElementBoundaries_global = nElementBoundaries_subdomain_new[rank]+elementBoundaries_overlap.size();
5614 mesh.subdomainp->nEdges_global = nEdges_subdomain_new[rank] + edges_overlap.size();
5615
5619 //load the elements, nodes. and elementBoundaries
5620 valarray<int> nodeNumbering_subdomain2global(mesh.subdomainp->nNodes_global);
5621 map<int,int> nodeNumbering_global2subdomain;
5622 mesh.subdomainp->nodeArray = new double[mesh.subdomainp->nNodes_global*3];
5624 for(int nN=0;nN<nNodes_subdomain_new[rank];nN++)
5625 {
5626 int nN_global = nN + nodeOffsets_new[rank];
5627 nodeNumbering_subdomain2global[nN] = nN_global;
5628 nodeNumbering_global2subdomain[nN_global] = nN;
5629 mesh.subdomainp->nodeArray[nN*3+0] = nodeArray_new[nN_global*3+0];
5630 mesh.subdomainp->nodeArray[nN*3+1] = nodeArray_new[nN_global*3+1];
5631 mesh.subdomainp->nodeArray[nN*3+2] = nodeArray_new[nN_global*3+2];
5632 mesh.subdomainp->nodeMaterialTypes[nN]= nodeMaterialTypes_new[nN_global];
5633 }
5634 //note: sets in C++ are sorted so the overlap is laid out in
5635 //contiguous chunks corresponding to the partitions
5636 set<int>::iterator nN_p=nodes_overlap.begin();
5637 for(int nN=nNodes_subdomain_new[rank];nN < nNodes_subdomain_new[rank] + int(nodes_overlap.size()); nN++)
5638 {
5639 int nN_global = *nN_p++;
5640 nodeNumbering_subdomain2global[nN] = nN_global;
5641 nodeNumbering_global2subdomain[nN_global] = nN;
5642 mesh.subdomainp->nodeArray[nN*3+0] = nodeArray_new[nN_global*3+0];
5643 mesh.subdomainp->nodeArray[nN*3+1] = nodeArray_new[nN_global*3+1];
5644 mesh.subdomainp->nodeArray[nN*3+2] = nodeArray_new[nN_global*3+2];
5645 mesh.subdomainp->nodeMaterialTypes[nN]= nodeMaterialTypes_new[nN_global];
5646 }
5647
5648 //see what we must/can set for element boundaries here
5649 valarray<int> elementBoundaryNumbering_subdomain2global(mesh.subdomainp->nElementBoundaries_global);
5650 map<int,int> elementBoundaryNumbering_global2subdomain;
5651 for (int ebN=0; ebN < nElementBoundaries_subdomain_new[rank]; ebN++)
5652 {
5653 int ebN_global = ebN + elementBoundaryOffsets_new[rank];
5654 elementBoundaryNumbering_subdomain2global[ebN]=ebN_global;
5655 elementBoundaryNumbering_global2subdomain[ebN_global] = ebN;
5656 }
5657 set<int>::iterator ebN_p = elementBoundaries_overlap.begin();
5658 for(int ebN=nElementBoundaries_subdomain_new[rank];ebN < nElementBoundaries_subdomain_new[rank] + int(elementBoundaries_overlap.size()); ebN++)
5659 {
5660 int ebN_global = *ebN_p++;
5661 elementBoundaryNumbering_subdomain2global[ebN] = ebN_global;
5662 elementBoundaryNumbering_global2subdomain[ebN_global] = ebN;
5663 }
5664
5665
5668 //try to use elementBoundariesArray to set unique element boundary id below
5671 valarray<int> elementNumbering_subdomain2global(mesh.subdomainp->nElements_global);
5672 for (int eN=0;eN<nElements_subdomain_new[rank];eN++)
5673 {
5674 int eN_global = eN+elementOffsets_new[rank];
5675 elementNumbering_subdomain2global[eN] = eN_global;
5676 mesh.subdomainp->elementMaterialTypes[eN] = elementMaterialTypes_new[eN_global];
5677 for (int nN=0;nN<mesh.subdomainp->nNodes_element;nN++)
5678 {
5680 nodeNumbering_global2subdomain[elementNodesArray_new[eN_global*mesh.nNodes_element + nN]];
5681 }
5682 for (int ebN=0;ebN<mesh.subdomainp->nElementBoundaries_element;ebN++)
5684 elementBoundaryNumbering_global2subdomain[elementBoundariesArray_new[eN_global*mesh.nElementBoundaries_element + ebN]];
5685 }
5686 set<int>::iterator eN_p=elements_overlap.begin();
5687 for(int eN=nElements_subdomain_new[rank];eN < nElements_subdomain_new[rank]+int(elements_overlap.size());eN++)
5688 {
5689 int eN_global = *eN_p++;
5690 mesh.subdomainp->elementMaterialTypes[eN] = elementMaterialTypes_new[eN_global];
5691 elementNumbering_subdomain2global[eN] = eN_global;
5692 for (int nN=0;nN<mesh.subdomainp->nNodes_element;nN++)
5693 {
5695 nodeNumbering_global2subdomain[elementNodesArray_new[eN_global*mesh.nNodes_element + nN]];
5696 }
5697 for (int ebN=0;ebN<mesh.subdomainp->nElementBoundaries_element;ebN++)
5699 elementBoundaryNumbering_global2subdomain[elementBoundariesArray_new[eN_global*mesh.nElementBoundaries_element + ebN]];
5700 }
5701
5702 //set edge information, main piece necessary for setting subdomain data structures consistently is a map
5703 //from (nN0,nN1) --> edge_subdomain
5704 valarray<int> edgeNumbering_subdomain2global(mesh.subdomainp->nEdges_global);
5705 mesh.subdomainp->edgeNodesArray = new int[mesh.subdomainp->nEdges_global*2];
5706 for (int i=0; i < nEdges_subdomain_new[rank]; i++)
5707 {
5708 const int ig = i+edgeOffsets_new[rank];
5709 const int nN0_global = edgeNodesArray_newNodesAndEdges[ig*2+0];
5710 const int nN1_global = edgeNodesArray_newNodesAndEdges[ig*2+1];
5711 //mwf todo double check can always count on having nodes on this processor
5712 assert(nodeNumbering_global2subdomain.find(nN0_global) != nodeNumbering_global2subdomain.end());
5713 assert(nodeNumbering_global2subdomain.find(nN1_global) != nodeNumbering_global2subdomain.end());
5714 const int nN0_subdomain = nodeNumbering_global2subdomain[nN0_global];
5715 const int nN1_subdomain = nodeNumbering_global2subdomain[nN1_global];
5716 mesh.subdomainp->edgeNodesArray[2*i+0]=nN0_subdomain;
5717 mesh.subdomainp->edgeNodesArray[2*i+1]=nN1_subdomain;
5718 edgeNumbering_subdomain2global[i] = ig;
5719 }
5720 set<int>::iterator edge_p = edges_overlap.begin();
5721 for (int i=nEdges_subdomain_new[rank]; i < nEdges_subdomain_new[rank] + int(edges_overlap.size()); i++)
5722 {
5723 const int ig =*edge_p++;
5724 const int nN0_global = edgeNodesArray_newNodesAndEdges[ig*2+0];
5725 const int nN1_global = edgeNodesArray_newNodesAndEdges[ig*2+1];
5726 //mwf todo make sure always have nodes for the edge on this processor
5727 const int nN0_subdomain = nodeNumbering_global2subdomain[nN0_global];
5728 const int nN1_subdomain = nodeNumbering_global2subdomain[nN1_global];
5729 mesh.subdomainp->edgeNodesArray[2*i+0]=nN0_subdomain;
5730 mesh.subdomainp->edgeNodesArray[2*i+1]=nN1_subdomain;
5731 edgeNumbering_subdomain2global[i] = ig;
5732 }
5733 //now fill in rest of boundary information, etc
5734 mesh.subdomainp->px = mesh.px;
5735 mesh.subdomainp->py = mesh.py;
5736 mesh.subdomainp->pz = mesh.pz;
5737
5738 if (mesh.px != 0)
5739 {
5740 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_tetrahedron(*mesh.subdomainp);
5744
5745 }
5746 else if (mesh.subdomainp->nNodes_element == 2)
5747 {
5748 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_edge(*mesh.subdomainp);
5752 }
5753
5754 else if (mesh.subdomainp->nNodes_element == 3)
5755 {
5756 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_triangle(*mesh.subdomainp);
5760 }
5761 else if (mesh.subdomainp->nNodes_element == 4 && mesh.subdomainp->nNodes_elementBoundary == 2)
5762 {
5763 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_tetrahedron(*mesh.subdomainp);
5767 }
5768 else if (mesh.subdomainp->nNodes_element == 4)
5769 {
5770 //constructElementBoundaryElementsArrayWithGivenElementBoundaryNumbers_tetrahedron(*mesh.subdomainp);
5774 }
5775 else if (mesh.subdomainp->nNodes_element == 8)
5776 {
5780 }
5781 else
5782 {
5783 assert(false);
5784 }
5785 if (mesh.elementBoundaryMaterialTypes != NULL)
5786 {
5787 assert(mesh.elementBoundariesArray != NULL);
5788 //todo need to check that local element boundary numbering for
5789 //element boundaries stays the same
5790 for (int eN=0;eN<mesh.subdomainp->nElements_global;eN++)
5791 {
5792 int eN_global_new = elementNumbering_subdomain2global[eN];
5793 int eN_global_old = elementNumbering_global_new2old[eN_global_new];
5794 for (int ebN_element = 0; ebN_element < mesh.nElementBoundaries_element; ebN_element++)
5795 {
5796 int ebN_global_old = mesh.elementBoundariesArray[eN_global_old*mesh.nElementBoundaries_element+ebN_element];
5797 int ebN_subdomain = mesh.subdomainp->elementBoundariesArray[eN*mesh.nElementBoundaries_element+ebN_element];
5798 mesh.subdomainp->elementBoundaryMaterialTypes[ebN_subdomain] = mesh.elementBoundaryMaterialTypes[ebN_global_old];
5799 }
5800 }
5801 }
5802 //now we've got the old mesh in the old ordering and the subdomain mesh in the new ordering
5803 //the first chunk of nodes and elements are the owned elements so we need to know how many of those there are
5804 //and the offset of the first one so we can compute subdomain2global
5805 mesh.nodeOffsets_subdomain_owned = new int[size+1];
5806 mesh.elementOffsets_subdomain_owned = new int[size+1];
5807 mesh.elementBoundaryOffsets_subdomain_owned = new int[size+1];
5808 mesh.edgeOffsets_subdomain_owned = new int[size+1];
5809 for (int sdN=0;sdN<size+1;sdN++)
5810 {
5811 mesh.nodeOffsets_subdomain_owned[sdN] = nodeOffsets_new[sdN];
5812 mesh.elementOffsets_subdomain_owned[sdN] = elementOffsets_new[sdN];
5813 mesh.elementBoundaryOffsets_subdomain_owned[sdN] = elementBoundaryOffsets_new[sdN];
5814 mesh.edgeOffsets_subdomain_owned[sdN] = edgeOffsets_new[sdN];
5815 }
5816 //we also need the subdomain 2 new global mappings
5818 for (int nN=0;nN<mesh.subdomainp->nNodes_global;nN++)
5819 mesh.nodeNumbering_subdomain2global[nN] = nodeNumbering_subdomain2global[nN];
5821 for (int eN=0;eN<mesh.subdomainp->nElements_global;eN++)
5822 mesh.elementNumbering_subdomain2global[eN] = elementNumbering_subdomain2global[eN];
5824 for (int ebN=0;ebN<mesh.subdomainp->nElementBoundaries_global;ebN++)
5825 mesh.elementBoundaryNumbering_subdomain2global[ebN] = elementBoundaryNumbering_subdomain2global[ebN];
5827 for (int i=0; i< mesh.subdomainp->nEdges_global; i++)
5828 mesh.edgeNumbering_subdomain2global[i] = edgeNumbering_subdomain2global[i];
5829
5830 //
5831 //go ahead and renumber global mesh
5832 //
5833 //std::cout<<"nodeArray"<<std::endl;
5834 for (int i=0;i<mesh.nNodes_global*3;i++)
5835 mesh.nodeArray[i] = nodeArray_new[i];
5836 //std::cout<<"elementNodesArray"<<std::endl;
5837 for (int i=0;i<mesh.nElements_global*mesh.nNodes_element;i++)
5838 mesh.elementNodesArray[i] = elementNodesArray_new[i];
5839 //std::cout<<"elementBoundaryNodesArray"<<std::endl;
5840 for (int i=0;i<mesh.nElementBoundaries_global*mesh.nNodes_elementBoundary;i++)
5841 mesh.elementBoundaryNodesArray[i] = elementBoundaryNodesArray_new[i];
5842 //std::cout<<"edgeNodesArray"<<std::endl;
5843 for (int i=0;i<mesh.nEdges_global*2;i++)
5844 mesh.edgeNodesArray[i] = edgeNodesArray_newNodesAndEdges[i];
5845 //std::cout<<"nodeStarArray"<<std::endl;
5846 for (int i=0;i<mesh.nodeStarOffsets[mesh.nNodes_global];i++)
5847 mesh.nodeStarArray[i] = nodeStarArray_new[i];
5848 //std::cout<<"elementNeighborsArray"<<std::endl;
5849 for (int i=0; i<mesh.nElements_global*mesh.nElementBoundaries_element; i++)
5850 mesh.elementNeighborsArray[i] = elementNeighborsArray_new[i];
5851 //std::cout<<"elementBoundariesArray"<<std::endl;
5852 for (int i=0; i<mesh.nElements_global*mesh.nElementBoundaries_element; i++)
5853 mesh.elementBoundariesArray[i] = elementBoundariesArray_new[i];
5854 //std::cout<<"elementBoundaryElementsArray"<<std::endl;
5855 for (int i=0; i<mesh.nElementBoundaries_global*2; i++)
5856 mesh.elementBoundaryElementsArray[i] = elementBoundaryElementsArray_new[i];
5857 //std::cout<<"elementBoundaryLocalElementBoundariesArray"<<std::endl;
5858 for (int i=0; i<mesh.nElementBoundaries_global*2; i++)
5859 mesh.elementBoundaryLocalElementBoundariesArray[i] = elementBoundaryLocalElementBoundariesArray_new[i];
5860 //
5861 //need material properties too
5862 //
5863 if (mesh.elementMaterialTypes != NULL)
5864 {
5865 //std::cout<<"elementMaterialTypes"<<std::endl;
5866 for (int i=0; i < mesh.nElements_global; i++)
5867 mesh.elementMaterialTypes[i] = elementMaterialTypes_new[i];
5868 }
5869 if (mesh.elementBoundaryMaterialTypes != NULL)
5870 {
5871 //std::cout<<"elementBoundaryMaterialTypes"<<std::endl;
5872 for (int i=0; i < mesh.nElementBoundaries_global; i++)
5873 mesh.elementBoundaryMaterialTypes[i] = elementBoundaryMaterialTypes_new[i];
5874 }
5875
5876 ISRestoreIndices(elementNumberingIS_global_old2new,&elementNumbering_global_old2new);
5877
5878 ISDestroy(&elementPartitioningIS_new);
5879 ISDestroy(&elementNumberingIS_subdomain_old2new);
5880 ISDestroy(&elementNumberingIS_global_old2new);
5881
5882 ISRestoreIndices(nodeNumberingIS_global_new2old,&nodeNumbering_global_new2old);
5883
5884 ISDestroy(&nodeNumberingIS_new2old);
5885 ISDestroy(&nodeNumberingIS_global_new2old);
5886
5887 ISRestoreIndices(elementBoundaryNumberingIS_global_new2old,&elementBoundaryNumbering_global_new2old);
5888
5889 ISDestroy(&elementBoundaryNumberingIS_new2old);
5890 ISDestroy(&elementBoundaryNumberingIS_global_new2old);
5891
5892 ISRestoreIndices(edgeNumberingIS_global_new2old,&edgeNumbering_global_new2old);
5893
5894 ISDestroy(&edgeNumberingIS_new2old);
5895 ISDestroy(&edgeNumberingIS_global_new2old);
5896
5897 return 0;
5898}
5899
5900int buildQuadraticSubdomain2GlobalMappings_1d(const MPI_Comm& PROTEUS_COMM_WORLD, Mesh& mesh,
5901 const int *elementOffsets_subdomain_owned,
5902 const int *nodeOffsets_subdomain_owned,
5903 const int *elementNumbering_subdomain2global,
5904 const int *nodeNumbering_subdomain2global,
5905 int& nDOF_all_processes,//total number of dofs in whole domain
5906 int& nDOF_subdomain,//total number of dofs in sub-domain
5907 int& max_dof_neighbors,//maximum number of neighbors for connectivity of dofs
5908 int *offsets_subdomain_owned, //starting point of local dofs on each processor (nProcs+1)
5909 int * subdomain_l2g, //local to global dof mapping on subdomain
5910 int* subdomain2global,//subdomain dof to global (parallel) numbering
5911 double * lagrangeNodesArray)//location of nodes corresponding to dofs
5912{
5913 using namespace std;
5914 int ierr,size,rank;
5915
5916 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);
5917 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);
5918
5919
5920 //In 1d the quadratic dofs can be associated with nodes and elements
5921 //assuming have ownership info and consistent local/global mappings for nodes, elements
5922 //build a mapping from local quadratic dofs to global quadratic dofs for petsc
5923 //assume a processor owns a dof if it owns that node or element
5924 assert(elementOffsets_subdomain_owned);
5925 assert(nodeOffsets_subdomain_owned);
5926 assert(elementNumbering_subdomain2global);
5927 assert(nodeNumbering_subdomain2global);
5928 assert(mesh.subdomainp);
5929
5930 const int nNodes_owned = nodeOffsets_subdomain_owned[rank+1]-nodeOffsets_subdomain_owned[rank];
5931 const int nElements_owned = elementOffsets_subdomain_owned[rank+1]-elementOffsets_subdomain_owned[rank];
5932
5933 //start with a logical global ordering of dofs as
5934 //[global nodes, global elements]
5935 //want to create global numbering
5936 //[nodes proc 0,elements proc 0,nodes proc 1, elements proc 1,...]
5937 valarray<int> quadraticNumbering_new2old(nNodes_owned + nElements_owned);
5938 for (int nN = 0; nN < nNodes_owned; nN++)
5939 {
5940 int dof_global = nodeNumbering_subdomain2global[nN];
5941 quadraticNumbering_new2old[nN] = dof_global;
5942 }
5943 for (int eN = 0; eN < nElements_owned; eN++)
5944 {
5945 int dof_global = mesh.nNodes_global + elementNumbering_subdomain2global[eN];
5946 quadraticNumbering_new2old[nNodes_owned + eN] = dof_global;
5947 }
5948
5949 //build an index set for new numbering
5950 IS quadraticNumberingIS_new2old;
5951 ISCreateGeneral(PROTEUS_COMM_WORLD,nNodes_owned + nElements_owned,&quadraticNumbering_new2old[0],PETSC_COPY_VALUES,&quadraticNumberingIS_new2old);
5952 IS quadraticNumberingIS_global_new2old;
5953 ISAllGather(quadraticNumberingIS_new2old,&quadraticNumberingIS_global_new2old);
5954 //get old 2 new mapping for dofs
5955 const PetscInt *quadraticNumbering_global_new2old;
5956 valarray<int> quadraticNumbering_old2new_global(mesh.nNodes_global + mesh.nElements_global);
5957 ISGetIndices(quadraticNumberingIS_global_new2old,&quadraticNumbering_global_new2old);
5958 for (int id = 0; id < mesh.nNodes_global + mesh.nElements_global; id++)
5959 quadraticNumbering_old2new_global[quadraticNumbering_global_new2old[id]] = id;
5960 // //mwf debug
5961 // for (int id = 0; id < mesh.nNodes_global + mesh.nElements_global; id++)
5962 // {
5963 // std::cout<<" rank= "<<rank<<" build c0p2 mappings new2old["<<id<<"]= "<<quadraticNumbering_global_new2old[id]
5964 // <<" old2new["<<quadraticNumbering_global_new2old[id]<<"]= "<<quadraticNumbering_old2new_global[quadraticNumbering_global_new2old[id]]
5965 // <<std::endl;
5966 // }
5967 assert(offsets_subdomain_owned);
5968 assert(subdomain2global);
5969 assert(subdomain_l2g);
5970 assert(lagrangeNodesArray);
5971 nDOF_all_processes = mesh.nNodes_global+mesh.nElements_global;
5972 nDOF_subdomain = mesh.subdomainp->nNodes_global+mesh.subdomainp->nElements_global;
5973 max_dof_neighbors = 2*mesh.max_nNodeNeighbors_node;
5974
5975 for (int sdN=0; sdN < size+1; sdN++)
5976 offsets_subdomain_owned[sdN] = nodeOffsets_subdomain_owned[sdN]+elementOffsets_subdomain_owned[sdN];
5977
5978 //loop through owned and ghost dofs build subdomain mapping by
5979 //going from old --> new
5980 int localOffset = 0;
5981 for (int nN = 0; nN < nNodes_owned; nN++)
5982 {
5983 int dof_global_old = nodeNumbering_subdomain2global[nN];
5984 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
5985 subdomain2global[localOffset + nN] = dof_global_new;
5986 //mwf debug
5987 //std::cout<<" rank= "<<rank<<" nN= "<<nN<<" local dof= "<<localOffset+nN<<" nNodes_owned= "<<nNodes_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
5988 }
5989 localOffset += nNodes_owned;
5990 for (int eN = 0; eN < nElements_owned; eN++)
5991 {
5992 int dof_global_old = mesh.nNodes_global + elementNumbering_subdomain2global[eN];
5993 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
5994 subdomain2global[localOffset + eN] = dof_global_new;
5995 //mwf debug
5996 //std::cout<<" rank= "<<rank<<" eN= "<<eN<<" local dof= "<<localOffset+eN<<" nElements_owned= "<<nElements_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
5997 }
5998 localOffset += nElements_owned;
5999 for (int nN = nNodes_owned; nN < mesh.subdomainp->nNodes_global; nN++)
6000 {
6001 int dof_global_old = nodeNumbering_subdomain2global[nN];
6002 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6003 subdomain2global[localOffset + nN -nNodes_owned] = dof_global_new;
6004 //mwf debug
6005 //std::cout<<" rank= "<<rank<<" nN= "<<nN<<" local dof= "<<localOffset+nN-nNodes_owned<<" nNodes_owned= "<<nNodes_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6006 }
6007 localOffset += mesh.subdomainp->nNodes_global - nNodes_owned;
6008 for (int eN = nElements_owned; eN < mesh.subdomainp->nElements_global; eN++)
6009 {
6010 int dof_global_old = mesh.nNodes_global + elementNumbering_subdomain2global[eN];
6011 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6012 subdomain2global[localOffset + eN-nElements_owned] = dof_global_new;
6013 //mwf debug
6014 //std::cout<<" rank= "<<rank<<" eN= "<<eN<<" local dof= "<<localOffset+eN-nElements_owned<<" nElements_owned= "<<nElements_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6015 }
6016 //setup local to global mapping on the subdomain for finite elements
6017 const int nDOF_element = 3;
6018 const int ghostNodeOffset = nNodes_owned + nElements_owned;
6019 const int ghostElementOffset = ghostNodeOffset + mesh.subdomainp->nNodes_global-nNodes_owned;
6020
6021 //for lagrange nodes
6022 int nN_global_subdomain[2];
6023 for (int eN=0; eN < mesh.subdomainp->nElements_global; eN++)
6024 {
6025 for (int nN=0; nN < mesh.subdomainp->nNodes_element; nN++)
6026 {
6027 nN_global_subdomain[nN] = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN];
6028 if (nN_global_subdomain[nN] < nNodes_owned)
6029 subdomain_l2g[eN*nDOF_element+nN] = nN_global_subdomain[nN];
6030 else
6031 subdomain_l2g[eN*nDOF_element+nN] = nN_global_subdomain[nN]-nNodes_owned + ghostNodeOffset;
6032 //vertex dof
6033 for (int eI=0; eI < 3; eI++)
6034 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+nN]*3+eI] = mesh.subdomainp->nodeArray[3*nN_global_subdomain[nN]+eI];
6035 }
6036 if (eN < nElements_owned)
6037 subdomain_l2g[eN*nDOF_element+2] = nNodes_owned + eN;
6038 else
6039 subdomain_l2g[eN*nDOF_element+2] = eN - nElements_owned + ghostElementOffset;
6040 //vertex dof
6041 for (int eI=0; eI < 3; eI++)
6042 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+2]*3+eI] = 0.5*(mesh.subdomainp->nodeArray[3*nN_global_subdomain[0]+eI]+mesh.subdomainp->nodeArray[3*nN_global_subdomain[1]+eI]);
6043 }
6044
6045 ISRestoreIndices(quadraticNumberingIS_global_new2old,&quadraticNumbering_global_new2old);
6046 ISDestroy(&quadraticNumberingIS_new2old);
6047 ISDestroy(&quadraticNumberingIS_global_new2old);
6048
6049 return 0;
6050}
6051
6052int buildQuadraticSubdomain2GlobalMappings_2d(const MPI_Comm& PROTEUS_COMM_WORLD, Mesh& mesh,
6053 const int *elementBoundaryOffsets_subdomain_owned,
6054 const int *nodeOffsets_subdomain_owned,
6055 const int *elementBoundaryNumbering_subdomain2global,
6056 const int *nodeNumbering_subdomain2global,
6057 int& nDOF_all_processes,//total number of dofs in whole domain
6058 int& nDOF_subdomain,//total number of dofs in sub-domain
6059 int& max_dof_neighbors,//maximum number of neighbors for connectivity of dofs
6060 int *offsets_subdomain_owned, //starting point of local dofs on each processor (nProcs+1)
6061 int *subdomain_l2g, //local to global dof mapping on subdomain
6062 int *subdomain2global,//subdomain dof to global (parallel) numbering
6063 double * lagrangeNodesArray)//location of nodes corresponding to dofs
6064{
6065 using namespace std;
6066 int ierr,size,rank;
6067
6068 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);
6069 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);
6070
6071 //In 2d the quadratic dofs can be associated with nodes and element Boundaries
6072 //assuming have ownership info and consistent local/global mappings for nodes, elementBoundaries
6073 //build a mapping from local quadratic dofs to global quadratic dofs for petsc
6074 //assume a processor owns a dof if it owns that node or element
6075 assert(elementBoundaryOffsets_subdomain_owned);
6076 assert(nodeOffsets_subdomain_owned);
6077 assert(elementBoundaryNumbering_subdomain2global);
6078 assert(nodeNumbering_subdomain2global);
6079 assert(mesh.subdomainp);
6080
6081 const int nNodes_owned = nodeOffsets_subdomain_owned[rank+1]-nodeOffsets_subdomain_owned[rank];
6082 const int nElementBoundaries_owned = elementBoundaryOffsets_subdomain_owned[rank+1]-elementBoundaryOffsets_subdomain_owned[rank];
6083 const int nDOFs_owned = nNodes_owned + nElementBoundaries_owned;
6084 const int nDOFs_global= mesh.nNodes_global + mesh.nElementBoundaries_global;
6085 //start with a logical global ordering of dofs as
6086 //[global nodes, global elementBoundaries]
6087 //want to create global numbering
6088 //[nodes proc 0,elementBoundaries proc 0,nodes proc 1, elementBoundaries proc 1,...]
6089 valarray<int> quadraticNumbering_new2old(nDOFs_owned);
6090 for (int nN = 0; nN < nNodes_owned; nN++)
6091 {
6092 int dof_global = nodeNumbering_subdomain2global[nN];
6093 quadraticNumbering_new2old[nN] = dof_global;
6094 }
6095 for (int ebN = 0; ebN < nElementBoundaries_owned; ebN++)
6096 {
6097 int dof_global = mesh.nNodes_global + elementBoundaryNumbering_subdomain2global[ebN];
6098 quadraticNumbering_new2old[nNodes_owned + ebN] = dof_global;
6099 }
6100
6101 //build an index set for new numbering
6102 IS quadraticNumberingIS_new2old;
6103 ISCreateGeneral(PROTEUS_COMM_WORLD,nDOFs_owned,&quadraticNumbering_new2old[0],PETSC_COPY_VALUES,&quadraticNumberingIS_new2old);
6104 IS quadraticNumberingIS_global_new2old;
6105 ISAllGather(quadraticNumberingIS_new2old,&quadraticNumberingIS_global_new2old);
6106 //get old 2 new mapping for dofs
6107 const PetscInt *quadraticNumbering_global_new2old;
6108 valarray<int> quadraticNumbering_old2new_global(nDOFs_global);
6109 ISGetIndices(quadraticNumberingIS_global_new2old,&quadraticNumbering_global_new2old);
6110 for (int id = 0; id < nDOFs_global; id++)
6111 quadraticNumbering_old2new_global[quadraticNumbering_global_new2old[id]] = id;
6112 //mwf debug
6113 //for (int id = 0; id < nDOFs_global; id++)
6114 // {
6115 // std::cout<<" rank= "<<rank<<" build 2d c0p2 mappings new2old["<<id<<"]= "<<quadraticNumbering_global_new2old[id]
6116 // <<" old2new["<<quadraticNumbering_global_new2old[id]<<"]= "<<quadraticNumbering_old2new_global[quadraticNumbering_global_new2old[id]]
6117 // <<std::endl;
6118 // }
6119 assert(offsets_subdomain_owned);
6120 assert(subdomain2global);
6121 assert(subdomain_l2g);
6122 assert(lagrangeNodesArray);
6123 for (int sdN=0; sdN < size+1; sdN++)
6124 offsets_subdomain_owned[sdN] = nodeOffsets_subdomain_owned[sdN]+elementBoundaryOffsets_subdomain_owned[sdN];
6125 nDOF_all_processes = mesh.nNodes_global+mesh.nElementBoundaries_global;
6126 nDOF_subdomain = mesh.subdomainp->nNodes_global+mesh.subdomainp->nElementBoundaries_global;
6127 max_dof_neighbors = 2*mesh.max_nNodeNeighbors_node;
6128
6129 //loop through owned and ghost dofs build subdomain mapping by
6130 //going from old --> new
6131 int localOffset = 0;
6132 for (int nN = 0; nN < nNodes_owned; nN++)
6133 {
6134 int dof_global_old = nodeNumbering_subdomain2global[nN];
6135 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6136 subdomain2global[localOffset + nN] = dof_global_new;
6137 //mwf debug
6138 //std::cout<<" rank= "<<rank<<" nN= "<<nN<<" local dof= "<<localOffset+nN<<" nNodes_owned= "<<nNodes_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6139 }
6140 localOffset += nNodes_owned;
6141 for (int ebN = 0; ebN < nElementBoundaries_owned; ebN++)
6142 {
6143 int dof_global_old = mesh.nNodes_global + elementBoundaryNumbering_subdomain2global[ebN];
6144 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6145 subdomain2global[localOffset + ebN] = dof_global_new;
6146 //mwf debug
6147 //std::cout<<" rank= "<<rank<<" ebN= "<<ebN<<" local dof= "<<localOffset+ebN<<" nElementBoundaries_owned= "<<nElementBoundaries_owned
6148 // <<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6149 }
6150 localOffset += nElementBoundaries_owned;
6151 for (int nN = nNodes_owned; nN < mesh.subdomainp->nNodes_global; nN++)
6152 {
6153 int dof_global_old = nodeNumbering_subdomain2global[nN];
6154 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6155 subdomain2global[localOffset + nN -nNodes_owned] = dof_global_new;
6156 //mwf debug
6157 //std::cout<<" rank= "<<rank<<" nN= "<<nN<<" local dof= "<<localOffset+nN-nNodes_owned<<" nNodes_owned= "<<nNodes_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6158 }
6159 localOffset += mesh.subdomainp->nNodes_global - nNodes_owned;
6160 for (int ebN = nElementBoundaries_owned; ebN < mesh.subdomainp->nElementBoundaries_global; ebN++)
6161 {
6162 int dof_global_old = mesh.nNodes_global + elementBoundaryNumbering_subdomain2global[ebN];
6163 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6164 subdomain2global[localOffset + ebN-nElementBoundaries_owned] = dof_global_new;
6165 //mwf debug
6166 //std::cout<<" rank= "<<rank<<" ebN= "<<ebN<<" local dof= "<<localOffset+ebN-nElementBoundaries_owned<<" nElementBoundaries_owned= "<<nElementBoundaries_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6167 }
6168 //setup local to global mapping on the subdomain for finite elements
6169 const int nDOF_element = 6;
6170 const int ghostNodeOffset = nNodes_owned + nElementBoundaries_owned;
6171 const int ghostElementBoundaryOffset = ghostNodeOffset + mesh.subdomainp->nNodes_global-nNodes_owned;
6172
6173 //for lagrange nodes
6174 int nN_global_subdomain[3];
6175 for (int eN=0; eN < mesh.subdomainp->nElements_global; eN++)
6176 {
6177 for (int nN=0; nN < mesh.subdomainp->nNodes_element; nN++)
6178 {
6179 nN_global_subdomain[nN] = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN];
6180 if (nN_global_subdomain[nN] < nNodes_owned)
6181 subdomain_l2g[eN*nDOF_element+nN] = nN_global_subdomain[nN];
6182 else
6183 subdomain_l2g[eN*nDOF_element+nN] = nN_global_subdomain[nN]-nNodes_owned + ghostNodeOffset;
6184 //vertex dof
6185 for (int eI=0; eI < 3; eI++)
6186 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+nN]*3+eI] = mesh.subdomainp->nodeArray[3*nN_global_subdomain[nN]+eI];
6187 }
6188 for (int ebN=0; ebN < mesh.subdomainp->nElementBoundaries_element; ebN++)
6189 {
6190 //take into account numbering of edges according to
6191 //vertex they are across from
6192 int ebN_global = mesh.subdomainp->elementBoundariesArray[eN*mesh.subdomainp->nElementBoundaries_element+((ebN+2)%3)];
6193 if (ebN_global < nElementBoundaries_owned)
6194 subdomain_l2g[eN*nDOF_element+3+ebN] = nNodes_owned + ebN_global;
6195 else
6196 subdomain_l2g[eN*nDOF_element+3+ebN] = ebN_global - nElementBoundaries_owned + ghostElementBoundaryOffset;
6197 //center of edge dof
6198 for (int eI=0; eI < 3; eI++)
6199 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+3+ebN]*3+eI] = 0.5*(mesh.subdomainp->nodeArray[3*nN_global_subdomain[(ebN+0)%3]+eI]+mesh.subdomainp->nodeArray[3*nN_global_subdomain[(ebN+1)%3]+eI]);
6200 }
6201 }//eN
6202
6203 ISRestoreIndices(quadraticNumberingIS_global_new2old,&quadraticNumbering_global_new2old);
6204 ISDestroy(&quadraticNumberingIS_new2old);
6205 ISDestroy(&quadraticNumberingIS_global_new2old);
6206
6207 return 0;
6208}
6209
6210
6211int buildQuadraticSubdomain2GlobalMappings_3d(const MPI_Comm& PROTEUS_COMM_WORLD, Mesh& mesh,
6212 const int *edgeOffsets_subdomain_owned,
6213 const int *nodeOffsets_subdomain_owned,
6214 const int *edgeNumbering_subdomain2global,
6215 const int *nodeNumbering_subdomain2global,
6216 int& nDOF_all_processes,//total number of dofs in whole domain
6217 int& nDOF_subdomain,//total number of dofs in sub-domain
6218 int& max_dof_neighbors,//maximum number of neighbors for connectivity of dofs
6219 int *offsets_subdomain_owned, //starting point of local dofs on each processor (nProcs+1)
6220 int *subdomain_l2g, //local to global dof mapping on subdomain
6221 int *subdomain2global,//subdomain dof to global (parallel) numbering
6222 double * lagrangeNodesArray)//location of nodes corresponding to dofs
6223{
6224 using namespace std;
6225 int ierr,size,rank;
6226
6227 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);
6228 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);
6229
6230 //In 2d the quadratic dofs can be associated with nodes and element Boundaries
6231 //assuming have ownership info and consistent local/global mappings for nodes, elementBoundaries
6232 //build a mapping from local quadratic dofs to global quadratic dofs for petsc
6233 //assume a processor owns a dof if it owns that node or element
6234 assert(edgeOffsets_subdomain_owned);
6235 assert(nodeOffsets_subdomain_owned);
6236 assert(edgeNumbering_subdomain2global);
6237 assert(nodeNumbering_subdomain2global);
6238 assert(mesh.subdomainp);
6239
6240 const int nNodes_owned = nodeOffsets_subdomain_owned[rank+1]-nodeOffsets_subdomain_owned[rank];
6241 const int nEdges_owned = edgeOffsets_subdomain_owned[rank+1]-edgeOffsets_subdomain_owned[rank];
6242 const int nDOFs_owned = nNodes_owned + nEdges_owned;
6243 const int nDOFs_global= mesh.nNodes_global + mesh.nEdges_global;
6244 //start with a logical global ordering of dofs as
6245 //[global nodes, global edges]
6246 //want to create global numbering
6247 //[nodes proc 0,edges proc 0,nodes proc 1, edges proc 1,...]
6248 valarray<int> quadraticNumbering_new2old(nDOFs_owned);
6249 for (int nN = 0; nN < nNodes_owned; nN++)
6250 {
6251 int dof_global = nodeNumbering_subdomain2global[nN];
6252 quadraticNumbering_new2old[nN] = dof_global;
6253 }
6254 for (int i = 0; i < nEdges_owned; i++)
6255 {
6256 int dof_global = mesh.nNodes_global + edgeNumbering_subdomain2global[i];
6257 quadraticNumbering_new2old[nNodes_owned + i] = dof_global;
6258 }
6259
6260 //build an index set for new numbering
6261 IS quadraticNumberingIS_new2old;
6262 ISCreateGeneral(PROTEUS_COMM_WORLD,nDOFs_owned,&quadraticNumbering_new2old[0],PETSC_COPY_VALUES,&quadraticNumberingIS_new2old);
6263 IS quadraticNumberingIS_global_new2old;
6264 ISAllGather(quadraticNumberingIS_new2old,&quadraticNumberingIS_global_new2old);
6265 //get old 2 new mapping for dofs
6266 const PetscInt *quadraticNumbering_global_new2old;
6267 valarray<int> quadraticNumbering_old2new_global(nDOFs_global);
6268 ISGetIndices(quadraticNumberingIS_global_new2old,&quadraticNumbering_global_new2old);
6269 for (int id = 0; id < nDOFs_global; id++)
6270 quadraticNumbering_old2new_global[quadraticNumbering_global_new2old[id]] = id;
6271 //mwf debug
6272 // if (rank == 0)
6273 // {
6274 // for (int id = 0; id < nDOFs_global; id++)
6275 // {
6276 // std::cout<<" rank= "<<rank<<" build 2d c0p2 mappings new2old["<<id<<"]= "<<quadraticNumbering_global_new2old[id]
6277 // <<" old2new["<<quadraticNumbering_global_new2old[id]<<"]= "<<quadraticNumbering_old2new_global[quadraticNumbering_global_new2old[id]]
6278 // <<std::endl;
6279 // }
6280 // }
6281 assert(offsets_subdomain_owned);
6282 assert(subdomain2global);
6283 assert(subdomain_l2g);
6284 assert(lagrangeNodesArray);
6285 for (int sdN=0; sdN < size+1; sdN++)
6286 offsets_subdomain_owned[sdN] = nodeOffsets_subdomain_owned[sdN]+edgeOffsets_subdomain_owned[sdN];
6287 nDOF_all_processes = mesh.nNodes_global+mesh.nEdges_global;
6288 nDOF_subdomain = mesh.subdomainp->nNodes_global+mesh.subdomainp->nEdges_global;
6289 max_dof_neighbors = 2*mesh.max_nNodeNeighbors_node;
6290
6291 //loop through owned and ghost dofs build subdomain mapping by
6292 //going from old --> new
6293 int localOffset = 0;
6294 for (int nN = 0; nN < nNodes_owned; nN++)
6295 {
6296 int dof_global_old = nodeNumbering_subdomain2global[nN];
6297 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6298 subdomain2global[localOffset + nN] = dof_global_new;
6299 //mwf debug
6300 // if (rank == 0)
6301 // std::cout<<" rank= "<<rank<<" nN= "<<nN<<" local dof= "<<localOffset+nN<<" nNodes_owned= "<<nNodes_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6302 }
6303 localOffset += nNodes_owned;
6304 for (int i = 0; i < nEdges_owned; i++)
6305 {
6306 int dof_global_old = mesh.nNodes_global + edgeNumbering_subdomain2global[i];
6307 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6308 subdomain2global[localOffset + i] = dof_global_new;
6309 //mwf debug
6310 // if (rank == 0)
6311 // std::cout<<" rank= "<<rank<<" i= "<<i<<" local dof= "<<localOffset+i<<" nEdges_owned= "<<nEdges_owned
6312 // <<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6313 }
6314 localOffset += nEdges_owned;
6315 for (int nN = nNodes_owned; nN < mesh.subdomainp->nNodes_global; nN++)
6316 {
6317 int dof_global_old = nodeNumbering_subdomain2global[nN];
6318 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6319 subdomain2global[localOffset + nN -nNodes_owned] = dof_global_new;
6320 //mwf debug
6321 // if (rank == 0)
6322 // std::cout<<" rank= "<<rank<<" nN= "<<nN<<" local dof= "<<localOffset+nN-nNodes_owned<<" nNodes_owned= "<<nNodes_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6323 }
6324 localOffset += mesh.subdomainp->nNodes_global - nNodes_owned;
6325 for (int i = nEdges_owned; i < mesh.subdomainp->nEdges_global; i++)
6326 {
6327 int dof_global_old = mesh.nNodes_global + edgeNumbering_subdomain2global[i];
6328 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6329 subdomain2global[localOffset + i-nEdges_owned] = dof_global_new;
6330 // //mwf debug
6331 // if (rank == 0)
6332 // std::cout<<" rank= "<<rank<<" i= "<<i<<" local dof= "<<localOffset+i-nEdges_owned<<" nEdges_owned= "<<nEdges_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6333 }
6334 //setup local to global mapping on the subdomain for finite elements
6335 const int nDOF_element = 10;
6336 const int ghostNodeOffset = nNodes_owned + nEdges_owned;
6337 const int ghostEdgeOffset = ghostNodeOffset + mesh.subdomainp->nNodes_global-nNodes_owned;
6338 //need mapping from nodes to edge to setup element based relationship
6339 map<NodeTuple<2>, int> nodesEdgeMap_subdomain;
6340 for (int i=0; i < mesh.subdomainp->nEdges_global; i++)
6341 {
6342 int nodes[2];
6343 nodes[0] = mesh.subdomainp->edgeNodesArray[2*i];
6344 nodes[1] = mesh.subdomainp->edgeNodesArray[2*i+1];
6345 NodeTuple<2> et(nodes);
6346 const int nN0 = mesh.subdomainp->edgeNodesArray[2*i];
6347 const int nN1 = mesh.subdomainp->edgeNodesArray[2*i+1];
6348 nodesEdgeMap_subdomain[et] = i;
6349 }
6350 for (int eN=0; eN < mesh.subdomainp->nElements_global; eN++)
6351 {
6352 int local_offset = 0;
6353 for (int nN=0; nN < mesh.subdomainp->nNodes_element; nN++)
6354 {
6355 //node_i --> unique subdomain node 0 <= i <= 3
6356 const int nN_global_subdomain = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN];
6357 //assign unique subdomain id based on |owned nodes|owned edges|ghost nodes|ghost edges|
6358 if (nN_global_subdomain < nNodes_owned)
6359 {
6360 subdomain_l2g[eN*nDOF_element + local_offset + nN] = nN_global_subdomain;
6361 }
6362 else
6363 {
6364 subdomain_l2g[eN*nDOF_element + local_offset + nN] = ghostNodeOffset + nN_global_subdomain - nNodes_owned;
6365 }
6366 //unique subdomain id --> unique cross processor id
6367 //subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]] = nodeNumbering_subdomain2global[nN_global_subdomain];
6368 //mwf debug
6369 // if (rank == 0)
6370 // {
6371 // std::cout<<"build loc2glob c0p2 3d eN= "<<eN<<" node= "<<nN<<" sub_dof= "<< subdomain_l2g[eN*nDOF_element + local_offset + nN]
6372 // <<" glob_dof= "<<subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]]<<std::endl;
6373 // }
6374 for (int eI=0; eI < 3; eI++)
6375 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element + local_offset +nN]*3+eI] = mesh.subdomainp->nodeArray[nN_global_subdomain*3+eI];
6376 }
6377 local_offset += mesh.subdomainp->nNodes_element;
6378 //(node_i,node_{i+1}) --> unique subdomain edge, 0 <= i < 3
6379 for (int nN = 0; nN < mesh.subdomainp->nNodes_element-1; nN++)
6380 {
6381 const int nN_neig = (nN+1)%mesh.subdomainp->nNodes_element;
6382 const int nN_global_subdomain = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN];
6383 const int nN_neig_global_subdomain= mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN_neig];
6384 //unique edge subdomain id and global id
6385 int edge_subdomain = -1,edge_global=-1;
6386 //see if edge is (nN,nN_neig) or vice versa
6387 int nodes[2];
6388 nodes[0] = nN_global_subdomain;
6389 nodes[1] = nN_neig_global_subdomain;
6390 NodeTuple<2> et(nodes);
6391 edge_subdomain = nodesEdgeMap_subdomain[et];
6392 edge_global = edgeNumbering_subdomain2global[edge_subdomain];
6393 assert(edge_subdomain >= 0 && edge_global >= 0);
6394
6395 //assign unique subdomain id based on |owned nodes|owned edges|ghost nodes|ghost edges|
6396 if (edge_subdomain < nEdges_owned)
6397 subdomain_l2g[eN*nDOF_element + local_offset + nN] = nNodes_owned + edge_subdomain;
6398 else
6399 subdomain_l2g[eN*nDOF_element + local_offset + nN] = ghostEdgeOffset + edge_subdomain - nEdges_owned;
6400 //unique subdomain id --> unique cross processor id
6401 //set above could do here subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]] = mesh.nNodes_global + edge_global;
6402 //mwf debug
6403 // if (rank == 0)
6404 // {
6405 // std::cout<<"build loc2glob c0p2 3d eN= "<<eN<<" edge("<<nN<<","<<nN_neig<<") sub_dof= "<< subdomain_l2g[eN*nDOF_element + local_offset + nN]
6406 // <<" glob_dof= "<<subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]]<<std::endl;
6407 // }
6408 for (int eI=0; eI < 3; eI++)
6409 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+local_offset+nN]*3+eI] = 0.5*(mesh.subdomainp->nodeArray[nN_global_subdomain*3+eI]+
6410 mesh.subdomainp->nodeArray[nN_neig_global_subdomain*3+eI]);
6411 }
6412 local_offset += mesh.subdomainp->nNodes_element-1;
6413 //(node_i,node_{i+2}) --> unique subdomain edge, 0 <= i < 2
6414 for (int nN = 0; nN < mesh.subdomainp->nNodes_element-2; nN++)
6415 {
6416 const int nN_neig = (nN+2)%mesh.subdomainp->nNodes_element;
6417 const int nN_global_subdomain = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN];
6418 const int nN_neig_global_subdomain= mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN_neig];
6419 //unique edge subdomain id and global id
6420 int edge_subdomain = -1, edge_global = -1;
6421 //see if edge is (nN,nN_neig) or vice versa
6422 int nodes[2];
6423 nodes[0] = nN_global_subdomain;
6424 nodes[1] = nN_neig_global_subdomain;
6425 NodeTuple<2> et(nodes);
6426 edge_subdomain = nodesEdgeMap_subdomain[et];
6427 edge_global = edgeNumbering_subdomain2global[edge_subdomain];
6428 assert(edge_subdomain >= 0 && edge_global >= 0);
6429 //assign unique subdomain id based on |owned nodes|owned edges|ghost nodes|ghost edges|
6430 if (edge_subdomain < nEdges_owned)
6431 subdomain_l2g[eN*nDOF_element + local_offset + nN] = nNodes_owned + edge_subdomain;
6432 else
6433 subdomain_l2g[eN*nDOF_element + local_offset + nN] = ghostEdgeOffset + edge_subdomain - nEdges_owned;
6434 //unique subdomain id --> unique cross processor id
6435 //subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]] = mesh.nNodes_global + edge_global;
6436 //mwf debug
6437 // if (rank == 0)
6438 // {
6439 // std::cout<<"build loc2glob c0p2 3d eN= "<<eN<<" edge("<<nN<<","<<nN_neig<<") sub_dof= "<< subdomain_l2g[eN*nDOF_element + local_offset + nN]
6440 // <<" glob_dof= "<<subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]]<<std::endl;
6441 // }
6442 for (int eI=0; eI < 3; eI++)
6443 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+local_offset+nN]*3+eI] = 0.5*(mesh.subdomainp->nodeArray[nN_global_subdomain*3+eI]+
6444 mesh.subdomainp->nodeArray[nN_neig_global_subdomain*3+eI]);
6445 }
6446 local_offset += mesh.subdomainp->nNodes_element-2;
6447 //(node_i,node_{i+3}) --> unique subdomain edge, 0 = i
6448 for (int nN = 0; nN < mesh.subdomainp->nNodes_element-3; nN++)
6449 {
6450 const int nN_neig = (nN+3)%mesh.subdomainp->nNodes_element;
6451 const int nN_global_subdomain = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN];
6452 const int nN_neig_global_subdomain= mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN_neig];
6453 //unique edge subdomain id and global id
6454 int edge_subdomain = -1, edge_global = -1;
6455 //see if edge is (nN,nN_neig) or vice versa
6456 int nodes[2];
6457 nodes[0] = nN_global_subdomain;
6458 nodes[1] = nN_neig_global_subdomain;
6459 NodeTuple<2> et(nodes);
6460 edge_subdomain = nodesEdgeMap_subdomain[et];
6461 edge_global = edgeNumbering_subdomain2global[edge_subdomain];
6462 assert(edge_subdomain >= 0 && edge_global >= 0);
6463 //assign unique subdomain id based on |owned nodes|owned edges|ghost nodes|ghost edges|
6464 if (edge_subdomain < nEdges_owned)
6465 subdomain_l2g[eN*nDOF_element + local_offset + nN] = nNodes_owned + edge_subdomain;
6466 else
6467 subdomain_l2g[eN*nDOF_element + local_offset + nN] = ghostEdgeOffset + edge_subdomain - nEdges_owned;
6468 //unique subdomain id --> unique cross processor id
6469 //subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]] = mesh.nNodes_global + edge_global;
6470 //mwf debug
6471 // if (rank == 0)
6472 // {
6473 // std::cout<<"build loc2glob c0p2 3d eN= "<<eN<<" edge("<<nN<<","<<nN_neig<<") sub_dof= "<< subdomain_l2g[eN*nDOF_element + local_offset + nN]
6474 // <<" glob_dof= "<<subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]]<<std::endl;
6475 // }
6476 for (int eI=0; eI < 3; eI++)
6477 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+local_offset+nN]*3+eI] = 0.5*(mesh.subdomainp->nodeArray[nN_global_subdomain*3+eI]+
6478 mesh.subdomainp->nodeArray[nN_neig_global_subdomain*3+eI]);
6479 }
6480
6481 }//eN
6482
6483 ISRestoreIndices(quadraticNumberingIS_global_new2old,&quadraticNumbering_global_new2old);
6484 ISDestroy(&quadraticNumberingIS_new2old);
6485 ISDestroy(&quadraticNumberingIS_global_new2old);
6486
6487 return 0;
6488}
6489
6490int buildQuadraticCubeSubdomain2GlobalMappings_3d(const MPI_Comm& PROTEUS_COMM_WORLD, Mesh& mesh,
6491 const int *edgeOffsets_subdomain_owned,
6492 const int *nodeOffsets_subdomain_owned,
6493 const int *edgeNumbering_subdomain2global,
6494 const int *nodeNumbering_subdomain2global,
6495 int& nDOF_all_processes,//total number of dofs in whole domain
6496 int& nDOF_subdomain,//total number of dofs in sub-domain
6497 int& max_dof_neighbors,//maximum number of neighbors for connectivity of dofs
6498 int *offsets_subdomain_owned, //starting point of local dofs on each processor (nProcs+1)
6499 int *subdomain_l2g, //local to global dof mapping on subdomain
6500 int *subdomain2global,//subdomain dof to global (parallel) numbering
6501 double * lagrangeNodesArray)//location of nodes corresponding to dofs
6502{
6503 using namespace std;
6504 int ierr,size,rank;
6505
6506 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);
6507 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);
6508
6509 //In 2d the quadratic dofs can be associated with nodes and element Boundaries
6510 //assuming have ownership info and consistent local/global mappings for nodes, elementBoundaries
6511 //build a mapping from local quadratic dofs to global quadratic dofs for petsc
6512 //assume a processor owns a dof if it owns that node or element
6513 assert(edgeOffsets_subdomain_owned);
6514 assert(nodeOffsets_subdomain_owned);
6515 assert(edgeNumbering_subdomain2global);
6516 assert(nodeNumbering_subdomain2global);
6517 assert(mesh.subdomainp);
6518
6519 const int *elementBoundaryOffsets_subdomain_owned=mesh.elementBoundaryOffsets_subdomain_owned;
6520 const int *elementOffsets_subdomain_owned=mesh.elementOffsets_subdomain_owned;
6521 const int *elementBoundaryNumbering_subdomain2global=mesh.elementBoundaryNumbering_subdomain2global;
6522 const int *elementNumbering_subdomain2global=mesh.elementNumbering_subdomain2global;
6523
6524 const int nNodes_owned = nodeOffsets_subdomain_owned[rank+1]-nodeOffsets_subdomain_owned[rank];
6525 const int nEdges_owned = edgeOffsets_subdomain_owned[rank+1]-edgeOffsets_subdomain_owned[rank];
6526 const int nBoundaries_owned = elementBoundaryOffsets_subdomain_owned[rank+1]-elementBoundaryOffsets_subdomain_owned[rank];
6527 const int nElements_owned = elementOffsets_subdomain_owned[rank+1]-elementOffsets_subdomain_owned[rank];
6528
6529 const int nDOFs_owned = nNodes_owned + nEdges_owned + nBoundaries_owned + nElements_owned;
6530 const int nDOFs_global= mesh.nNodes_global + mesh.nEdges_global + mesh.nElementBoundaries_global + mesh.nElements_global;
6531 //start with a logical global ordering of dofs as
6532 //[global nodes, global edges]
6533 //want to create global numbering
6534 //[nodes proc 0,edges proc 0,nodes proc 1, edges proc 1,...]
6535 valarray<int> quadraticNumbering_new2old(nDOFs_owned);
6536 for (int nN = 0; nN < nNodes_owned; nN++)
6537 {
6538 int dof_global = nodeNumbering_subdomain2global[nN];
6539 quadraticNumbering_new2old[nN] = dof_global;
6540 }
6541 for (int i = 0; i < nEdges_owned; i++)
6542 {
6543 int dof_global = mesh.nNodes_global + edgeNumbering_subdomain2global[i];
6544 quadraticNumbering_new2old[nNodes_owned + i] = dof_global;
6545 }
6546
6547 //-------------------
6548 for (int i = 0; i < nBoundaries_owned; i++)
6549 {
6550 int dof_global = mesh.nNodes_global + mesh.nEdges_global + elementBoundaryNumbering_subdomain2global[i];
6551 quadraticNumbering_new2old[nNodes_owned + nEdges_owned + i] = dof_global;
6552 }
6553 for (int i = 0; i < nElements_owned; i++)
6554 {
6555 int dof_global = mesh.nNodes_global + mesh.nEdges_global + mesh.nElementBoundaries_global + elementNumbering_subdomain2global[i];
6556 quadraticNumbering_new2old[nNodes_owned + nEdges_owned + nBoundaries_owned + i] = dof_global;
6557 }
6558 //-------------------
6559
6560
6561 //build an index set for new numbering
6562 IS quadraticNumberingIS_new2old;
6563 ISCreateGeneral(PROTEUS_COMM_WORLD,nDOFs_owned,&quadraticNumbering_new2old[0],PETSC_COPY_VALUES,&quadraticNumberingIS_new2old);
6564 IS quadraticNumberingIS_global_new2old;
6565 ISAllGather(quadraticNumberingIS_new2old,&quadraticNumberingIS_global_new2old);
6566 //get old 2 new mapping for dofs
6567 const PetscInt *quadraticNumbering_global_new2old;
6568 valarray<int> quadraticNumbering_old2new_global(nDOFs_global);
6569 ISGetIndices(quadraticNumberingIS_global_new2old,&quadraticNumbering_global_new2old);
6570 for (int id = 0; id < nDOFs_global; id++)
6571 quadraticNumbering_old2new_global[quadraticNumbering_global_new2old[id]] = id;
6572 //mwf debug
6573 // if (rank == 0)
6574 // {
6575 // for (int id = 0; id < nDOFs_global; id++)
6576 // {
6577 // std::cout<<" rank= "<<rank<<" build 2d c0p2 mappings new2old["<<id<<"]= "<<quadraticNumbering_global_new2old[id]
6578 // <<" old2new["<<quadraticNumbering_global_new2old[id]<<"]= "<<quadraticNumbering_old2new_global[quadraticNumbering_global_new2old[id]]
6579 // <<std::endl;
6580 // }
6581 // }
6582 assert(offsets_subdomain_owned);
6583 assert(subdomain2global);
6584 assert(subdomain_l2g);
6585 assert(lagrangeNodesArray);
6586 for (int sdN=0; sdN < size+1; sdN++)
6587 offsets_subdomain_owned[sdN] = nodeOffsets_subdomain_owned[sdN]+edgeOffsets_subdomain_owned[sdN]+elementBoundaryOffsets_subdomain_owned[sdN]+elementOffsets_subdomain_owned[sdN];
6588 nDOF_all_processes = mesh.nNodes_global+mesh.nEdges_global+ mesh.nElementBoundaries_global+mesh.nElements_global;
6590 max_dof_neighbors = 2*mesh.max_nNodeNeighbors_node;//8*27?
6591
6592 //loop through owned and ghost dofs build subdomain mapping by
6593 //going from old --> new
6594 int localOffset = 0;
6595 for (int nN = 0; nN < nNodes_owned; nN++)
6596 {
6597 int dof_global_old = nodeNumbering_subdomain2global[nN];
6598 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6599 subdomain2global[localOffset + nN] = dof_global_new;
6600 //mwf debug
6601 // if (rank == 0)
6602 // std::cout<<" rank= "<<rank<<" nN= "<<nN<<" local dof= "<<localOffset+nN<<" nNodes_owned= "<<nNodes_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6603 }
6604
6605 localOffset += nNodes_owned;
6606 for (int i = 0; i < nEdges_owned; i++)
6607 {
6608 int dof_global_old = mesh.nNodes_global + edgeNumbering_subdomain2global[i];
6609 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6610 subdomain2global[localOffset + i] = dof_global_new;
6611 //mwf debug
6612 // if (rank == 0)
6613 // std::cout<<" rank= "<<rank<<" i= "<<i<<" local dof= "<<localOffset+i<<" nEdges_owned= "<<nEdges_owned
6614 // <<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6615 }
6616
6617
6618 localOffset += nEdges_owned;
6619 for (int i = 0; i < nBoundaries_owned; i++)
6620 {
6621 int dof_global_old = mesh.nNodes_global + mesh.nEdges_global + elementBoundaryNumbering_subdomain2global[i];
6622 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6623 subdomain2global[localOffset + i] = dof_global_new;
6624 //mwf debug
6625 // if (rank == 0)
6626 // std::cout<<" rank= "<<rank<<" i= "<<i<<" local dof= "<<localOffset+i<<" nEdges_owned= "<<nEdges_owned
6627 // <<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6628 }
6629
6630 localOffset += nBoundaries_owned;
6631 for (int i = 0; i < nElements_owned; i++)
6632 {
6633 int dof_global_old = mesh.nNodes_global + mesh.nEdges_global + mesh.nElementBoundaries_global + elementNumbering_subdomain2global[i];
6634 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6635 subdomain2global[localOffset + i] = dof_global_new;
6636 //mwf debug
6637 // if (rank == 0)
6638 // std::cout<<" rank= "<<rank<<" i= "<<i<<" local dof= "<<localOffset+i<<" nEdges_owned= "<<nEdges_owned
6639 // <<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6640 }
6641
6642 localOffset += nElements_owned;
6643 for (int nN = nNodes_owned; nN < mesh.subdomainp->nNodes_global; nN++)
6644 {
6645 int dof_global_old = nodeNumbering_subdomain2global[nN];
6646 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6647 subdomain2global[localOffset + nN - nNodes_owned] = dof_global_new;
6648 //mwf debug
6649 // if (rank == 0)
6650 // std::cout<<" rank= "<<rank<<" nN= "<<nN<<" local dof= "<<localOffset+nN-nNodes_owned<<" nNodes_owned= "<<nNodes_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6651 }
6652
6653 localOffset += mesh.subdomainp->nNodes_global - nNodes_owned;
6654 for (int i = nEdges_owned; i < mesh.subdomainp->nEdges_global; i++)
6655 {
6656 int dof_global_old = mesh.nNodes_global + edgeNumbering_subdomain2global[i];
6657 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6658 subdomain2global[localOffset + i - nEdges_owned] = dof_global_new;
6659 // //mwf debug
6660 // if (rank == 0)
6661 // std::cout<<" rank= "<<rank<<" i= "<<i<<" local dof= "<<localOffset+i-nEdges_owned<<" nEdges_owned= "<<nEdges_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6662 }
6663
6664 localOffset += mesh.subdomainp->nEdges_global - nEdges_owned;
6665 for (int i = nBoundaries_owned; i < mesh.subdomainp->nElementBoundaries_global; i++)
6666 {
6667 int dof_global_old = mesh.nNodes_global + mesh.nEdges_global + elementBoundaryNumbering_subdomain2global[i];
6668 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6669 subdomain2global[localOffset + i - nBoundaries_owned] = dof_global_new;
6670 // //mwf debug
6671 // if (rank == 0)
6672 // std::cout<<" rank= "<<rank<<" i= "<<i<<" local dof= "<<localOffset+i-nEdges_owned<<" nEdges_owned= "<<nEdges_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6673 }
6674
6675 localOffset += mesh.subdomainp->nElementBoundaries_global - nBoundaries_owned;
6676 for (int i = nElements_owned; i < mesh.subdomainp->nElements_global; i++)
6677 {
6678 int dof_global_old = mesh.nNodes_global + mesh.nEdges_global + mesh.nElementBoundaries_global + elementNumbering_subdomain2global[i];
6679 int dof_global_new = quadraticNumbering_old2new_global[dof_global_old];
6680 subdomain2global[localOffset + i - nElements_owned] = dof_global_new;
6681 // //mwf debug
6682 // if (rank == 0)
6683 // std::cout<<" rank= "<<rank<<" i= "<<i<<" local dof= "<<localOffset+i-nEdges_owned<<" nEdges_owned= "<<nEdges_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6684 }
6685
6686 //setup local to global mapping on the subdomain for finite elements
6687 const int nDOF_element = 27;
6688 const int ghostNodeOffset = nNodes_owned + nEdges_owned + nBoundaries_owned + nElements_owned;
6689 const int ghostEdgeOffset = ghostNodeOffset + mesh.subdomainp->nNodes_global-nNodes_owned;
6690 const int ghostBoundaryOffset = ghostEdgeOffset + mesh.subdomainp->nEdges_global-nEdges_owned;
6691 const int ghostElementOffset = ghostBoundaryOffset + mesh.subdomainp->nElementBoundaries_global-nBoundaries_owned;
6692
6693 int ledge[12][2] = {{0,1},{1,2},{2,3},{3,0},
6694 {0,4},{1,5},{2,6},{3,7},
6695 {4,5},{5,6},{6,7},{7,4}};
6696
6697 int nEdges_element = 12;
6698
6699 int lface[6][4] = {{0,1,2,3},
6700 {0,1,5,4},
6701 {1,2,6,5},
6702 {2,3,7,6},
6703 {3,0,4,7},
6704 {4,5,6,7}};
6705
6706 assert(mesh.subdomainp->nElementBoundaries_element == 6);
6707 //need mapping from nodes to edge to setup element based relationship
6708 map<NodeTuple<2>, int> nodesEdgeMap_subdomain;
6709 for (int i=0; i < mesh.subdomainp->nEdges_global; i++)
6710 {
6711 int nodes[2];
6712 nodes[0] = mesh.subdomainp->edgeNodesArray[2*i+0];
6713 nodes[1] = mesh.subdomainp->edgeNodesArray[2*i+1];
6714 NodeTuple<2> nt(nodes);
6715 nodesEdgeMap_subdomain[nt] = i;
6716 }
6717
6718 map<NodeTuple<4>, int> nodesBoundaryMap_subdomain;
6719 for (int i=0; i < mesh.subdomainp->nElementBoundaries_global; i++)
6720 {
6721
6722 int nodes[4];
6723 nodes[0] = mesh.subdomainp->elementBoundaryNodesArray[i*4+0];
6724 nodes[1] = mesh.subdomainp->elementBoundaryNodesArray[i*4+1];
6725 nodes[2] = mesh.subdomainp->elementBoundaryNodesArray[i*4+2];
6726 nodes[3] = mesh.subdomainp->elementBoundaryNodesArray[i*4+3];
6727 NodeTuple<4> ebt(nodes);
6728 assert(nodesBoundaryMap_subdomain.find(ebt) == nodesBoundaryMap_subdomain.end());
6729 nodesBoundaryMap_subdomain[ebt] = i;
6730 }
6731
6732 for (int eN=0; eN < mesh.subdomainp->nElements_global; eN++)
6733 {
6734 int local_offset = 0;
6735 for (int nN=0; nN < mesh.subdomainp->nNodes_element; nN++)
6736 {
6737 //node_i --> unique subdomain node 0 <= i <= 3
6738 const int nN_global_subdomain = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + nN];
6739 //assign unique subdomain id based on |owned nodes|owned edges|ghost nodes|ghost edges|
6740 if (nN_global_subdomain < nNodes_owned)
6741 {
6742 subdomain_l2g[eN*nDOF_element + local_offset + nN] = nN_global_subdomain;
6743 }
6744 else
6745 {
6746 subdomain_l2g[eN*nDOF_element + local_offset + nN] = ghostNodeOffset + nN_global_subdomain - nNodes_owned;
6747 }
6748 //unique subdomain id --> unique cross processor id
6749 //subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]] = nodeNumbering_subdomain2global[nN_global_subdomain];
6750 //mwf debug
6751 // if (rank == 0)
6752 // {
6753 // std::cout<<"build loc2glob c0p2 3d eN= "<<eN<<" node= "<<nN<<" sub_dof= "<< subdomain_l2g[eN*nDOF_element + local_offset + nN]
6754 // <<" glob_dof= "<<subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]]<<std::endl;
6755 // }
6756 for (int eI=0; eI < 3; eI++)
6757 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element + local_offset +nN]*3+eI] = mesh.subdomainp->nodeArray[nN_global_subdomain*3+eI];
6758 }
6759 local_offset += mesh.subdomainp->nNodes_element;
6760 for (int nN = 0; nN < nEdges_element; nN++)
6761 {
6762 int nodes[2];
6763 nodes[0] = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + ledge[nN][0]];
6764 nodes[1] = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + ledge[nN][1]];
6765 NodeTuple<2> nt(nodes);
6766 int edge_subdomain = nodesEdgeMap_subdomain[nt];
6767 int edge_global = edgeNumbering_subdomain2global[edge_subdomain];
6768 assert(edge_subdomain >= 0 && edge_global >= 0);
6769 //assign unique subdomain id based on |owned nodes|owned edges|ghost nodes|ghost edges|
6770 if (edge_subdomain < nEdges_owned)
6771 subdomain_l2g[eN*nDOF_element + local_offset + nN] = nNodes_owned + edge_subdomain;
6772 else
6773 subdomain_l2g[eN*nDOF_element + local_offset + nN] = ghostEdgeOffset + edge_subdomain - nEdges_owned;
6774 //unique subdomain id --> unique cross processor id
6775 //set above could do here subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]] = mesh.nNodes_global + edge_global;
6776 //mwf debug
6777 // if (rank == 0)
6778 // {
6779 // std::cout<<"build loc2glob c0p2 3d eN= "<<eN<<" edge("<<nN<<","<<nN_neig<<") sub_dof= "<< subdomain_l2g[eN*nDOF_element + local_offset + nN]
6780 // <<" glob_dof= "<<subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]]<<std::endl;
6781 // }
6782 for (int eI=0; eI < 3; eI++)
6783 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+local_offset+nN]*3+eI] = 0.5*(mesh.subdomainp->nodeArray[nodes[0]*3+eI]+
6784 mesh.subdomainp->nodeArray[nodes[1]*3+eI]);
6785 }
6786
6787 local_offset += nEdges_element;
6788 for (int nN = 0; nN < mesh.subdomainp->nElementBoundaries_element; nN++)
6789 {
6790
6791 int nodes[4];
6792 nodes[0] = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element+lface[nN][0]];
6793 nodes[1] = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element+lface[nN][1]];
6794 nodes[2] = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element+lface[nN][2]];
6795 nodes[3] = mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element+lface[nN][3]];
6796 NodeTuple<4> ebt(nodes);
6797
6798
6799 int boundary_subdomain = nodesBoundaryMap_subdomain[ebt];
6800 int boundary_global = elementBoundaryNumbering_subdomain2global[boundary_subdomain];
6801
6802 assert(boundary_subdomain >= 0 && boundary_global >= 0);
6803
6804 //assign unique subdomain id based on |owned nodes|owned edges|ghost nodes|ghost edges|
6805 if (boundary_subdomain < nBoundaries_owned)
6806 subdomain_l2g[eN*nDOF_element + local_offset + nN] = nNodes_owned + nEdges_owned + boundary_subdomain;
6807 else
6808 subdomain_l2g[eN*nDOF_element + local_offset + nN] = ghostBoundaryOffset + boundary_subdomain - nBoundaries_owned;
6809 //unique subdomain id --> unique cross processor id
6810 //set above could do here subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]] = mesh.nNodes_global + edge_global;
6811 //mwf debug
6812 // if (rank == 0)
6813 // {
6814 // std::cout<<"build loc2glob c0p2 3d eN= "<<eN<<" edge("<<nN<<","<<nN_neig<<") sub_dof= "<< subdomain_l2g[eN*nDOF_element + local_offset + nN]
6815 // <<" glob_dof= "<<subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]]<<std::endl;
6816 // }
6817 for (int eI=0; eI < 3; eI++)
6818 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+local_offset+nN]*3+eI] = 0.25*(mesh.subdomainp->nodeArray[nodes[0]*3+eI]+
6819 mesh.subdomainp->nodeArray[nodes[1]*3+eI]+
6820 mesh.subdomainp->nodeArray[nodes[2]*3+eI]+
6821 mesh.subdomainp->nodeArray[nodes[3]*3+eI]);
6822 }
6823
6824 local_offset += mesh.subdomainp->nElementBoundaries_element;
6825
6826 // Interior node!!!
6827
6828 if (eN < nElements_owned)
6829 subdomain_l2g[eN*nDOF_element + local_offset] = nNodes_owned + nEdges_owned + nBoundaries_owned + eN;
6830 else
6831 subdomain_l2g[eN*nDOF_element + local_offset] = ghostElementOffset + eN - nElements_owned;
6832 //unique subdomain id --> unique cross processor id
6833 //set above could do here subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]] = mesh.nNodes_global + edge_global;
6834 //mwf debug
6835 // if (rank == 0)
6836 // {
6837 // std::cout<<"build loc2glob c0p2 3d eN= "<<eN<<" edge("<<nN<<","<<nN_neig<<") sub_dof= "<< subdomain_l2g[eN*nDOF_element + local_offset + nN]
6838 // <<" glob_dof= "<<subdomain2global[subdomain_l2g[eN*nDOF_element + local_offset + nN]]<<std::endl;
6839 // }
6840 for (int eI=0; eI < 3; eI++)
6841 lagrangeNodesArray[subdomain_l2g[eN*nDOF_element+local_offset]*3+eI] = 0.125*(mesh.subdomainp->nodeArray[mesh.subdomainp->elementNodesArray[eN*mesh.subdomainp->nNodes_element + 0]*3+eI]+
6849
6850
6851 }//eN
6852
6853 ISRestoreIndices(quadraticNumberingIS_global_new2old,&quadraticNumbering_global_new2old);
6854 ISDestroy(&quadraticNumberingIS_new2old);
6855 ISDestroy(&quadraticNumberingIS_global_new2old);
6856
6857 return 0;
6858}
6859
6860
6861
6862
6863
6864int buildDiscontinuousGalerkinSubdomain2GlobalMappings(const MPI_Comm& PROTEUS_COMM_WORLD, Mesh& mesh,
6865 const int *elementOffsets_subdomain_owned,
6866 const int *elementNumbering_subdomain2global,
6867 int nDOF_element,
6868 int& nDOF_all_processes,//total number of dofs in whole domain
6869 int& nDOF_subdomain,//total number of dofs in sub-domain
6870 int& max_dof_neighbors,//maximum number of neighbors for connectivity of dofs
6871 int *offsets_subdomain_owned, //starting point of local dofs on each processor (nProcs+1)
6872 int * subdomain_l2g, //local to global dof mapping on subdomain
6873 int* subdomain2global)//subdomain dof to global (parallel) numbering
6874
6875{
6876 using namespace std;
6877 int ierr,size,rank;
6878 ierr = MPI_Comm_size(PROTEUS_COMM_WORLD,&size);
6879 ierr = MPI_Comm_rank(PROTEUS_COMM_WORLD,&rank);
6880
6881 //DG dofs stored element wise
6882 //[...,eN_0,eN_1,..,eN_ndof_local,...]
6883 //assume a processor owns a dof if it owns that element
6884 assert(elementOffsets_subdomain_owned);
6885 assert(elementNumbering_subdomain2global);
6886 assert(mesh.subdomainp);
6887
6888 const int nElements_owned = elementOffsets_subdomain_owned[rank+1]-elementOffsets_subdomain_owned[rank];
6889
6890 assert(offsets_subdomain_owned);
6891 assert(subdomain2global);
6892 assert(subdomain_l2g);
6893 nDOF_all_processes = mesh.nElements_global*nDOF_element;
6894 nDOF_subdomain = mesh.subdomainp->nElements_global*nDOF_element;
6895 max_dof_neighbors = mesh.nElementBoundaries_element*nDOF_element;
6896
6897 for (int sdN=0; sdN < size+1; sdN++)
6898 offsets_subdomain_owned[sdN] = elementOffsets_subdomain_owned[sdN]*nDOF_element;
6899
6900 //loop through owned and ghost dofs build subdomain mapping
6901 for (int eN = 0; eN < mesh.subdomainp->nElements_global; eN++)
6902 {
6903 for (int i = 0; i < nDOF_element; i++)
6904 {
6905 subdomain2global[eN*nDOF_element + i] = elementNumbering_subdomain2global[eN]*nDOF_element + i;
6906 //mwf debug
6907 //std::cout<<" rank= "<<rank<<" eN= "<<eN<<" local dof= "<<localOffset+eN<<" nElements_owned= "<<nElements_owned<<" dof_old= "<<dof_global_old<<" new= "<<dof_global_new<<std::endl;
6908 subdomain_l2g[eN*nDOF_element+i] = eN*nDOF_element + i;
6909 }
6910 }
6911
6912 return 0;
6913}
6914}
float * vector(long nl, long nh)
void init(void)
Double * z
Definition Headers.h:49
int nodes[nNodes]
Definition mesh.h:440
#define max(a, b)
int constructElementBoundaryElementsArray_edge(Mesh &mesh)
Definition mesh.cpp:622
int allocateGeometricInfo_hexahedron(Mesh &mesh)
Definition mesh.cpp:3651
int computeGeometricInfo_NURBS(Mesh &mesh)
Definition mesh.cpp:3749
int constructElementBoundaryElementsArrayWithGivenElementBoundaryAndEdgeNumbers_hexahedron(Mesh &mesh)
Definition mesh.cpp:3305
int allocateGeometricInfo_triangle(Mesh &mesh)
Definition mesh.cpp:3756
int constructElementBoundaryElementsArrayWithGivenElementBoundaryAndEdgeNumbers_edge(Mesh &mesh)
Definition mesh.cpp:2632
int allocateGeometricInfo_quadrilateral(Mesh &mesh)
Definition mesh.cpp:3856
int constructElementBoundaryElementsArray_tetrahedron(Mesh &mesh)
Definition mesh.cpp:1118
int computeGeometricInfo_edge(Mesh &mesh)
Definition mesh.cpp:3938
int allocateGeometricInfo_edge(Mesh &mesh)
Definition mesh.cpp:3926
int constructElementBoundaryElementsArrayWithGivenElementBoundaryAndEdgeNumbers_triangle(Mesh &mesh)
Definition mesh.cpp:2787
int constructElementBoundaryElementsArrayWithGivenElementBoundaryAndEdgeNumbers_NURBS(Mesh &mesh)
Definition mesh.cpp:1738
int constructElementBoundaryElementsArray_triangle(Mesh &mesh)
Definition mesh.cpp:780
int constructElementBoundaryElementsArrayWithGivenElementBoundaryAndEdgeNumbers_quadrilateral(Mesh &mesh)
Definition mesh.cpp:2962
int computeGeometricInfo_quadrilateral(Mesh &mesh)
Definition mesh.cpp:3866
int computeGeometricInfo_triangle(Mesh &mesh)
Definition mesh.cpp:3768
int allocateGeometricInfo_NURBS(Mesh &mesh)
Definition mesh.cpp:3743
int allocateGeometricInfo_tetrahedron(Mesh &mesh)
Definition mesh.cpp:3535
int constructElementBoundaryElementsArrayWithGivenElementBoundaryAndEdgeNumbers_tetrahedron(Mesh &mesh)
Definition mesh.cpp:3117
int computeGeometricInfo_hexahedron(Mesh &mesh)
Definition mesh.cpp:3663
int computeGeometricInfo_tetrahedron(Mesh &mesh)
Definition mesh.cpp:3547
const int INTERIOR_ELEMENT_BOUNDARY_MATERIAL
Definition mesh.cpp:52
const int EXTERIOR_NODE_MATERIAL
Definition mesh.cpp:51
const int DEFAULT_NODE_MATERIAL
Definition mesh.cpp:49
const int INTERIOR_NODE_MATERIAL
Definition mesh.cpp:50
const int EXTERIOR_ELEMENT_BOUNDARY_MATERIAL
Definition mesh.cpp:53
std::istream & eatcomments(std::istream &s)
Definition meshio.cpp:21
std::istream & eatline(std::istream &s)
Definition meshio.cpp:11
Definition ADR.h:19
int partitionNodesFromTetgenFiles(const MPI_Comm &PROTEUS_COMM_WORLD, const char *filebase, int indexBase, Mesh &newMesh, int nNodes_overlap, double memHardLimit)
int buildQuadraticSubdomain2GlobalMappings_1d(const MPI_Comm &PROTEUS_COMM_WORLD, Mesh &mesh, const int *elementOffsets_subdomain_owned, const int *nodeOffsets_subdomain_owned, const int *elementNumbering_subdomain2global, const int *nodeNumbering_subdomain2global, int &nDOF_all_processes, int &nDOF_subdomain, int &max_dof_neighbors, int *offsets_subdomain_owned, int *subdomain_l2g, int *subdomain2global, double *lagrangeNodesArray)
int buildQuadraticCubeSubdomain2GlobalMappings_3d(const MPI_Comm &PROTEUS_COMM_WORLD, Mesh &mesh, const int *edgeOffsets_subdomain_owned, const int *nodeOffsets_subdomain_owned, const int *edgeNumbering_subdomain2global, const int *nodeNumbering_subdomain2global, int &nDOF_all_processes, int &nDOF_subdomain, int &max_dof_neighbors, int *offsets_subdomain_owned, int *subdomain_l2g, int *subdomain2global, double *lagrangeNodesArray)
int partitionNodesFromTriangleFiles(const MPI_Comm &PROTEUS_COMM_WORLD, const char *filebase, int indexBase, Mesh &newMesh, int nNodes_overlap)
int buildDiscontinuousGalerkinSubdomain2GlobalMappings(const MPI_Comm &PROTEUS_COMM_WORLD, Mesh &mesh, const int *elementOffsets_subdomain_owned, const int *elementNumbering_subdomain2global, int nDOF_element, int &nDOF_all_processes, int &nDOF_subdomain, int &max_dof_neighbors, int *offsets_subdomain_owned, int *subdomain_l2g, int *subdomain2global)
int buildQuadraticSubdomain2GlobalMappings_3d(const MPI_Comm &PROTEUS_COMM_WORLD, Mesh &mesh, const int *edgeOffsets_subdomain_owned, const int *nodeOffsets_subdomain_owned, const int *edgeNumbering_subdomain2global, const int *nodeNumbering_subdomain2global, int &nDOF_all_processes, int &nDOF_subdomain, int &max_dof_neighbors, int *offsets_subdomain_owned, int *subdomain_l2g, int *subdomain2global, double *lagrangeNodesArray)
int partitionElements(const MPI_Comm &PROTEUS_COMM_WORLD, Mesh &mesh, int nElements_overlap)
int partitionNodes(const MPI_Comm &PROTEUS_COMM_WORLD, Mesh &mesh, int nNodes_overlap)
int partitionElementsOriginal(const MPI_Comm &PROTEUS_COMM_WORLD, Mesh &mesh, int nElements_overlap)
int buildQuadraticSubdomain2GlobalMappings_2d(const MPI_Comm &PROTEUS_COMM_WORLD, Mesh &mesh, const int *elementBoundaryOffsets_subdomain_owned, const int *nodeOffsets_subdomain_owned, const int *elementBoundaryNumbering_subdomain2global, const int *nodeNumbering_subdomain2global, int &nDOF_all_processes, int &nDOF_subdomain, int &max_dof_neighbors, int *offsets_subdomain_owned, int *subdomain_l2g, int *subdomain2global, double *lagrangeNodesArray)
int enforceMemoryLimit(const MPI_Comm &PROTEUS_COMM_WORLD, int rank, double max_rss_gb, const char *msg)
#define RANK
Definition mesh.h:30
int * elementBoundaryNodesArray
Definition mesh.h:49
int * edgeNumbering_subdomain2global
Definition mesh.h:85
int * nodeStarOffsets
Definition mesh.h:56
int * elementBoundaryNumbering_subdomain2global
Definition mesh.h:83
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 * elementBoundaryOffsets_subdomain_owned
Definition mesh.h:82
int * nodeElementsArray
Definition mesh.h:45
int nElements_global
Definition mesh.h:32
int * elementOffsets_subdomain_owned
Definition mesh.h:78
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 py
Definition mesh.h:66
int * exteriorElementBoundariesArray
Definition mesh.h:53
int * elementBoundaryLocalElementBoundariesArray
Definition mesh.h:51
int nExteriorElementBoundaries_global
Definition mesh.h:39
int pz
Definition mesh.h:66
int nElementBoundaries_element
Definition mesh.h:36
int * elementNumbering_subdomain2global
Definition mesh.h:79
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 * edgeOffsets_subdomain_owned
Definition mesh.h:84
Mesh * subdomainp
Definition mesh.h:90
int px
Definition mesh.h:66
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
bool usePlex
Definition mesh.h:88