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-2025 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 "timeSelector.H"
38 #include "IOobjectList.H"
39 #include "fvMesh.H"
40 #include "polyTopoChange.H"
41 #include "ReadFields.H"
42 #include "volFields.H"
43 #include "surfaceFields.H"
44 #include "SortableList.H"
45 #include "decompositionMethod.H"
46 #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 #include "hexRef8Data.H"
54 
55 using namespace Foam;
56 
57 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
58 
59 void writeCellLabels
60 (
61  const fvMesh& mesh,
62  const word& name,
63  const labelList& elems
64 )
65 {
67  (
68  IOobject
69  (
70  name,
71  mesh.time().name(),
72  mesh,
75  ),
76  mesh,
77  dimless,
78  scalarField(scalarList(elems))
79  );
80 
81  fld.write();
82 }
83 
84 
85 // Calculate band of matrix
86 label getBand(const labelList& owner, const labelList& neighbour)
87 {
88  label band = 0;
89 
90  forAll(neighbour, facei)
91  {
92  label diff = neighbour[facei] - owner[facei];
93 
94  if (diff > band)
95  {
96  band = diff;
97  }
98  }
99  return band;
100 }
101 
102 
103 // Calculate band of matrix
104 void getBand
105 (
106  const bool calculateIntersect,
107  const label nCells,
108  const labelList& owner,
109  const labelList& neighbour,
110  label& bandwidth,
111  scalar& profile, // scalar to avoid overflow
112  scalar& sumSqrIntersect // scalar to avoid overflow
113 )
114 {
115  labelList cellBandwidth(nCells, 0);
116  scalarField nIntersect(nCells, 0.0);
117 
118  forAll(neighbour, facei)
119  {
120  label own = owner[facei];
121  label nei = neighbour[facei];
122 
123  // Note: mag not necessary for correct (upper-triangular) ordering.
124  label diff = nei-own;
125  cellBandwidth[nei] = max(cellBandwidth[nei], diff);
126  }
127 
128  bandwidth = max(cellBandwidth);
129 
130  // Do not use field algebra because of conversion label to scalar
131  profile = 0.0;
132  forAll(cellBandwidth, celli)
133  {
134  profile += 1.0*cellBandwidth[celli];
135  }
136 
137  sumSqrIntersect = 0.0;
138  if (calculateIntersect)
139  {
140  forAll(nIntersect, celli)
141  {
142  for (label colI = celli-cellBandwidth[celli]; colI <= celli; colI++)
143  {
144  nIntersect[colI] += 1.0;
145  }
146  }
147 
148  sumSqrIntersect = sum(Foam::sqr(nIntersect));
149  }
150 }
151 
152 
153 // Determine upper-triangular face order
154 labelList getFaceOrder
155 (
156  const primitiveMesh& mesh,
157  const labelList& cellOrder // New to old cell
158 )
159 {
160  labelList reverseCellOrder(invert(cellOrder.size(), cellOrder));
161 
162  labelList oldToNewFace(mesh.nFaces(), -1);
163 
164  label newFacei = 0;
165 
166  labelList nbr;
168 
169  forAll(cellOrder, newCelli)
170  {
171  label oldCelli = cellOrder[newCelli];
172 
173  const cell& cFaces = mesh.cells()[oldCelli];
174 
175  // Neighbouring cells
176  nbr.setSize(cFaces.size());
177 
178  forAll(cFaces, i)
179  {
180  label facei = cFaces[i];
181 
182  if (mesh.isInternalFace(facei))
183  {
184  // Internal face. Get cell on other side.
185  label nbrCelli = reverseCellOrder[mesh.faceNeighbour()[facei]];
186  if (nbrCelli == newCelli)
187  {
188  nbrCelli = reverseCellOrder[mesh.faceOwner()[facei]];
189  }
190 
191  if (newCelli < nbrCelli)
192  {
193  // Celli is master
194  nbr[i] = nbrCelli;
195  }
196  else
197  {
198  // nbrCell is master. Let it handle this face.
199  nbr[i] = -1;
200  }
201  }
202  else
203  {
204  // External face. Do later.
205  nbr[i] = -1;
206  }
207  }
208 
209  order.setSize(nbr.size());
210  sortedOrder(nbr, order);
211 
212  forAll(order, i)
213  {
214  label index = order[i];
215  if (nbr[index] != -1)
216  {
217  oldToNewFace[cFaces[index]] = newFacei++;
218  }
219  }
220  }
221 
222  // Leave patch faces intact.
223  for (label facei = newFacei; facei < mesh.nFaces(); facei++)
224  {
225  oldToNewFace[facei] = facei;
226  }
227 
228 
229  // Check done all faces.
230  forAll(oldToNewFace, facei)
231  {
232  if (oldToNewFace[facei] == -1)
233  {
235  << "Did not determine new position" << " for face " << facei
236  << abort(FatalError);
237  }
238  }
239 
240  return invert(mesh.nFaces(), oldToNewFace);
241 }
242 
243 
244 // Determine face order such that inside region faces are sorted
245 // upper-triangular but in between region faces are handled like boundary faces.
246 labelList getRegionFaceOrder
247 (
248  const primitiveMesh& mesh,
249  const labelList& cellOrder, // New to old cell
250  const labelList& cellToRegion // Old cell to region
251 )
252 {
253  labelList reverseCellOrder(invert(cellOrder.size(), cellOrder));
254 
255  labelList oldToNewFace(mesh.nFaces(), -1);
256 
257  label newFacei = 0;
258 
259  label prevRegion = -1;
260 
261  forAll(cellOrder, newCelli)
262  {
263  label oldCelli = cellOrder[newCelli];
264 
265  if (cellToRegion[oldCelli] != prevRegion)
266  {
267  prevRegion = cellToRegion[oldCelli];
268  }
269 
270  const cell& cFaces = mesh.cells()[oldCelli];
271 
272  SortableList<label> nbr(cFaces.size());
273 
274  forAll(cFaces, i)
275  {
276  label facei = cFaces[i];
277 
278  if (mesh.isInternalFace(facei))
279  {
280  // Internal face. Get cell on other side.
281  label nbrCelli = reverseCellOrder[mesh.faceNeighbour()[facei]];
282  if (nbrCelli == newCelli)
283  {
284  nbrCelli = reverseCellOrder[mesh.faceOwner()[facei]];
285  }
286 
287  if (cellToRegion[oldCelli] != cellToRegion[cellOrder[nbrCelli]])
288  {
289  // Treat like external face. Do later.
290  nbr[i] = -1;
291  }
292  else if (newCelli < nbrCelli)
293  {
294  // Celli is master
295  nbr[i] = nbrCelli;
296  }
297  else
298  {
299  // nbrCell is master. Let it handle this face.
300  nbr[i] = -1;
301  }
302  }
303  else
304  {
305  // External face. Do later.
306  nbr[i] = -1;
307  }
308  }
309 
310  nbr.sort();
311 
312  forAll(nbr, i)
313  {
314  if (nbr[i] != -1)
315  {
316  oldToNewFace[cFaces[nbr.indices()[i]]] = newFacei++;
317  }
318  }
319  }
320 
321  // Do region interfaces
322  label nRegions = max(cellToRegion)+1;
323  {
324  // Sort in increasing region
326 
327  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
328  {
329  label ownRegion = cellToRegion[mesh.faceOwner()[facei]];
330  label neiRegion = cellToRegion[mesh.faceNeighbour()[facei]];
331 
332  if (ownRegion != neiRegion)
333  {
334  sortKey[facei] =
335  min(ownRegion, neiRegion)*nRegions
336  +max(ownRegion, neiRegion);
337  }
338  }
339  sortKey.sort();
340 
341  // Extract.
342  label prevKey = -1;
343  forAll(sortKey, i)
344  {
345  label key = sortKey[i];
346 
347  if (key == labelMax)
348  {
349  break;
350  }
351 
352  if (prevKey != key)
353  {
354  prevKey = key;
355  }
356 
357  oldToNewFace[sortKey.indices()[i]] = newFacei++;
358  }
359  }
360 
361  // Leave patch faces intact.
362  for (label facei = newFacei; facei < mesh.nFaces(); facei++)
363  {
364  oldToNewFace[facei] = facei;
365  }
366 
367 
368  // Check done all faces.
369  forAll(oldToNewFace, facei)
370  {
371  if (oldToNewFace[facei] == -1)
372  {
374  << "Did not determine new position"
375  << " for face " << facei
376  << abort(FatalError);
377  }
378  }
379 
380  return invert(mesh.nFaces(), oldToNewFace);
381 }
382 
383 
384 // cellOrder: old cell for every new cell
385 // faceOrder: old face for every new face. Ordering of boundary faces not
386 // changed.
387 autoPtr<polyTopoChangeMap> reorderMesh
388 (
389  polyMesh& mesh,
390  labelList& cellOrder,
391  labelList& faceOrder
392 )
393 {
394  labelList reverseCellOrder(invert(cellOrder.size(), cellOrder));
395  labelList reverseFaceOrder(invert(faceOrder.size(), faceOrder));
396 
397  faceList newFaces(reorder(reverseFaceOrder, mesh.faces()));
398  labelList newOwner
399  (
400  renumber
401  (
402  reverseCellOrder,
403  reorder(reverseFaceOrder, mesh.faceOwner())
404  )
405  );
406  labelList newNeighbour
407  (
408  renumber
409  (
410  reverseCellOrder,
411  reorder(reverseFaceOrder, mesh.faceNeighbour())
412  )
413  );
414 
415  // Check if any faces need swapping.
416  labelHashSet flipFaceFlux(newOwner.size());
417  forAll(newNeighbour, facei)
418  {
419  label own = newOwner[facei];
420  label nei = newNeighbour[facei];
421 
422  if (nei < own)
423  {
424  newFaces[facei].flip();
425  Swap(newOwner[facei], newNeighbour[facei]);
426  flipFaceFlux.insert(facei);
427  }
428  }
429 
431  labelList patchSizes(patches.size());
432  labelList patchStarts(patches.size());
433  labelList oldPatchNMeshPoints(patches.size());
434  labelListList patchPointMap(patches.size());
435 
437  {
438  patchSizes[patchi] = patches[patchi].size();
439  patchStarts[patchi] = patches[patchi].start();
440  oldPatchNMeshPoints[patchi] = patches[patchi].nPoints();
441  patchPointMap[patchi] = identityMap(patches[patchi].nPoints());
442  }
443 
445  (
446  NullObjectMove<pointField>(),
447  move(newFaces),
448  move(newOwner),
449  move(newNeighbour),
450  patchSizes,
451  patchStarts,
452  true
453  );
454 
456  (
458  (
459  mesh, // const polyMesh& mesh,
460  mesh.nPoints(), // nOldPoints,
461  mesh.nFaces(), // nOldFaces,
462  mesh.nCells(), // nOldCells,
463  identityMap(mesh.nPoints()), // pointMap,
464  List<objectMap>(0), // pointsFromPoints,
465  move(faceOrder), // faceMap,
466  List<objectMap>(0), // facesFromFaces,
467  move(cellOrder), // cellMap,
468  List<objectMap>(0), // cellsFromCells,
469  identityMap(mesh.nPoints()), // reversePointMap,
470  move(reverseFaceOrder), // reverseFaceMap,
471  move(reverseCellOrder), // reverseCellMap,
472  move(flipFaceFlux), // flipFaceFlux,
473  move(patchPointMap), // patchPointMap,
474  move(patchSizes), // oldPatchSizes
475  move(patchStarts), // oldPatchStarts,
476  move(oldPatchNMeshPoints), // oldPatchNMeshPoints
477  autoPtr<scalarField>() // oldCellVolumes
478  )
479  );
480 }
481 
482 
483 // Return new to old cell numbering
484 labelList regionRenumber
485 (
486  const renumberMethod& method,
487  const fvMesh& mesh,
488  const labelList& cellToRegion
489 )
490 {
491  Info<< "Determining cell order:" << endl;
492 
493  labelList cellOrder(cellToRegion.size());
494 
495  label nRegions = max(cellToRegion)+1;
496 
497  labelListList regionToCells(invertOneToMany(nRegions, cellToRegion));
498 
499  label celli = 0;
500 
501  forAll(regionToCells, regionI)
502  {
503  Info<< " region " << regionI << " starts at " << celli << endl;
504 
505  // Make sure no parallel comms
506  bool oldParRun = UPstream::parRun();
507  UPstream::parRun() = false;
508 
509  // Per region do a reordering.
510  fvMeshSubset subsetter(mesh);
511  subsetter.setLargeCellSubset(cellToRegion, regionI);
512 
513  const fvMesh& subMesh = subsetter.subMesh();
514 
515  labelList subCellOrder = method.renumber
516  (
517  subMesh,
518  subMesh.cellCentres()
519  );
520 
521  // Restore state
522  UPstream::parRun() = oldParRun;
523 
524  const labelList& cellMap = subsetter.cellMap();
525 
526  forAll(subCellOrder, i)
527  {
528  cellOrder[celli++] = cellMap[subCellOrder[i]];
529  }
530  }
531  Info<< endl;
532 
533  return cellOrder;
534 }
535 
536 
537 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
538 
539 int main(int argc, char *argv[])
540 {
542  (
543  "Renumber mesh to minimise bandwidth"
544  );
545 
546  #include "addMeshOption.H"
547  #include "addRegionOption.H"
548  #include "addNoOverwriteOption.H"
550  #include "addDictOption.H"
552  (
553  "frontWidth",
554  "calculate the rms of the frontwidth"
555  );
557  (
558  "noFields",
559  "do not update fields"
560  );
561 
562  #include "setRootCase.H"
564 
565  // Get times list
566  const instantList Times = timeSelector::select0(runTime, args);
567 
569  const word oldInstance = mesh.pointsInstance();
570 
571  const bool readDict = args.optionFound("dict");
572  const bool doFrontWidth = args.optionFound("frontWidth");
573  #include "setNoOverwrite.H"
574  const bool fields = !args.optionFound("noFields");
575 
576  label band;
577  scalar profile;
578  scalar sumSqrIntersect;
579  getBand
580  (
581  doFrontWidth,
582  mesh.nCells(),
583  mesh.faceOwner(),
585  band,
586  profile,
587  sumSqrIntersect
588  );
589 
590  reduce(band, maxOp<label>());
591  reduce(profile, sumOp<scalar>());
592  scalar rmsFrontwidth = Foam::sqrt
593  (
595  (
596  sumSqrIntersect,
597  sumOp<scalar>()
599  );
600 
601  Info<< "Mesh size: " << mesh.globalData().nTotalCells() << nl
602  << "Before renumbering :" << nl
603  << " band : " << band << nl
604  << " profile : " << profile << nl;
605 
606  if (doFrontWidth)
607  {
608  Info<< " rms frontwidth : " << rmsFrontwidth << nl;
609  }
610 
611  Info<< endl;
612 
613  bool sortCoupledFaceCells = false;
614  bool writeMaps = false;
615  bool orderPoints = false;
616  label blockSize = 0;
617  bool renumberSets = true;
618 
619  // Construct renumberMethod
620  autoPtr<dictionary> renumberDictPtr;
621  autoPtr<renumberMethod> renumberPtr;
622 
623  if (readDict)
624  {
625  renumberDictPtr.reset
626  (
627  new dictionary(systemDict("renumberMeshDict", args, mesh))
628  );
629  const dictionary& renumberDict = renumberDictPtr();
630 
631  renumberPtr = renumberMethod::New(renumberDict);
632 
633  sortCoupledFaceCells = renumberDict.lookupOrDefault
634  (
635  "sortCoupledFaceCells",
636  false
637  );
638  if (sortCoupledFaceCells)
639  {
640  Info<< "Sorting cells on coupled boundaries to be last." << nl
641  << endl;
642  }
643 
644  blockSize = renumberDict.lookupOrDefault("blockSize", 0);
645  if (blockSize > 0)
646  {
647  Info<< "Ordering cells into regions of size " << blockSize
648  << " (using decomposition);"
649  << " ordering faces into region-internal and region-external."
650  << nl << endl;
651 
652  if (blockSize < 0 || blockSize >= mesh.nCells())
653  {
655  << "Block size " << blockSize
656  << " should be positive integer"
657  << " and less than the number of cells in the mesh."
658  << exit(FatalError);
659  }
660  }
661 
662  orderPoints = renumberDict.lookupOrDefault("orderPoints", false);
663  if (orderPoints)
664  {
665  Info<< "Ordering points into internal and boundary points." << nl
666  << endl;
667  }
668 
669  renumberDict.lookup("writeMaps") >> writeMaps;
670  if (writeMaps)
671  {
672  Info<< "Writing renumber maps (new to old) to polyMesh." << nl
673  << endl;
674  }
675 
676  renumberSets = renumberDict.lookupOrDefault("renumberSets", true);
677  }
678  else
679  {
680  Info<< "Using default renumberMethod." << nl << endl;
681  renumberPtr.reset(new CuthillMcKeeRenumber(dictionary::null));
682  }
683 
684  Info<< "Selecting renumberMethod " << renumberPtr().type() << nl << endl;
685 
686 
687 
688  // Read parallel reconstruct maps
689  labelIOList cellProcAddressing
690  (
691  IOobject
692  (
693  "cellProcAddressing",
696  mesh,
698  ),
699  labelList(0)
700  );
701 
702  labelIOList faceProcAddressing
703  (
704  IOobject
705  (
706  "faceProcAddressing",
709  mesh,
711  ),
712  labelList(0)
713  );
714  labelIOList pointProcAddressing
715  (
716  IOobject
717  (
718  "pointProcAddressing",
721  mesh,
723  ),
724  labelList(0)
725  );
726 
727 
728  // Read objects in time directory
729  IOobjectList objects(mesh, runTime.name());
730 
731  if (fields) Info<< "Reading geometric fields" << nl << endl;
732 
733  #include "readVolFields.H"
734  #include "readSurfaceFields.H"
735  #include "readPointFields.H"
736 
737  Info<< endl;
738 
739 
740  // Read hex-refinement data (if any)
741  hexRef8Data refData
742  (
743  IOobject
744  (
745  "dummy",
748  mesh,
751  false
752  )
753  );
754 
755 
756  // From renumbering:
757  // - from new cell/face back to original cell/face
758  labelList cellOrder;
759  labelList faceOrder;
760 
761  if (blockSize > 0)
762  {
763  // Renumbering in two phases. Should be done in one so mapping of
764  // fields is done correctly!
765 
766  label nBlocks = mesh.nCells()/blockSize;
767  Info<< "nBlocks = " << nBlocks << endl;
768 
769  // Read decompositionMethod dictionary
770  dictionary decomposeDict(renumberDictPtr().subDict("blockCoeffs"));
771  decomposeDict.set("numberOfSubdomains", nBlocks);
772 
773  bool oldParRun = UPstream::parRun();
774  UPstream::parRun() = false;
775 
776  autoPtr<decompositionMethod> decomposePtr
777  (
779  );
780 
781  labelList cellToRegion
782  (
783  decomposePtr().decompose
784  (
785  mesh,
786  mesh.cellCentres()
787  )
788  );
789 
790  // Restore state
791  UPstream::parRun() = oldParRun;
792 
793  // For debugging: write out region
794  writeCellLabels
795  (
796  mesh,
797  "cellProc",
798  cellToRegion
799  );
800  Info<< nl << "Written decomposition as volScalarField::Internal to "
801  << "cellProc for use in postprocessing."
802  << nl << endl;
803 
804  cellOrder = regionRenumber(renumberPtr(), mesh, cellToRegion);
805 
806  // Determine new to old face order with new cell numbering
807  faceOrder = getRegionFaceOrder
808  (
809  mesh,
810  cellOrder,
811  cellToRegion
812  );
813  }
814  else
815  {
816  // Determines sorted back to original cell ordering
817  cellOrder = renumberPtr().renumber
818  (
819  mesh,
820  mesh.cellCentres()
821  );
822 
823  if (sortCoupledFaceCells)
824  {
825  // Change order so all coupled patch faceCells are at the end.
826  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
827 
828  // Collect all boundary cells on coupled patches
829  label nBndCells = 0;
830  forAll(pbm, patchi)
831  {
832  if (pbm[patchi].coupled())
833  {
834  nBndCells += pbm[patchi].size();
835  }
836  }
837 
838  labelList reverseCellOrder = invert(mesh.nCells(), cellOrder);
839 
840  labelList bndCells(nBndCells);
841  labelList bndCellMap(nBndCells);
842  nBndCells = 0;
843  forAll(pbm, patchi)
844  {
845  if (pbm[patchi].coupled())
846  {
847  const labelUList& faceCells = pbm[patchi].faceCells();
848  forAll(faceCells, i)
849  {
850  label celli = faceCells[i];
851 
852  if (reverseCellOrder[celli] != -1)
853  {
854  bndCells[nBndCells] = celli;
855  bndCellMap[nBndCells++] = reverseCellOrder[celli];
856  reverseCellOrder[celli] = -1;
857  }
858  }
859  }
860  }
861  bndCells.setSize(nBndCells);
862  bndCellMap.setSize(nBndCells);
863 
864  // Sort
866  sortedOrder(bndCellMap, order);
867 
868  // Redo newReverseCellOrder
869  labelList newReverseCellOrder(mesh.nCells(), -1);
870 
871  label sortedI = mesh.nCells();
872  forAllReverse(order, i)
873  {
874  label origCelli = bndCells[order[i]];
875  newReverseCellOrder[origCelli] = --sortedI;
876  }
877 
878  Info<< "Ordered all " << nBndCells << " cells with a coupled face"
879  << " to the end of the cell list, starting at " << sortedI
880  << endl;
881 
882  // Compact
883  sortedI = 0;
884  forAll(cellOrder, newCelli)
885  {
886  label origCelli = cellOrder[newCelli];
887  if (newReverseCellOrder[origCelli] == -1)
888  {
889  newReverseCellOrder[origCelli] = sortedI++;
890  }
891  }
892 
893  // Update sorted back to original (unsorted) map
894  cellOrder = invert(mesh.nCells(), newReverseCellOrder);
895  }
896 
897 
898  // Determine new to old face order with new cell numbering
899  faceOrder = getFaceOrder
900  (
901  mesh,
902  cellOrder // New to old cell
903  );
904  }
905 
906 
907  if (!overwrite)
908  {
909  runTime++;
910  }
911 
912 
913  // Change the mesh.
914  autoPtr<polyTopoChangeMap> map = reorderMesh(mesh, cellOrder, faceOrder);
915 
916 
917  if (orderPoints)
918  {
919  polyTopoChange meshMod(mesh);
920  autoPtr<polyTopoChangeMap> pointOrderMap = meshMod.changeMesh
921  (
922  mesh,
923  true, // syncParallel
924  false, // orderCells
925  orderPoints // orderPoints
926  );
927 
928  // Combine point reordering into map.
929  const_cast<labelList&>(map().pointMap()) = UIndirectList<label>
930  (
931  map().pointMap(),
932  pointOrderMap().pointMap()
933  )();
934 
936  (
937  pointOrderMap().reversePointMap(),
938  const_cast<labelList&>(map().reversePointMap())
939  );
940  }
941 
942 
943  // Update fields
944  mesh.topoChange(map);
945 
946 
947  // Update proc maps
948  if
949  (
950  cellProcAddressing.headerOk()
951  && cellProcAddressing.size() == mesh.nCells()
952  )
953  {
954  Info<< "Renumbering processor cell decomposition map "
955  << cellProcAddressing.name() << endl;
956 
957  cellProcAddressing = labelList
958  (
959  UIndirectList<label>(cellProcAddressing, map().cellMap())
960  );
961  }
962  if
963  (
964  faceProcAddressing.headerOk()
965  && faceProcAddressing.size() == mesh.nFaces()
966  )
967  {
968  Info<< "Renumbering processor face decomposition map "
969  << faceProcAddressing.name() << endl;
970 
971  faceProcAddressing = labelList
972  (
973  UIndirectList<label>(faceProcAddressing, map().faceMap())
974  );
975 
976  // Detect any flips.
977  const labelHashSet& fff = map().flipFaceFlux();
978  forAllConstIter(labelHashSet, fff, iter)
979  {
980  label facei = iter.key();
981  label masterFacei = faceProcAddressing[facei];
982 
983  faceProcAddressing[facei] = -masterFacei;
984 
985  if (masterFacei == 0)
986  {
988  << " masterFacei:" << masterFacei << exit(FatalError);
989  }
990  }
991  }
992  if
993  (
994  pointProcAddressing.headerOk()
995  && pointProcAddressing.size() == mesh.nPoints()
996  )
997  {
998  Info<< "Renumbering processor point decomposition map "
999  << pointProcAddressing.name() << endl;
1000 
1001  pointProcAddressing = labelList
1002  (
1003  UIndirectList<label>(pointProcAddressing, map().pointMap())
1004  );
1005  }
1006 
1007 
1008  {
1009  label band;
1010  scalar profile;
1011  scalar sumSqrIntersect;
1012  getBand
1013  (
1014  doFrontWidth,
1015  mesh.nCells(),
1016  mesh.faceOwner(),
1017  mesh.faceNeighbour(),
1018  band,
1019  profile,
1020  sumSqrIntersect
1021  );
1022  reduce(band, maxOp<label>());
1023  reduce(profile, sumOp<scalar>());
1024  scalar rmsFrontwidth = Foam::sqrt
1025  (
1026  returnReduce
1027  (
1028  sumSqrIntersect,
1029  sumOp<scalar>()
1031  );
1032 
1033  Info<< "After renumbering :" << nl
1034  << " band : " << band << nl
1035  << " profile : " << profile << nl;
1036 
1037  if (doFrontWidth)
1038  {
1039 
1040  Info<< " rms frontwidth : " << rmsFrontwidth << nl;
1041  }
1042 
1043  Info<< endl;
1044  }
1045 
1046 
1047  if (orderPoints)
1048  {
1049  // Force edge calculation (since only reason that points would need to
1050  // be sorted)
1051  (void)mesh.edges();
1052 
1053  label nTotPoints = returnReduce
1054  (
1055  mesh.nPoints(),
1056  sumOp<label>()
1057  );
1058  label nTotIntPoints = returnReduce
1059  (
1061  sumOp<label>()
1062  );
1063 
1064  label nTotEdges = returnReduce
1065  (
1066  mesh.nEdges(),
1067  sumOp<label>()
1068  );
1069  label nTotIntEdges = returnReduce
1070  (
1071  mesh.nInternalEdges(),
1072  sumOp<label>()
1073  );
1074  label nTotInt0Edges = returnReduce
1075  (
1077  sumOp<label>()
1078  );
1079  label nTotInt1Edges = returnReduce
1080  (
1082  sumOp<label>()
1083  );
1084 
1085  Info<< "Points:" << nl
1086  << " total : " << nTotPoints << nl
1087  << " internal: " << nTotIntPoints << nl
1088  << " boundary: " << nTotPoints-nTotIntPoints << nl
1089  << "Edges:" << nl
1090  << " total : " << nTotEdges << nl
1091  << " internal: " << nTotIntEdges << nl
1092  << " internal using 0 boundary points: "
1093  << nTotInt0Edges << nl
1094  << " internal using 1 boundary points: "
1095  << nTotInt1Edges-nTotInt0Edges << nl
1096  << " internal using 2 boundary points: "
1097  << nTotIntEdges-nTotInt1Edges << nl
1098  << " boundary: " << nTotEdges-nTotIntEdges << nl
1099  << endl;
1100  }
1101 
1102 
1103  if (overwrite)
1104  {
1105  mesh.setInstance(oldInstance);
1106  }
1107 
1108  Info<< "Writing mesh to " << mesh.facesInstance() << endl;
1109 
1110  mesh.write();
1111 
1112  refData.topoChange(map);
1113  refData.write();
1114 
1115  if (cellProcAddressing.headerOk())
1116  {
1117  cellProcAddressing.instance() = mesh.facesInstance();
1118  if (cellProcAddressing.size() == mesh.nCells())
1119  {
1120  cellProcAddressing.write();
1121  }
1122  else
1123  {
1124  // procAddressing file no longer valid. Delete it.
1125  const fileName fName(cellProcAddressing.filePath());
1126  if (fName.size())
1127  {
1128  Info<< "Deleting inconsistent processor cell decomposition"
1129  << " map " << fName << endl;
1130  rm(fName);
1131  }
1132  }
1133  }
1134 
1135  if (faceProcAddressing.headerOk())
1136  {
1137  faceProcAddressing.instance() = mesh.facesInstance();
1138  if (faceProcAddressing.size() == mesh.nFaces())
1139  {
1140  faceProcAddressing.write();
1141  }
1142  else
1143  {
1144  const fileName fName(faceProcAddressing.filePath());
1145  if (fName.size())
1146  {
1147  Info<< "Deleting inconsistent processor face decomposition"
1148  << " map " << fName << endl;
1149  rm(fName);
1150  }
1151  }
1152  }
1153 
1154  if (pointProcAddressing.headerOk())
1155  {
1156  pointProcAddressing.instance() = mesh.facesInstance();
1157  if (pointProcAddressing.size() == mesh.nPoints())
1158  {
1159  pointProcAddressing.write();
1160  }
1161  else
1162  {
1163  const fileName fName(pointProcAddressing.filePath());
1164  if (fName.size())
1165  {
1166  Info<< "Deleting inconsistent processor point decomposition"
1167  << " map " << fName << endl;
1168  rm(fName);
1169  }
1170  }
1171  }
1172 
1173  if (writeMaps)
1174  {
1175  // For debugging: write out region
1176  writeCellLabels
1177  (
1178  mesh,
1179  "origCellID",
1180  map().cellMap()
1181  );
1182 
1183  writeCellLabels
1184  (
1185  mesh,
1186  "cellID",
1188  );
1189 
1190  Info<< nl << "Written current cellID and origCellID as volScalarField"
1191  << " for use in postprocessing."
1192  << nl << endl;
1193 
1194  labelIOList
1195  (
1196  IOobject
1197  (
1198  "cellMap",
1199  mesh.facesInstance(),
1201  mesh,
1204  false
1205  ),
1206  map().cellMap()
1207  ).write();
1208 
1209  labelIOList
1210  (
1211  IOobject
1212  (
1213  "faceMap",
1214  mesh.facesInstance(),
1216  mesh,
1219  false
1220  ),
1221  map().faceMap()
1222  ).write();
1223 
1224  labelIOList
1225  (
1226  IOobject
1227  (
1228  "pointMap",
1229  mesh.facesInstance(),
1231  mesh,
1234  false
1235  ),
1236  map().pointMap()
1237  ).write();
1238  }
1239 
1240 
1241  // Renumber sets if required
1242  if (renumberSets)
1243  {
1244  Info<< endl;
1245 
1246  // Read sets
1247  IOobjectList objects(mesh, mesh.facesInstance(), "polyMesh/sets");
1248 
1249  {
1250  IOobjectList cSets(objects.lookupClass(cellSet::typeName));
1251  if (cSets.size())
1252  {
1253  Info<< "Renumbering cellSets:" << endl;
1254  forAllConstIter(IOobjectList, cSets, iter)
1255  {
1256  cellSet cs(*iter());
1257  Info<< " " << cs.name() << endl;
1258  cs.topoChange(map());
1259  cs.instance() = mesh.facesInstance();
1260  cs.write();
1261  }
1262  }
1263  }
1264 
1265  {
1266  IOobjectList fSets(objects.lookupClass(faceSet::typeName));
1267  if (fSets.size())
1268  {
1269  Info<< "Renumbering faceSets:" << endl;
1270  forAllConstIter(IOobjectList, fSets, iter)
1271  {
1272  faceSet fs(*iter());
1273  Info<< " " << fs.name() << endl;
1274  fs.topoChange(map());
1275  fs.instance() = mesh.facesInstance();
1276  fs.write();
1277  }
1278  }
1279  }
1280 
1281  {
1282  IOobjectList pSets(objects.lookupClass(pointSet::typeName));
1283  if (pSets.size())
1284  {
1285  Info<< "Renumbering pointSets:" << endl;
1286  forAllConstIter(IOobjectList, pSets, iter)
1287  {
1288  pointSet ps(*iter());
1289  Info<< " " << ps.name() << endl;
1290  ps.topoChange(map());
1291  ps.instance() = mesh.facesInstance();
1292  ps.write();
1293  }
1294  }
1295  }
1296  }
1297 
1298  Info<< "End\n" << endl;
1299 
1300  return 0;
1301 }
1302 
1303 
1304 // ************************************************************************* //
Field reading functions for post-processing utilities.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: UList.H:445
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:476
Cuthill-McKee renumbering.
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:53
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
A list that is sorted upon construction or when explicitly requested with the sort() method.
Definition: SortableList.H:55
A List with indirect addressing.
Definition: UIndirectList.H:60
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:159
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:118
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
void reset(T *=nullptr)
If object pointer already set, delete object and set to given.
Definition: autoPtrI.H:114
A collection of cell labels.
Definition: cellSet.H:51
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:60
static autoPtr< decompositionMethod > NewDecomposer(const dictionary &decompositionDict)
Return a reference to the selected decomposition method.
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:740
T lookupOrDefault(const word &, const T &, const bool writeDefault=writeOptionalEntries > 0) const
Find and return a T, if not found return the given default.
static const dictionary null
Null dictionary.
Definition: dictionary.H:273
const word & name() const
Return const reference to name.
A list of face labels.
Definition: faceSet.H:51
A class for handling file names.
Definition: fileName.H:82
Post-processing mesh subset tool. Given the original mesh and the list of selected cells,...
Definition: fvMeshSubset.H:74
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:96
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:420
virtual bool write(const bool write=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1780
const word & name() const
Return reference to name.
Definition: fvMesh.H:434
virtual void topoChange(const polyTopoChangeMap &map)
Update mesh corresponding to the given map.
Definition: fvMesh.C:1364
label nTotalCells() const
Return total number of cells in decomposed mesh.
Various for reading/decomposing/reconstructing/distributing refinement data.
Definition: hexRef8Data.H:58
A set of point labels.
Definition: pointSet.H:51
Foam::polyBoundaryMesh.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:992
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1315
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:714
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1328
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1486
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:986
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:382
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1334
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:254
void setInstance(const fileName &)
Set the instance for mesh files.
Definition: polyMeshIO.C:91
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Direct mesh changes based on v1.3 polyTopoChange syntax.
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:75
label nInternal1Edges() const
Internal edges using 0 or 1 boundary point.
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
label nInternalEdges() const
Internal edges using 0,1 or 2 boundary points.
label nInternalPoints() const
Points not on boundary.
label nInternalFaces() const
const vectorField & cellCentres() const
label nCells() const
label nPoints() const
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
const cellList & cells() const
label nEdges() const
label nInternal0Edges() const
Internal edges (i.e. not on boundary face) using.
label nFaces() const
virtual bool write(const bool write=true) const
Write using setting from DB.
Abstract base class for renumbering.
static autoPtr< renumberMethod > New(const dictionary &renumberDict)
Return a reference to the selected renumbering method.
virtual labelList renumber(const pointField &) const
Return the order in which cells need to be visited, i.e.
static void addOptions(const bool constant=true, const bool withZero=false)
Add the options handled by timeSelector to argList::validOptions.
Definition: timeSelector.C:114
static instantList select0(Time &runTime, const argList &args)
Return the set of times selected based on the argList options.
Definition: timeSelector.C:252
A class for handling words, derived from string.
Definition: word.H:62
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
int main(int argc, char *argv[])
Definition: financialFoam.C:44
label patchi
label nPoints
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const fvPatchList & patches
Info<< "Calculating turbulent flame speed field St\n"<< endl;volScalarField St(IOobject("St", runTime.name(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE), flameWrinkling->Xi() *Su);multivariateSurfaceInterpolationScheme< scalar >::fieldTable fields
Definition: createFields.H:234
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< label > labelList
A List of labels.
Definition: labelList.H:56
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
bool rm(const fileName &)
Remove a file, returning true if successful otherwise false.
Definition: POSIX.C:1017
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:258
labelList invert(const label len, const labelUList &)
Invert one-to-one map. Unmapped elements will be -1.
Definition: ListOps.C:37
int order(const scalar s)
errorManip< error > abort(error &err)
Definition: errorManip.H:131
const dimensionSet dimless
ListType renumber(const labelUList &oldToNew, const ListType &)
Renumber the values (not the indices) of a list.
messageStream Info
labelListList invertOneToMany(const label len, const labelUList &)
Invert one-to-many map. Unmapped elements will be size 0.
Definition: ListOps.C:67
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:50
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
ListType reorder(const label size, const typename ListType::value_type &defaultValue, const labelUList &oldToNew, const ListType &lst)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
scalar diff(const triad &A, const triad &B)
Return a quantity of the difference between two triads.
Definition: triad.C:409
void inplaceRenumber(const labelUList &oldToNew, ListType &)
Inplace renumber the values of a list.
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
IOList< label > labelIOList
Label container classes.
Definition: labelIOList.H:42
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
void sqr(LagrangianPatchField< typename outerProduct< Type, Type >::type > &f, const LagrangianPatchField< Type > &f1)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
error FatalError
void Swap(T &a, T &b)
Definition: Swap.H:43
static const label labelMax
Definition: label.H:62
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
IOdictionary systemDict(const word &dictName, const argList &args, const objectRegistry &ob, const word &regionName=polyMesh::defaultRegion, const fileName &path=fileName::null)
Definition: systemDict.C:93
void sortedOrder(const UList< T > &, labelList &order)
Generate the (stable) sort order for the list.
void sqrt(LagrangianPatchField< scalar > &f, const LagrangianPatchField< scalar > &f1)
static const char nl
Definition: Ostream.H:267
objects
const bool overwrite
Definition: setNoOverwrite.H:1
Foam::argList args(argc, argv)
Foam::surfaceFields.