Skip to content
Snippets Groups Projects
splitMeshRegions.C 56.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*---------------------------------------------------------------------------*\
      =========                 |
      \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
       \\    /   O peration     |
    
        \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
    
         \\/     M anipulation  |
    -------------------------------------------------------------------------------
    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 <http://www.gnu.org/licenses/>.
    
    mattijs's avatar
    mattijs committed
    Application
        splitMeshRegions
    
        Splits mesh into multiple regions.
    
        Each region is defined as a domain whose cells can all be reached by
        cell-face-cell walking without crossing
    
        - boundary faces
        - additional faces from faceset (-blockedFaces faceSet).
        - any face inbetween differing cellZones (-cellZones)
    
        Output is:
    
        - volScalarField with regions as different scalars (-detectOnly)
                or
    
        - mesh with multiple regions and mapped patches. These patches
    
          either cover the whole interface between two region (default) or
          only part according to faceZones (-useFaceZones)
                or
    
        - mesh with cells put into cellZones (-makeCellZones)
    
    
        - cellZonesOnly does not do a walk and uses the cellZones only. Use
        this if you don't mind having disconnected domains in a single region.
        This option requires all cells to be in one (and one only) cellZone.
    
        - cellZonesFileOnly behaves like -cellZonesOnly but reads the cellZones
        from the specified file. This allows one to explicitly specify the region
        distribution and still have multiple cellZones per region.
    
        - useCellZonesOnly does not do a walk and uses the cellZones only. Use
        this if you don't mind having disconnected domains in a single region.
        This option requires all cells to be in one (and one only) cellZone.
    
    
        - prefixRegion prefixes all normal patches with region name (interface
        (patches already have region name prefix)
    
        - Should work in parallel.
        cellZones can differ on either side of processor boundaries in which case
    
        the faces get moved from processor patch to directMapped patch. Not
    
        the faces get moved from processor patch to mapped patch. Not
    
        - If a cell zone gets split into more than one region it can detect
        the largest matching region (-sloppyCellZones). This will accept any
        region that covers more than 50% of the zone. It has to be a subset
        so cannot have any cells in any other zone.
    
        - If explicitly a single region has been selected (-largestOnly or
          -insidePoint) its region name will be either
            - name of a cellZone it matches to or
            - "largestOnly" respectively "insidePoint" or
            - polyMesh::defaultRegion if additionally -overwrite
              (so it will overwrite the input mesh!)
    
    
    mattijs's avatar
    mattijs committed
        - writes maps like decomposePar back to original mesh:
            - pointRegionAddressing : for every point in this region the point in
            the original mesh
            - cellRegionAddressing  :   ,,      cell                ,,  cell    ,,
            - faceRegionAddressing  :   ,,      face                ,,  face in
            the original mesh + 'turning index'. For a face in the same orientation
            this is the original facelabel+1, for a turned face this is -facelabel-1
    
            - boundaryRegionAddressing : for every patch in this region the
            patch in the original mesh (or -1 if added patch)
    
    \*---------------------------------------------------------------------------*/
    
    #include "SortableList.H"
    #include "argList.H"
    #include "regionSplit.H"
    #include "fvMeshSubset.H"
    #include "IOobjectList.H"
    #include "volFields.H"
    #include "faceSet.H"
    #include "cellSet.H"
    #include "polyTopoChange.H"
    #include "removeCells.H"
    #include "EdgeMap.H"
    #include "syncTools.H"
    #include "ReadFields.H"
    
    #include "mappedWallPolyPatch.H"
    
    #include "zeroGradientFvPatchFields.H"
    
    
    using namespace Foam;
    
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    
    
    // Prepend prefix to selected patches.
    void renamePatches
    (
        fvMesh& mesh,
        const word& prefix,
        const labelList& patchesToRename
    )
    {
        polyBoundaryMesh& polyPatches =
            const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
        forAll(patchesToRename, i)
        {
    
            label patchi = patchesToRename[i];
            polyPatch& pp = polyPatches[patchi];
    
                WarningInFunction
                    << "Encountered coupled patch " << pp.name()
    
                    << ". Will only rename the patch itself,"
                    << " not any referred patches."
                    << " This might have to be done by hand."
                    << endl;
            }
    
            pp.name() = prefix + '_' + pp.name();
        }
        // Recalculate any demand driven data (e.g. group to name lookup)
        polyPatches.updateMesh();
    }
    
    
    
    template<class GeoField>
    void subsetVolFields
    (
        const fvMesh& mesh,
        const fvMesh& subMesh,
        const labelList& cellMap,
    
        const labelList& faceMap,
        const labelHashSet& addedPatches
    
    )
    {
        const labelList patchMap(identity(mesh.boundaryMesh().size()));
    
        HashTable<const GeoField*> fields
        (
            mesh.objectRegistry::lookupClass<GeoField>()
        );
        forAllConstIter(typename HashTable<const GeoField*>, fields, iter)
        {
            const GeoField& fld = *iter();
    
            Info<< "Mapping field " << fld.name() << endl;
    
            tmp<GeoField> tSubFld
            (
                fvMeshSubset::interpolate
                (
                    fld,
                    subMesh,
                    patchMap,
                    cellMap,
                    faceMap
                )
            );
    
            // Hack: set value to 0 for introduced patches (since don't
            //       get initialised.
    
            forAll(tSubFld().boundaryField(), patchi)
    
                if (addedPatches.found(patchi))
    
                    tSubFld.ref().boundaryFieldRef()[patchi] ==
    
                }
            }
    
            // Store on subMesh
            GeoField* subFld = tSubFld.ptr();
            subFld->rename(fld.name());
            subFld->writeOpt() = IOobject::AUTO_WRITE;
            subFld->store();
        }
    }
    
    
    template<class GeoField>
    void subsetSurfaceFields
    (
        const fvMesh& mesh,
        const fvMesh& subMesh,
    
        const labelList& cellMap,
    
        const labelList& faceMap,
        const labelHashSet& addedPatches
    
    )
    {
        const labelList patchMap(identity(mesh.boundaryMesh().size()));
    
        HashTable<const GeoField*> fields
        (
            mesh.objectRegistry::lookupClass<GeoField>()
        );
        forAllConstIter(typename HashTable<const GeoField*>, fields, iter)
        {
            const GeoField& fld = *iter();
    
            Info<< "Mapping field " << fld.name() << endl;
    
            tmp<GeoField> tSubFld
            (
                fvMeshSubset::interpolate
                (
                    fld,
                    subMesh,
                    patchMap,
    
                    faceMap
                )
            );
    
            // Hack: set value to 0 for introduced patches (since don't
            //       get initialised.
    
            forAll(tSubFld().boundaryField(), patchi)
    
                if (addedPatches.found(patchi))
    
                    tSubFld.ref().boundaryFieldRef()[patchi] ==
    
                }
            }
    
            // Store on subMesh
            GeoField* subFld = tSubFld.ptr();
            subFld->rename(fld.name());
            subFld->writeOpt() = IOobject::AUTO_WRITE;
            subFld->store();
        }
    }
    
    // Select all cells not in the region
    labelList getNonRegionCells(const labelList& cellRegion, const label regionI)
    {
        DynamicList<label> nonRegionCells(cellRegion.size());
    
        forAll(cellRegion, celli)
    
            if (cellRegion[celli] != regionI)
    
                nonRegionCells.append(celli);
    
    void addToInterface
    (
        const polyMesh& mesh,
        const label zoneID,
        const label ownRegion,
        const label neiRegion,
    
    )
    {
        edge interface
        (
            min(ownRegion, neiRegion),
            max(ownRegion, neiRegion)
        );
    
    
        EdgeMap<Map<label>>::iterator iter = regionsToSize.find
    
        (
            interface
        );
    
        if (iter != regionsToSize.end())
        {
            // Check if zone present
            Map<label>::iterator zoneFnd = iter().find(zoneID);
            if (zoneFnd != iter().end())
            {
                // Found zone. Increment count.
                zoneFnd()++;
            }
            else
            {
                // New or no zone. Insert with count 1.
                iter().insert(zoneID, 1);
            }
        }
        else
        {
            // Create new interface of size 1.
            Map<label> zoneToSize;
            zoneToSize.insert(zoneID, 1);
            regionsToSize.insert(interface, zoneToSize);
        }
    }
    
    
    // Get region-region interface name and sizes.
    
    mattijs's avatar
    mattijs committed
    // Returns interfaces as straight list for looping in identical order.
    void getInterfaceSizes
    
    (
        const polyMesh& mesh,
    
        const labelList& cellRegion,
    
    mattijs's avatar
    mattijs committed
    
        edgeList& interfaces,
    
        labelList& interfaceSizes,
        labelList& faceToInterface
    
        // From region-region to faceZone (or -1) to number of faces.
    
    
    
        // Internal faces
        // ~~~~~~~~~~~~~~
    
    
        forAll(mesh.faceNeighbour(), facei)
    
            label ownRegion = cellRegion[mesh.faceOwner()[facei]];
            label neiRegion = cellRegion[mesh.faceNeighbour()[facei]];
    
    
            if (ownRegion != neiRegion)
            {
    
                    (useFaceZones ? mesh.faceZones().whichZone(facei) : -1),
    
        // Boundary faces
        // ~~~~~~~~~~~~~~
    
        // Neighbour cellRegion.
        labelList coupledRegion(mesh.nFaces()-mesh.nInternalFaces());
    
        forAll(coupledRegion, i)
        {
    
            label celli = mesh.faceOwner()[i+mesh.nInternalFaces()];
            coupledRegion[i] = cellRegion[celli];
    
        syncTools::swapBoundaryFaceList(mesh, coupledRegion);
    
    
        forAll(coupledRegion, i)
        {
    
            label facei = i+mesh.nInternalFaces();
            label ownRegion = cellRegion[mesh.faceOwner()[facei]];
    
            label neiRegion = coupledRegion[i];
    
            if (ownRegion != neiRegion)
            {
    
                    (useFaceZones ? mesh.faceZones().whichZone(facei) : -1),
    
        {
            if (Pstream::master())
            {
                // Receive and add to my sizes
                for
                (
                    int slave=Pstream::firstSlave();
                    slave<=Pstream::lastSlave();
                    slave++
                )
                {
    
                    IPstream fromSlave(Pstream::commsTypes::blocking, slave);
    
                    forAllConstIter(EdgeMap<Map<label>>, slaveSizes, slaveIter)
    
                            regionsToSize.find(slaveIter.key());
    
                        if (masterIter != regionsToSize.end())
    
                            // Same inter-region
                            const Map<label>& slaveInfo = slaveIter();
                            Map<label>& masterInfo = masterIter();
    
                            forAllConstIter(Map<label>, slaveInfo, iter)
                            {
                                label zoneID = iter.key();
                                label slaveSize = iter();
    
                                Map<label>::iterator zoneFnd = masterInfo.find
                                (
                                    zoneID
                                );
                                if (zoneFnd != masterInfo.end())
                                {
                                    zoneFnd() += slaveSize;
                                }
                                else
                                {
                                    masterInfo.insert(zoneID, slaveSize);
                                }
                            }
    
                            regionsToSize.insert(slaveIter.key(), slaveIter());
    
                    OPstream toMaster
                    (
                        Pstream::commsTypes::blocking,
                        Pstream::masterNo()
                    );
    
    andy's avatar
    andy committed
        // Rework
    
    
        Pstream::scatter(regionsToSize);
    
    
    
        // Now we have the global sizes of all inter-regions.
        // Invert this on master and distribute.
        label nInterfaces = 0;
    
        forAllConstIter(EdgeMap<Map<label>>, regionsToSize, iter)
    
        {
            const Map<label>& info = iter();
            nInterfaces += info.size();
        }
    
        interfaces.setSize(nInterfaces);
        interfaceNames.setSize(nInterfaces);
        interfaceSizes.setSize(nInterfaces);
    
        EdgeMap<Map<label>> regionsToInterface(nInterfaces);
    
        forAllConstIter(EdgeMap<Map<label>>, regionsToSize, iter)
    
        {
            const edge& e = iter.key();
            const word& name0 = regionNames[e[0]];
            const word& name1 = regionNames[e[1]];
    
            const Map<label>& info = iter();
            forAllConstIter(Map<label>, info, infoIter)
            {
                interfaces[nInterfaces] = iter.key();
                label zoneID = infoIter.key();
                if (zoneID == -1)
    
                    interfaceNames[nInterfaces] = Pair<word>
                    (
                        name0 + "_to_" + name1,
                        name1 + "_to_" + name0
                    );
    
                else
                {
                    const word& zoneName = mesh.faceZones()[zoneID].name();
                    interfaceNames[nInterfaces] = Pair<word>
                    (
                        zoneName + "_" + name0 + "_to_" + name1,
                        zoneName + "_" + name1 + "_to_" + name0
                    );
                }
                interfaceSizes[nInterfaces] = infoIter();
    
    
    mattijs's avatar
    mattijs committed
                if (regionsToInterface.found(e))
                {
                    regionsToInterface[e].insert(zoneID, nInterfaces);
                }
                else
                {
                    Map<label> zoneAndInterface;
                    zoneAndInterface.insert(zoneID, nInterfaces);
                    regionsToInterface.insert(e, zoneAndInterface);
                }
    
    
        // Now all processor have consistent interface information
    
        Pstream::scatter(interfaces);
        Pstream::scatter(interfaceNames);
        Pstream::scatter(interfaceSizes);
        Pstream::scatter(regionsToInterface);
    
        // Mark all inter-region faces.
        faceToInterface.setSize(mesh.nFaces(), -1);
    
    
        forAll(mesh.faceNeighbour(), facei)
    
    mattijs's avatar
    mattijs committed
        {
    
            label ownRegion = cellRegion[mesh.faceOwner()[facei]];
            label neiRegion = cellRegion[mesh.faceNeighbour()[facei]];
    
    
            if (ownRegion != neiRegion)
            {
                label zoneID = -1;
                if (useFaceZones)
                {
    
                    zoneID = mesh.faceZones().whichZone(facei);
    
                }
    
                edge interface
                (
                    min(ownRegion, neiRegion),
                    max(ownRegion, neiRegion)
                );
    
    
                faceToInterface[facei] = regionsToInterface[interface][zoneID];
    
            label facei = i+mesh.nInternalFaces();
            label ownRegion = cellRegion[mesh.faceOwner()[facei]];
    
            label neiRegion = coupledRegion[i];
    
            if (ownRegion != neiRegion)
            {
                label zoneID = -1;
                if (useFaceZones)
                {
    
                    zoneID = mesh.faceZones().whichZone(facei);
    
                }
    
                edge interface
                (
                    min(ownRegion, neiRegion),
                    max(ownRegion, neiRegion)
                );
    
    
                faceToInterface[facei] = regionsToInterface[interface][zoneID];
    
    mattijs's avatar
    mattijs committed
        }
    
    }
    
    
    // Create mesh for region.
    autoPtr<mapPolyMesh> createRegionMesh
    (
        const fvMesh& mesh,
    
        // Region info
        const labelList& cellRegion,
    
        const label regionI,
        const word& regionName,
    
        // Interface info
        const labelList& interfacePatches,
        const labelList& faceToInterface,
    
    
        autoPtr<fvMesh>& newMesh
    )
    {
        // Create dummy system/fv*
        {
            IOobject io
            (
                "fvSchemes",
                mesh.time().system(),
                regionName,
    
    mattijs's avatar
    mattijs committed
                mesh,
    
                IOobject::NO_READ,
                IOobject::NO_WRITE,
                false
            );
    
            Info<< "Testing:" << io.objectPath() << endl;
    
            if (!io.headerOk())
    
            // if (!exists(io.objectPath()))
    
            {
                Info<< "Writing dummy " << regionName/io.name() << endl;
                dictionary dummyDict;
                dictionary divDict;
                dummyDict.add("divSchemes", divDict);
                dictionary gradDict;
                dummyDict.add("gradSchemes", gradDict);
                dictionary laplDict;
                dummyDict.add("laplacianSchemes", laplDict);
    
                IOdictionary(io, dummyDict).regIOobject::write();
            }
        }
        {
            IOobject io
            (
                "fvSolution",
                mesh.time().system(),
                regionName,
    
    mattijs's avatar
    mattijs committed
                mesh,
    
                IOobject::NO_READ,
                IOobject::NO_WRITE,
                false
            );
    
            if (!io.headerOk())
            //if (!exists(io.objectPath()))
            {
                Info<< "Writing dummy " << regionName/io.name() << endl;
                dictionary dummyDict;
                IOdictionary(io, dummyDict).regIOobject::write();
            }
        }
    
    
    
        // Neighbour cellRegion.
        labelList coupledRegion(mesh.nFaces()-mesh.nInternalFaces());
    
        forAll(coupledRegion, i)
        {
    
            label celli = mesh.faceOwner()[i+mesh.nInternalFaces()];
            coupledRegion[i] = cellRegion[celli];
    
        syncTools::swapBoundaryFaceList(mesh, coupledRegion);
    
        // Topology change container. Start off from existing mesh.
        polyTopoChange meshMod(mesh);
    
        // Cell remover engine
        removeCells cellRemover(mesh);
    
        // Select all but region cells
        labelList cellsToRemove(getNonRegionCells(cellRegion, regionI));
    
        // Find out which faces will get exposed. Note that this
        // gets faces in mesh face order. So both regions will get same
        // face in same order (important!)
        labelList exposedFaces = cellRemover.getExposedFaces(cellsToRemove);
    
        labelList exposedPatchIDs(exposedFaces.size());
        forAll(exposedFaces, i)
        {
    
            label facei = exposedFaces[i];
            label interfacei = faceToInterface[facei];
    
            label ownRegion = cellRegion[mesh.faceOwner()[facei]];
    
            label neiRegion = -1;
    
    
            if (mesh.isInternalFace(facei))
    
                neiRegion = cellRegion[mesh.faceNeighbour()[facei]];
    
                neiRegion = coupledRegion[facei-mesh.nInternalFaces()];
    
    
            // Check which side is being kept - determines which of the two
            // patches will be used.
    
    
            label otherRegion = -1;
    
            if (ownRegion == regionI && neiRegion != regionI)
            {
                otherRegion = neiRegion;
            }
            else if (ownRegion != regionI && neiRegion == regionI)
            {
                otherRegion = ownRegion;
            }
            else
            {
    
                    << "Exposed face:" << facei
                    << " fc:" << mesh.faceCentres()[facei]
    
                    << " has owner region " << ownRegion
                    << " and neighbour region " << neiRegion
                    << " when handling region:" << regionI
                    << exit(FatalError);
            }
    
    
            // Find the patch.
            if (regionI < otherRegion)
    
                exposedPatchIDs[i] = interfacePatches[interfacei];
    
                exposedPatchIDs[i] = interfacePatches[interfacei]+1;
    
    Andrew Heather's avatar
    Andrew Heather committed
            }
    
        }
    
        // Remove faces
        cellRemover.setRefinement
        (
            cellsToRemove,
            exposedFaces,
            exposedPatchIDs,
            meshMod
        );
    
        autoPtr<mapPolyMesh> map = meshMod.makeMesh
        (
            newMesh,
            IOobject
            (
                regionName,
                mesh.time().timeName(),
                mesh.time(),
                IOobject::NO_READ,
                IOobject::AUTO_WRITE
            ),
            mesh
        );
    
        return map;
    }
    
    
    void createAndWriteRegion
    (
        const fvMesh& mesh,
    
        const labelList& cellRegion,
    
        const wordList& regionNames,
    
        const labelList& faceToInterface,
        const labelList& interfacePatches,
    
    mattijs's avatar
    mattijs committed
        const label regionI,
        const word& newMeshInstance
    
    )
    {
        Info<< "Creating mesh for region " << regionI
            << ' ' << regionNames[regionI] << endl;
    
        autoPtr<fvMesh> newMesh;
        autoPtr<mapPolyMesh> map = createRegionMesh
        (
            mesh,
    
            regionI,
            regionNames[regionI],
    
    
        // Make map of all added patches
    
        labelHashSet addedPatches(2*interfacePatches.size());
    
        forAll(interfacePatches, interfacei)
    
            addedPatches.insert(interfacePatches[interfacei]);
            addedPatches.insert(interfacePatches[interfacei]+1);
    
        Info<< "Mapping fields" << endl;
    
        // Map existing fields
        newMesh().updateMesh(map());
    
        // Add subsetted fields
        subsetVolFields<volScalarField>
        (
            mesh,
            newMesh(),
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
        subsetVolFields<volVectorField>
        (
            mesh,
            newMesh(),
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
        subsetVolFields<volSphericalTensorField>
        (
            mesh,
            newMesh(),
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
        subsetVolFields<volSymmTensorField>
        (
            mesh,
            newMesh(),
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
        subsetVolFields<volTensorField>
        (
            mesh,
            newMesh(),
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
    
        subsetSurfaceFields<surfaceScalarField>
        (
            mesh,
            newMesh(),
    
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
        subsetSurfaceFields<surfaceVectorField>
        (
            mesh,
            newMesh(),
    
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
        subsetSurfaceFields<surfaceSphericalTensorField>
        (
            mesh,
            newMesh(),
    
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
        subsetSurfaceFields<surfaceSymmTensorField>
        (
            mesh,
            newMesh(),
    
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
        subsetSurfaceFields<surfaceTensorField>
        (
            mesh,
            newMesh(),
    
            map().cellMap(),
    
            map().faceMap(),
            addedPatches
    
        );
    
    
        const polyBoundaryMesh& newPatches = newMesh().boundaryMesh();
    
    mattijs's avatar
    mattijs committed
        newPatches.checkParallelSync(true);
    
    
        // Delete empty patches
        // ~~~~~~~~~~~~~~~~~~~~
    
        // Create reordering list to move patches-to-be-deleted to end
        labelList oldToNew(newPatches.size(), -1);
    
        DynamicList<label> sharedPatches(newPatches.size());
    
        label newI = 0;
    
        Info<< "Deleting empty patches" << endl;
    
        // Assumes all non-proc boundaries are on all processors!
    
        forAll(newPatches, patchi)
    
            const polyPatch& pp = newPatches[patchi];
    
    mattijs's avatar
    mattijs committed
            if (!isA<processorPolyPatch>(pp))
    
    mattijs's avatar
    mattijs committed
                if (returnReduce(pp.size(), sumOp<label>()) > 0)
                {
    
                    oldToNew[patchi] = newI;
                    if (!addedPatches.found(patchi))
    
                    {
                        sharedPatches.append(newI);
                    }
                    newI++;
    
    mattijs's avatar
    mattijs committed
                }
    
            }
        }
    
        // Same for processor patches (but need no reduction)
    
        forAll(newPatches, patchi)
    
            const polyPatch& pp = newPatches[patchi];
    
            if (isA<processorPolyPatch>(pp) && pp.size())
    
                oldToNew[patchi] = newI++;
    
            }
        }
    
        const label nNewPatches = newI;
    
        // Move all deleteable patches to the end
    
        forAll(oldToNew, patchi)
    
            if (oldToNew[patchi] == -1)
    
                oldToNew[patchi] = newI++;
    
        //reorderPatches(newMesh(), oldToNew, nNewPatches);
        fvMeshTools::reorderPatches(newMesh(), oldToNew, nNewPatches, true);
    
        // Rename shared patches with region name
        if (prefixRegion)
        {
            Info<< "Prefixing patches with region name" << endl;
    
            renamePatches(newMesh(), regionNames[regionI], sharedPatches);
        }
    
    
    
        Info<< "Writing new mesh" << endl;
    
    
    mattijs's avatar
    mattijs committed
        newMesh().setInstance(newMeshInstance);
    
        newMesh().write();
    
        // Write addressing files like decomposePar
        Info<< "Writing addressing to base mesh" << endl;
    
        labelIOList pointProcAddressing
        (
            IOobject
            (
                "pointRegionAddressing",
                newMesh().facesInstance(),
                newMesh().meshSubDir,
                newMesh(),
                IOobject::NO_READ,
                IOobject::NO_WRITE,
                false
            ),
            map().pointMap()
        );
        Info<< "Writing map " << pointProcAddressing.name()
            << " from region" << regionI
            << " points back to base mesh." << endl;
        pointProcAddressing.write();
    
        labelIOList faceProcAddressing
        (
            IOobject
            (
                "faceRegionAddressing",
                newMesh().facesInstance(),
                newMesh().meshSubDir,
                newMesh(),
                IOobject::NO_READ,
                IOobject::NO_WRITE,
                false
            ),
            newMesh().nFaces()
        );
    
        forAll(faceProcAddressing, facei)
    
        {
            // face + turning index. (see decomposePar)
            // Is the face pointing in the same direction?
    
            label oldFacei = map().faceMap()[facei];
    
                map().cellMap()[newMesh().faceOwner()[facei]]
    
             == mesh.faceOwner()[oldFacei]
    
                faceProcAddressing[facei] = oldFacei+1;
    
                faceProcAddressing[facei] = -(oldFacei+1);