renumberMesh.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Application
25  renumberMesh
26 
27 Description
28  Renumbers the cell list in order to reduce the bandwidth, reading and
29  renumbering all fields from all the time directories.
30 
31  By default uses bandCompression (CuthillMcKee) but will
32  read system/renumberMeshDict if -dict option is present
33 
34 \*---------------------------------------------------------------------------*/
35 
36 #include "argList.H"
37 #include "IOobjectList.H"
38 #include "fvMesh.H"
39 #include "polyTopoChange.H"
40 #include "ReadFields.H"
41 #include "volFields.H"
42 #include "surfaceFields.H"
43 #include "SortableList.H"
44 #include "decompositionMethod.H"
45 #include "renumberMethod.H"
47 #include "CuthillMcKeeRenumber.H"
48 #include "fvMeshSubset.H"
49 #include "cellSet.H"
50 #include "faceSet.H"
51 #include "pointSet.H"
52 #include "systemDict.H"
53 
54 #ifdef FOAM_USE_ZOLTAN
55  #include "zoltanRenumber.H"
56 #endif
57 
58 
59 using namespace Foam;
60 
61 
62 // Create named field from labelList for postprocessing
63 tmp<volScalarField> createScalarField
64 (
65  const fvMesh& mesh,
66  const word& name,
67  const labelList& elems
68 )
69 {
71  (
73  (
74  name,
75  mesh,
77  zeroGradientFvPatchScalarField::typeName
78  )
79  );
80  volScalarField& fld = tfld.ref();
81 
82  forAll(fld, celli)
83  {
84  fld[celli] = elems[celli];
85  }
86 
87  return tfld;
88 }
89 
90 
91 // Calculate band of matrix
92 label getBand(const labelList& owner, const labelList& neighbour)
93 {
94  label band = 0;
95 
96  forAll(neighbour, facei)
97  {
98  label diff = neighbour[facei] - owner[facei];
99 
100  if (diff > band)
101  {
102  band = diff;
103  }
104  }
105  return band;
106 }
107 
108 
109 // Calculate band of matrix
110 void getBand
111 (
112  const bool calculateIntersect,
113  const label nCells,
114  const labelList& owner,
115  const labelList& neighbour,
116  label& bandwidth,
117  scalar& profile, // scalar to avoid overflow
118  scalar& sumSqrIntersect // scalar to avoid overflow
119 )
120 {
121  labelList cellBandwidth(nCells, 0);
122  scalarField nIntersect(nCells, 0.0);
123 
124  forAll(neighbour, facei)
125  {
126  label own = owner[facei];
127  label nei = neighbour[facei];
128 
129  // Note: mag not necessary for correct (upper-triangular) ordering.
130  label diff = nei-own;
131  cellBandwidth[nei] = max(cellBandwidth[nei], diff);
132  }
133 
134  bandwidth = max(cellBandwidth);
135 
136  // Do not use field algebra because of conversion label to scalar
137  profile = 0.0;
138  forAll(cellBandwidth, celli)
139  {
140  profile += 1.0*cellBandwidth[celli];
141  }
142 
143  sumSqrIntersect = 0.0;
144  if (calculateIntersect)
145  {
146  forAll(nIntersect, celli)
147  {
148  for (label colI = celli-cellBandwidth[celli]; colI <= celli; colI++)
149  {
150  nIntersect[colI] += 1.0;
151  }
152  }
153 
154  sumSqrIntersect = sum(Foam::sqr(nIntersect));
155  }
156 }
157 
158 
159 // Determine upper-triangular face order
160 labelList getFaceOrder
161 (
162  const primitiveMesh& mesh,
163  const labelList& cellOrder // New to old cell
164 )
165 {
166  labelList reverseCellOrder(invert(cellOrder.size(), cellOrder));
167 
168  labelList oldToNewFace(mesh.nFaces(), -1);
169 
170  label newFacei = 0;
171 
172  labelList nbr;
173  labelList order;
174 
175  forAll(cellOrder, newCelli)
176  {
177  label oldCelli = cellOrder[newCelli];
178 
179  const cell& cFaces = mesh.cells()[oldCelli];
180 
181  // Neighbouring cells
182  nbr.setSize(cFaces.size());
183 
184  forAll(cFaces, i)
185  {
186  label facei = cFaces[i];
187 
188  if (mesh.isInternalFace(facei))
189  {
190  // Internal face. Get cell on other side.
191  label nbrCelli = reverseCellOrder[mesh.faceNeighbour()[facei]];
192  if (nbrCelli == newCelli)
193  {
194  nbrCelli = reverseCellOrder[mesh.faceOwner()[facei]];
195  }
196 
197  if (newCelli < nbrCelli)
198  {
199  // Celli is master
200  nbr[i] = nbrCelli;
201  }
202  else
203  {
204  // nbrCell is master. Let it handle this face.
205  nbr[i] = -1;
206  }
207  }
208  else
209  {
210  // External face. Do later.
211  nbr[i] = -1;
212  }
213  }
214 
215  order.setSize(nbr.size());
216  sortedOrder(nbr, order);
217 
218  forAll(order, i)
219  {
220  label index = order[i];
221  if (nbr[index] != -1)
222  {
223  oldToNewFace[cFaces[index]] = newFacei++;
224  }
225  }
226  }
227 
228  // Leave patch faces intact.
229  for (label facei = newFacei; facei < mesh.nFaces(); facei++)
230  {
231  oldToNewFace[facei] = facei;
232  }
233 
234 
235  // Check done all faces.
236  forAll(oldToNewFace, facei)
237  {
238  if (oldToNewFace[facei] == -1)
239  {
241  << "Did not determine new position" << " for face " << facei
242  << abort(FatalError);
243  }
244  }
245 
246  return invert(mesh.nFaces(), oldToNewFace);
247 }
248 
249 
250 // Determine face order such that inside region faces are sorted
251 // upper-triangular but in between region faces are handled like boundary faces.
252 labelList getRegionFaceOrder
253 (
254  const primitiveMesh& mesh,
255  const labelList& cellOrder, // New to old cell
256  const labelList& cellToRegion // Old cell to region
257 )
258 {
259  labelList reverseCellOrder(invert(cellOrder.size(), cellOrder));
260 
261  labelList oldToNewFace(mesh.nFaces(), -1);
262 
263  label newFacei = 0;
264 
265  label prevRegion = -1;
266 
267  forAll(cellOrder, newCelli)
268  {
269  label oldCelli = cellOrder[newCelli];
270 
271  if (cellToRegion[oldCelli] != prevRegion)
272  {
273  prevRegion = cellToRegion[oldCelli];
274  }
275 
276  const cell& cFaces = mesh.cells()[oldCelli];
277 
278  SortableList<label> nbr(cFaces.size());
279 
280  forAll(cFaces, i)
281  {
282  label facei = cFaces[i];
283 
284  if (mesh.isInternalFace(facei))
285  {
286  // Internal face. Get cell on other side.
287  label nbrCelli = reverseCellOrder[mesh.faceNeighbour()[facei]];
288  if (nbrCelli == newCelli)
289  {
290  nbrCelli = reverseCellOrder[mesh.faceOwner()[facei]];
291  }
292 
293  if (cellToRegion[oldCelli] != cellToRegion[cellOrder[nbrCelli]])
294  {
295  // Treat like external face. Do later.
296  nbr[i] = -1;
297  }
298  else if (newCelli < nbrCelli)
299  {
300  // Celli is master
301  nbr[i] = nbrCelli;
302  }
303  else
304  {
305  // nbrCell is master. Let it handle this face.
306  nbr[i] = -1;
307  }
308  }
309  else
310  {
311  // External face. Do later.
312  nbr[i] = -1;
313  }
314  }
315 
316  nbr.sort();
317 
318  forAll(nbr, i)
319  {
320  if (nbr[i] != -1)
321  {
322  oldToNewFace[cFaces[nbr.indices()[i]]] = newFacei++;
323  }
324  }
325  }
326 
327  // Do region interfaces
328  label nRegions = max(cellToRegion)+1;
329  {
330  // Sort in increasing region
331  SortableList<label> sortKey(mesh.nFaces(), labelMax);
332 
333  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
334  {
335  label ownRegion = cellToRegion[mesh.faceOwner()[facei]];
336  label neiRegion = cellToRegion[mesh.faceNeighbour()[facei]];
337 
338  if (ownRegion != neiRegion)
339  {
340  sortKey[facei] =
341  min(ownRegion, neiRegion)*nRegions
342  +max(ownRegion, neiRegion);
343  }
344  }
345  sortKey.sort();
346 
347  // Extract.
348  label prevKey = -1;
349  forAll(sortKey, i)
350  {
351  label key = sortKey[i];
352 
353  if (key == labelMax)
354  {
355  break;
356  }
357 
358  if (prevKey != key)
359  {
360  prevKey = key;
361  }
362 
363  oldToNewFace[sortKey.indices()[i]] = newFacei++;
364  }
365  }
366 
367  // Leave patch faces intact.
368  for (label facei = newFacei; facei < mesh.nFaces(); facei++)
369  {
370  oldToNewFace[facei] = facei;
371  }
372 
373 
374  // Check done all faces.
375  forAll(oldToNewFace, facei)
376  {
377  if (oldToNewFace[facei] == -1)
378  {
380  << "Did not determine new position"
381  << " for face " << facei
382  << abort(FatalError);
383  }
384  }
385 
386  return invert(mesh.nFaces(), oldToNewFace);
387 }
388 
389 
390 // cellOrder: old cell for every new cell
391 // faceOrder: old face for every new face. Ordering of boundary faces not
392 // changed.
393 autoPtr<mapPolyMesh> reorderMesh
394 (
395  polyMesh& mesh,
396  const labelList& cellOrder,
397  const labelList& faceOrder
398 )
399 {
400  labelList reverseCellOrder(invert(cellOrder.size(), cellOrder));
401  labelList reverseFaceOrder(invert(faceOrder.size(), faceOrder));
402 
403  faceList newFaces(reorder(reverseFaceOrder, mesh.faces()));
404  labelList newOwner
405  (
406  renumber
407  (
408  reverseCellOrder,
409  reorder(reverseFaceOrder, mesh.faceOwner())
410  )
411  );
412  labelList newNeighbour
413  (
414  renumber
415  (
416  reverseCellOrder,
417  reorder(reverseFaceOrder, mesh.faceNeighbour())
418  )
419  );
420 
421  // Check if any faces need swapping.
422  labelHashSet flipFaceFlux(newOwner.size());
423  forAll(newNeighbour, facei)
424  {
425  label own = newOwner[facei];
426  label nei = newNeighbour[facei];
427 
428  if (nei < own)
429  {
430  newFaces[facei].flip();
431  Swap(newOwner[facei], newNeighbour[facei]);
432  flipFaceFlux.insert(facei);
433  }
434  }
435 
436  const polyBoundaryMesh& patches = mesh.boundaryMesh();
437  labelList patchSizes(patches.size());
438  labelList patchStarts(patches.size());
439  labelList oldPatchNMeshPoints(patches.size());
440  labelListList patchPointMap(patches.size());
441 
442  forAll(patches, patchi)
443  {
444  patchSizes[patchi] = patches[patchi].size();
445  patchStarts[patchi] = patches[patchi].start();
446  oldPatchNMeshPoints[patchi] = patches[patchi].nPoints();
447  patchPointMap[patchi] = identity(patches[patchi].nPoints());
448  }
449 
450  mesh.resetPrimitives
451  (
452  NullObjectMove<pointField>(),
453  move(newFaces),
454  move(newOwner),
455  move(newNeighbour),
456  patchSizes,
457  patchStarts,
458  true
459  );
460 
461 
462  // Re-do the faceZones
463  {
464  meshFaceZones& faceZones = mesh.faceZones();
465  faceZones.clearAddressing();
466  forAll(faceZones, zoneI)
467  {
468  faceZone& fZone = faceZones[zoneI];
469  labelList newAddressing(fZone.size());
470  boolList newFlipMap(fZone.size());
471  forAll(fZone, i)
472  {
473  label oldFacei = fZone[i];
474  newAddressing[i] = reverseFaceOrder[oldFacei];
475  if (flipFaceFlux.found(newAddressing[i]))
476  {
477  newFlipMap[i] = !fZone.flipMap()[i];
478  }
479  else
480  {
481  newFlipMap[i] = fZone.flipMap()[i];
482  }
483  }
484  labelList newToOld;
485  sortedOrder(newAddressing, newToOld);
486  fZone.resetAddressing
487  (
488  UIndirectList<label>(newAddressing, newToOld)(),
489  UIndirectList<bool>(newFlipMap, newToOld)()
490  );
491  }
492  }
493  // Re-do the cellZones
494  {
495  meshCellZones& cellZones = mesh.cellZones();
496  cellZones.clearAddressing();
497  forAll(cellZones, zoneI)
498  {
499  cellZones[zoneI] = UIndirectList<label>
500  (
501  reverseCellOrder,
502  cellZones[zoneI]
503  )();
504  Foam::sort(cellZones[zoneI]);
505  }
506  }
507 
508 
509  return autoPtr<mapPolyMesh>
510  (
511  new mapPolyMesh
512  (
513  mesh, // const polyMesh& mesh,
514  mesh.nPoints(), // nOldPoints,
515  mesh.nFaces(), // nOldFaces,
516  mesh.nCells(), // nOldCells,
517  identity(mesh.nPoints()), // pointMap,
518  List<objectMap>(0), // pointsFromPoints,
519  faceOrder, // faceMap,
520  List<objectMap>(0), // facesFromPoints,
521  List<objectMap>(0), // facesFromEdges,
522  List<objectMap>(0), // facesFromFaces,
523  cellOrder, // cellMap,
524  List<objectMap>(0), // cellsFromPoints,
525  List<objectMap>(0), // cellsFromEdges,
526  List<objectMap>(0), // cellsFromFaces,
527  List<objectMap>(0), // cellsFromCells,
528  identity(mesh.nPoints()), // reversePointMap,
529  reverseFaceOrder, // reverseFaceMap,
530  reverseCellOrder, // reverseCellMap,
531  flipFaceFlux, // flipFaceFlux,
532  patchPointMap, // patchPointMap,
533  labelListList(0), // pointZoneMap,
534  labelListList(0), // faceZonePointMap,
535  labelListList(0), // faceZoneFaceMap,
536  labelListList(0), // cellZoneMap,
537  pointField(0), // preMotionPoints,
538  patchStarts, // oldPatchStarts,
539  oldPatchNMeshPoints, // oldPatchNMeshPoints
540  autoPtr<scalarField>() // oldCellVolumes
541  )
542  );
543 }
544 
545 
546 // Return new to old cell numbering
547 labelList regionRenumber
548 (
549  const renumberMethod& method,
550  const fvMesh& mesh,
551  const labelList& cellToRegion
552 )
553 {
554  Info<< "Determining cell order:" << endl;
555 
556  labelList cellOrder(cellToRegion.size());
557 
558  label nRegions = max(cellToRegion)+1;
559 
560  labelListList regionToCells(invertOneToMany(nRegions, cellToRegion));
561 
562  label celli = 0;
563 
564  forAll(regionToCells, regionI)
565  {
566  Info<< " region " << regionI << " starts at " << celli << endl;
567 
568  // Make sure no parallel comms
569  bool oldParRun = UPstream::parRun();
570  UPstream::parRun() = false;
571 
572  // Per region do a reordering.
573  fvMeshSubset subsetter(mesh);
574  subsetter.setLargeCellSubset(cellToRegion, regionI);
575 
576  const fvMesh& subMesh = subsetter.subMesh();
577 
578  labelList subCellOrder = method.renumber
579  (
580  subMesh,
581  subMesh.cellCentres()
582  );
583 
584  // Restore state
585  UPstream::parRun() = oldParRun;
586 
587  const labelList& cellMap = subsetter.cellMap();
588 
589  forAll(subCellOrder, i)
590  {
591  cellOrder[celli++] = cellMap[subCellOrder[i]];
592  }
593  }
594  Info<< endl;
595 
596  return cellOrder;
597 }
598 
599 
600 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
601 
602 int main(int argc, char *argv[])
603 {
605  (
606  "Renumber mesh to minimise bandwidth"
607  );
608 
609  #include "addRegionOption.H"
610  #include "addOverwriteOption.H"
611  #include "addTimeOptions.H"
612  #include "addDictOption.H"
614  (
615  "frontWidth",
616  "calculate the rms of the frontwidth"
617  );
619  (
620  "noFields",
621  "do not update fields"
622  );
623 
624  #include "setRootCase.H"
625  #include "createTime.H"
627 
628  // Force linker to include zoltan symbols. This section is only needed since
629  // Zoltan is a static library
630  #ifdef FOAM_USE_ZOLTAN
631  Info<< "renumberMesh built with zoltan support." << nl << endl;
632  (void)zoltanRenumber::typeName;
633  #endif
634 
635  // Get times list
636  instantList Times = runTime.times();
637 
638  // Set startTime and endTime depending on -time and -latestTime options
639  #include "checkTimeOptions.H"
640 
641  runTime.setTime(Times[startTime], startTime);
642 
643  #include "createNamedMesh.H"
644  const word oldInstance = mesh.pointsInstance();
645 
646  const bool readDict = args.optionFound("dict");
647  const bool doFrontWidth = args.optionFound("frontWidth");
648  const bool overwrite = args.optionFound("overwrite");
649  const bool fields = !args.optionFound("noFields");
650 
651  label band;
652  scalar profile;
653  scalar sumSqrIntersect;
654  getBand
655  (
656  doFrontWidth,
657  mesh.nCells(),
658  mesh.faceOwner(),
659  mesh.faceNeighbour(),
660  band,
661  profile,
662  sumSqrIntersect
663  );
664 
665  reduce(band, maxOp<label>());
666  reduce(profile, sumOp<scalar>());
667  scalar rmsFrontwidth = Foam::sqrt
668  (
670  (
671  sumSqrIntersect,
672  sumOp<scalar>()
673  )/mesh.globalData().nTotalCells()
674  );
675 
676  Info<< "Mesh size: " << mesh.globalData().nTotalCells() << nl
677  << "Before renumbering :" << nl
678  << " band : " << band << nl
679  << " profile : " << profile << nl;
680 
681  if (doFrontWidth)
682  {
683  Info<< " rms frontwidth : " << rmsFrontwidth << nl;
684  }
685 
686  Info<< endl;
687 
688  bool sortCoupledFaceCells = false;
689  bool writeMaps = false;
690  bool orderPoints = false;
691  label blockSize = 0;
692  bool renumberSets = true;
693 
694  // Construct renumberMethod
695  autoPtr<dictionary> renumberDictPtr;
696  autoPtr<renumberMethod> renumberPtr;
697 
698  if (readDict)
699  {
700  renumberDictPtr.reset
701  (
702  new dictionary(systemDict("renumberMeshDict", args, mesh))
703  );
704  const dictionary& renumberDict = renumberDictPtr();
705 
706  renumberPtr = renumberMethod::New(renumberDict);
707 
708  sortCoupledFaceCells = renumberDict.lookupOrDefault
709  (
710  "sortCoupledFaceCells",
711  false
712  );
713  if (sortCoupledFaceCells)
714  {
715  Info<< "Sorting cells on coupled boundaries to be last." << nl
716  << endl;
717  }
718 
719  blockSize = renumberDict.lookupOrDefault("blockSize", 0);
720  if (blockSize > 0)
721  {
722  Info<< "Ordering cells into regions of size " << blockSize
723  << " (using decomposition);"
724  << " ordering faces into region-internal and region-external."
725  << nl << endl;
726 
727  if (blockSize < 0 || blockSize >= mesh.nCells())
728  {
730  << "Block size " << blockSize
731  << " should be positive integer"
732  << " and less than the number of cells in the mesh."
733  << exit(FatalError);
734  }
735  }
736 
737  orderPoints = renumberDict.lookupOrDefault("orderPoints", false);
738  if (orderPoints)
739  {
740  Info<< "Ordering points into internal and boundary points." << nl
741  << endl;
742  }
743 
744  renumberDict.lookup("writeMaps") >> writeMaps;
745  if (writeMaps)
746  {
747  Info<< "Writing renumber maps (new to old) to polyMesh." << nl
748  << endl;
749  }
750 
751  renumberSets = renumberDict.lookupOrDefault("renumberSets", true);
752  }
753  else
754  {
755  Info<< "Using default renumberMethod." << nl << endl;
756  dictionary renumberDict;
757  renumberPtr.reset(new CuthillMcKeeRenumber(renumberDict));
758  }
759 
760  Info<< "Selecting renumberMethod " << renumberPtr().type() << nl << endl;
761 
762 
763 
764  // Read parallel reconstruct maps
765  labelIOList cellProcAddressing
766  (
767  IOobject
768  (
769  "cellProcAddressing",
770  mesh.facesInstance(),
772  mesh,
774  ),
775  labelList(0)
776  );
777 
779  (
780  IOobject
781  (
782  "faceProcAddressing",
783  mesh.facesInstance(),
785  mesh,
787  ),
788  labelList(0)
789  );
790  labelIOList pointProcAddressing
791  (
792  IOobject
793  (
794  "pointProcAddressing",
795  mesh.pointsInstance(),
797  mesh,
799  ),
800  labelList(0)
801  );
802  labelIOList boundaryProcAddressing
803  (
804  IOobject
805  (
806  "boundaryProcAddressing",
807  mesh.pointsInstance(),
809  mesh,
811  ),
812  labelList(0)
813  );
814 
815 
816  // Read objects in time directory
818 
819  if (fields) Info<< "Reading geometric fields" << nl << endl;
820 
821  #include "readVolFields.H"
822  #include "readSurfaceFields.H"
823  #include "readPointFields.H"
824 
825  Info<< endl;
826 
827  // From renumbering:
828  // - from new cell/face back to original cell/face
829  labelList cellOrder;
830  labelList faceOrder;
831 
832  if (blockSize > 0)
833  {
834  // Renumbering in two phases. Should be done in one so mapping of
835  // fields is done correctly!
836 
837  label nBlocks = mesh.nCells()/blockSize;
838  Info<< "nBlocks = " << nBlocks << endl;
839 
840  // Read decompositionMethod dictionary
841  dictionary decomposeDict(renumberDictPtr().subDict("blockCoeffs"));
842  decomposeDict.set("numberOfSubdomains", nBlocks);
843 
844  bool oldParRun = UPstream::parRun();
845  UPstream::parRun() = false;
846 
848  (
849  decomposeDict
850  );
851 
852  labelList cellToRegion
853  (
854  decomposePtr().decompose
855  (
856  mesh,
857  mesh.cellCentres()
858  )
859  );
860 
861  // Restore state
862  UPstream::parRun() = oldParRun;
863 
864  // For debugging: write out region
865  createScalarField
866  (
867  mesh,
868  "cellDist",
869  cellToRegion
870  )().write();
871 
872  Info<< nl << "Written decomposition as volScalarField to "
873  << "cellDist for use in postprocessing."
874  << nl << endl;
875 
876 
877  cellOrder = regionRenumber(renumberPtr(), mesh, cellToRegion);
878 
879  // Determine new to old face order with new cell numbering
880  faceOrder = getRegionFaceOrder
881  (
882  mesh,
883  cellOrder,
884  cellToRegion
885  );
886  }
887  else
888  {
889  // Determines sorted back to original cell ordering
890  cellOrder = renumberPtr().renumber
891  (
892  mesh,
893  mesh.cellCentres()
894  );
895 
896  if (sortCoupledFaceCells)
897  {
898  // Change order so all coupled patch faceCells are at the end.
899  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
900 
901  // Collect all boundary cells on coupled patches
902  label nBndCells = 0;
903  forAll(pbm, patchi)
904  {
905  if (pbm[patchi].coupled())
906  {
907  nBndCells += pbm[patchi].size();
908  }
909  }
910 
911  labelList reverseCellOrder = invert(mesh.nCells(), cellOrder);
912 
913  labelList bndCells(nBndCells);
914  labelList bndCellMap(nBndCells);
915  nBndCells = 0;
916  forAll(pbm, patchi)
917  {
918  if (pbm[patchi].coupled())
919  {
920  const labelUList& faceCells = pbm[patchi].faceCells();
921  forAll(faceCells, i)
922  {
923  label celli = faceCells[i];
924 
925  if (reverseCellOrder[celli] != -1)
926  {
927  bndCells[nBndCells] = celli;
928  bndCellMap[nBndCells++] = reverseCellOrder[celli];
929  reverseCellOrder[celli] = -1;
930  }
931  }
932  }
933  }
934  bndCells.setSize(nBndCells);
935  bndCellMap.setSize(nBndCells);
936 
937  // Sort
938  labelList order;
939  sortedOrder(bndCellMap, order);
940 
941  // Redo newReverseCellOrder
942  labelList newReverseCellOrder(mesh.nCells(), -1);
943 
944  label sortedI = mesh.nCells();
945  forAllReverse(order, i)
946  {
947  label origCelli = bndCells[order[i]];
948  newReverseCellOrder[origCelli] = --sortedI;
949  }
950 
951  Info<< "Ordered all " << nBndCells << " cells with a coupled face"
952  << " to the end of the cell list, starting at " << sortedI
953  << endl;
954 
955  // Compact
956  sortedI = 0;
957  forAll(cellOrder, newCelli)
958  {
959  label origCelli = cellOrder[newCelli];
960  if (newReverseCellOrder[origCelli] == -1)
961  {
962  newReverseCellOrder[origCelli] = sortedI++;
963  }
964  }
965 
966  // Update sorted back to original (unsorted) map
967  cellOrder = invert(mesh.nCells(), newReverseCellOrder);
968  }
969 
970 
971  // Determine new to old face order with new cell numbering
972  faceOrder = getFaceOrder
973  (
974  mesh,
975  cellOrder // New to old cell
976  );
977  }
978 
979 
980  if (!overwrite)
981  {
982  runTime++;
983  }
984 
985 
986  // Change the mesh.
987  autoPtr<mapPolyMesh> map = reorderMesh(mesh, cellOrder, faceOrder);
988 
989 
990  if (orderPoints)
991  {
992  polyTopoChange meshMod(mesh);
993  autoPtr<mapPolyMesh> pointOrderMap = meshMod.changeMesh
994  (
995  mesh,
996  false, // inflate
997  true, // syncParallel
998  false, // orderCells
999  orderPoints // orderPoints
1000  );
1001 
1002  // Combine point reordering into map.
1003  const_cast<labelList&>(map().pointMap()) = UIndirectList<label>
1004  (
1005  map().pointMap(),
1006  pointOrderMap().pointMap()
1007  )();
1008 
1010  (
1011  pointOrderMap().reversePointMap(),
1012  const_cast<labelList&>(map().reversePointMap())
1013  );
1014  }
1015 
1016 
1017  // Update fields
1018  mesh.updateMesh(map);
1019 
1020  // Update proc maps
1021  if
1022  (
1023  cellProcAddressing.headerOk()
1024  && cellProcAddressing.size() == mesh.nCells()
1025  )
1026  {
1027  Info<< "Renumbering processor cell decomposition map "
1028  << cellProcAddressing.name() << endl;
1029 
1030  cellProcAddressing = labelList
1031  (
1032  UIndirectList<label>(cellProcAddressing, map().cellMap())
1033  );
1034  }
1035  if
1036  (
1037  faceProcAddressing.headerOk()
1038  && faceProcAddressing.size() == mesh.nFaces()
1039  )
1040  {
1041  Info<< "Renumbering processor face decomposition map "
1042  << faceProcAddressing.name() << endl;
1043 
1045  (
1047  );
1048 
1049  // Detect any flips.
1050  const labelHashSet& fff = map().flipFaceFlux();
1051  forAllConstIter(labelHashSet, fff, iter)
1052  {
1053  label facei = iter.key();
1054  label masterFacei = faceProcAddressing[facei];
1055 
1056  faceProcAddressing[facei] = -masterFacei;
1057 
1058  if (masterFacei == 0)
1059  {
1061  << " masterFacei:" << masterFacei << exit(FatalError);
1062  }
1063  }
1064  }
1065  if
1066  (
1067  pointProcAddressing.headerOk()
1068  && pointProcAddressing.size() == mesh.nPoints()
1069  )
1070  {
1071  Info<< "Renumbering processor point decomposition map "
1072  << pointProcAddressing.name() << endl;
1073 
1074  pointProcAddressing = labelList
1075  (
1076  UIndirectList<label>(pointProcAddressing, map().pointMap())
1077  );
1078  }
1079 
1080 
1081  // Move mesh (since morphing might not do this)
1082  if (map().hasMotionPoints())
1083  {
1084  mesh.movePoints(map().preMotionPoints());
1085  }
1086 
1087 
1088  {
1089  label band;
1090  scalar profile;
1091  scalar sumSqrIntersect;
1092  getBand
1093  (
1094  doFrontWidth,
1095  mesh.nCells(),
1096  mesh.faceOwner(),
1097  mesh.faceNeighbour(),
1098  band,
1099  profile,
1100  sumSqrIntersect
1101  );
1102  reduce(band, maxOp<label>());
1103  reduce(profile, sumOp<scalar>());
1104  scalar rmsFrontwidth = Foam::sqrt
1105  (
1106  returnReduce
1107  (
1108  sumSqrIntersect,
1109  sumOp<scalar>()
1110  )/mesh.globalData().nTotalCells()
1111  );
1112 
1113  Info<< "After renumbering :" << nl
1114  << " band : " << band << nl
1115  << " profile : " << profile << nl;
1116 
1117  if (doFrontWidth)
1118  {
1119 
1120  Info<< " rms frontwidth : " << rmsFrontwidth << nl;
1121  }
1122 
1123  Info<< endl;
1124  }
1125 
1126  if (orderPoints)
1127  {
1128  // Force edge calculation (since only reason that points would need to
1129  // be sorted)
1130  (void)mesh.edges();
1131 
1132  label nTotPoints = returnReduce
1133  (
1134  mesh.nPoints(),
1135  sumOp<label>()
1136  );
1137  label nTotIntPoints = returnReduce
1138  (
1139  mesh.nInternalPoints(),
1140  sumOp<label>()
1141  );
1142 
1143  label nTotEdges = returnReduce
1144  (
1145  mesh.nEdges(),
1146  sumOp<label>()
1147  );
1148  label nTotIntEdges = returnReduce
1149  (
1150  mesh.nInternalEdges(),
1151  sumOp<label>()
1152  );
1153  label nTotInt0Edges = returnReduce
1154  (
1155  mesh.nInternal0Edges(),
1156  sumOp<label>()
1157  );
1158  label nTotInt1Edges = returnReduce
1159  (
1160  mesh.nInternal1Edges(),
1161  sumOp<label>()
1162  );
1163 
1164  Info<< "Points:" << nl
1165  << " total : " << nTotPoints << nl
1166  << " internal: " << nTotIntPoints << nl
1167  << " boundary: " << nTotPoints-nTotIntPoints << nl
1168  << "Edges:" << nl
1169  << " total : " << nTotEdges << nl
1170  << " internal: " << nTotIntEdges << nl
1171  << " internal using 0 boundary points: "
1172  << nTotInt0Edges << nl
1173  << " internal using 1 boundary points: "
1174  << nTotInt1Edges-nTotInt0Edges << nl
1175  << " internal using 2 boundary points: "
1176  << nTotIntEdges-nTotInt1Edges << nl
1177  << " boundary: " << nTotEdges-nTotIntEdges << nl
1178  << endl;
1179  }
1180 
1181 
1182  if (overwrite)
1183  {
1184  mesh.setInstance(oldInstance);
1185  }
1186 
1187  Info<< "Writing mesh to " << mesh.facesInstance() << endl;
1188 
1189  mesh.write();
1190 
1191  if (cellProcAddressing.headerOk())
1192  {
1193  cellProcAddressing.instance() = mesh.facesInstance();
1194  if (cellProcAddressing.size() == mesh.nCells())
1195  {
1196  cellProcAddressing.write();
1197  }
1198  else
1199  {
1200  // procAddressing file no longer valid. Delete it.
1201  const fileName fName(cellProcAddressing.filePath());
1202  if (fName.size())
1203  {
1204  Info<< "Deleting inconsistent processor cell decomposition"
1205  << " map " << fName << endl;
1206  rm(fName);
1207  }
1208  }
1209  }
1210 
1211  if (faceProcAddressing.headerOk())
1212  {
1213  faceProcAddressing.instance() = mesh.facesInstance();
1214  if (faceProcAddressing.size() == mesh.nFaces())
1215  {
1216  faceProcAddressing.write();
1217  }
1218  else
1219  {
1220  const fileName fName(faceProcAddressing.filePath());
1221  if (fName.size())
1222  {
1223  Info<< "Deleting inconsistent processor face decomposition"
1224  << " map " << fName << endl;
1225  rm(fName);
1226  }
1227  }
1228  }
1229 
1230  if (pointProcAddressing.headerOk())
1231  {
1232  pointProcAddressing.instance() = mesh.facesInstance();
1233  if (pointProcAddressing.size() == mesh.nPoints())
1234  {
1235  pointProcAddressing.write();
1236  }
1237  else
1238  {
1239  const fileName fName(pointProcAddressing.filePath());
1240  if (fName.size())
1241  {
1242  Info<< "Deleting inconsistent processor point decomposition"
1243  << " map " << fName << endl;
1244  rm(fName);
1245  }
1246  }
1247  }
1248 
1249  if (boundaryProcAddressing.headerOk())
1250  {
1251  boundaryProcAddressing.instance() = mesh.facesInstance();
1252  if (boundaryProcAddressing.size() == mesh.boundaryMesh().size())
1253  {
1254  boundaryProcAddressing.write();
1255  }
1256  else
1257  {
1258  const fileName fName(boundaryProcAddressing.filePath());
1259  if (fName.size())
1260  {
1261  Info<< "Deleting inconsistent processor patch decomposition"
1262  << " map " << fName << endl;
1263  rm(fName);
1264  }
1265  }
1266  }
1267 
1268  if (writeMaps)
1269  {
1270  // For debugging: write out region
1271  createScalarField
1272  (
1273  mesh,
1274  "origCellID",
1275  map().cellMap()
1276  )().write();
1277 
1278  createScalarField
1279  (
1280  mesh,
1281  "cellID",
1282  identity(mesh.nCells())
1283  )().write();
1284 
1285  Info<< nl << "Written current cellID and origCellID as volScalarField"
1286  << " for use in postprocessing."
1287  << nl << endl;
1288 
1289  labelIOList
1290  (
1291  IOobject
1292  (
1293  "cellMap",
1294  mesh.facesInstance(),
1296  mesh,
1299  false
1300  ),
1301  map().cellMap()
1302  ).write();
1303 
1304  labelIOList
1305  (
1306  IOobject
1307  (
1308  "faceMap",
1309  mesh.facesInstance(),
1311  mesh,
1314  false
1315  ),
1316  map().faceMap()
1317  ).write();
1318 
1319  labelIOList
1320  (
1321  IOobject
1322  (
1323  "pointMap",
1324  mesh.facesInstance(),
1326  mesh,
1329  false
1330  ),
1331  map().pointMap()
1332  ).write();
1333  }
1334 
1335 
1336  // Renumber sets if required
1337  if (renumberSets)
1338  {
1339  Info<< endl;
1340 
1341  // Read sets
1342  IOobjectList objects(mesh, mesh.facesInstance(), "polyMesh/sets");
1343 
1344  {
1345  IOobjectList cSets(objects.lookupClass(cellSet::typeName));
1346  if (cSets.size())
1347  {
1348  Info<< "Renumbering cellSets:" << endl;
1349  forAllConstIter(IOobjectList, cSets, iter)
1350  {
1351  cellSet cs(*iter());
1352  Info<< " " << cs.name() << endl;
1353  cs.updateMesh(map());
1354  cs.instance() = mesh.facesInstance();
1355  cs.write();
1356  }
1357  }
1358  }
1359 
1360  {
1361  IOobjectList fSets(objects.lookupClass(faceSet::typeName));
1362  if (fSets.size())
1363  {
1364  Info<< "Renumbering faceSets:" << endl;
1365  forAllConstIter(IOobjectList, fSets, iter)
1366  {
1367  faceSet fs(*iter());
1368  Info<< " " << fs.name() << endl;
1369  fs.updateMesh(map());
1370  fs.instance() = mesh.facesInstance();
1371  fs.write();
1372  }
1373  }
1374  }
1375 
1376  {
1377  IOobjectList pSets(objects.lookupClass(pointSet::typeName));
1378  if (pSets.size())
1379  {
1380  Info<< "Renumbering pointSets:" << endl;
1381  forAllConstIter(IOobjectList, pSets, iter)
1382  {
1383  pointSet ps(*iter());
1384  Info<< " " << ps.name() << endl;
1385  ps.updateMesh(map());
1386  ps.instance() = mesh.facesInstance();
1387  ps.write();
1388  }
1389  }
1390  }
1391  }
1392 
1393  Info<< "End\n" << endl;
1394 
1395  return 0;
1396 }
1397 
1398 
1399 // ************************************************************************* //
Foam::surfaceFields.
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:434
ListType renumber(const labelUList &oldToNew, const ListType &)
Renumber the values (not the indices) of a list.
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
virtual labelList renumber(const pointField &) const
Return the order in which cells need to be visited, i.e.
scalar diff(const triad &A, const triad &B)
Return a quantity of the difference between two triads.
Definition: triad.C:403
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
virtual Ostream & write(const char)=0
Write character.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
virtual void resetAddressing(const labelUList &, const boolList &)
Reset addressing and flip map (clearing demand-driven data)
Definition: faceZone.C:378
void sortedOrder(const UList< T > &, labelList &order)
Generate the (stable) sort order for the list.
A class for handling file names.
Definition: fileName.H:79
A list of face labels.
Definition: faceSet.H:48
void inplaceRenumber(const labelUList &oldToNew, ListType &)
Inplace renumber the values of a list.
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:50
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:808
void reset(T *=nullptr)
If object pointer already set, delete object and set to given.
Definition: autoPtrI.H:114
void off()
Switch the function objects off.
A set of point labels.
Definition: pointSet.H:48
const meshCellZones & cellZones() const
Return cell zones.
Definition: polyMesh.H:482
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:323
label nInternalFaces() const
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1175
A list that is sorted upon construction or when explicitly requested with the sort() method...
Definition: List.H:80
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:74
PtrList< labelIOList > & faceProcAddressing
label nFaces() const
dimensionedSymmTensor sqr(const dimensionedVector &dv)
labelListList invertOneToMany(const label len, const labelUList &)
Invert one-to-many map. Unmapped elements will be size 0.
Definition: ListOps.C:67
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:312
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
const boolList & flipMap() const
Return face flip map.
Definition: faceZone.H:248
label nCells() const
static tmp< GeometricField< scalar, fvPatchField, volMesh > > New(const word &name, const Internal &, const PtrList< fvPatchField< scalar >> &)
Return a temporary field constructed from name,.
engineTime & runTime
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
static autoPtr< renumberMethod > New(const dictionary &renumberDict)
Return a reference to the selected renumbering method.
label nTotalCells() const
Return total number of cells in decomposed mesh.
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: UList.H:446
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
const cellList & cells() const
Field reading functions for post-processing utilities.
static word timeName(const scalar, const int precision=precision_)
Return time name of given scalar time.
Definition: Time.C:636
const dimensionSet dimless
IOdictionary systemDict(const word &dictName, const argList &args, const objectRegistry &ob, const word &regionName=polyMesh::defaultRegion)
Definition: systemDict.C:92
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:158
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
virtual const labelList & faceNeighbour() const =0
Face face-neighbour addressing.
Abstract base class for renumbering.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:802
labelList invert(const label len, const labelUList &)
Invert one-to-one map. Unmapped elements will be -1.
Definition: ListOps.C:37
dynamicFvMesh & mesh
void Swap(T &a, T &b)
Definition: Swap.H:43
A class for handling words, derived from string.
Definition: word.H:59
label nPoints
Cuthill-McKee renumbering.
void sort(UList< T > &)
Definition: UList.C:115
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1169
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1394
static const label labelMax
Definition: label.H:62
List< label > labelList
A List of labels.
Definition: labelList.H:56
virtual void setTime(const Time &)
Reset the time and time-index to those of the given time.
Definition: Time.C:899
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1156
const vectorField & cellCentres() const
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:60
static autoPtr< decompositionMethod > New(const dictionary &decompositionDict)
Return a reference to the selected decomposition method.
Foam::polyBoundaryMesh.
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
ListType reorder(const labelUList &oldToNew, const ListType &)
Reorder the elements (indices, not values) of a list.
static const char nl
Definition: Ostream.H:260
void resetPrimitives(pointField &&points, faceList &&faces, labelList &&owner, labelList &&neighbour, const labelList &patchSizes, const labelList &patchStarts, const bool validBoundary=true)
Reset mesh primitive data. Assumes all patch info correct.
Definition: polyMesh.C:672
objects
Post-processing mesh subset tool. Given the original mesh and the list of selected cells...
Definition: fvMeshSubset.H:73
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Internal & ref()
Return a reference to the dimensioned internal field.
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
void setSize(const label)
Reset size of List.
Definition: List.C:281
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
label patchi
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
const functionObjectList & functionObjects() const
Return the list of function objects.
Definition: Time.H:410
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:56
A collection of cell labels.
Definition: cellSet.H:48
const meshFaceZones & faceZones() const
Return face zones.
Definition: polyMesh.H:476
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
A List with indirect addressing.
Definition: fvMatrix.H:106
Direct mesh changes based on v1.3 polyTopoChange syntax.
instantList times() const
Search the case for valid time directories.
Definition: Time.C:652
messageStream Info
virtual const labelList & faceOwner() const =0
Face face-owner addressing.
label nPoints() const
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:118
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:64
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:159
A class for managing temporary objects.
Definition: PtrList.H:53
bool rm(const fileName &)
Remove a file, returning true if successful otherwise false.
Definition: POSIX.C:1017
Foam::argList args(argc, argv)
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:92
void clearAddressing()
Clear addressing.
Definition: MeshZones.C:387
IOList< label > labelIOList
Label container classes.
Definition: labelIOList.H:42
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:844