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