Skip to content
Snippets Groups Projects
autoLayerDriver.C 127 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*---------------------------------------------------------------------------*\
      =========                 |
      \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
       \\    /   O peration     |
    
    mattijs's avatar
    mattijs committed
        \\  /    A nd           | Copyright (C) 2011-2014 OpenFOAM Foundation
    
         \\/     M anipulation  | Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
    
    
    Description
        All to do with adding cell layers
    
    \*----------------------------------------------------------------------------*/
    
    #include "autoLayerDriver.H"
    #include "fvMesh.H"
    #include "Time.H"
    #include "meshRefinement.H"
    #include "removePoints.H"
    #include "pointFields.H"
    #include "motionSmoother.H"
    
    #include "unitConversion.H"
    
    #include "pointSet.H"
    #include "faceSet.H"
    #include "cellSet.H"
    #include "polyTopoChange.H"
    #include "mapPolyMesh.H"
    #include "addPatchCellLayer.H"
    #include "mapDistributePolyMesh.H"
    
    #include "OBJstream.H"
    
    #include "layerParameters.H"
    #include "combineFaces.H"
    
    #include "IOmanip.H"
    
    #include "DynamicField.H"
    
    #include "PatchTools.H"
    
    #include "slipPointPatchFields.H"
    #include "fixedValuePointPatchFields.H"
    
    #include "zeroFixedValuePointPatchFields.H"
    
    #include "calculatedPointPatchFields.H"
    #include "cyclicSlipPointPatchFields.H"
    
    #include "fixedValueFvPatchFields.H"
    
    #include "localPointRegion.H"
    
    #include "externalDisplacementMeshMover.H"
    #include "scalarIOField.H"
    
    
    // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
    
    namespace Foam
    {
    
    defineTypeNameAndDebug(autoLayerDriver, 0);
    
    } // End namespace Foam
    
    
    // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
    
    // For debugging: Dump displacement to .obj files
    void Foam::autoLayerDriver::dumpDisplacement
    (
        const fileName& prefix,
        const indirectPrimitivePatch& pp,
        const vectorField& patchDisp,
        const List<extrudeMode>& extrudeStatus
    )
    {
    
        OBJstream dispStr(prefix + "_disp.obj");
    
        Info<< "Writing all displacements to " << dispStr.name() << endl;
    
    
        forAll(patchDisp, patchPointI)
        {
            const point& pt = pp.localPoints()[patchPointI];
    
            dispStr.write(linePointRef(pt, pt + patchDisp[patchPointI]));
    
        OBJstream illStr(prefix + "_illegal.obj");
    
        Info<< "Writing invalid displacements to " << illStr.name() << endl;
    
    
        forAll(patchDisp, patchPointI)
        {
            if (extrudeStatus[patchPointI] != EXTRUDE)
            {
                const point& pt = pp.localPoints()[patchPointI];
    
                illStr.write(linePointRef(pt, pt + patchDisp[patchPointI]));
    
    Foam::tmp<Foam::scalarField> Foam::autoLayerDriver::avgPointData
    (
        const indirectPrimitivePatch& pp,
        const scalarField& pointFld
    )
    {
        tmp<scalarField> tfaceFld(new scalarField(pp.size(), 0.0));
        scalarField& faceFld = tfaceFld();
    
        forAll(pp.localFaces(), faceI)
        {
            const face& f = pp.localFaces()[faceI];
            if (f.size())
            {
                forAll(f, fp)
                {
                    faceFld[faceI] += pointFld[f[fp]];
                }
                faceFld[faceI] /= f.size();
            }
        }
        return tfaceFld;
    }
    
    
    
    // Check that primitivePatch is not multiply connected. Collect non-manifold
    // points in pointSet.
    void Foam::autoLayerDriver::checkManifold
    (
        const indirectPrimitivePatch& fp,
        pointSet& nonManifoldPoints
    )
    {
        // Check for non-manifold points (surface pinched at point)
        fp.checkPointManifold(false, &nonManifoldPoints);
    
        // Check for edge-faces (surface pinched at edge)
        const labelListList& edgeFaces = fp.edgeFaces();
    
        forAll(edgeFaces, edgeI)
        {
            const labelList& eFaces = edgeFaces[edgeI];
    
            if (eFaces.size() > 2)
            {
                const edge& e = fp.edges()[edgeI];
    
                nonManifoldPoints.insert(fp.meshPoints()[e[0]]);
                nonManifoldPoints.insert(fp.meshPoints()[e[1]]);
            }
        }
    }
    
    
    void Foam::autoLayerDriver::checkMeshManifold() const
    {
        const fvMesh& mesh = meshRefiner_.mesh();
    
        Info<< nl << "Checking mesh manifoldness ..." << endl;
    
        // Get all outside faces
        labelList outsideFaces(mesh.nFaces() - mesh.nInternalFaces());
    
        for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
        {
             outsideFaces[faceI - mesh.nInternalFaces()] = faceI;
        }
    
        pointSet nonManifoldPoints
        (
            mesh,
            "nonManifoldPoints",
            mesh.nPoints() / 100
        );
    
        // Build primitivePatch out of faces and check it for problems.
        checkManifold
        (
            indirectPrimitivePatch
            (
                IndirectList<face>(mesh.faces(), outsideFaces),
                mesh.points()
            ),
            nonManifoldPoints
        );
    
        label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
    
        if (nNonManif > 0)
        {
            Info<< "Outside of mesh is multiply connected across edges or"
                << " points." << nl
                << "This is not a fatal error but might cause some unexpected"
                << " behaviour." << nl
    
                //<< "Writing " << nNonManif
                //<< " points where this happens to pointSet "
                //<< nonManifoldPoints.name()
                << endl;
    
            //nonManifoldPoints.instance() = meshRefiner_.timeName();
            //nonManifoldPoints.write();
    
        }
        Info<< endl;
    }
    
    
    
    // Unset extrusion on point. Returns true if anything unset.
    bool Foam::autoLayerDriver::unmarkExtrusion
    (
        const label patchPointI,
        pointField& patchDisp,
        labelList& patchNLayers,
        List<extrudeMode>& extrudeStatus
    )
    {
        if (extrudeStatus[patchPointI] == EXTRUDE)
        {
            extrudeStatus[patchPointI] = NOEXTRUDE;
            patchNLayers[patchPointI] = 0;
            patchDisp[patchPointI] = vector::zero;
            return true;
        }
        else if (extrudeStatus[patchPointI] == EXTRUDEREMOVE)
        {
            extrudeStatus[patchPointI] = NOEXTRUDE;
            patchNLayers[patchPointI] = 0;
            patchDisp[patchPointI] = vector::zero;
            return true;
        }
        else
        {
            return false;
        }
    }
    
    
    // Unset extrusion on face. Returns true if anything unset.
    bool Foam::autoLayerDriver::unmarkExtrusion
    (
        const face& localFace,
        pointField& patchDisp,
        labelList& patchNLayers,
        List<extrudeMode>& extrudeStatus
    )
    {
        bool unextruded = false;
    
        forAll(localFace, fp)
        {
            if
            (
                unmarkExtrusion
                (
                    localFace[fp],
                    patchDisp,
                    patchNLayers,
                    extrudeStatus
                )
            )
            {
                unextruded = true;
            }
        }
        return unextruded;
    }
    
    
    // No extrusion at non-manifold points.
    void Foam::autoLayerDriver::handleNonManifolds
    (
        const indirectPrimitivePatch& pp,
        const labelList& meshEdges,
    
        const labelListList& edgeGlobalFaces,
    
        pointField& patchDisp,
        labelList& patchNLayers,
        List<extrudeMode>& extrudeStatus
    ) const
    {
        const fvMesh& mesh = meshRefiner_.mesh();
    
        Info<< nl << "Handling non-manifold points ..." << endl;
    
        // Detect non-manifold points
        Info<< nl << "Checking patch manifoldness ..." << endl;
    
        pointSet nonManifoldPoints(mesh, "nonManifoldPoints", pp.nPoints());
    
        // 1. Local check
        checkManifold(pp, nonManifoldPoints);
    
    
        // 2. Remote check for boundary edges on coupled boundaries
        forAll(edgeGlobalFaces, edgeI)
        {
            if
            (
                pp.edgeFaces()[edgeI].size() == 1
             && edgeGlobalFaces[edgeI].size() > 2
            )
            {
                // So boundary edges that are connected to more than 2 processors
                // i.e. a non-manifold edge which is exactly on a processor
                // boundary.
                const edge& e = pp.edges()[edgeI];
                nonManifoldPoints.insert(pp.meshPoints()[e[0]]);
                nonManifoldPoints.insert(pp.meshPoints()[e[1]]);
            }
        }
    
    
        // 3. Remote check for end of layer across coupled boundaries
        {
            PackedBoolList isCoupledEdge(mesh.nEdges());
    
            const labelList& cpEdges = mesh.globalData().coupledPatchMeshEdges();
            forAll(cpEdges, i)
            {
                isCoupledEdge[cpEdges[i]] = true;
            }
            syncTools::syncEdgeList
            (
                mesh,
                isCoupledEdge,
                orEqOp<unsigned int>(),
                0
            );
    
            forAll(edgeGlobalFaces, edgeI)
            {
                label meshEdgeI = meshEdges[edgeI];
    
                if
                (
                    pp.edgeFaces()[edgeI].size() == 1
                 && edgeGlobalFaces[edgeI].size() == 1
                 && isCoupledEdge[meshEdgeI]
                )
                {
                    // Edge of patch but no continuation across processor.
                    const edge& e = pp.edges()[edgeI];
                    //Pout<< "** Stopping extrusion on edge "
                    //    << pp.localPoints()[e[0]]
                    //    << pp.localPoints()[e[1]] << endl;
                    nonManifoldPoints.insert(pp.meshPoints()[e[0]]);
                    nonManifoldPoints.insert(pp.meshPoints()[e[1]]);
                }
            }
        }
    
    
    
        label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
    
        Info<< "Outside of local patch is multiply connected across edges or"
            << " points at " << nNonManif << " points." << endl;
    
    
        if (nNonManif > 0)
        {
            const labelList& meshPoints = pp.meshPoints();
    
            forAll(meshPoints, patchPointI)
            {
                if (nonManifoldPoints.found(meshPoints[patchPointI]))
                {
                    unmarkExtrusion
                    (
                        patchPointI,
                        patchDisp,
                        patchNLayers,
                        extrudeStatus
                    );
                }
            }
        }
    
    
        Info<< "Set displacement to zero for all " << nNonManif
            << " non-manifold points" << endl;
    }
    
    
    // Parallel feature edge detection. Assumes non-manifold edges already handled.
    void Foam::autoLayerDriver::handleFeatureAngle
    (
        const indirectPrimitivePatch& pp,
        const labelList& meshEdges,
        const scalar minCos,
        pointField& patchDisp,
        labelList& patchNLayers,
        List<extrudeMode>& extrudeStatus
    ) const
    {
        const fvMesh& mesh = meshRefiner_.mesh();
    
        Info<< nl << "Handling feature edges ..." << endl;
    
        if (minCos < 1-SMALL)
        {
            // Normal component of normals of connected faces.
    
            vectorField edgeNormal(mesh.nEdges(), point::max);
    
    
            const labelListList& edgeFaces = pp.edgeFaces();
    
            forAll(edgeFaces, edgeI)
            {
                const labelList& eFaces = pp.edgeFaces()[edgeI];
    
                label meshEdgeI = meshEdges[edgeI];
    
                forAll(eFaces, i)
                {
                    nomalsCombine()
                    (
                        edgeNormal[meshEdgeI],
                        pp.faceNormals()[eFaces[i]]
                    );
                }
            }
    
            syncTools::syncEdgeList
            (
                mesh,
                edgeNormal,
                nomalsCombine(),
    
                point::max          // null value
    
            autoPtr<OBJstream> str;
    
    mattijs's avatar
    mattijs committed
            if (debug&meshRefinement::MESH)
    
                    new OBJstream
    
                    (
                        mesh.time().path()
                      / "featureEdges_"
                      + meshRefiner_.timeName()
                      + ".obj"
                    )
                );
    
                Info<< "Writing feature edges to " << str().name() << endl;
            }
    
            label nFeats = 0;
    
            // Now on coupled edges the edgeNormal will have been truncated and
            // only be still be the old value where two faces have the same normal
            forAll(edgeFaces, edgeI)
            {
                const labelList& eFaces = pp.edgeFaces()[edgeI];
    
                label meshEdgeI = meshEdges[edgeI];
    
                const vector& n = edgeNormal[meshEdgeI];
    
    
                if (n != point::max)
    
                {
                    scalar cos = n & pp.faceNormals()[eFaces[0]];
    
                    if (cos < minCos)
                    {
                        const edge& e = pp.edges()[edgeI];
    
                        unmarkExtrusion
                        (
                            e[0],
                            patchDisp,
                            patchNLayers,
                            extrudeStatus
                        );
                        unmarkExtrusion
                        (
                            e[1],
                            patchDisp,
                            patchNLayers,
                            extrudeStatus
                        );
    
                        nFeats++;
    
                        if (str.valid())
                        {
    
                            const point& p0 = pp.localPoints()[e[0]];
                            const point& p1 = pp.localPoints()[e[1]];
                            str().write(linePointRef(p0, p1));
    
                        }
                    }
                }
            }
    
            Info<< "Set displacement to zero for points on "
                << returnReduce(nFeats, sumOp<label>())
                << " feature edges" << endl;
        }
    }
    
    
    // No extrusion on cells with warped faces. Calculates the thickness of the
    // layer and compares it to the space the warped face takes up. Disables
    // extrusion if layer thickness is more than faceRatio of the thickness of
    // the face.
    void Foam::autoLayerDriver::handleWarpedFaces
    (
        const indirectPrimitivePatch& pp,
        const scalar faceRatio,
        const scalar edge0Len,
        const labelList& cellLevel,
        pointField& patchDisp,
        labelList& patchNLayers,
        List<extrudeMode>& extrudeStatus
    ) const
    {
        const fvMesh& mesh = meshRefiner_.mesh();
    
        Info<< nl << "Handling cells with warped patch faces ..." << nl;
    
        const pointField& points = mesh.points();
    
        label nWarpedFaces = 0;
    
        forAll(pp, i)
        {
            const face& f = pp[i];
    
            if (f.size() > 3)
            {
                label faceI = pp.addressing()[i];
    
                label ownLevel = cellLevel[mesh.faceOwner()[faceI]];
                scalar edgeLen = edge0Len/(1<<ownLevel);
    
                // Normal distance to face centre plane
                const point& fc = mesh.faceCentres()[faceI];
                const vector& fn = pp.faceNormals()[i];
    
                scalarField vProj(f.size());
    
                forAll(f, fp)
                {
                    vector n = points[f[fp]] - fc;
                    vProj[fp] = (n & fn);
                }
    
                // Get normal 'span' of face
                scalar minVal = min(vProj);
                scalar maxVal = max(vProj);
    
                if ((maxVal - minVal) > faceRatio * edgeLen)
                {
                    if
                    (
                        unmarkExtrusion
                        (
                            pp.localFaces()[i],
                            patchDisp,
                            patchNLayers,
                            extrudeStatus
                        )
                    )
                    {
                        nWarpedFaces++;
                    }
                }
            }
        }
    
        Info<< "Set displacement to zero on "
            << returnReduce(nWarpedFaces, sumOp<label>())
            << " warped faces since layer would be > " << faceRatio
            << " of the size of the bounding box." << endl;
    }
    
    
    //// No extrusion on cells with multiple patch faces. There ususally is a reason
    //// why combinePatchFaces hasn't succeeded.
    //void Foam::autoLayerDriver::handleMultiplePatchFaces
    //(
    //    const indirectPrimitivePatch& pp,
    //    pointField& patchDisp,
    //    labelList& patchNLayers,
    //    List<extrudeMode>& extrudeStatus
    //) const
    //{
    //    const fvMesh& mesh = meshRefiner_.mesh();
    //
    //    Info<< nl << "Handling cells with multiple patch faces ..." << nl;
    //
    //    const labelListList& pointFaces = pp.pointFaces();
    //
    //    // Cells that should not get an extrusion layer
    //    cellSet multiPatchCells(mesh, "multiPatchCells", pp.size());
    //
    //    // Detect points that use multiple faces on same cell.
    //    forAll(pointFaces, patchPointI)
    //    {
    //        const labelList& pFaces = pointFaces[patchPointI];
    //
    //        labelHashSet pointCells(pFaces.size());
    //
    //        forAll(pFaces, i)
    //        {
    //            label cellI = mesh.faceOwner()[pp.addressing()[pFaces[i]]];
    //
    //            if (!pointCells.insert(cellI))
    //            {
    //                // Second or more occurrence of cell so cell has two or more
    //                // pp faces connected to this point.
    //                multiPatchCells.insert(cellI);
    //            }
    //        }
    //    }
    //
    //    label nMultiPatchCells = returnReduce
    //    (
    //        multiPatchCells.size(),
    //        sumOp<label>()
    //    );
    //
    //    Info<< "Detected " << nMultiPatchCells
    //        << " cells with multiple (connected) patch faces." << endl;
    //
    //    label nChanged = 0;
    //
    //    if (nMultiPatchCells > 0)
    //    {
    
    //        multiPatchCells.instance() = meshRefiner_.timeName();
    
    //        Info<< "Writing " << nMultiPatchCells
    //            << " cells with multiple (connected) patch faces to cellSet "
    //            << multiPatchCells.objectPath() << endl;
    //        multiPatchCells.write();
    //
    //
    //        // Go through all points and remove extrusion on any cell in
    //        // multiPatchCells
    //        // (has to be done in separate loop since having one point on
    //        // multipatches has to reset extrusion on all points of cell)
    //
    //        forAll(pointFaces, patchPointI)
    //        {
    //            if (extrudeStatus[patchPointI] != NOEXTRUDE)
    //            {
    //                const labelList& pFaces = pointFaces[patchPointI];
    //
    //                forAll(pFaces, i)
    //                {
    //                    label cellI =
    //                        mesh.faceOwner()[pp.addressing()[pFaces[i]]];
    //
    //                    if (multiPatchCells.found(cellI))
    //                    {
    //                        if
    //                        (
    //                            unmarkExtrusion
    //                            (
    //                                patchPointI,
    //                                patchDisp,
    //                                patchNLayers,
    //                                extrudeStatus
    //                            )
    //                        )
    //                        {
    //                            nChanged++;
    //                        }
    //                    }
    //                }
    //            }
    //        }
    //
    //        reduce(nChanged, sumOp<label>());
    //    }
    //
    //    Info<< "Prevented extrusion on " << nChanged
    //        << " points due to multiple patch faces." << nl << endl;
    //}
    
    
    void Foam::autoLayerDriver::setNumLayers
    (
        const labelList& patchToNLayers,
        const labelList& patchIDs,
        const indirectPrimitivePatch& pp,
        pointField& patchDisp,
        labelList& patchNLayers,
    
        List<extrudeMode>& extrudeStatus,
        label& nAddedCells
    
    ) const
    {
        const fvMesh& mesh = meshRefiner_.mesh();
    
        Info<< nl << "Handling points with inconsistent layer specification ..."
            << endl;
    
    
    andy's avatar
    andy committed
        // Get for every point (really only necessary on patch external points)
    
        // the max and min of any patch faces using it.
        labelList maxLayers(patchNLayers.size(), labelMin);
        labelList minLayers(patchNLayers.size(), labelMax);
    
        forAll(patchIDs, i)
        {
            label patchI = patchIDs[i];
    
            const labelList& meshPoints = mesh.boundaryMesh()[patchI].meshPoints();
    
            label wantedLayers = patchToNLayers[patchI];
    
            forAll(meshPoints, patchPointI)
            {
                label ppPointI = pp.meshPointMap()[meshPoints[patchPointI]];
    
                maxLayers[ppPointI] = max(wantedLayers, maxLayers[ppPointI]);
                minLayers[ppPointI] = min(wantedLayers, minLayers[ppPointI]);
            }
        }
    
        syncTools::syncPointList
        (
            mesh,
            pp.meshPoints(),
            maxLayers,
            maxEqOp<label>(),
    
    mattijs's avatar
    mattijs committed
            labelMin            // null value
    
        );
        syncTools::syncPointList
        (
            mesh,
            pp.meshPoints(),
            minLayers,
            minEqOp<label>(),
    
    mattijs's avatar
    mattijs committed
            labelMax            // null value
    
        );
    
        // Unmark any point with different min and max
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
        //label nConflicts = 0;
    
        forAll(maxLayers, i)
        {
            if (maxLayers[i] == labelMin || minLayers[i] == labelMax)
            {
                FatalErrorIn("setNumLayers(..)")
                    << "Patchpoint:" << i << " coord:" << pp.localPoints()[i]
                    << " maxLayers:" << maxLayers
                    << " minLayers:" << minLayers
                    << abort(FatalError);
            }
            else if (maxLayers[i] == minLayers[i])
            {
                // Ok setting.
                patchNLayers[i] = maxLayers[i];
            }
            else
            {
                // Inconsistent num layers between patch faces using point
                //if
                //(
                //    unmarkExtrusion
                //    (
                //        i,
                //        patchDisp,
                //        patchNLayers,
                //        extrudeStatus
                //    )
                //)
                //{
                //    nConflicts++;
                //}
                patchNLayers[i] = maxLayers[i];
            }
        }
    
    
    
        // Calculate number of cells to create
        nAddedCells = 0;
        forAll(pp.localFaces(), faceI)
        {
            const face& f = pp.localFaces()[faceI];
    
            // Get max of extrusion per point
            label nCells = 0;
            forAll(f, fp)
            {
                nCells = max(nCells, patchNLayers[f[fp]]);
            }
    
            nAddedCells += nCells;
        }
        reduce(nAddedCells, sumOp<label>());
    
    
        //reduce(nConflicts, sumOp<label>());
        //
        //Info<< "Set displacement to zero for " << nConflicts
        //    << " points due to points being on multiple regions"
        //    << " with inconsistent nLayers specification." << endl;
    }
    
    
    
    // Construct pointVectorField with correct boundary conditions for adding
    // layers
    Foam::tmp<Foam::pointVectorField>
    Foam::autoLayerDriver::makeLayerDisplacementField
    (
        const pointMesh& pMesh,
        const labelList& numLayers
    )
    {
        // Construct displacement field.
        const pointBoundaryMesh& pointPatches = pMesh.boundary();
    
        wordList patchFieldTypes
        (
            pointPatches.size(),
            slipPointPatchVectorField::typeName
        );
    
        wordList actualPatchTypes(patchFieldTypes.size());
        forAll(pointPatches, patchI)
        {
            actualPatchTypes[patchI] = pointPatches[patchI].type();
        }
    
            //  0 layers: do not allow slip so fixedValue 0
    
            // >0 layers: fixedValue which gets adapted
    
            if (numLayers[patchI] == 0)
            {
                patchFieldTypes[patchI] =
                    zeroFixedValuePointPatchVectorField::typeName;
            }
            else if (numLayers[patchI] > 0)
    
            {
                patchFieldTypes[patchI] = fixedValuePointPatchVectorField::typeName;
            }
        }
    
        forAll(pointPatches, patchI)
        {
            if (isA<processorPointPatch>(pointPatches[patchI]))
            {
                patchFieldTypes[patchI] = calculatedPointPatchVectorField::typeName;
            }
            else if (isA<cyclicPointPatch>(pointPatches[patchI]))
            {
                patchFieldTypes[patchI] = cyclicSlipPointPatchVectorField::typeName;
            }
        }
    
    
        const polyMesh& mesh = pMesh();
    
        // Note: time().timeName() instead of meshRefinement::timeName() since
        // postprocessable field.
        tmp<pointVectorField> tfld
        (
            new pointVectorField
            (
                IOobject
                (
                    "pointDisplacement",
                    mesh.time().timeName(),
                    mesh,
                    IOobject::NO_READ,
                    IOobject::AUTO_WRITE
                ),
                pMesh,
                dimensionedVector("displacement", dimLength, vector::zero),
    
                patchFieldTypes,
                actualPatchTypes
    
    void Foam::autoLayerDriver::growNoExtrusion
    (
        const indirectPrimitivePatch& pp,
        pointField& patchDisp,
        labelList& patchNLayers,
        List<extrudeMode>& extrudeStatus
    
    {
        Info<< nl << "Growing non-extrusion points by one layer ..." << endl;
    
        List<extrudeMode> grownExtrudeStatus(extrudeStatus);
    
        const faceList& localFaces = pp.localFaces();
    
        label nGrown = 0;
    
        forAll(localFaces, faceI)
        {
            const face& f = localFaces[faceI];
    
            bool hasSqueeze = false;
            forAll(f, fp)
            {
                if (extrudeStatus[f[fp]] == NOEXTRUDE)
                {
                    hasSqueeze = true;
                    break;
                }
            }
    
            if (hasSqueeze)
            {
                // Squeeze all points of face
                forAll(f, fp)
                {
                    if
                    (
    
                        extrudeStatus[f[fp]] == EXTRUDE
    
                     && grownExtrudeStatus[f[fp]] != NOEXTRUDE
                    )
                    {
                        grownExtrudeStatus[f[fp]] = NOEXTRUDE;
                        nGrown++;
                    }
                }
            }
        }
    
        extrudeStatus.transfer(grownExtrudeStatus);
    
    
    
        // Synchronise since might get called multiple times.
        // Use the fact that NOEXTRUDE is the minimum value.
        {
            labelList status(extrudeStatus.size());
            forAll(status, i)
            {
                status[i] = extrudeStatus[i];
            }
            syncTools::syncPointList
            (
                meshRefiner_.mesh(),
                pp.meshPoints(),
                status,
                minEqOp<label>(),
    
                labelMax            // null value
    
            );
            forAll(status, i)
            {
                extrudeStatus[i] = extrudeMode(status[i]);
            }
        }
    
    
    
        forAll(extrudeStatus, patchPointI)
        {
            if (extrudeStatus[patchPointI] == NOEXTRUDE)
            {
                patchDisp[patchPointI] = vector::zero;
                patchNLayers[patchPointI] = 0;
            }
        }
    
        reduce(nGrown, sumOp<label>());
    
        Info<< "Set displacement to zero for an additional " << nGrown
            << " points." << endl;
    }
    
    
    
    void Foam::autoLayerDriver::determineSidePatches
    (
        const globalIndex& globalFaces,
        const labelListList& edgeGlobalFaces,
        const indirectPrimitivePatch& pp,
    
    
        labelList& edgePatchID,
        labelList& edgeZoneID,
        boolList& edgeFlip,
        labelList& inflateFaceID
    
    )
    {
        // Sometimes edges-to-be-extruded are on more than 2 processors.
        // Work out which 2 hold the faces to be extruded and thus which procpatch
    
        // the edge-face should be in. As an additional complication this might
    
        // mean that 2 procesors that were only edge-connected now suddenly need
        // to become face-connected i.e. have a processor patch between them.
    
        fvMesh& mesh = meshRefiner_.mesh();
    
    
        // Determine edgePatchID. Any additional processor boundary gets added to
    
        // patchToNbrProc,nbrProcToPatch and nPatches gets set to the new number
        // of patches.
        label nPatches;
        Map<label> nbrProcToPatch;
        Map<label> patchToNbrProc;