Program Listing for File CrawlingCellFinder.C

Return to documentation for file (cellFinders/CrawlingCellFinder/CrawlingCellFinder.C)

/*---------------------------------------------------------------------------* \
License
    This file is part of libWallModelledLES.

    libWallModelledLES 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.

    libWallModelledLES 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 libWallModelledLES.
    If not, see <http://www.gnu.org/licenses/>.

\*---------------------------------------------------------------------------*/

#include "CrawlingCellFinder.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "codeRules.H"
#include <math.h>


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
namespace Foam
{
    defineTypeNameAndDebug(CrawlingCellFinder, 0);
    addToRunTimeSelectionTable(CellFinder, CrawlingCellFinder, Patch);
}
#endif


// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //



// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //

Foam::CrawlingCellFinder::CrawlingCellFinder
(
    const fvPatch & p
)
:
    CellFinder(p)
{
    if (debug)
    {
        Info << "CrawlingCellFinder: Constructing from patch" << nl;
    }

    createFields();
}

Foam::CrawlingCellFinder::CrawlingCellFinder
(
    const word & cellFinderName,
    const fvPatch & p
)
:
   CellFinder(p)
{
}

// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //


void Foam::CrawlingCellFinder::findCellIndices
(
    labelList & indexList,
    const scalarField & h,
    const bool hIsIndex
) const
{
    const labelList & owner = mesh_.faceOwner();
    const labelList & neighbour = mesh_.faceNeighbour();
    const vectorField & faceCentres = mesh().Cf().primitiveField();
    const List<cell> & cells = mesh().cells();

    const vectorField & patchFaceCentres = patch().Cf();
    const tmp<vectorField> tfaceNormals = patch().nf();
    const vectorField faceNormals = tfaceNormals();
    const tmp<vectorField> tcellCentres = patch().Cn();
    const vectorField cellCentres = tcellCentres();
    const volVectorField & C = mesh_.C();
    const UList<label> & faceCells = patch().faceCells();
    const List<face> & faces = mesh().faces();
    const label patchStart = patch().start();
    const polyBoundaryMesh & boundaryMesh = mesh().boundaryMesh();

    if (hIsIndex)
    {
        Info<< "CrawlingCellFinder: Treating h as indices!" << nl;
    }
    else
    {
        Info<< "CrawlingCellFinder: Treating h as distances!" << nl;
    }

    forAll(patch(), patchFaceI)
    {

        label nLayers = 0;

        if (hIsIndex)
        {
            nLayers = std::round(h[patchFaceI]);
            if (nLayers < 1)
            {
                Warning
                    << "CrawlingCellFinder: Could not round "
                    << h[patchFaceI] << " to a valid cell layer index. "
                    << "Will fall back to wall-adjacent cell for face "
                    <<  patchFaceI << " on patch " << patch().name() << nl;
                indexList[patchFaceI] = faceCells[patchFaceI];
                continue;
            }
            else if (nLayers == 1)
            {
                indexList[patchFaceI] = faceCells[patchFaceI];
                continue;
            }
        }
        else
        {
            if (h[patchFaceI] < 0)
            {
                Warning
                    << "CrawlingCellFinder: " << h[patchFaceI]
                    << " is negative and thus not a valid distance. "
                    << "Will fall back to wall-adjacent cell for face "
                    <<  patchFaceI << " on patch " << patch().name() << nl;
                indexList[patchFaceI] = faceCells[patchFaceI];
                continue;
            }
            else if (h[patchFaceI] == 0)
            {
                indexList[patchFaceI] = faceCells[patchFaceI];
                continue;
            }

            nLayers = 100; // arbitrary big number
        }


        label startCellIndex = faceCells[patchFaceI];
        cell startCell = cells[startCellIndex];
        label startFaceLabel = patchStart + patchFaceI;
        label nextCellIndex = -1;

        for (label layer=0; layer < nLayers-1; layer++)
        {
            label opposingFace =
                startCell.opposingFaceLabel(startFaceLabel, faces);

            if (opposingFace == -1)
            {
                Warning
                    << "CrawlingCellFinder: Could not find opposing face"
                    << "for cell " << startCellIndex << " with cell center "
                    << C[startCellIndex] << " and face " << startFaceLabel << nl
                    << "Will stop crawling and use the last valid cell "
                    << "corresponding to index " << layer + 1
                    << nl;

                indexList[patchFaceI] = startCellIndex;
                break;
            }
            else if (opposingFace > mesh().nInternalFaces())
            {
                label opposingPatchInd = boundaryMesh.whichPatch(opposingFace);
                const fvPatch & opposingPatch =
                    mesh().boundary()[opposingPatchInd];
                word opposingPatchName = opposingPatch.name();

                // distance that will be used due to abortion in crawling
                scalar distance =
                    mag(C[startCellIndex] - patchFaceCentres[patchFaceI]);

                // If distance-based we might actually get the right h
                // in the last cell, so need to check for that
                // before issuing the warning
                if (hIsIndex || mag(distance - h[patchFaceI])/distance > SMALL)
                {
                    Warning
                        << "CrawlingCellFinder: The opposing face for cell "
                        << startCellIndex << " with cell center "
                        << C[startCellIndex] << " and face " << startFaceLabel
                        << " belongs to patch " << opposingPatchName << nl
                        << "Will stop crawling and use the last valid cell "
                        << "corresponding to index " << layer + 1
                        << " and cell centre at distance " << distance
                        << ". Requested index/distance is " << h[patchFaceI]
                        << " which may or may not correspond to this cell."
                        << nl;
                }

                break;
            }

            scalar distance =
                mag(faceCentres[opposingFace] - patchFaceCentres[patchFaceI]);

            // if the opposing face is above h, stop and grab the cell
            if ((!hIsIndex) && (distance > h[patchFaceI]))
            {
                break;
            }

            if (owner[opposingFace] == startCellIndex)
            {
                nextCellIndex = neighbour[opposingFace];
            }
            else
            {
                nextCellIndex = owner[opposingFace];
            }

            startFaceLabel = opposingFace;
            startCellIndex = nextCellIndex;
            startCell = cells[startCellIndex];
        }

        indexList[patchFaceI] = startCellIndex;
    }
}


