Skip to content
Snippets Groups Projects
surfaceFieldValue.C 19.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*---------------------------------------------------------------------------*\
      =========                 |
      \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
       \\    /   O peration     |
    
        \\  /    A nd           | Copyright (C) 2011-2016 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 "fvMesh.H"
    #include "cyclicPolyPatch.H"
    #include "emptyPolyPatch.H"
    
    #include "coupledPolyPatch.H"
    
    #include "mergePoints.H"
    #include "indirectPrimitivePatch.H"
    
    #include "PatchTools.H"
    
    #include "addToRunTimeSelectionTable.H"
    
    
    // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
    
    
    namespace functionObjects
    {
    namespace fieldValues
    {
    
        defineTypeNameAndDebug(surfaceFieldValue, 0);
        addToRunTimeSelectionTable(fieldValue, surfaceFieldValue, dictionary);
        addToRunTimeSelectionTable(functionObject, surfaceFieldValue, dictionary);
    
        Foam::functionObjects::fieldValues::surfaceFieldValue::regionTypes,
    
        Foam::functionObjects::fieldValues::surfaceFieldValue::operationType,
    
        15
    >::names[] =
    {
        "none",
        "sum",
        "sumMag",
        "sumDirection",
        "sumDirectionBalance",
        "average",
        "weightedAverage",
        "areaAverage",
        "weightedAreaAverage",
        "areaIntegrate",
        "min",
        "max",
        "CoV",
        "areaNormalAverage",
        "areaNormalIntegrate"
    };
    
    const Foam::NamedEnum
    <
    
        Foam::functionObjects::fieldValues::surfaceFieldValue::regionTypes,
    
    > Foam::functionObjects::fieldValues::surfaceFieldValue::regionTypeNames_;
    
        Foam::functionObjects::fieldValues::surfaceFieldValue::operationType,
    
    > Foam::functionObjects::fieldValues::surfaceFieldValue::operationTypeNames_;
    
    
    
    // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
    
    
    void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces()
    
        label zoneId = mesh_.faceZones().findZoneID(regionName_);
    
            FatalErrorInFunction
    
                << type() << " " << name() << ": "
    
                << regionTypeNames_[regionType_] << "(" << regionName_ << "):" << nl
                << "    Unknown face zone name: " << regionName_
    
                << ". Valid face zones are: " << mesh_.faceZones().names()
    
                << nl << exit(FatalError);
        }
    
    
        const faceZone& fZone = mesh_.faceZones()[zoneId];
    
        DynamicList<label> faceIds(fZone.size());
        DynamicList<label> facePatchIds(fZone.size());
        DynamicList<label> faceSigns(fZone.size());
    
            label facei = fZone[i];
    
    
            label faceId = -1;
            label facePatchId = -1;
    
                facePatchId = mesh_.boundaryMesh().whichPatch(facei);
                const polyPatch& pp = mesh_.boundaryMesh()[facePatchId];
    
                if (isA<coupledPolyPatch>(pp))
    
                    if (refCast<const coupledPolyPatch>(pp).owner())
    
                        faceId = pp.whichFace(facei);
    
                    }
                    else
                    {
                        faceId = -1;
                    }
                }
                else if (!isA<emptyPolyPatch>(pp))
                {
    
                    faceId = facei - pp.start();
    
                }
                else
                {
                    faceId = -1;
                    facePatchId = -1;
                }
            }
    
            if (faceId >= 0)
            {
                if (fZone.flipMap()[i])
                {
    
                    faceSigns.append(-1);
    
                    faceSigns.append(1);
    
                faceIds.append(faceId);
                facePatchIds.append(facePatchId);
    
        faceId_.transfer(faceIds);
        facePatchId_.transfer(facePatchIds);
        faceSign_.transfer(faceSigns);
    
        nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
    
            Pout<< "Original face zone size = " << fZone.size()
    
                << ", new size = " << faceId_.size() << endl;
    
    void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces()
    
        const label patchid = mesh_.boundaryMesh().findPatchID(regionName_);
    
            FatalErrorInFunction
    
                << type() << " " << name() << ": "
    
                << regionTypeNames_[regionType_] << "(" << regionName_ << "):" << nl
                << "    Unknown patch name: " << regionName_
    
                << ". Valid patch names are: "
    
                << mesh_.boundaryMesh().names() << nl
    
        const polyPatch& pp = mesh_.boundaryMesh()[patchid];
    
    
        label nFaces = pp.size();
    
        if (isA<emptyPolyPatch>(pp))
    
        {
            nFaces = 0;
        }
    
        faceId_.setSize(nFaces);
        facePatchId_.setSize(nFaces);
    
        faceSign_.setSize(nFaces);
        nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
    
        forAll(faceId_, facei)
    
            faceId_[facei] = facei;
            facePatchId_[facei] = patchid;
            faceSign_[facei] = 1;
    
    void Foam::functionObjects::fieldValues::surfaceFieldValue::sampledSurfaceFaces
    
            dict.subDict("sampledSurfaceDict")
        );
        surfacePtr_().update();
        nFaces_ = returnReduce(surfacePtr_().faces().size(), sumOp<label>());
    }
    
    
    
    void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
    
    (
        faceList& faces,
        pointField& points
    ) const
    {
        List<faceList> allFaces(Pstream::nProcs());
        List<pointField> allPoints(Pstream::nProcs());
    
        labelList globalFacesIs(faceId_);
        forAll(globalFacesIs, i)
        {
            if (facePatchId_[i] != -1)
            {
    
                label patchi = facePatchId_[i];
    
                globalFacesIs[i] += mesh_.boundaryMesh()[patchi].start();
    
            }
        }
    
        // Add local faces and points to the all* lists
        indirectPrimitivePatch pp
        (
    
            IndirectList<face>(mesh_.faces(), globalFacesIs),
            mesh_.points()
    
        );
        allFaces[Pstream::myProcNo()] = pp.localFaces();
        allPoints[Pstream::myProcNo()] = pp.localPoints();
    
        Pstream::gatherList(allFaces);
        Pstream::gatherList(allPoints);
    
        // Renumber and flatten
        label nFaces = 0;
        label nPoints = 0;
    
            nFaces += allFaces[proci].size();
            nPoints += allPoints[proci].size();
    
        }
    
        faces.setSize(nFaces);
        points.setSize(nPoints);
    
        nFaces = 0;
        nPoints = 0;
    
        // My own data first
        {
            const faceList& fcs = allFaces[Pstream::myProcNo()];
            forAll(fcs, i)
            {
                const face& f = fcs[i];
                face& newF = faces[nFaces++];
                newF.setSize(f.size());
                forAll(f, fp)
                {
                    newF[fp] = f[fp] + nPoints;
                }
            }
    
            const pointField& pts = allPoints[Pstream::myProcNo()];
            forAll(pts, i)
            {
                points[nPoints++] = pts[i];
            }
        }
    
        // Other proc data follows
    
            if (proci != Pstream::myProcNo())
    
                const faceList& fcs = allFaces[proci];
    
                forAll(fcs, i)
                {
                    const face& f = fcs[i];
                    face& newF = faces[nFaces++];
                    newF.setSize(f.size());
                    forAll(f, fp)
                    {
                        newF[fp] = f[fp] + nPoints;
                    }
                }
    
    
                const pointField& pts = allPoints[proci];
    
                forAll(pts, i)
                {
                    points[nPoints++] = pts[i];
                }
            }
        }
    
        // Merge
        labelList oldToNew;
        pointField newPoints;
        bool hasMerged = mergePoints
        (
            points,
            SMALL,
            false,
            oldToNew,
            newPoints
        );
    
        if (hasMerged)
        {
            if (debug)
            {
                Pout<< "Merged from " << points.size()
                    << " down to " << newPoints.size() << " points" << endl;
            }
    
            points.transfer(newPoints);
            forAll(faces, i)
            {
                inplaceRenumber(oldToNew, faces[i]);
            }
        }
    }
    
    
    
    void Foam::functionObjects::fieldValues::surfaceFieldValue::
    combineSurfaceGeometry
    
    (
        faceList& faces,
        pointField& points
    ) const
    {
        if (surfacePtr_.valid())
        {
            const sampledSurface& s = surfacePtr_();
    
            if (Pstream::parRun())
            {
    
                // Dimension as fraction of mesh bounding box
    
                scalar mergeDim = 1e-10*mesh_.bounds().mag();
    
    
                labelList pointsMap;
    
                PatchTools::gatherAndMerge
                (
                    mergeDim,
                    primitivePatch
                    (
                        SubList<face>(s.faces(), s.faces().size()),
                        s.points()
                    ),
                    points,
                    faces,
                    pointsMap
                );
            }
            else
            {
                faces = s.faces();
                points = s.points();
            }
        }
    }
    
    
    
    Foam::functionObjects::fieldValues::surfaceFieldValue::totalArea() const
    
    {
        scalar totalArea;
    
        if (surfacePtr_.valid())
        {
            totalArea = gSum(surfacePtr_().magSf());
        }
        else
        {
    
            totalArea = gSum(filterField(mesh_.magSf(), false));
    
    // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
    
    
    void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
    
        {
            case stFaceZone:
            {
                setFaceZoneFaces();
                break;
            }
            case stPatch:
            {
                setPatchFaces();
                break;
            }
    
            case stSampledSurface:
            {
                sampledSurfaceFaces(dict);
                break;
            }
    
                FatalErrorInFunction
    
                    << type() << " " << name() << ": "
    
                    << regionTypeNames_[regionType_] << "(" << regionName_ << "):"
    
                    << nl << "    Unknown region type. Valid region types are:"
                    << regionTypeNames_.sortedToc() << nl << exit(FatalError);
    
                << type() << " " << name() << ": "
    
                << regionTypeNames_[regionType_] << "(" << regionName_ << "):" << nl
    
                << "    Region has no faces" << exit(FatalError);
    
        totalArea_ = totalArea();
    
    
        Info<< type() << " " << name() << ":" << nl
    
            << "    total faces  = " << nFaces_
            << nl
    
            << "    total area   = " << totalArea_
    
        if (dict.readIfPresent("weightField", weightFieldName_))
    
            Info<< "    weight field = " << weightFieldName_ << nl;
    
    mattijs's avatar
    mattijs committed
    
    
    mattijs's avatar
    mattijs committed
            {
    
                FatalIOErrorInFunction(dict)
    
    mattijs's avatar
    mattijs committed
                    << "Cannot use weightField for a sampledSurface"
                    << exit(FatalIOError);
            }
    
        }
    
        if (dict.found("orientedWeightField"))
        {
            if (weightFieldName_ == "none")
            {
                dict.lookup("orientedWeightField") >>  weightFieldName_;
                Info<< "    weight field = " << weightFieldName_ << nl;
                orientWeightField_ = true;
            }
            else
            {
    
                FatalIOErrorInFunction(dict)
    
                    << "Either weightField or orientedWeightField can be supplied, "
                    << "but not both"
                    << exit(FatalIOError);
            }
        }
    
        List<word> orientedFields;
        if (dict.readIfPresent("orientedFields", orientedFields))
        {
            orientedFieldsStart_ = fields_.size();
            fields_.append(orientedFields);
    
        if (dict.readIfPresent("scaleFactor", scaleFactor_))
        {
    
            Info<< "    scale factor = " << scaleFactor_ << nl;
    
        Info<< nl << endl;
    
            const word surfaceFormat(dict.lookup("surfaceFormat"));
    
    
                surfaceWriter::New
                (
                    surfaceFormat,
                    dict.subOrEmptyDict("formatOptions").
                        subOrEmptyDict(surfaceFormat)
                ).ptr()
    
    void Foam::functionObjects::fieldValues::surfaceFieldValue::writeFileHeader
    
            writeCommented(file(), "Region type : ");
            file() << regionTypeNames_[regionType_] << " " << regionName_ << endl;
            writeCommented(file(), "Faces  : ");
            file() << nFaces_ << endl;
            writeCommented(file(), "Area   : ");
            file() << totalArea_ << endl;
    
            writeCommented(file(), "Time");
            if (writeArea_)
            {
                file() << tab << "Area";
            }
    
            forAll(fields_, i)
            {
                file()
    
                << tab << operationTypeNames_[operation_]
    
    Foam::scalar Foam::functionObjects::fieldValues::surfaceFieldValue::
    processValues
    
    (
        const Field<scalar>& values,
        const vectorField& Sf,
        const scalarField& weightField
    ) const
    {
        switch (operation_)
        {
            case opSumDirection:
            {
    
                vector n(dict_.lookup("direction"));
                return sum(pos(values*(Sf & n))*mag(values));
            }
            case opSumDirectionBalance:
            {
                vector n(dict_.lookup("direction"));
                const scalarField nv(values*(Sf & n));
    
                return sum(pos(nv)*mag(values) - neg(nv)*mag(values));
    
            }
            default:
            {
                // Fall through to other operations
                return processSameTypeValues(values, Sf, weightField);
            }
        }
    }
    
    
    
    Foam::vector Foam::functionObjects::fieldValues::surfaceFieldValue::
    processValues
    
    (
        const Field<vector>& values,
        const vectorField& Sf,
        const scalarField& weightField
    ) const
    {
        switch (operation_)
        {
    
                vector n(dict_.lookup("direction"));
                n /= mag(n) + ROOTVSMALL;
                const scalarField nv(n & values);
    
                return sum(pos(nv)*n*(nv));
            }
            case opSumDirectionBalance:
            {
                vector n(dict_.lookup("direction"));
                n /= mag(n) + ROOTVSMALL;
                const scalarField nv(n & values);
    
                return sum(pos(nv)*n*(nv));
    
            case opAreaNormalAverage:
            {
    
                scalar result = sum(values & Sf)/sum(mag(Sf));
    
                return vector(result, 0.0, 0.0);
            }
            case opAreaNormalIntegrate:
            {
    
                scalar result = sum(values & Sf);
    
                return vector(result, 0.0, 0.0);
            }
            default:
            {
                // Fall through to other operations
                return processSameTypeValues(values, Sf, weightField);
            }
        }
    }
    
    
    
    // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
    
    
    Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
    
    (
        const word& name,
        const Time& runTime,
        const dictionary& dict
    )
    :
        fieldValue(name, runTime, dict, typeName),
    
        surfaceWriterPtr_(nullptr),
    
        regionType_(regionTypeNames_.read(dict.lookup("regionType"))),
    
        operation_(operationTypeNames_.read(dict.lookup("operation"))),
        weightFieldName_("none"),
        orientWeightField_(false),
        orientedFieldsStart_(labelMax),
        scaleFactor_(1.0),
        writeArea_(dict.lookupOrDefault("writeArea", false)),
        nFaces_(0),
        faceId_(),
        facePatchId_(),
        faceSign_()
    {
        read(dict);
    }
    
    
    Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
    
    (
        const word& name,
        const objectRegistry& obr,
    
        fieldValue(name, obr, dict, typeName),
    
        surfaceWriterPtr_(nullptr),
    
        regionType_(regionTypeNames_.read(dict.lookup("regionType"))),
    
        operation_(operationTypeNames_.read(dict.lookup("operation"))),
    
        orientWeightField_(false),
        orientedFieldsStart_(labelMax),
    
        scaleFactor_(1.0),
    
        writeArea_(dict.lookupOrDefault("writeArea", false)),
    
        faceId_(),
        facePatchId_(),
    
    // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
    
    
    Foam::functionObjects::fieldValues::surfaceFieldValue::~surfaceFieldValue()
    
    {}
    
    
    // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
    
    
    bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
    
    Andrew Heather's avatar
    Andrew Heather committed
        fieldValue::read(dict);
    
    bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
    
    Andrew Heather's avatar
    Andrew Heather committed
    
    
        if (operation_ != opNone && Pstream::master())
    
            if (operation_ != opNone && Pstream::master())
    
            Log << "    total area = " << totalArea_ << endl;
    
        // Write the surface geometry
        if (surfaceWriterPtr_.valid())
        {
            faceList faces;
            pointField points;
    
            if (surfacePtr_.valid())
            {
                combineSurfaceGeometry(faces, points);
            }
            else
            {
                combineMeshGeometry(faces, points);
            }
    
            if (Pstream::master())
            {
                surfaceWriterPtr_->write
                (
                    outputDir(),
                    regionTypeNames_[regionType_] + ("_" + regionName_),
                    points,
                    faces,
                    false
                );
            }
        }
    
        // Construct weight field. Note: zero size means weight = 1
    
        scalarField weightField;
        if (weightFieldName_ != "none")
        {
            weightField =
                getFieldValues<scalar>
                (
                    weightFieldName_,
                    true,
                    orientWeightField_
                );
        }
    
        // Combine onto master
        combineFields(weightField);
    
        forAll(fields_, i)
        {
            const word& fieldName = fields_[i];
            bool ok = false;
    
            bool orient = i >= orientedFieldsStart_;
            ok = ok || writeValues<scalar>(fieldName, weightField, orient);
            ok = ok || writeValues<vector>(fieldName, weightField, orient);
            ok = ok
              || writeValues<sphericalTensor>(fieldName, weightField, orient);
            ok = ok || writeValues<symmTensor>(fieldName, weightField, orient);
            ok = ok || writeValues<tensor>(fieldName, weightField, orient);
    
                WarningInFunction
                    << "Requested field " << fieldName
                    << " not found in database and not processed"
                    << endl;
    
        if (operation_ != opNone && Pstream::master())
    
    }
    
    
    // ************************************************************************* //