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-2026 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 
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  // Read parallel reconstruct maps
688  labelIOList cellProcAddressing
689  (
690  IOobject
691  (
692  "cellProcAddressing",
695  mesh,
697  ),
698  labelList(0)
699  );
700 
701  labelIOList faceProcAddressing
702  (
703  IOobject
704  (
705  "faceProcAddressing",
708  mesh,
710  ),
711  labelList(0)
712  );
713  labelIOList pointProcAddressing
714  (
715  IOobject
716  (
717  "pointProcAddressing",
720  mesh,
722  ),
723  labelList(0)
724  );
725 
726 
727  // Read objects in time directory
728  IOobjectList objects(mesh, runTime.name());
729 
730  if (fields) Info<< "Reading geometric fields" << nl << endl;
731 
732  #include "readVolFields.H"
733  #include "readSurfaceFields.H"
734  #include "readPointFields.H"
735 
736  Info<< endl;
737 
738 
739  // Read hex-refinement data (if any)
740  hexRef8Data refData
741  (
742  IOobject
743  (
744  "dummy",
747  mesh,
750  false
751  )
752  );
753 
754 
755  // From renumbering:
756  // - from new cell/face back to original cell/face
757  labelList cellOrder;
758  labelList faceOrder;
759 
760  if (blockSize > 0)
761  {
762  // Renumbering in two phases. Should be done in one so mapping of
763  // fields is done correctly!
764 
765  label nBlocks = mesh.nCells()/blockSize;
766  Info<< "nBlocks = " << nBlocks << endl;
767 
768  // Read decompositionMethod dictionary
769  dictionary decomposeDict(renumberDictPtr().typeDict("block"));
770  decomposeDict.set("numberOfSubdomains", nBlocks);
771 
772  bool oldParRun = UPstream::parRun();
773  UPstream::parRun() = false;
774 
775  autoPtr<decompositionMethod> decomposePtr
776  (
778  );
779 
780  labelList cellToRegion
781  (
782  decomposePtr().decompose
783  (
784  mesh,
785  mesh.cellCentres()
786  )
787  );
788 
789  // Restore state
790  UPstream::parRun() = oldParRun;
791 
792  // For debugging: write out region
793  writeCellLabels
794  (
795  mesh,
796  "cellProc",
797  cellToRegion
798  );
799  Info<< nl << "Written decomposition as volScalarField::Internal to "
800  << "cellProc for use in postprocessing."
801  << nl << endl;
802 
803  cellOrder = regionRenumber(renumberPtr(), mesh, cellToRegion);
804 
805  // Determine new to old face order with new cell numbering
806  faceOrder = getRegionFaceOrder
807  (
808  mesh,
809  cellOrder,
810  cellToRegion
811  );
812  }
813  else
814  {
815  // Determines sorted back to original cell ordering
816  cellOrder = renumberPtr().renumber
817  (
818  mesh,
819  mesh.cellCentres()
820  );
821 
822  if (sortCoupledFaceCells)
823  {
824  // Change order so all coupled patch faceCells are at the end.
825  const polyBoundaryMesh& pbm = mesh.poly().boundary();
826 
827  // Collect all boundary cells on coupled patches
828  label nBndCells = 0;
829  forAll(pbm, patchi)
830  {
831  if (pbm[patchi].coupled())
832  {
833  nBndCells += pbm[patchi].size();
834  }
835  }
836 
837  labelList reverseCellOrder = invert(mesh.nCells(), cellOrder);
838 
839  labelList bndCells(nBndCells);
840  labelList bndCellMap(nBndCells);
841  nBndCells = 0;
842  forAll(pbm, patchi)
843  {
844  if (pbm[patchi].coupled())
845  {
846  const labelUList& faceCells = pbm[patchi].faceCells();
847  forAll(faceCells, i)
848  {
849  label celli = faceCells[i];
850 
851  if (reverseCellOrder[celli] != -1)
852  {
853  bndCells[nBndCells] = celli;
854  bndCellMap[nBndCells++] = reverseCellOrder[celli];
855  reverseCellOrder[celli] = -1;
856  }
857  }
858  }
859  }
860  bndCells.setSize(nBndCells);
861  bndCellMap.setSize(nBndCells);
862 
863  // Sort
865  sortedOrder(bndCellMap, order);
866 
867  // Redo newReverseCellOrder
868  labelList newReverseCellOrder(mesh.nCells(), -1);
869 
870  label sortedI = mesh.nCells();
871  forAllReverse(order, i)
872  {
873  label origCelli = bndCells[order[i]];
874  newReverseCellOrder[origCelli] = --sortedI;
875  }
876 
877  Info<< "Ordered all " << nBndCells << " cells with a coupled face"
878  << " to the end of the cell list, starting at " << sortedI
879  << endl;
880 
881  // Compact
882  sortedI = 0;
883  forAll(cellOrder, newCelli)
884  {
885  label origCelli = cellOrder[newCelli];
886  if (newReverseCellOrder[origCelli] == -1)
887  {
888  newReverseCellOrder[origCelli] = sortedI++;
889  }
890  }
891 
892  // Update sorted back to original (unsorted) map
893  cellOrder = invert(mesh.nCells(), newReverseCellOrder);
894  }
895 
896 
897  // Determine new to old face order with new cell numbering
898  faceOrder = getFaceOrder
899  (
900  mesh,
901  cellOrder // New to old cell
902  );
903  }
904 
905 
906  if (!overwrite)
907  {
908  runTime++;
909  }
910 
911 
912  // Change the mesh.
913  autoPtr<polyTopoChangeMap> map = reorderMesh(mesh, cellOrder, faceOrder);
914 
915 
916  if (orderPoints)
917  {
918  polyTopoChange meshMod(mesh);
919  autoPtr<polyTopoChangeMap> pointOrderMap = meshMod.changeMesh
920  (
921  mesh,
922  true, // syncParallel
923  false, // orderCells
924  orderPoints // orderPoints
925  );
926 
927  // Combine point reordering into map.
928  const_cast<labelList&>(map().pointMap()) = UIndirectList<label>
929  (
930  map().pointMap(),
931  pointOrderMap().pointMap()
932  )();
933 
935  (
936  pointOrderMap().reversePointMap(),
937  const_cast<labelList&>(map().reversePointMap())
938  );
939  }
940 
941 
942  // Update fields
943  mesh.topoChange(map);
944 
945 
946  // Update proc maps
947  if
948  (
949  cellProcAddressing.headerOk()
950  && cellProcAddressing.size() == mesh.nCells()
951  )
952  {
953  Info<< "Renumbering processor cell decomposition map "
954  << cellProcAddressing.name() << endl;
955 
956  cellProcAddressing = labelList
957  (
958  UIndirectList<label>(cellProcAddressing, map().cellMap())
959  );
960  }
961  if
962  (
963  faceProcAddressing.headerOk()
964  && faceProcAddressing.size() == mesh.nFaces()
965  )
966  {
967  Info<< "Renumbering processor face decomposition map "
968  << faceProcAddressing.name() << endl;
969 
970  faceProcAddressing = labelList
971  (
972  UIndirectList<label>(faceProcAddressing, map().faceMap())
973  );
974 
975  // Detect any flips.
976  const labelHashSet& fff = map().flipFaceFlux();
977  forAllConstIter(labelHashSet, fff, iter)
978  {
979  label facei = iter.key();
980  label masterFacei = faceProcAddressing[facei];
981 
982  faceProcAddressing[facei] = -masterFacei;
983 
984  if (masterFacei == 0)
985  {
987  << " masterFacei:" << masterFacei << exit(FatalError);
988  }
989  }
990  }
991  if
992  (
993  pointProcAddressing.headerOk()
994  && pointProcAddressing.size() == mesh.nPoints()
995  )
996  {
997  Info<< "Renumbering processor point decomposition map "
998  << pointProcAddressing.name() << endl;
999 
1000  pointProcAddressing = labelList
1001  (
1002  UIndirectList<label>(pointProcAddressing, map().pointMap())
1003  );
1004  }
1005 
1006 
1007  {
1008  label band;
1009  scalar profile;
1010  scalar sumSqrIntersect;
1011  getBand
1012  (
1013  doFrontWidth,
1014  mesh.nCells(),
1015  mesh.faceOwner(),
1016  mesh.faceNeighbour(),
1017  band,
1018  profile,
1019  sumSqrIntersect
1020  );
1021  reduce(band, maxOp<label>());
1022  reduce(profile, sumOp<scalar>());
1023  scalar rmsFrontwidth = Foam::sqrt
1024  (
1025  returnReduce
1026  (
1027  sumSqrIntersect,
1028  sumOp<scalar>()
1030  );
1031 
1032  Info<< "After renumbering :" << nl
1033  << " band : " << band << nl
1034  << " profile : " << profile << nl;
1035 
1036  if (doFrontWidth)
1037  {
1038 
1039  Info<< " rms frontwidth : " << rmsFrontwidth << nl;
1040  }
1041 
1042  Info<< endl;
1043  }
1044 
1045 
1046  if (orderPoints)
1047  {
1048  // Force edge calculation (since only reason that points would need to
1049  // be sorted)
1050  (void)mesh.edges();
1051 
1052  label nTotPoints = returnReduce
1053  (
1054  mesh.nPoints(),
1055  sumOp<label>()
1056  );
1057  label nTotIntPoints = returnReduce
1058  (
1060  sumOp<label>()
1061  );
1062 
1063  label nTotEdges = returnReduce
1064  (
1065  mesh.nEdges(),
1066  sumOp<label>()
1067  );
1068  label nTotIntEdges = returnReduce
1069  (
1070  mesh.nInternalEdges(),
1071  sumOp<label>()
1072  );
1073  label nTotInt0Edges = returnReduce
1074  (
1076  sumOp<label>()
1077  );
1078  label nTotInt1Edges = returnReduce
1079  (
1081  sumOp<label>()
1082  );
1083 
1084  Info<< "Points:" << nl
1085  << " total : " << nTotPoints << nl
1086  << " internal: " << nTotIntPoints << nl
1087  << " boundary: " << nTotPoints-nTotIntPoints << nl
1088  << "Edges:" << nl
1089  << " total : " << nTotEdges << nl
1090  << " internal: " << nTotIntEdges << nl
1091  << " internal using 0 boundary points: "
1092  << nTotInt0Edges << nl
1093  << " internal using 1 boundary points: "
1094  << nTotInt1Edges-nTotInt0Edges << nl
1095  << " internal using 2 boundary points: "
1096  << nTotIntEdges-nTotInt1Edges << nl
1097  << " boundary: " << nTotEdges-nTotIntEdges << nl
1098  << endl;
1099  }
1100 
1101 
1102  if (overwrite)
1103  {
1104  mesh.setInstance(oldInstance);
1105  }
1106 
1107  Info<< "Writing mesh to " << mesh.facesInstance() << endl;
1108 
1109  mesh.write();
1110 
1111  refData.topoChange(map);
1112  refData.write();
1113 
1114  if (cellProcAddressing.headerOk())
1115  {
1116  cellProcAddressing.instance() = mesh.facesInstance();
1117  if (cellProcAddressing.size() == mesh.nCells())
1118  {
1119  cellProcAddressing.write();
1120  }
1121  else
1122  {
1123  // procAddressing file no longer valid. Delete it.
1124  const fileName fName(cellProcAddressing.filePath());
1125  if (fName.size())
1126  {
1127  Info<< "Deleting inconsistent processor cell decomposition"
1128  << " map " << fName << endl;
1129  rm(fName);
1130  }
1131  }
1132  }
1133 
1134  if (faceProcAddressing.headerOk())
1135  {
1136  faceProcAddressing.instance() = mesh.facesInstance();
1137  if (faceProcAddressing.size() == mesh.nFaces())
1138  {
1139  faceProcAddressing.write();
1140  }
1141  else
1142  {
1143  const fileName fName(faceProcAddressing.filePath());
1144  if (fName.size())
1145  {
1146  Info<< "Deleting inconsistent processor face decomposition"
1147  << " map " << fName << endl;
1148  rm(fName);
1149  }
1150  }
1151  }
1152 
1153  if (pointProcAddressing.headerOk())
1154  {
1155  pointProcAddressing.instance() = mesh.facesInstance();
1156  if (pointProcAddressing.size() == mesh.nPoints())
1157  {
1158  pointProcAddressing.write();
1159  }
1160  else
1161  {
1162  const fileName fName(pointProcAddressing.filePath());
1163  if (fName.size())
1164  {
1165  Info<< "Deleting inconsistent processor point decomposition"
1166  << " map " << fName << endl;
1167  rm(fName);
1168  }
1169  }
1170  }
1171 
1172  if (writeMaps)
1173  {
1174  // For debugging: write out region
1175  writeCellLabels
1176  (
1177  mesh,
1178  "origCellID",
1179  map().cellMap()
1180  );
1181 
1182  writeCellLabels
1183  (
1184  mesh,
1185  "cellID",
1187  );
1188 
1189  Info<< nl << "Written current cellID and origCellID as volScalarField"
1190  << " for use in postprocessing."
1191  << nl << endl;
1192 
1193  labelIOList
1194  (
1195  IOobject
1196  (
1197  "cellMap",
1198  mesh.facesInstance(),
1200  mesh,
1203  false
1204  ),
1205  map().cellMap()
1206  ).write();
1207 
1208  labelIOList
1209  (
1210  IOobject
1211  (
1212  "faceMap",
1213  mesh.facesInstance(),
1215  mesh,
1218  false
1219  ),
1220  map().faceMap()
1221  ).write();
1222 
1223  labelIOList
1224  (
1225  IOobject
1226  (
1227  "pointMap",
1228  mesh.facesInstance(),
1230  mesh,
1233  false
1234  ),
1235  map().pointMap()
1236  ).write();
1237  }
1238 
1239 
1240  // Renumber sets if required
1241  if (renumberSets)
1242  {
1243  Info<< endl;
1244 
1245  // Read sets
1246  IOobjectList objects(mesh, mesh.facesInstance(), "polyMesh/sets");
1247 
1248  {
1249  IOobjectList cSets(objects.lookupClass(cellSet::typeName));
1250  if (cSets.size())
1251  {
1252  Info<< "Renumbering cellSets:" << endl;
1253  forAllConstIter(IOobjectList, cSets, iter)
1254  {
1255  cellSet cs(*iter());
1256  Info<< " " << cs.name() << endl;
1257  cs.topoChange(map());
1258  cs.instance() = mesh.facesInstance();
1259  cs.write();
1260  }
1261  }
1262  }
1263 
1264  {
1265  IOobjectList fSets(objects.lookupClass(faceSet::typeName));
1266  if (fSets.size())
1267  {
1268  Info<< "Renumbering faceSets:" << endl;
1269  forAllConstIter(IOobjectList, fSets, iter)
1270  {
1271  faceSet fs(*iter());
1272  Info<< " " << fs.name() << endl;
1273  fs.topoChange(map());
1274  fs.instance() = mesh.facesInstance();
1275  fs.write();
1276  }
1277  }
1278  }
1279 
1280  {
1281  IOobjectList pSets(objects.lookupClass(pointSet::typeName));
1282  if (pSets.size())
1283  {
1284  Info<< "Renumbering pointSets:" << endl;
1285  forAllConstIter(IOobjectList, pSets, iter)
1286  {
1287  pointSet ps(*iter());
1288  Info<< " " << ps.name() << endl;
1289  ps.topoChange(map());
1290  ps.instance() = mesh.facesInstance();
1291  ps.write();
1292  }
1293  }
1294  }
1295  }
1296 
1297  Info<< "End\n" << endl;
1298 
1299  return 0;
1300 }
1301 
1302 
1303 // ************************************************************************* //
Field reading functions for post-processing utilities.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: UList.H:461
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:492
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:61
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:152
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:111
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
T lookupOrDefault(const word &, const T &) const
Find and return a T, if not found return the given default.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:669
static const dictionary null
Null dictionary.
Definition: dictionary.H:261
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:98
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:433
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:932
const word & name() const
Return reference to name.
Definition: fvMesh.H:447
virtual void topoChange(const polyTopoChangeMap &map)
Update mesh corresponding to the given map.
Definition: fvMesh.C:1335
const polyMesh & poly() const
Return reference to polyMesh.
Definition: fvMesh.H:456
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:1012
const polyBoundaryMesh & boundary() const
Return boundary mesh.
Definition: polyMesh.H:393
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1308
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:710
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1321
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1471
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:1006
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1327
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:263
void setInstance(const fileName &)
Set the instance for mesh files.
Definition: polyMeshIO.C:102
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:63
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
const dimensionSet & dimless
Definition: dimensions.C:138
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:288
labelList invert(const label len, const labelUList &)
Invert one-to-one map. Unmapped elements will be -1.
Definition: ListOps.C:37
String typeName(const std::type_info &info)
Return the un-mangled name given the standard type info.
int order(const scalar s)
errorManip< error > abort(error &err)
Definition: errorManip.H:131
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
tmp< DimensionedField< typename outerProduct< Type, Type >::type, GeoMesh, Field >> sqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
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
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
void inplaceRenumber(const labelUList &oldToNew, ListType &)
Inplace renumber the values of a list.
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
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)
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:297
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
objects
const bool overwrite
Definition: setNoOverwrite.H:1
Foam::argList args(argc, argv)
Foam::surfaceFields.