Initial commit for version 2.0.x patch release
[OpenFOAM-2.0.x.git] / applications / utilities / mesh / manipulation / renumberMesh / renumberMesh.C
blobe6a34f6201e93785e58dbf6b2c263f3690db7f8f
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 2004-2010 OpenCFD Ltd.
6      \\/     M anispulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
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.
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.
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/>.
24 Application
25     renumberMesh
27 Description
28     Renumbers the cell list in order to reduce the bandwidth, reading and
29     renumbering all fields from all the time directories.
31 \*---------------------------------------------------------------------------*/
33 #include "argList.H"
34 #include "IOobjectList.H"
35 #include "fvMesh.H"
36 #include "polyTopoChange.H"
37 #include "ReadFields.H"
38 #include "volFields.H"
39 #include "surfaceFields.H"
40 #include "bandCompression.H"
41 #include "faceSet.H"
42 #include "SortableList.H"
43 #include "decompositionMethod.H"
44 #include "fvMeshSubset.H"
45 #include "zeroGradientFvPatchFields.H"
47 using namespace Foam;
50 // Calculate band of matrix
51 label getBand(const labelList& owner, const labelList& neighbour)
53     label band = 0;
55     forAll(neighbour, faceI)
56     {
57         label diff = neighbour[faceI] - owner[faceI];
59         if (diff > band)
60         {
61             band = diff;
62         }
63     }
64     return band;
68 // Return new to old cell numbering
69 labelList regionBandCompression
71     const fvMesh& mesh,
72     const labelList& cellToRegion
75     Pout<< "Determining cell order:" << endl;
77     labelList cellOrder(cellToRegion.size());
79     label nRegions = max(cellToRegion)+1;
81     labelListList regionToCells(invertOneToMany(nRegions, cellToRegion));
83     label cellI = 0;
85     forAll(regionToCells, regionI)
86     {
87         Pout<< "    region " << regionI << " starts at " << cellI << endl;
89         // Per region do a reordering.
90         fvMeshSubset subsetter(mesh);
91         subsetter.setLargeCellSubset(cellToRegion, regionI);
92         const fvMesh& subMesh = subsetter.subMesh();
93         labelList subCellOrder(bandCompression(subMesh.cellCells()));
95         const labelList& cellMap = subsetter.cellMap();
97         forAll(subCellOrder, i)
98         {
99             cellOrder[cellI++] = cellMap[subCellOrder[i]];
100         }
101     }
102     Pout<< endl;
104     return cellOrder;
108 // Determine face order such that inside region faces are sorted
109 // upper-triangular but inbetween region faces are handled like boundary faces.
110 labelList regionFaceOrder
112     const primitiveMesh& mesh,
113     const labelList& cellOrder,     // new to old cell
114     const labelList& cellToRegion   // old cell to region
117     Pout<< "Determining face order:" << endl;
119     labelList reverseCellOrder(invert(cellOrder.size(), cellOrder));
121     labelList oldToNewFace(mesh.nFaces(), -1);
123     label newFaceI = 0;
125     label prevRegion = -1;
127     forAll(cellOrder, newCellI)
128     {
129         label oldCellI = cellOrder[newCellI];
131         if (cellToRegion[oldCellI] != prevRegion)
132         {
133             prevRegion = cellToRegion[oldCellI];
134             Pout<< "    region " << prevRegion << " internal faces start at "
135                 << newFaceI << endl;
136         }
138         const cell& cFaces = mesh.cells()[oldCellI];
140         SortableList<label> nbr(cFaces.size());
142         forAll(cFaces, i)
143         {
144             label faceI = cFaces[i];
146             if (mesh.isInternalFace(faceI))
147             {
148                 // Internal face. Get cell on other side.
149                 label nbrCellI = reverseCellOrder[mesh.faceNeighbour()[faceI]];
150                 if (nbrCellI == newCellI)
151                 {
152                     nbrCellI = reverseCellOrder[mesh.faceOwner()[faceI]];
153                 }
155                 if (cellToRegion[oldCellI] != cellToRegion[cellOrder[nbrCellI]])
156                 {
157                     // Treat like external face. Do later.
158                     nbr[i] = -1;
159                 }
160                 else if (newCellI < nbrCellI)
161                 {
162                     // CellI is master
163                     nbr[i] = nbrCellI;
164                 }
165                 else
166                 {
167                     // nbrCell is master. Let it handle this face.
168                     nbr[i] = -1;
169                 }
170             }
171             else
172             {
173                 // External face. Do later.
174                 nbr[i] = -1;
175             }
176         }
178         nbr.sort();
180         forAll(nbr, i)
181         {
182             if (nbr[i] != -1)
183             {
184                 oldToNewFace[cFaces[nbr.indices()[i]]] = newFaceI++;
185             }
186         }
187     }
189     // Do region interfaces
190     label nRegions = max(cellToRegion)+1;
191     {
192         // Sort in increasing region
193         SortableList<label> sortKey(mesh.nFaces(), labelMax);
195         for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
196         {
197             label ownRegion = cellToRegion[mesh.faceOwner()[faceI]];
198             label neiRegion = cellToRegion[mesh.faceNeighbour()[faceI]];
200             if (ownRegion != neiRegion)
201             {
202                 sortKey[faceI] =
203                     min(ownRegion, neiRegion)*nRegions
204                    +max(ownRegion, neiRegion);
205             }
206         }
207         sortKey.sort();
209         // Extract.
210         label prevKey = -1;
211         forAll(sortKey, i)
212         {
213             label key = sortKey[i];
215             if (key == labelMax)
216             {
217                 break;
218             }
220             if (prevKey != key)
221             {
222                 Pout<< "    faces inbetween region " << key/nRegions
223                     << " and " << key%nRegions
224                     << " start at " << newFaceI << endl;
225                 prevKey = key;
226             }
228             oldToNewFace[sortKey.indices()[i]] = newFaceI++;
229         }
230     }
232     // Leave patch faces intact.
233     for (label faceI = newFaceI; faceI < mesh.nFaces(); faceI++)
234     {
235         oldToNewFace[faceI] = faceI;
236     }
239     // Check done all faces.
240     forAll(oldToNewFace, faceI)
241     {
242         if (oldToNewFace[faceI] == -1)
243         {
244             FatalErrorIn
245             (
246                 "polyDualMesh::getFaceOrder"
247                 "(const labelList&, const labelList&, const label) const"
248             )   << "Did not determine new position"
249                 << " for face " << faceI
250                 << abort(FatalError);
251         }
252     }
253     Pout<< endl;
255     return invert(mesh.nFaces(), oldToNewFace);
259 // cellOrder: old cell for every new cell
260 // faceOrder: old face for every new face. Ordering of boundary faces not
261 // changed.
262 autoPtr<mapPolyMesh> reorderMesh
264     polyMesh& mesh,
265     const labelList& cellOrder,
266     const labelList& faceOrder
269     labelList reverseCellOrder(invert(cellOrder.size(), cellOrder));
270     labelList reverseFaceOrder(invert(faceOrder.size(), faceOrder));
272     faceList newFaces(reorder(reverseFaceOrder, mesh.faces()));
273     labelList newOwner
274     (
275         renumber
276         (
277             reverseCellOrder,
278             reorder(reverseFaceOrder, mesh.faceOwner())
279         )
280     );
281     labelList newNeighbour
282     (
283         renumber
284         (
285             reverseCellOrder,
286             reorder(reverseFaceOrder, mesh.faceNeighbour())
287         )
288     );
290     // Check if any faces need swapping.
291     forAll(newNeighbour, faceI)
292     {
293         label own = newOwner[faceI];
294         label nei = newNeighbour[faceI];
296         if (nei < own)
297         {
298             newFaces[faceI].flip();
299             Swap(newOwner[faceI], newNeighbour[faceI]);
300         }
301     }
303     const polyBoundaryMesh& patches = mesh.boundaryMesh();
304     labelList patchSizes(patches.size());
305     labelList patchStarts(patches.size());
306     labelList oldPatchNMeshPoints(patches.size());
307     labelListList patchPointMap(patches.size());
309     forAll(patches, patchI)
310     {
311         patchSizes[patchI] = patches[patchI].size();
312         patchStarts[patchI] = patches[patchI].start();
313         oldPatchNMeshPoints[patchI] = patches[patchI].nPoints();
314         patchPointMap[patchI] = identity(patches[patchI].nPoints());
315     }
317     mesh.resetPrimitives
318     (
319         Xfer<pointField>::null(),
320         xferMove(newFaces),
321         xferMove(newOwner),
322         xferMove(newNeighbour),
323         patchSizes,
324         patchStarts,
325         true
326     );
328     return autoPtr<mapPolyMesh>
329     (
330         new mapPolyMesh
331         (
332             mesh,                       //const polyMesh& mesh,
333             mesh.nPoints(),             // nOldPoints,
334             mesh.nFaces(),              // nOldFaces,
335             mesh.nCells(),              // nOldCells,
336             identity(mesh.nPoints()),   // pointMap,
337             List<objectMap>(0),         // pointsFromPoints,
338             faceOrder,                  // faceMap,
339             List<objectMap>(0),         // facesFromPoints,
340             List<objectMap>(0),         // facesFromEdges,
341             List<objectMap>(0),         // facesFromFaces,
342             cellOrder,                  // cellMap,
343             List<objectMap>(0),         // cellsFromPoints,
344             List<objectMap>(0),         // cellsFromEdges,
345             List<objectMap>(0),         // cellsFromFaces,
346             List<objectMap>(0),         // cellsFromCells,
347             identity(mesh.nPoints()),   // reversePointMap,
348             reverseFaceOrder,           // reverseFaceMap,
349             reverseCellOrder,           // reverseCellMap,
350             labelHashSet(0),            // flipFaceFlux,
351             patchPointMap,              // patchPointMap,
352             labelListList(0),           // pointZoneMap,
353             labelListList(0),           // faceZonePointMap,
354             labelListList(0),           // faceZoneFaceMap,
355             labelListList(0),           // cellZoneMap,
356             pointField(0),              // preMotionPoints,
357             patchStarts,                // oldPatchStarts,
358             oldPatchNMeshPoints         // oldPatchNMeshPoints
359         )
360     );
364 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
366 int main(int argc, char *argv[])
368     argList::addBoolOption
369     (
370         "blockOrder",
371         "order cells into regions (using decomposition)"
372     );
373     argList::addBoolOption
374     (
375         "orderPoints",
376         "order points into internal and boundary points"
377     );
378     argList::addBoolOption
379     (
380         "writeMaps",
381         "write cellMap, faceMap, pointMap in polyMesh/"
382     );
384 #   include "addRegionOption.H"
385 #   include "addOverwriteOption.H"
386 #   include "addTimeOptions.H"
388 #   include "setRootCase.H"
389 #   include "createTime.H"
390     runTime.functionObjects().off();
392     // Get times list
393     instantList Times = runTime.times();
395     // set startTime and endTime depending on -time and -latestTime options
396 #   include "checkTimeOptions.H"
398     runTime.setTime(Times[startTime], startTime);
400 #   include "createNamedMesh.H"
401     const word oldInstance = mesh.pointsInstance();
403     const bool blockOrder = args.optionFound("blockOrder");
404     if (blockOrder)
405     {
406         Info<< "Ordering cells into regions (using decomposition);"
407             << " ordering faces into region-internal and region-external." << nl
408             << endl;
409     }
411     const bool orderPoints = args.optionFound("orderPoints");
412     if (orderPoints)
413     {
414         Info<< "Ordering points into internal and boundary points." << nl
415             << endl;
416     }
418     const bool writeMaps = args.optionFound("writeMaps");
420     if (writeMaps)
421     {
422         Info<< "Writing renumber maps (new to old) to polyMesh." << nl
423             << endl;
424     }
426     const bool overwrite = args.optionFound("overwrite");
428     label band = getBand(mesh.faceOwner(), mesh.faceNeighbour());
430     Info<< "Mesh size: " << returnReduce(mesh.nCells(), sumOp<label>()) << nl
431         << "Band before renumbering: "
432         << returnReduce(band, maxOp<label>()) << nl << endl;
435     // Read parallel reconstruct maps
436     labelIOList cellProcAddressing
437     (
438         IOobject
439         (
440             "cellProcAddressing",
441             mesh.facesInstance(),
442             polyMesh::meshSubDir,
443             mesh,
444             IOobject::READ_IF_PRESENT
445         ),
446         labelList(0)
447     );
449     labelIOList faceProcAddressing
450     (
451         IOobject
452         (
453             "faceProcAddressing",
454             mesh.facesInstance(),
455             polyMesh::meshSubDir,
456             mesh,
457             IOobject::READ_IF_PRESENT
458         ),
459         labelList(0)
460     );
461     labelIOList pointProcAddressing
462     (
463         IOobject
464         (
465             "pointProcAddressing",
466             mesh.pointsInstance(),
467             polyMesh::meshSubDir,
468             mesh,
469             IOobject::READ_IF_PRESENT
470         ),
471         labelList(0)
472     );
473     labelIOList boundaryProcAddressing
474     (
475         IOobject
476         (
477             "boundaryProcAddressing",
478             mesh.pointsInstance(),
479             polyMesh::meshSubDir,
480             mesh,
481             IOobject::READ_IF_PRESENT
482         ),
483         labelList(0)
484     );
487     // Read objects in time directory
488     IOobjectList objects(mesh, runTime.timeName());
490     // Read vol fields.
492     PtrList<volScalarField> vsFlds;
493     ReadFields(mesh, objects, vsFlds);
495     PtrList<volVectorField> vvFlds;
496     ReadFields(mesh, objects, vvFlds);
498     PtrList<volSphericalTensorField> vstFlds;
499     ReadFields(mesh, objects, vstFlds);
501     PtrList<volSymmTensorField> vsymtFlds;
502     ReadFields(mesh, objects, vsymtFlds);
504     PtrList<volTensorField> vtFlds;
505     ReadFields(mesh, objects, vtFlds);
507     // Read surface fields.
509     PtrList<surfaceScalarField> ssFlds;
510     ReadFields(mesh, objects, ssFlds);
512     PtrList<surfaceVectorField> svFlds;
513     ReadFields(mesh, objects, svFlds);
515     PtrList<surfaceSphericalTensorField> sstFlds;
516     ReadFields(mesh, objects, sstFlds);
518     PtrList<surfaceSymmTensorField> ssymtFlds;
519     ReadFields(mesh, objects, ssymtFlds);
521     PtrList<surfaceTensorField> stFlds;
522     ReadFields(mesh, objects, stFlds);
525     autoPtr<mapPolyMesh> map;
527     if (blockOrder)
528     {
529         // Renumbering in two phases. Should be done in one so mapping of
530         // fields is done correctly!
532         // Read decomposePar dictionary
533         IOdictionary decomposeDict
534         (
535             IOobject
536             (
537                 "decomposeParDict",
538                 runTime.system(),
539                 mesh,
540                 IOobject::MUST_READ_IF_MODIFIED,
541                 IOobject::NO_WRITE
542             )
543         );
544         autoPtr<decompositionMethod> decomposePtr = decompositionMethod::New
545         (
546             decomposeDict
547         );
549         labelList cellToRegion
550         (
551             decomposePtr().decompose
552             (
553                 mesh,
554                 mesh.cellCentres()
555             )
556         );
558         // For debugging: write out region
559         {
560             volScalarField cellDist
561             (
562                 IOobject
563                 (
564                     "cellDist",
565                     runTime.timeName(),
566                     mesh,
567                     IOobject::NO_READ,
568                     IOobject::NO_WRITE,
569                     false
570                 ),
571                 mesh,
572                 dimensionedScalar("cellDist", dimless, 0),
573                 zeroGradientFvPatchScalarField::typeName
574             );
576             forAll(cellToRegion, cellI)
577             {
578                cellDist[cellI] = cellToRegion[cellI];
579             }
581             cellDist.write();
583             Info<< nl << "Written decomposition as volScalarField to "
584                 << cellDist.name() << " for use in postprocessing."
585                 << nl << endl;
586         }
588         // Use block based renumbering.
589         //labelList cellOrder(bandCompression(mesh.cellCells()));
590         labelList cellOrder(regionBandCompression(mesh, cellToRegion));
592         // Determine new to old face order with new cell numbering
593         labelList faceOrder
594         (
595             regionFaceOrder
596             (
597                 mesh,
598                 cellOrder,
599                 cellToRegion
600             )
601         );
603         if (!overwrite)
604         {
605             runTime++;
606         }
608         // Change the mesh.
609         map = reorderMesh(mesh, cellOrder, faceOrder);
610     }
611     else
612     {
613         // Use built-in renumbering.
615         polyTopoChange meshMod(mesh);
617         if (!overwrite)
618         {
619             runTime++;
620         }
622         // Change the mesh.
623         map = meshMod.changeMesh
624         (
625             mesh,
626             false,      // inflate
627             true,       // parallel sync
628             true,       // cell ordering
629             orderPoints // point ordering
630         );
631     }
633     // Update fields
634     mesh.updateMesh(map);
636     // Update proc maps
637     if (cellProcAddressing.headerOk())
638     {
639         Info<< "Renumbering processor cell decomposition map "
640             << cellProcAddressing.name() << endl;
642         cellProcAddressing = labelList
643         (
644             UIndirectList<label>(cellProcAddressing, map().cellMap())
645         );
646     }
647     if (faceProcAddressing.headerOk())
648     {
649         Info<< "Renumbering processor face decomposition map "
650             << faceProcAddressing.name() << endl;
652         faceProcAddressing = labelList
653         (
654             UIndirectList<label>(faceProcAddressing, map().faceMap())
655         );
656     }
657     if (pointProcAddressing.headerOk())
658     {
659         Info<< "Renumbering processor point decomposition map "
660             << pointProcAddressing.name() << endl;
662         pointProcAddressing = labelList
663         (
664             UIndirectList<label>(pointProcAddressing, map().pointMap())
665         );
666     }
669     // Move mesh (since morphing might not do this)
670     if (map().hasMotionPoints())
671     {
672         mesh.movePoints(map().preMotionPoints());
673     }
676     band = getBand(mesh.faceOwner(), mesh.faceNeighbour());
678     Info<< "Band after renumbering: "
679         << returnReduce(band, maxOp<label>()) << nl << endl;
682     if (orderPoints)
683     {
684         // Force edge calculation (since only reason that points would need to
685         // be sorted)
686         (void)mesh.edges();
688         label nTotPoints = returnReduce
689         (
690             mesh.nPoints(),
691             sumOp<label>()
692         );
693         label nTotIntPoints = returnReduce
694         (
695             mesh.nInternalPoints(),
696             sumOp<label>()
697         );
699         label nTotEdges = returnReduce
700         (
701             mesh.nEdges(),
702             sumOp<label>()
703         );
704         label nTotIntEdges = returnReduce
705         (
706             mesh.nInternalEdges(),
707             sumOp<label>()
708         );
709         label nTotInt0Edges = returnReduce
710         (
711             mesh.nInternal0Edges(),
712             sumOp<label>()
713         );
714         label nTotInt1Edges = returnReduce
715         (
716             mesh.nInternal1Edges(),
717             sumOp<label>()
718         );
720         Info<< "Points:" << nl
721             << "    total   : " << nTotPoints << nl
722             << "    internal: " << nTotIntPoints << nl
723             << "    boundary: " << nTotPoints-nTotIntPoints << nl
724             << "Edges:" << nl
725             << "    total   : " << nTotEdges << nl
726             << "    internal: " << nTotIntEdges << nl
727             << "        internal using 0 boundary points: "
728             << nTotInt0Edges << nl
729             << "        internal using 1 boundary points: "
730             << nTotInt1Edges-nTotInt0Edges << nl
731             << "        internal using 2 boundary points: "
732             << nTotIntEdges-nTotInt1Edges << nl
733             << "    boundary: " << nTotEdges-nTotIntEdges << nl
734             << endl;
735     }
738     if (overwrite)
739     {
740         mesh.setInstance(oldInstance);
741     }
743     Info<< "Writing mesh to " << mesh.facesInstance() << endl;
745     mesh.write();
746     if (cellProcAddressing.headerOk())
747     {
748         cellProcAddressing.instance() = mesh.facesInstance();
749         cellProcAddressing.write();
750     }
751     if (faceProcAddressing.headerOk())
752     {
753         faceProcAddressing.instance() = mesh.facesInstance();
754         faceProcAddressing.write();
755     }
756     if (pointProcAddressing.headerOk())
757     {
758         pointProcAddressing.instance() = mesh.facesInstance();
759         pointProcAddressing.write();
760     }
761     if (boundaryProcAddressing.headerOk())
762     {
763         boundaryProcAddressing.instance() = mesh.facesInstance();
764         boundaryProcAddressing.write();
765     }
768     if (writeMaps)
769     {
770         labelIOList
771         (
772             IOobject
773             (
774                 "cellMap",
775                 mesh.facesInstance(),
776                 polyMesh::meshSubDir,
777                 mesh,
778                 IOobject::NO_READ,
779                 IOobject::NO_WRITE,
780                 false
781             ),
782             map().cellMap()
783         ).write();
784         labelIOList
785         (
786             IOobject
787             (
788                 "faceMap",
789                 mesh.facesInstance(),
790                 polyMesh::meshSubDir,
791                 mesh,
792                 IOobject::NO_READ,
793                 IOobject::NO_WRITE,
794                 false
795             ),
796             map().faceMap()
797         ).write();
798         labelIOList
799         (
800             IOobject
801             (
802                 "pointMap",
803                 mesh.facesInstance(),
804                 polyMesh::meshSubDir,
805                 mesh,
806                 IOobject::NO_READ,
807                 IOobject::NO_WRITE,
808                 false
809             ),
810             map().pointMap()
811         ).write();
812     }
814     Info<< "\nEnd.\n" << endl;
816     return 0;
820 // ************************************************************************* //