From e6f8d27553542c6edbcb53779e468ec9f9024ad5 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@Germany>
Date: Thu, 15 Dec 2016 12:59:35 +0100
Subject: [PATCH] ENH: integrate surfField-based fluxSummary

- additional surface and surfaceAndDirection modes
---
 .../field/fluxSummary/fluxSummary.C           | 289 ++++++++++++++++--
 .../field/fluxSummary/fluxSummary.H           |  39 ++-
 2 files changed, 300 insertions(+), 28 deletions(-)

diff --git a/src/functionObjects/field/fluxSummary/fluxSummary.C b/src/functionObjects/field/fluxSummary/fluxSummary.C
index 5950b33c4a5..f176b2dda45 100644
--- a/src/functionObjects/field/fluxSummary/fluxSummary.C
+++ b/src/functionObjects/field/fluxSummary/fluxSummary.C
@@ -25,6 +25,8 @@ License
 
 #include "fluxSummary.H"
 #include "surfaceFields.H"
+#include "surfFields.H"
+#include "surfMesh.H"
 #include "dictionary.H"
 #include "Time.H"
 #include "syncTools.H"
@@ -54,33 +56,59 @@ template<>
 const char* NamedEnum
 <
     functionObjects::fluxSummary::modeType,
-    3
+    5
 >::names[] =
 {
     "faceZone",
     "faceZoneAndDirection",
-    "cellZoneAndDirection"
+    "cellZoneAndDirection",
+    "surface",
+    "surfaceAndDirection"
 };
 }
 
 
