/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . Application renumberMesh Group grpMeshManipulationUtilities Description Renumbers the cell list in order to reduce the bandwidth, reading and renumbering all fields from all the time directories. By default uses bandCompression (CuthillMcKee) but will read system/renumberMeshDict if -dict option is present \*---------------------------------------------------------------------------*/ #include "argList.H" #include "IOobjectList.H" #include "fvMesh.H" #include "polyTopoChange.H" #include "ReadFields.H" #include "volFields.H" #include "surfaceFields.H" #include "SortableList.H" #include "decompositionMethod.H" #include "renumberMethod.H" #include "zeroGradientFvPatchFields.H" #include "CuthillMcKeeRenumber.H" #include "fvMeshSubset.H" #include "cellSet.H" #include "faceSet.H" #include "pointSet.H" #include "processorMeshes.H" #include "hexRef8.H" #ifdef FOAM_USE_ZOLTAN #include "zoltanRenumber.H" #endif using namespace Foam; // Create named field from labelList for postprocessing tmp createScalarField ( const fvMesh& mesh, const word& name, const labelList& elems ) { tmp tfld ( new volScalarField ( IOobject ( name, mesh.time().timeName(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE, false ), mesh, dimensionedScalar("zero", dimless, 0), zeroGradientFvPatchScalarField::typeName ) ); volScalarField& fld = tfld.ref(); forAll(fld, celli) { fld[celli] = elems[celli]; } return tfld; } // Calculate band of matrix label getBand(const labelList& owner, const labelList& neighbour) { label band = 0; forAll(neighbour, facei) { label diff = neighbour[facei] - owner[facei]; if (diff > band) { band = diff; } } return band; } // Calculate band of matrix void getBand ( const bool calculateIntersect, const label nCells, const labelList& owner, const labelList& neighbour, label& bandwidth, scalar& profile, // scalar to avoid overflow scalar& sumSqrIntersect // scalar to avoid overflow ) { labelList cellBandwidth(nCells, 0); scalarField nIntersect(nCells, 0.0); forAll(neighbour, facei) { label own = owner[facei]; label nei = neighbour[facei]; // Note: mag not necessary for correct (upper-triangular) ordering. label diff = nei-own; cellBandwidth[nei] = max(cellBandwidth[nei], diff); } bandwidth = max(cellBandwidth); // Do not use field algebra because of conversion label to scalar profile = 0.0; forAll(cellBandwidth, celli) { profile += 1.0*cellBandwidth[celli]; } sumSqrIntersect = 0.0; if (calculateIntersect) { forAll(nIntersect, celli) { for (label colI = celli-cellBandwidth[celli]; colI <= celli; colI++) { nIntersect[colI] += 1.0; } } sumSqrIntersect = sum(Foam::sqr(nIntersect)); } } // Determine upper-triangular face order labelList getFaceOrder ( const primitiveMesh& mesh, const labelList& cellOrder // New to old cell ) { labelList reverseCellOrder(invert(cellOrder.size(), cellOrder)); labelList oldToNewFace(mesh.nFaces(), -1); label newFacei = 0; labelList nbr; labelList order; forAll(cellOrder, newCelli) { label oldCelli = cellOrder[newCelli]; const cell& cFaces = mesh.cells()[oldCelli]; // Neighbouring cells nbr.setSize(cFaces.size()); forAll(cFaces, i) { label facei = cFaces[i]; if (mesh.isInternalFace(facei)) { // Internal face. Get cell on other side. label nbrCelli = reverseCellOrder[mesh.faceNeighbour()[facei]]; if (nbrCelli == newCelli) { nbrCelli = reverseCellOrder[mesh.faceOwner()[facei]]; } if (newCelli < nbrCelli) { // Celli is master nbr[i] = nbrCelli; } else { // nbrCell is master. Let it handle this face. nbr[i] = -1; } } else { // External face. Do later. nbr[i] = -1; } } order.setSize(nbr.size()); sortedOrder(nbr, order); forAll(order, i) { label index = order[i]; if (nbr[index] != -1) { oldToNewFace[cFaces[index]] = newFacei++; } } } // Leave patch faces intact. for (label facei = newFacei; facei < mesh.nFaces(); facei++) { oldToNewFace[facei] = facei; } // Check done all faces. forAll(oldToNewFace, facei) { if (oldToNewFace[facei] == -1) { FatalErrorInFunction << "Did not determine new position" << " for face " << facei << abort(FatalError); } } return invert(mesh.nFaces(), oldToNewFace); } // Determine face order such that inside region faces are sorted // upper-triangular but inbetween region faces are handled like boundary faces. labelList getRegionFaceOrder ( const primitiveMesh& mesh, const labelList& cellOrder, // New to old cell const labelList& cellToRegion // Old cell to region ) { labelList reverseCellOrder(invert(cellOrder.size(), cellOrder)); labelList oldToNewFace(mesh.nFaces(), -1); label newFacei = 0; label prevRegion = -1; forAll(cellOrder, newCelli) { label oldCelli = cellOrder[newCelli]; if (cellToRegion[oldCelli] != prevRegion) { prevRegion = cellToRegion[oldCelli]; } const cell& cFaces = mesh.cells()[oldCelli]; SortableList