void Foam::CrawlingCellFinder::findCellIndices
(
    labelListList & indexList,
    const scalarField & h,
    const bool hIsIndex,
    const bool excludeWallAdjacent
) const
{
    const labelList & owner = mesh_.faceOwner();
    const labelList & neighbour = mesh_.faceNeighbour();
    const vectorField & faceCentres = mesh().Cf().primitiveField();
    const List<cell> & cells = mesh().cells();

    const vectorField & patchFaceCentres = patch().Cf();
    const tmp<vectorField> tfaceNormals = patch().nf();
    const vectorField faceNormals = tfaceNormals();
    const tmp<vectorField> tcellCentres = patch().Cn();
    const vectorField cellCentres = tcellCentres();
    const volVectorField & C = mesh_.C();
    const UList<label> & faceCells = patch().faceCells();
    const List<face> & faces = mesh().faces();
    const label patchStart = patch().start();
    const polyBoundaryMesh & boundaryMesh = mesh().boundaryMesh();

    if (hIsIndex)
    {
        Info<< "CrawlingCellFinder: Treating h as indices!" << nl;
    }
    else
    {
        Info<< "CrawlingCellFinder: Treating h as distances!" << nl;
    }

    forAll(patch(), patchFaceI)
    {

        label nLayers = 0;

        if (hIsIndex)
        {
            nLayers = std::round(h[patchFaceI]);
            if (nLayers < 1)
            {
                Warning
                    << "CrawlingCellFinder: Could not round "
                    << h[patchFaceI] << " to a valid cell layer index. "
                    << "Will fall back to wall-adjacent cell for face "
                    <<  patchFaceI << " on patch " << patch().name() << nl;
                indexList[patchFaceI].setSize(1, faceCells[patchFaceI]);
                continue;
            }
            else if (nLayers == 1)
            {
                indexList[patchFaceI].setSize(1, faceCells[patchFaceI]);
                continue;
            }
        }
        else
        {
            if (h[patchFaceI] < 0)
            {
                Warning
                    << "CrawlingCellFinder: " << h[patchFaceI]
                    << " is negative and thus not a valid distance. "
                    << "Will fall back to wall-adjacent cell for face "
                    <<  patchFaceI << " on patch " << patch().name() << nl;
                indexList[patchFaceI].setSize(1, faceCells[patchFaceI]);
                continue;
            }
            else if (h[patchFaceI] == 0)
            {
                indexList[patchFaceI].setSize(1, faceCells[patchFaceI]);
                continue;
            }

            nLayers = 100; // arbitrary big number
        }
        indexList[patchFaceI].setSize(nLayers, -1);

        label startCellIndex = faceCells[patchFaceI];
        cell startCell = cells[startCellIndex];
        label startFaceLabel = patchStart + patchFaceI;
        label nextCellIndex = -1;

        label layerCounter = 0;

        for (label layer=0; layer < nLayers; layer++)
        {
            layerCounter++;

            // Grab the next cell
            indexList[patchFaceI][layer] = startCellIndex;

            label opposingFace =
                startCell.opposingFaceLabel(startFaceLabel, faces);

            if (opposingFace == -1)
            {
                Warning
                    << "CrawlingCellFinder: Could not find opposing face"
                    << "for cell " << startCellIndex << " with cell center "
                    << C[startCellIndex] << " and face " << startFaceLabel << nl
                    << "Will stop crawling and use the last valid cell "
                    << "corresponding to index " << layer + 1
                    << nl;
                indexList[patchFaceI].setSize(layerCounter);
                break;
            }
            // if we hit a patch
            else if (opposingFace > mesh().nInternalFaces())
            {
                label opposingPatchInd = boundaryMesh.whichPatch(opposingFace);
                const fvPatch & opposingPatch =
                    mesh().boundary()[opposingPatchInd];
                word opposingPatchName = opposingPatch.name();

                // Recompute as the actual distance that will be used
                // due to abortion in crawling
                scalar distance =
                    mag(C[startCellIndex] - patchFaceCentres[patchFaceI]);

                Warning
                    << "CrawlingCellFinder: The opposing face for cell "
                    << startCellIndex << " with cell center "
                    << C[startCellIndex] << " and face " << startFaceLabel
                    << " belongs to patch " << opposingPatchName << nl
                    << "Will stop crawling and use the last valid cell "
                    << "corresponding to index " << layer + 1
                    << " and distance " << distance
                    << nl;

                // Need this when hIsIndex
                indexList[patchFaceI].setSize(layerCounter);
                break;
            }

            scalar distance =
                mag(faceCentres[opposingFace] - patchFaceCentres[patchFaceI]);

            // if the opposing face is above h, stop
            if ((!hIsIndex) && (distance > h[patchFaceI]))
            {
                indexList[patchFaceI].setSize(layerCounter);
                break;
            }

            // find index of the next cell
            if (owner[opposingFace] == startCellIndex)
            {
                nextCellIndex = neighbour[opposingFace];
            }
            else
            {
                nextCellIndex = owner[opposingFace];
            }

            startFaceLabel = opposingFace;
            startCellIndex = nextCellIndex;
            startCell = cells[startCellIndex];
        }

        if ((indexList[patchFaceI].size() != 1) && excludeWallAdjacent)
        {
            for(int j=0; j<indexList[patchFaceI].size()-1; j++)
            {
                indexList[patchFaceI][j] = indexList[patchFaceI][j+1];
            }
            indexList[patchFaceI].setSize(indexList[patchFaceI].size()-1);

        }
    }
}

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //