Skip to content
Snippets Groups Projects
polyMesh.C 33.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*---------------------------------------------------------------------------*\
      =========                 |
      \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
       \\    /   O peration     |
    
        \\  /    A nd           | Copyright (C) 2011-2014 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/>.
    
    
    \*---------------------------------------------------------------------------*/
    
    #include "polyMesh.H"
    #include "Time.H"
    #include "cellIOList.H"
    #include "wedgePolyPatch.H"
    #include "emptyPolyPatch.H"
    #include "globalMeshData.H"
    #include "processorPolyPatch.H"
    
    #include "polyMeshTetDecomposition.H"
    
    #include "indexedOctree.H"
    #include "treeDataCell.H"
    
    #include "pointMesh.H"
    
    mattijs's avatar
    mattijs committed
    
    
    // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
    
    
        word polyMesh::defaultRegion = "region0";
        word polyMesh::meshSubDir = "polyMesh";
    
    
    
    // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
    
    void Foam::polyMesh::calcDirections() const
    {
        for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
        {
    
    mattijs's avatar
    mattijs committed
            solutionD_[cmpt] = 1;
    
    mattijs's avatar
    mattijs committed
        // Knock out empty and wedge directions. Note:they will be present on all
        // domains.
    
    
        label nEmptyPatches = 0;
    
    mattijs's avatar
    mattijs committed
        label nWedgePatches = 0;
    
    mattijs's avatar
    mattijs committed
        vector emptyDirVec = vector::zero;
        vector wedgeDirVec = vector::zero;
    
    
        forAll(boundaryMesh(), patchi)
        {
    
    mattijs's avatar
    mattijs committed
            if (boundaryMesh()[patchi].size())
    
    mattijs's avatar
    mattijs committed
                if (isA<emptyPolyPatch>(boundaryMesh()[patchi]))
    
    mattijs's avatar
    mattijs committed
                    emptyDirVec += sum(cmptMag(boundaryMesh()[patchi].faceAreas()));
                }
                else if (isA<wedgePolyPatch>(boundaryMesh()[patchi]))
                {
                    const wedgePolyPatch& wpp = refCast<const wedgePolyPatch>
                    (
                        boundaryMesh()[patchi]
                    );
    
                    nWedgePatches++;
                    wedgeDirVec += cmptMag(wpp.centreNormal());
    
        reduce(nEmptyPatches, maxOp<label>());
        reduce(nWedgePatches, maxOp<label>());
    
    
    mattijs's avatar
    mattijs committed
            reduce(emptyDirVec, sumOp<vector>());
    
    mattijs's avatar
    mattijs committed
            emptyDirVec /= mag(emptyDirVec);
    
    
            for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
            {
    
    mattijs's avatar
    mattijs committed
                if (emptyDirVec[cmpt] > 1e-6)
    
    mattijs's avatar
    mattijs committed
                    solutionD_[cmpt] = -1;
    
    mattijs's avatar
    mattijs committed
                    solutionD_[cmpt] = 1;
                }
            }
        }
    
    
        // Knock out wedge directions
    
        geometricD_ = solutionD_;
    
        if (nWedgePatches)
        {
            reduce(wedgeDirVec, sumOp<vector>());
    
            wedgeDirVec /= mag(wedgeDirVec);
    
            for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
            {
                if (wedgeDirVec[cmpt] > 1e-6)
                {
                    geometricD_[cmpt] = -1;
                }
                else
                {
                    geometricD_[cmpt] = 1;
    
                }
            }
        }
    }
    
    
    // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
    
    Foam::polyMesh::polyMesh(const IOobject& io)
    :
        objectRegistry(io),
        primitiveMesh(),
        points_
        (
            IOobject
            (
                "points",
                time().findInstance(meshDir(), "points"),
                meshSubDir,
                *this,
                IOobject::MUST_READ,
                IOobject::NO_WRITE
            )
        ),
        faces_
        (
            IOobject
            (
                "faces",
                time().findInstance(meshDir(), "faces"),
                meshSubDir,
                *this,
                IOobject::MUST_READ,
                IOobject::NO_WRITE
            )
        ),
        owner_
        (
            IOobject
            (
                "owner",
    
                faces_.instance(),
    
                meshSubDir,
                *this,
                IOobject::READ_IF_PRESENT,
                IOobject::NO_WRITE
            )
        ),
        neighbour_
        (
            IOobject
            (
                "neighbour",
    
                faces_.instance(),
    
                meshSubDir,
                *this,
                IOobject::READ_IF_PRESENT,
                IOobject::NO_WRITE
            )
        ),
        clearedPrimitives_(false),
        boundary_
        (
            IOobject
            (
                "boundary",
                time().findInstance(meshDir(), "boundary"),
                meshSubDir,
                *this,
                IOobject::MUST_READ,
                IOobject::NO_WRITE
            ),
            *this
        ),
        bounds_(points_),
    
        comm_(UPstream::worldComm),
    
    mattijs's avatar
    mattijs committed
        geometricD_(Vector<label>::zero),
        solutionD_(Vector<label>::zero),
    
        tetBasePtIsPtr_(NULL),
    
        pointZones_
        (
            IOobject
            (
                "pointZones",
                time().findInstance
                (
                    meshDir(),
                    "pointZones",
                    IOobject::READ_IF_PRESENT
                ),
                meshSubDir,
                *this,
                IOobject::READ_IF_PRESENT,
                IOobject::NO_WRITE
            ),
            *this
        ),
        faceZones_
        (
            IOobject
            (
                "faceZones",
                time().findInstance
                (
                    meshDir(),
                    "faceZones",
                    IOobject::READ_IF_PRESENT
                ),
                meshSubDir,
                *this,
                IOobject::READ_IF_PRESENT,
                IOobject::NO_WRITE
            ),
            *this
        ),
        cellZones_
        (
            IOobject
            (
                "cellZones",
                time().findInstance
                (
                    meshDir(),
                    "cellZones",
                    IOobject::READ_IF_PRESENT
                ),
                meshSubDir,
                *this,
                IOobject::READ_IF_PRESENT,
                IOobject::NO_WRITE
            ),
            *this
        ),
        globalMeshDataPtr_(NULL),
        moving_(false),
    
        topoChanging_(false),
    
        curMotionTimeIndex_(time().timeIndex()),
        oldPointsPtr_(NULL)
    {
        if (exists(owner_.objectPath()))
        {
            initMesh();
        }
        else
        {
    
            cellCompactIOList cLst
    
            (
                IOobject
                (
                    "cells",
                    time().findInstance(meshDir(), "cells"),
                    meshSubDir,
                    *this,
                    IOobject::MUST_READ,
                    IOobject::NO_WRITE
                )
            );
    
            // Set the primitive mesh
    
            initMesh(cLst);
    
    
            owner_.write();
            neighbour_.write();
        }
    
        // Calculate topology for the patches (processor-processor comms etc.)
        boundary_.updateMesh();
    
        // Calculate the geometry for the patches (transformation tensors etc.)
        boundary_.calcGeometry();
    
    
        // Warn if global empty mesh
        if (returnReduce(nPoints(), sumOp<label>()) == 0)
    
        {
            WarningIn("polyMesh(const IOobject&)")
                << "no points in mesh" << endl;
        }
    
        if (returnReduce(nCells(), sumOp<label>()) == 0)
    
        {
            WarningIn("polyMesh(const IOobject&)")
                << "no cells in mesh" << endl;
        }
    
    
        // Initialise demand-driven data
        calcDirections();
    
    }
    
    
    Foam::polyMesh::polyMesh
    (
        const IOobject& io,
    
        const Xfer<pointField>& points,
        const Xfer<faceList>& faces,
        const Xfer<labelList>& owner,
        const Xfer<labelList>& neighbour,
    
        const bool syncPar
    )
    :
        objectRegistry(io),
        primitiveMesh(),
        points_
        (
            IOobject
            (
                "points",
                instance(),
                meshSubDir,
                *this,
    
                IOobject::AUTO_WRITE
            ),
            points
        ),
        faces_
        (
            IOobject
            (
                "faces",
                instance(),
                meshSubDir,
                *this,
    
                IOobject::AUTO_WRITE
            ),
            faces
        ),
        owner_
        (
            IOobject
            (
                "owner",
                instance(),
                meshSubDir,
                *this,
    
                IOobject::AUTO_WRITE
            ),
            owner
        ),
        neighbour_
        (
            IOobject
            (
                "neighbour",
                instance(),
                meshSubDir,
                *this,
    
                IOobject::AUTO_WRITE
            ),
            neighbour
        ),
        clearedPrimitives_(false),
        boundary_
        (
            IOobject
            (
                "boundary",
                instance(),
                meshSubDir,
                *this,
    
                IOobject::AUTO_WRITE
            ),
            *this,
    
        ),
        bounds_(points_, syncPar),
    
        comm_(UPstream::worldComm),
    
    mattijs's avatar
    mattijs committed
        geometricD_(Vector<label>::zero),
        solutionD_(Vector<label>::zero),
    
        tetBasePtIsPtr_(NULL),
    
        pointZones_
        (
            IOobject
            (
                "pointZones",
                instance(),
                meshSubDir,
                *this,
    
                IOobject::NO_WRITE
            ),
            *this,
    
        ),
        faceZones_
        (
            IOobject
            (
                "faceZones",
                instance(),
                meshSubDir,
                *this,
    
                IOobject::NO_WRITE
            ),
            *this,
    
        ),
        cellZones_
        (
            IOobject
            (
                "cellZones",
                instance(),
                meshSubDir,
                *this,
    
                IOobject::NO_WRITE
            ),
            *this,
    
        ),
        globalMeshDataPtr_(NULL),
        moving_(false),
    
        topoChanging_(false),
    
        curMotionTimeIndex_(time().timeIndex()),
        oldPointsPtr_(NULL)
    {
        // Check if the faces and cells are valid
    
        {
            const face& curFace = faces_[faceI];
    
            if (min(curFace) < 0 || max(curFace) > points_.size())
            {
                FatalErrorIn
                (
                    "polyMesh::polyMesh\n"
                    "(\n"
                    "    const IOobject& io,\n"
                    "    const pointField& points,\n"
                    "    const faceList& faces,\n"
                    "    const cellList& cells\n"
                    ")\n"
                )   << "Face " << faceI << "contains vertex labels out of range: "
                    << curFace << " Max point index = " << points_.size()
                    << abort(FatalError);
            }
        }
    
        // Set the primitive mesh
        initMesh();
    }
    
    
    Foam::polyMesh::polyMesh
    (
        const IOobject& io,
    
        const Xfer<pointField>& points,
        const Xfer<faceList>& faces,
        const Xfer<cellList>& cells,
    
        const bool syncPar
    )
    :
        objectRegistry(io),
        primitiveMesh(),
        points_
        (
            IOobject
            (
                "points",
                instance(),
                meshSubDir,
                *this,
                IOobject::NO_READ,
                IOobject::AUTO_WRITE
            ),
            points
        ),
        faces_
        (
            IOobject
            (
                "faces",
                instance(),
                meshSubDir,
                *this,
                IOobject::NO_READ,
                IOobject::AUTO_WRITE
            ),
            faces
        ),
        owner_
        (
            IOobject
            (
                "owner",
                instance(),
                meshSubDir,
                *this,
                IOobject::NO_READ,
                IOobject::AUTO_WRITE
            ),
            0
        ),
        neighbour_
        (
            IOobject
            (
                "neighbour",
                instance(),
                meshSubDir,
                *this,
                IOobject::NO_READ,
                IOobject::AUTO_WRITE
            ),
            0
        ),
        clearedPrimitives_(false),
        boundary_
        (
            IOobject
            (
                "boundary",
                instance(),
                meshSubDir,
                *this,
                IOobject::NO_READ,
                IOobject::AUTO_WRITE
            ),
            *this,
            0
        ),
        bounds_(points_, syncPar),
    
        comm_(UPstream::worldComm),
    
    mattijs's avatar
    mattijs committed
        geometricD_(Vector<label>::zero),
        solutionD_(Vector<label>::zero),
    
        tetBasePtIsPtr_(NULL),
    
        pointZones_
        (
            IOobject
            (
                "pointZones",
                instance(),
                meshSubDir,
                *this,
                IOobject::NO_READ,
                IOobject::NO_WRITE
            ),
            *this,
            0
        ),
        faceZones_
        (
            IOobject
            (
                "faceZones",
                instance(),
                meshSubDir,
                *this,
                IOobject::NO_READ,
                IOobject::NO_WRITE
            ),
            *this,
            0
        ),
        cellZones_
        (
            IOobject
            (
                "cellZones",
                instance(),
                meshSubDir,
                *this,
                IOobject::NO_READ,
                IOobject::NO_WRITE
            ),
            *this,
            0
        ),
        globalMeshDataPtr_(NULL),
        moving_(false),
    
        topoChanging_(false),
    
        curMotionTimeIndex_(time().timeIndex()),
        oldPointsPtr_(NULL)
    {
    
    mattijs's avatar
    mattijs committed
        // Check if faces are valid
    
        {
            const face& curFace = faces_[faceI];
    
            if (min(curFace) < 0 || max(curFace) > points_.size())
            {
                FatalErrorIn
                (
                    "polyMesh::polyMesh\n"
                    "(\n"
    
    mattijs's avatar
    mattijs committed
                    "    const IOobject&,\n"
    
                    "    const Xfer<pointField>&,\n"
                    "    const Xfer<faceList>&,\n"
                    "    const Xfer<cellList>&\n"
    
                    ")\n"
                )   << "Face " << faceI << "contains vertex labels out of range: "
                    << curFace << " Max point index = " << points_.size()
                    << abort(FatalError);
            }
        }
    
    
        // transfer in cell list
        cellList cLst(cells);
    
    mattijs's avatar
    mattijs committed
    
        // Check if cells are valid
    
    mattijs's avatar
    mattijs committed
            const cell& curCell = cLst[cellI];
    
    
            if (min(curCell) < 0 || max(curCell) > faces_.size())
            {
                FatalErrorIn
                (
                    "polyMesh::polyMesh\n"
                    "(\n"
    
    mattijs's avatar
    mattijs committed
                    "    const IOobject&,\n"
    
                    "    const Xfer<pointField>&,\n"
                    "    const Xfer<faceList>&,\n"
                    "    const Xfer<cellList>&\n"
    
                    ")\n"
                )   << "Cell " << cellI << "contains face labels out of range: "
                    << curCell << " Max face index = " << faces_.size()
                    << abort(FatalError);
            }
        }
    
        // Set the primitive mesh
    
        initMesh(cLst);
    
    }
    
    
    void Foam::polyMesh::resetPrimitives
    (
    
        const Xfer<pointField>& points,
        const Xfer<faceList>& faces,
        const Xfer<labelList>& owner,
        const Xfer<labelList>& neighbour,
    
        const labelList& patchSizes,
        const labelList& patchStarts,
        const bool validBoundary
    )
    {
    
        // Clear addressing. Keep geometric props and updateable props for mapping.
        clearAddressing(true);
    
    mattijs's avatar
    mattijs committed
        // Take over new primitive data.
    
        // Optimized to avoid overwriting data at all
        if (&points)
    
            points_.transfer(points());
    
            bounds_ = boundBox(points_, validBoundary);
        }
    
            faces_.transfer(faces());
    
            owner_.transfer(owner());
    
            neighbour_.transfer(neighbour());
    
    mattijs's avatar
    mattijs committed
    
    
        // Reset patch sizes and starts
        forAll(boundary_, patchI)
        {
            boundary_[patchI] = polyPatch
            (
    
                boundary_[patchI],
                boundary_,
    
                patchSizes[patchI],
                patchStarts[patchI]
    
            );
        }
    
    
        // Flags the mesh files as being changed
        setInstance(time().timeName());
    
        // Check if the faces and cells are valid
    
        {
            const face& curFace = faces_[faceI];
    
            if (min(curFace) < 0 || max(curFace) > points_.size())
            {
                FatalErrorIn
                (
                    "polyMesh::polyMesh::resetPrimitives\n"
                    "(\n"
    
                    "    const Xfer<pointField>&,\n"
                    "    const Xfer<faceList>&,\n"
                    "    const Xfer<labelList>& owner,\n"
                    "    const Xfer<labelList>& neighbour,\n"
    
                    "    const labelList& patchSizes,\n"
                    "    const labelList& patchStarts\n"
    
    mattijs's avatar
    mattijs committed
                    "    const bool validBoundary\n"
    
                    ")\n"
                )   << "Face " << faceI << " contains vertex labels out of range: "
                    << curFace << " Max point index = " << points_.size()
                    << abort(FatalError);
            }
        }
    
    
    
        // Set the primitive mesh from the owner_, neighbour_.
        // Works out from patch end where the active faces stop.
    
        initMesh();
    
    
        if (validBoundary)
        {
            // Note that we assume that all the patches stay the same and are
            // correct etc. so we can already use the patches to do
            // processor-processor comms.
    
            // Calculate topology for the patches (processor-processor comms etc.)
            boundary_.updateMesh();
    
            // Calculate the geometry for the patches (transformation tensors etc.)
            boundary_.calcGeometry();
    
    
            // Warn if global empty mesh
            if
            (
                (returnReduce(nPoints(), sumOp<label>()) == 0)
             || (returnReduce(nCells(), sumOp<label>()) == 0)
            )
    
            {
                FatalErrorIn
                (
                    "polyMesh::polyMesh::resetPrimitives\n"
                    "(\n"
    
                    "    const Xfer<pointField>&,\n"
                    "    const Xfer<faceList>&,\n"
                    "    const Xfer<labelList>& owner,\n"
                    "    const Xfer<labelList>& neighbour,\n"
    
                    "    const labelList& patchSizes,\n"
                    "    const labelList& patchStarts\n"
    
    mattijs's avatar
    mattijs committed
                    "    const bool validBoundary\n"
    
    mattijs's avatar
    mattijs committed
                )   << "no points or no cells in mesh" << endl;
    
            }
        }
    }
    
    
    // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
    
    Foam::polyMesh::~polyMesh()
    {
        clearOut();
        resetMotion();
    }
    
    
    // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
    
    const Foam::fileName& Foam::polyMesh::dbDir() const
    {
        if (objectRegistry::dbDir() == defaultRegion)
        {
            return parent().dbDir();
        }
        else
        {
            return objectRegistry::dbDir();
        }
    }
    
    
    Foam::fileName Foam::polyMesh::meshDir() const
    {
        return dbDir()/meshSubDir;
    }
    
    
    const Foam::fileName& Foam::polyMesh::pointsInstance() const
    {
        return points_.instance();
    }
    
    
    const Foam::fileName& Foam::polyMesh::facesInstance() const
    {
        return faces_.instance();
    }
    
    
    
    mattijs's avatar
    mattijs committed
    const Foam::Vector<Foam::label>& Foam::polyMesh::geometricD() const
    
    mattijs's avatar
    mattijs committed
        if (geometricD_.x() == 0)
    
    mattijs's avatar
    mattijs committed
        return geometricD_;
    
    }
    
    
    Foam::label Foam::polyMesh::nGeometricD() const
    {
    
    mattijs's avatar
    mattijs committed
        return cmptSum(geometricD() + Vector<label>::one)/2;
    }
    
    mattijs's avatar
    mattijs committed
    const Foam::Vector<Foam::label>& Foam::polyMesh::solutionD() const
    {
        if (solutionD_.x() == 0)
    
    mattijs's avatar
    mattijs committed
            calcDirections();
    
    mattijs's avatar
    mattijs committed
        return solutionD_;
    
    }
    
    
    Foam::label Foam::polyMesh::nSolutionD() const
    {
    
    mattijs's avatar
    mattijs committed
        return cmptSum(solutionD() + Vector<label>::one)/2;
    
    const Foam::labelList& Foam::polyMesh::tetBasePtIs() const
    {
    
        if (tetBasePtIsPtr_.empty())
    
        {
            if (debug)
            {
                WarningIn("const labelList& polyMesh::tetBasePtIs() const")
                    << "Tet base point indices not available.  "
                    << "Forcing storage of base points."
                    << endl;
            }
    
    
            tetBasePtIsPtr_.reset
    
                new labelList
                (
                    polyMeshTetDecomposition::findFaceBasePts(*this)
                )
    
        return tetBasePtIsPtr_();
    }
    
    
    const Foam::indexedOctree<Foam::treeDataCell>&
    Foam::polyMesh::cellTree() const
    {
        if (cellTreePtr_.empty())
        {
            treeBoundBox overallBb(points());
    
            Random rndGen(261782);
    
    
            overallBb = overallBb.extend(rndGen, 1e-4);
    
            overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
            overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
    
            cellTreePtr_.reset
            (
                new indexedOctree<treeDataCell>
                (
                    treeDataCell
                    (
                        false,          // not cache bb
                        *this,
                        FACEDIAGTETS    // use tetDecomposition for any inside test
                    ),
                    overallBb,
                    8,              // maxLevel
                    10,             // leafsize
                    5.0             // duplicity
                )
            );
        }
    
        return cellTreePtr_();
    
    // Add boundary patches. Constructor helper
    void Foam::polyMesh::addPatches
    (
        const List<polyPatch*>& p,
        const bool validBoundary
    )
    {
    
        {
            FatalErrorIn
            (
                "void polyMesh::addPatches(const List<polyPatch*>&, const bool)"
            )   << "boundary already exists"
                << abort(FatalError);
        }
    
    
    mattijs's avatar
    mattijs committed
        // Reset valid directions
        geometricD_ = Vector<label>::zero;
        solutionD_ = Vector<label>::zero;
    
    
        boundary_.setSize(p.size());
    
        // Copy the patch pointers
    
        {
            boundary_.set(pI, p[pI]);
        }
    
        // parallelData depends on the processorPatch ordering so force
        // recalculation. Problem: should really be done in removeBoundary but
        // there is some info in parallelData which might be interesting inbetween
        // removeBoundary and addPatches.
    
        globalMeshDataPtr_.clear();
    
    
        if (validBoundary)
        {
            // Calculate topology for the patches (processor-processor comms etc.)
            boundary_.updateMesh();
    
            // Calculate the geometry for the patches (transformation tensors etc.)
            boundary_.calcGeometry();
    
            boundary_.checkDefinition();
        }
    }
    
    
    // Add mesh zones. Constructor helper
    void Foam::polyMesh::addZones
    (
        const List<pointZone*>& pz,
        const List<faceZone*>& fz,
        const List<cellZone*>& cz
    )
    {
    
        if (pointZones().size() || faceZones().size() || cellZones().size())
    
        {
            FatalErrorIn
            (
                "void addZones\n"
                "(\n"
    
                "    const List<pointZone*>&,\n"
                "    const List<faceZone*>&,\n"
                "    const List<cellZone*>&\n"
    
                ")"
            )   << "point, face or cell zone already exists"
                << abort(FatalError);
        }
    
        // Point zones
        if (pz.size())
        {
            pointZones_.setSize(pz.size());
    
            // Copy the zone pointers