-const Foam::NamedEnum<Foam::functionObjects::fluxSummary::modeType, 3>
+const Foam::NamedEnum<Foam::functionObjects::fluxSummary::modeType, 5>
 Foam::functionObjects::fluxSummary::modeTypeNames_;
 
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
+bool Foam::functionObjects::fluxSummary::isSurfaceMode() const
+{
+    bool isSurf = false;
+
+    switch (mode_)
+    {
+        case mdSurface:
+        case mdSurfaceAndDirection:
+            isSurf = true;
+            break;
+
+        default:
+            break;
+    }
+
+    return isSurf;
+}
+
+
 Foam::word Foam::functionObjects::fluxSummary::checkFlowType
 (
-    const dimensionSet& dims,
+    const dimensionSet& fieldDims,
     const word& fieldName
 ) const
 {
-    if (dims == dimVolume/dimTime)
+    // Surfaces are multipled by their area, so account for that
+    // in the dimension checking
+    dimensionSet dims =
+        fieldDims * (isSurfaceMode() ? dimTime*dimArea : dimTime);
+
+    if (dims == dimVolume)
     {
         return "volumetric";
     }
-    else if (dims == dimMass/dimTime)
+    else if (dims == dimMass)
     {
         return "mass";
     }
@@ -88,7 +116,7 @@ Foam::word Foam::functionObjects::fluxSummary::checkFlowType
     {
         FatalErrorInFunction
             << "Unsupported flux field " << fieldName << " with dimensions "
-            << dims
+            << fieldDims
             << ".  Expected either mass flow or volumetric flow rate."
             << abort(FatalError);
 
@@ -97,6 +125,76 @@ Foam::word Foam::functionObjects::fluxSummary::checkFlowType
 }
 
 
+void Foam::functionObjects::fluxSummary::initialiseSurface
+(
+    const word& surfName,
+    DynamicList<word>& names,
+    DynamicList<vector>& directions,
+    DynamicList<boolList>& faceFlip
+) const
+{
+    const surfMesh* sPtr = mesh_.lookupObjectPtr<surfMesh>(surfName);
+    if (!sPtr)
+    {
+        FatalErrorInFunction
+            << "Unable to find surface " << surfName
+            << ".  Valid surfaces are: " << mesh_.sortedNames<surfMesh>()
+            << '.'
+            << exit(FatalError);
+    }
+
+    names.append(surfName);
+    directions.append(Zero); // dummy value
+    faceFlip.append(boolList(0)); // no flip-map
+}
+
+
+void Foam::functionObjects::fluxSummary::initialiseSurfaceAndDirection
+(
+    const word& surfName,
+    const vector& dir,
+    DynamicList<word>& names,
+    DynamicList<vector>& directions,
+    DynamicList<boolList>& faceFlip
+) const
+{
+    const surfMesh* sPtr = mesh_.lookupObjectPtr<surfMesh>(surfName);
+    if (!sPtr)
+    {
+        FatalErrorInFunction
+            << "Unable to find surface " << surfName
+            << ".  Valid surfaces are: " << mesh_.sortedNames<surfMesh>()
+            << '.'
+            << exit(FatalError);
+    }
+
+    const surfMesh& s = *sPtr;
+    const vector refDir = dir/(mag(dir) + ROOTVSMALL);
+
+    names.append(surfName);
+    directions.append(refDir);
+    faceFlip.append(boolList(0));
+
+    boolList& flips = faceFlip[faceFlip.size()-1];
+    flips.setSize(s.size(), false);
+
+    forAll(s, i)
+    {
+        // orientation set by comparison with reference direction
+        const vector& n = s.faceNormals()[i];
+
+        if ((n & refDir) > tolerance_)
+        {
+            flips[i] = false;
+        }
+        else
+        {
+            flips[i] = true;
+        }
+    }
+}
+
+
 void Foam::functionObjects::fluxSummary::initialiseFaceZone
 (
     const word& faceZoneName,
@@ -570,31 +668,120 @@ void Foam::functionObjects::fluxSummary::initialiseCellZoneAndDirection
 
 Foam::scalar Foam::functionObjects::fluxSummary::totalArea
 (
-    const label zonei
+    const label idx
 ) const
 {
-    const surfaceScalarField& magSf = mesh_.magSf();
+    scalar sumMagSf = 0;
+
+    if (isSurfaceMode())
+    {
+        const surfMesh& s = mesh_.lookupObject<surfMesh>(zoneNames_[idx]);
+        sumMagSf = sum(s.magSf());
+    }
+    else
+    {
+        const surfaceScalarField& magSf = mesh_.magSf();
 
-    const labelList& faceIDs = faceID_[zonei];
-    const labelList& facePatchIDs = facePatchID_[zonei];
+        const labelList& faceIDs = faceID_[idx];
+        const labelList& facePatchIDs = facePatchID_[idx];
 
-    scalar sumMagSf = 0;
-    forAll(faceIDs, i)
+        forAll(faceIDs, i)
+        {
+            label facei = faceIDs[i];
+
+            if (facePatchIDs[i] == -1)
+            {
+                sumMagSf += magSf[facei];
+            }
+            else
+            {
+                label patchi = facePatchIDs[i];
+                sumMagSf += magSf.boundaryField()[patchi][facei];
+            }
+        }
+    }
+
+    return returnReduce(sumMagSf, sumOp<scalar>());
+}
+
+
+bool Foam::functionObjects::fluxSummary::surfaceModeWrite()
+{
+    if (zoneNames_.size())
+    {
+        const label surfi = 0;
+        const surfMesh& s = mesh_.lookupObject<surfMesh>(zoneNames_[surfi]);
+        const surfVectorField& phi = s.lookupObject<surfVectorField>(phiName_);
+
+        Log << type() << ' ' << name() << ' '
+            << checkFlowType(phi.dimensions(), phi.name()) << " write:" << nl;
+    }
+
+
+    forAll(zoneNames_, surfi)
     {
-        label facei = faceIDs[i];
+        const surfMesh& s = mesh_.lookupObject<surfMesh>(zoneNames_[surfi]);
+        const surfVectorField& phi = s.lookupObject<surfVectorField>(phiName_);
+
+        checkFlowType(phi.dimensions(), phi.name());
+
+        const boolList& flips = faceFlip_[surfi];
+
+        scalar phiPos = scalar(0);
+        scalar phiNeg = scalar(0);
 
-        if (facePatchIDs[i] == -1)
+        tmp<scalarField> tphis = phi & s.Sf();
+        const scalarField& phis = tphis();
+
+        forAll(s, i)
         {
-            sumMagSf += magSf[facei];
+            scalar phif = phis[i];
+            if (flips[i])
+            {
+                phif *= -1;
+            }
+
+            if (phif > 0)
+            {
+                phiPos += phif;
+            }
+            else
+            {
+                phiNeg += phif;
+            }
         }
-        else
+
+        reduce(phiPos, sumOp<scalar>());
+        reduce(phiNeg, sumOp<scalar>());
+
+        phiPos *= scaleFactor_;
+        phiNeg *= scaleFactor_;
+
+        scalar netFlux = phiPos + phiNeg;
+        scalar absoluteFlux = phiPos - phiNeg;
+
+        Log << "    surface " << zoneNames_[surfi] << ':' << nl
+            << "        positive : " << phiPos << nl
+            << "        negative : " << phiNeg << nl
+            << "        net      : " << netFlux << nl
+            << "        absolute : " << absoluteFlux
+            << nl << endl;
+
+        if (writeToFile())
         {
-            label patchi = facePatchIDs[i];
-            sumMagSf += magSf.boundaryField()[patchi][facei];
+            filePtrs_[surfi]
+                << time_.value() << token::TAB
+                << phiPos << token::TAB
+                << phiNeg << token::TAB
+                << netFlux << token::TAB
+                << absoluteFlux
+                << endl;
         }
     }
 
-    return returnReduce(sumMagSf, sumOp<scalar>());
+    Log << endl;
+
+    return true;
 }
 
 
@@ -708,6 +895,40 @@ bool Foam::functionObjects::fluxSummary::read(const dictionary& dict)
             }
             break;
         }
+        case mdSurface:
+        {
+            List<word> surfs(dict.lookup("surfaces"));
+
+            forAll(surfs, i)
+            {
+                initialiseSurface
+                (
+                    surfs[i],
+                    faceZoneName,
+                    refDir,
+                    faceFlips
+                );
+            }
+            break;
+        }
+        case mdSurfaceAndDirection:
+        {
+            List<Tuple2<word, vector>>
+                surfAndDirection(dict.lookup("surfaceAndDirection"));
+
+            forAll(surfAndDirection, i)
+            {
+                initialiseSurfaceAndDirection
+                (
+                    surfAndDirection[i].first(),
+                    surfAndDirection[i].second(),
+                    faceZoneName,
+                    refDir,
+                    faceFlips
+                );
+            }
+            break;
+        }
         default:
         {
             FatalIOErrorInFunction(dict)
@@ -730,7 +951,16 @@ bool Foam::functionObjects::fluxSummary::read(const dictionary& dict)
         const word& zoneName = zoneNames_[zonei];
         areas[zonei] = totalArea(zonei);
 
-        Info<< "    Zone: " << zoneName << ", area: " << areas[zonei] << nl;
+        if (isSurfaceMode())
+        {
+            Info<< "    Surface: " << zoneName
+                << ", area: " << areas[zonei] << nl;
+        }
+        else
+        {
+            Info<< "    Zone: " << zoneName
+                << ", area: " << areas[zonei] << nl;
+        }
     }
     Info<< endl;
 
@@ -752,7 +982,7 @@ bool Foam::functionObjects::fluxSummary::read(const dictionary& dict)
         }
     }
 
-    return true;
+    return !zoneNames_.empty();
 }
 
 
