From a5fbb36d73faf3a8616ec5f5d1d76f5add0de520 Mon Sep 17 00:00:00 2001
From: mark <mark@opencfd>
Date: Fri, 16 Sep 2016 21:33:40 +0200
Subject: [PATCH] ENH: runTime calculation of zeroGradient volume fields (issue
 #235)

Extrapolate internal field to walls for post-processing.
Uses as new syntax for handling the naming of multiple fields.

The input fields are selected via a wordReList.
For example,

    fields      (U "(T|k|epsilon|omega)");

The names of the resulting output fields use placeholder tokens for
flexibility. For example,

    result      zeroGradient(@@);

The '@@' placeholder is replaced by the name of the input field.
Eg,
    fields      (U T);
    result      zeroGradient(@@);
->  zeroGradient(U), zeroGradient(T)

Or,
    fields      (U T);
    result      @@nearWall;
->  UnearWall, TnearWall

NOTE:
    The function object will skip over fields that only have
    processor, empty, zeroGradient patches. The operation does not
    make much sense for these, and it avoids inadvertently
    re-processing fields twice.
---
 .../functionObjects/utilities/Make/files      |   3 +
 .../utilities/zeroGradient/IOzeroGradient.H   |  49 +++
 .../utilities/zeroGradient/zeroGradient.C     | 341 ++++++++++++++++++
 .../utilities/zeroGradient/zeroGradient.H     | 220 +++++++++++
 .../zeroGradient/zeroGradientFunctionObject.C |  42 +++
 .../zeroGradient/zeroGradientFunctionObject.H |  54 +++
 6 files changed, 709 insertions(+)
 create mode 100644 src/postProcessing/functionObjects/utilities/zeroGradient/IOzeroGradient.H
 create mode 100644 src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradient.C
 create mode 100644 src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradient.H
 create mode 100644 src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradientFunctionObject.C
 create mode 100644 src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradientFunctionObject.H

diff --git a/src/postProcessing/functionObjects/utilities/Make/files b/src/postProcessing/functionObjects/utilities/Make/files
index 4b7341f296a..fdb2b220ea0 100644
--- a/src/postProcessing/functionObjects/utilities/Make/files
+++ b/src/postProcessing/functionObjects/utilities/Make/files
@@ -54,6 +54,9 @@ wallShearStress/wallShearStressFunctionObject.C
 yPlus/yPlus.C
 yPlus/yPlusFunctionObject.C
 
+zeroGradient/zeroGradient.C
+zeroGradient/zeroGradientFunctionObject.C
+
 setTimeStep/setTimeStepFunctionObject.C
 
 reactionSensitivityAnalysis/reactionsSensitivityAnalysisFunctionObject.C
diff --git a/src/postProcessing/functionObjects/utilities/zeroGradient/IOzeroGradient.H b/src/postProcessing/functionObjects/utilities/zeroGradient/IOzeroGradient.H
new file mode 100644
index 00000000000..eabf6bab3c3
--- /dev/null
+++ b/src/postProcessing/functionObjects/utilities/zeroGradient/IOzeroGradient.H
@@ -0,0 +1,49 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+Typedef
+    Foam::IOzeroGradient
+
+Description
+    Instance of the generic IOOutputFilter for zeroGradient.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef IOzeroGradient_H
+#define IOzeroGradient_H
+
+#include "zeroGradient.H"
+#include "IOOutputFilter.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    typedef IOOutputFilter<zeroGradient> IOzeroGradient;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradient.C b/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradient.C
new file mode 100644
index 00000000000..4b12a948e0f
--- /dev/null
+++ b/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradient.C
@@ -0,0 +1,341 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "zeroGradient.H"
+
+#include "volFields.H"
+#include "dictionary.H"
+#include "symmetryFvPatchField.H"
+#include "symmetryPlaneFvPatchField.H"
+#include "zeroGradientFvPatchField.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(zeroGradient, 0);
+}
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+bool Foam::zeroGradient::checkFormatName(const word& str)
+{
+    if (str.find("@@") == string::npos)
+    {
+        WarningInFunction
+            << "Bad result naming "
+            << "(no '@@' token found), deactivating."
+            << nl << endl;
+
+        return false;
+    }
+    else if (str == "@@")
+    {
+        WarningInFunction
+            << "Bad result naming "
+            << "(only a '@@' token found), deactivating."
+            << nl
+            << endl;
+
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+
+
+void Foam::zeroGradient::uniqWords(wordReList& lst)
+{
+    boolList retain(lst.size());
+    wordHashSet uniq;
+    forAll(lst, i)
+    {
+        const wordRe& select = lst[i];
+
+        retain[i] =
+        (
+            select.isPattern()
+         || uniq.insert(static_cast<const word&>(select))
+        );
+    }
+
+    inplaceSubset(retain, lst);
+}
+
+
+template<class Type>
+bool Foam::zeroGradient::accept
+(
+    const GeometricField<Type, fvPatchField, volMesh>& input
+)
+{
+    const typename GeometricField<Type, fvPatchField, volMesh>
+    ::GeometricBoundaryField& patches = input.boundaryField();
+
+    forAll(patches, patchi)
+    {
+        const fvPatchField<Type>& p = patches[patchi];
+        const polyPatch& pp = p.patch().patch();
+
+        bool ignore =
+        (
+            isA<emptyPolyPatch>(pp)
+         || isA<processorPolyPatch>(pp)
+
+         || isA<zeroGradientFvPatchField<Type>>(p)
+         || isA<symmetryFvPatchField<Type>>(p)
+         || isA<symmetryPlaneFvPatchField<Type>>(p)
+        );
+
+        if (!ignore)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+
+template<class Type>
+int Foam::zeroGradient::apply
+(
+    const fvMesh& mesh,
+    const word& inputName,
+    int& state
+)
+{
+    typedef GeometricField<Type, fvPatchField, volMesh> vfType;
+
+    // state: return 0 (not-processed), -1 (skip), +1 ok
+
+    // already done, or not available
+    if (state || !mesh.foundObject<vfType>(inputName))
+    {
+        return state;
+    }
+
+    const vfType& input = mesh.lookupObject<vfType>(inputName);
+
+    if (!returnReduce(accept(input), orOp<bool>()))
+    {
+        state = -1;
+        return state;
+    }
+
+    word outputName(resultName_);
+    outputName.replace("@@", inputName);
+
+    // also save the field-type, just in case we want it later
+    results_.set(outputName, vfType::typeName);
+
+    if (!mesh.foundObject<vfType>(outputName))
+    {
+        mesh.objectRegistry::store
+        (
+            new vfType
+            (
+                IOobject
+                (
+                    outputName,
+                    mesh.time().timeName(),
+                    mesh,
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE
+                ),
+                mesh,
+                dimensioned<Type>("0", input.dimensions(), Zero),
+                zeroGradientFvPatchField<Type>::typeName
+            )
+        );
+    }
+
+    vfType& output = const_cast<vfType&>(mesh.lookupObject<vfType>(outputName));
+    output = input;
+    output.correctBoundaryConditions();
+
+    state = +1;
+    return state;
+}
+
+
+int Foam::zeroGradient::process(const fvMesh& mesh, const word& fieldName)
+{
+    int state = 0;
+    apply<scalar>(mesh, fieldName, state);
+    apply<vector>(mesh, fieldName, state);
+    apply<sphericalTensor>(mesh, fieldName, state);
+    apply<symmTensor>(mesh, fieldName, state);
+    apply<tensor>(mesh, fieldName, state);
+
+    return state;
+}
+
+
+void Foam::zeroGradient::process(const fvMesh& mesh)
+{
+    results_.clear();
+
+    wordHashSet candidates = subsetStrings(selectFields_, mesh.names());
+    DynamicList<word> missing(selectFields_.size());
+    DynamicList<word> ignored(selectFields_.size());
+
+    // check exact matches first
+    forAll(selectFields_, i)
+    {
+        const wordRe& select = selectFields_[i];
+        if (!select.isPattern())
+        {
+            const word& fieldName = static_cast<const word&>(select);
+
+            if (!candidates.erase(fieldName))
+            {
+                missing.append(fieldName);
+            }
+            else if (process(mesh, fieldName) < 1)
+            {
+                ignored.append(fieldName);
+            }
+        }
+    }
+
+    forAllConstIter(wordHashSet, candidates, iter)
+    {
+        process(mesh, iter.key());
+    }
+
+    if (missing.size())
+    {
+        WarningInFunction
+            << "Missing field " << missing << endl;
+    }
+    if (ignored.size())
+    {
+        WarningInFunction
+            << "Unprocessed field " << ignored << endl;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::zeroGradient::zeroGradient
+(
+    const word& name,
+    const objectRegistry& obr,
+    const dictionary& dict,
+    const bool loadFromFiles
+)
+:
+    name_(name),
+    obr_(obr),
+    active_(true),
+    selectFields_(),
+    resultName_(string::null),
+    results_(),
+    log_(false)
+{
+    // Check if the available mesh is an fvMesh, otherwise deactivate
+    if (!isA<fvMesh>(obr_))
+    {
+        active_ = false;
+        WarningInFunction
+            << "No fvMesh available, deactivating." << nl
+            << endl;
+    }
+
+    read(dict);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::zeroGradient::~zeroGradient()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::zeroGradient::read(const dictionary& dict)
+{
+    if (active_)
+    {
+        log_ = dict.lookupOrDefault<Switch>("log", false);
+
+        dict.lookup("fields") >> selectFields_;
+        uniqWords(selectFields_);
+
+        resultName_ = dict.lookupOrDefault<word>
+        (
+            "result",
+            type() + "(@@)"
+        );
+        active_ = checkFormatName(resultName_);
+    }
+}
+
+
+void Foam::zeroGradient::execute()
+{
+    results_.clear();
+    if (active_)
+    {
+        process(refCast<const fvMesh>(obr_));
+    }
+}
+
+
+void Foam::zeroGradient::write()
+{
+    if (active_)
+    {
+        // consistent output order
+        const wordList outputList = results_.sortedToc();
+
+        forAll(outputList, i)
+        {
+            const word& fieldName = outputList[i];
+
+            if (obr_.foundObject<regIOobject>(fieldName))
+            {
+                const regIOobject& io =
+                    obr_.lookupObject<regIOobject>(fieldName);
+
+                if (log_)
+                {
+                    Info<< type() << " " << name_
+                        << " output: writing field " << fieldName << endl;
+                }
+
+                io.write();
+            }
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradient.H b/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradient.H
new file mode 100644
index 00000000000..74b83cfa894
--- /dev/null
+++ b/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradient.H
@@ -0,0 +1,220 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+Class
+    Foam::zeroGradient
+
+Group
+    grpFVFunctionObjects
+
+Description
+    This function object creates a volume field with zero-gradient
+    boundary conditions from another volume field.
+
+    The result can be used, for example, to post-process near-wall
+    field values.
+
+    Example of function object specification:
+    \verbatim
+    zeroGrad
+    {
+        type        zeroGradient;
+        functionObjectLibs ("libutilityFunctionObjects.so");
+        fields      (U "(T|k|epsilon|omega)");
+        result      @@nearWall;
+        ...
+    }
+    \endverbatim
+
+    \heading Function object usage
+    \table
+        Property | Description                | Required  | Default value
+        type     | type name: zeroGradient    | yes       |
+        fields   | Name of fields to process  | yes       |
+        result   | Name of results            | no        | zeroGradient(@@)
+        log      | Log to standard output     | no        | no
+    \endtable
+
+    A list of fields can contain exact names or regular expressions.
+    The token '\@\@' in the result name is replaced by the name of the source
+    field.
+
+    The function object will skip over fields that would not benefit
+    - ie, only processor, empty, zeroGradient, symmetry patches.
+    This check should also prevent processing fields multiple times.
+
+SourceFiles
+    zeroGradient.C
+    zeroGradientFunctionObject.C
+    IOzeroGradient.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef zeroGradient_H
+#define zeroGradient_H
+
+#include "volFieldsFwd.H"
+#include "OFstream.H"
+#include "wordReList.H"
+#include "Switch.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class objectRegistry;
+class dictionary;
+class fvMesh;
+class polyMesh;
+class mapPolyMesh;
+
+/*---------------------------------------------------------------------------*\
+                            Class zeroGradient Declaration
+\*---------------------------------------------------------------------------*/
+
+class zeroGradient
+{
+    // Private data
+
+        //- Name of this zeroGradient object
+        word name_;
+
+        //- Reference to the database
+        const objectRegistry& obr_;
+
+        //- On/off switch
+        bool active_;
+
+        //- Name of fields to process
+        wordReList selectFields_;
+
+        //- Formatting for the result fields.
+        word resultName_;
+
+        //- Hashed names of result fields, and their type
+        HashTable<word> results_;
+
+        //- Switch to send output to Info as well as to file
+        Switch log_;
+
+
+    // Private Member Functions
+
+        //- Check that the word contains the appropriate substitution token(s).
+        static bool checkFormatName(const word&);
+
+        //- Eliminate duplicate 'word' entries
+        static void uniqWords(wordReList&);
+
+
+        //- Accept unless field only has empty/zero-gradient/processor patches
+        template<class Type>
+        static bool accept(const GeometricField<Type, fvPatchField, volMesh>&);
+
+        //- Apply for the volume field type
+        template<class Type>
+        int apply(const fvMesh& mesh, const word& inputName, int& state);
+
+        //- Process by trying to apply for various volume field types.
+        int process(const fvMesh& mesh, const word& inputName);
+
+        //- Calculate the zeroGradient fields
+        void process(const fvMesh& mesh);
+
+
+        //- Disallow default bitwise copy construct
+        zeroGradient(const zeroGradient&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const zeroGradient&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("zeroGradient");
+
+
+    // Constructors
+
+        //- Construct for given objectRegistry and dictionary.
+        //  Allow the possibility to load fields from files
+        zeroGradient
+        (
+            const word& name,
+            const objectRegistry&,
+            const dictionary&,
+            const bool loadFromFiles = false
+        );
+
+
+    //- Destructor
+    virtual ~zeroGradient();
+
+
+    // Member Functions
+
+        //- Return name of the zeroGradient function object
+        virtual const word& name() const
+        {
+            return name_;
+        }
+
+        //- Read the zeroGradient specification
+        virtual void read(const dictionary&);
+
+        //- Calculate the zeroGradient fields
+        virtual void execute();
+
+        //- Execute at the final time-loop, currently does nothing
+        virtual void end()
+        {}
+
+        //- Called when time was set at the end of the Time::operator++
+        virtual void timeSet()
+        {}
+
+        //- Write the zeroGradient fields
+        virtual void write();
+
+        //- Update for changes of mesh
+        virtual void updateMesh(const mapPolyMesh&)
+        {}
+
+        //- Update for changes of mesh
+        virtual void movePoints(const polyMesh&)
+        {}
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradientFunctionObject.C b/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradientFunctionObject.C
new file mode 100644
index 00000000000..89b5c7f09a0
--- /dev/null
+++ b/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradientFunctionObject.C
@@ -0,0 +1,42 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "zeroGradientFunctionObject.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineNamedTemplateTypeNameAndDebug(zeroGradientFunctionObject, 0);
+
+    addToRunTimeSelectionTable
+    (
+        functionObject,
+        zeroGradientFunctionObject,
+        dictionary
+    );
+}
+
+// ************************************************************************* //
diff --git a/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradientFunctionObject.H b/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradientFunctionObject.H
new file mode 100644
index 00000000000..cccea11df97
--- /dev/null
+++ b/src/postProcessing/functionObjects/utilities/zeroGradient/zeroGradientFunctionObject.H
@@ -0,0 +1,54 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+Typedef
+    Foam::zeroGradientFunctionObject
+
+Description
+    FunctionObject wrapper around zeroGradient to allow it to be created
+    via the functions entry within controlDict.
+
+SourceFiles
+    zeroGradientFunctionObject.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef zeroGradientFunctionObject_H
+#define zeroGradientFunctionObject_H
+
+#include "zeroGradient.H"
+#include "OutputFilterFunctionObject.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    typedef OutputFilterFunctionObject<zeroGradient>
+        zeroGradientFunctionObject;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
-- 
GitLab