@@ -765,13 +995,21 @@ void Foam::functionObjects::fluxSummary::writeFileHeader
 ) const
 {
     writeHeader(os, "Flux summary");
-    writeHeaderValue(os, "Face zone", zoneName);
+    if (isSurfaceMode())
+    {
+        writeHeaderValue(os, "Surface", zoneName);
+    }
+    else
+    {
+        writeHeaderValue(os, "Face zone", zoneName);
+    }
     writeHeaderValue(os, "Total area", area);
 
     switch (mode_)
     {
         case mdFaceZoneAndDirection:
         case mdCellZoneAndDirection:
+        case mdSurfaceAndDirection:
         {
             writeHeaderValue(os, "Reference direction", refDir);
             break;
@@ -799,6 +1037,11 @@ bool Foam::functionObjects::fluxSummary::execute()
 
 bool Foam::functionObjects::fluxSummary::write()
 {
+    if (isSurfaceMode())
+    {
+        return surfaceModeWrite();
+    }
+
     const surfaceScalarField& phi = lookupObject<surfaceScalarField>(phiName_);
 
     Log << type() << ' ' << name() << ' '
diff --git a/src/functionObjects/field/fluxSummary/fluxSummary.H b/src/functionObjects/field/fluxSummary/fluxSummary.H
index 2e135d2300a..287c6a3782f 100644
--- a/src/functionObjects/field/fluxSummary/fluxSummary.H
+++ b/src/functionObjects/field/fluxSummary/fluxSummary.H
@@ -68,6 +68,8 @@ Usage
     - faceZone
     - faceZoneAndDirection
     - cellZoneAndDirection
+    - surface
+    - surfaceAndDirection
 
     Output data is written to files of the form \<timeDir\>/<faceZoneName>.dat
 
@@ -116,11 +118,13 @@ public:
         {
             mdFaceZone,                 //!< face zone
             mdFaceZoneAndDirection,     //!< face zone with prescribed direction
-            mdCellZoneAndDirection      //!< cell zone with prescribed direction
+            mdCellZoneAndDirection,     //!< cell zone with prescribed direction
+            mdSurface,                  //!< surfMesh
+            mdSurfaceAndDirection       //!< surfMesh with prescribed direction
         };
 
         //- Mode type names
-        static const NamedEnum<modeType, 3> modeTypeNames_;
+        static const NamedEnum<modeType, 5> modeTypeNames_;
 
 
 protected:
@@ -161,14 +165,36 @@ protected:
 
     // Private Member Functions
 
+        //- Check if surface mode instead of zone mode
+        bool isSurfaceMode() const;
+
         //- Check flowType (mass or volume).
         //  Return name on success, fatal error on failure.
         word checkFlowType
         (
-            const dimensionSet& dims,
+            const dimensionSet& fieldDims,
             const word& fieldName
         ) const;
 
+        //- Initialise for given surface name
+        void initialiseSurface
+        (
+            const word& surfName,
+            DynamicList<word>& names,
+            DynamicList<vector>& dir,
+            DynamicList<boolList>& faceFlip
+        ) const;
+
+        //- Initialise for given surface name and direction
+        void initialiseSurfaceAndDirection
+        (
+            const word& surfName,
+            const vector& refDir,
+            DynamicList<word>& names,
+            DynamicList<vector>& dir,
+            DynamicList<boolList>& faceFlip
+        ) const;
+
         //- Initialise face set from face zone
         void initialiseFaceZone
         (
@@ -204,8 +230,8 @@ protected:
             DynamicList<boolList>& faceFlip
         ) const;
 
-        //- Calculate the total area for the derived faceZone
-        scalar totalArea(const label zonei) const;
+        //- Calculate the total area for the surface or derived faceZone
+        scalar totalArea(const label idx) const;
 
         //- Output file header information
         virtual void writeFileHeader
@@ -216,6 +242,9 @@ protected:
             Ostream& os
         ) const;
 
+        //- Specialized write for surfaces
+        bool surfaceModeWrite();
+
         //- Disallow default bitwise copy construct
         fluxSummary(const fluxSummary&) = delete;
 
-- 
GitLab