From 9fe527ba3a3dfdc100e014cf4983795fd50157df Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Tue, 11 Mar 2025 15:18:43 +0000
Subject: [PATCH 01/31] WIP: fieldStatistics: new function object

---
 src/functionObjects/field/Make/files          |   2 +
 .../field/fieldStatistics/fieldStatistics.C   | 312 ++++++++++++++++++
 .../field/fieldStatistics/fieldStatistics.H   | 277 ++++++++++++++++
 .../fieldStatisticsTemplates.C                | 183 ++++++++++
 4 files changed, 774 insertions(+)
 create mode 100644 src/functionObjects/field/fieldStatistics/fieldStatistics.C
 create mode 100644 src/functionObjects/field/fieldStatistics/fieldStatistics.H
 create mode 100644 src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C

diff --git a/src/functionObjects/field/Make/files b/src/functionObjects/field/Make/files
index fe9eec32830..060eb3e1685 100644
--- a/src/functionObjects/field/Make/files
+++ b/src/functionObjects/field/Make/files
@@ -154,4 +154,6 @@ resolutionIndex/resolutionIndexModels/CelikEtaIndex/CelikEtaIndex.C
 age/age.C
 comfort/comfort.C
 
+fieldStatistics/fieldStatistics.C
+
 LIB = $(FOAM_LIBBIN)/libfieldFunctionObjects
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
new file mode 100644
index 00000000000..c54d581f0e2
--- /dev/null
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -0,0 +1,312 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2025 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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 "fieldStatistics.H"
+#include "fieldTypes.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+    defineTypeNameAndDebug(fieldStatistics, 0);
+    addToRunTimeSelectionTable(functionObject, fieldStatistics, dictionary);
+}
+}
+
+const Foam::Enum
+<
+    Foam::functionObjects::fieldStatistics::modeType
+>
+Foam::functionObjects::fieldStatistics::modeTypeNames_
+({
+    { modeType::mdMag,  "magnitude" },
+    { modeType::mdCmpt, "component" },
+});
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::functionObjects::fieldStatistics::statistic
+Foam::functionObjects::fieldStatistics::createStatistic
+(
+    const word& statName,
+    const modeType& mode
+)
+{
+    statistic m;
+    m.name_ = statName;
+
+    m.calc = [this, statName, mode](variantInput input) -> variantOutput
+    {
+        return std::visit
+        (
+            [this, statName, mode](auto&& arg) -> variantOutput
+            {
+                using T = std::decay_t<decltype(arg)>;
+                using BaseType = typename T::value_type;
+
+                if (statName == "min")
+                {
+                    if (mode == mdMag) return mag(calcMin<BaseType>(arg));
+                    else return calcMin<BaseType>(arg);
+                }
+                else if (statName == "max")
+                {
+                    if (mode == mdMag) return mag(calcMax<BaseType>(arg));
+                    else return calcMax<BaseType>(arg);
+                }
+                else if (statName == "mean")
+                {
+                    if (mode == mdMag) return mag(calcMean<BaseType>(arg));
+                    else return calcMean<BaseType>(arg);
+                }
+                else if (statName == "variance")
+                {
+                    if (mode == mdMag) return mag(calcVariance<BaseType>(arg));
+                    else return calcVariance<BaseType>(arg);
+                }
+                else return scalar{};  // Default case (for compiler)
+            },
+            input
+        );
+    };
+
+    return m;
+}
+
+
+void Foam::functionObjects::fieldStatistics::writeFileHeader
+(
+    Ostream& os,
+    const word& fieldName
+)
+{
+    writeHeader(os, word("Field Statistics: " + fieldName));
+    writeCommented(os, "Time");
+
+    // Number of input statistics (i.e., statistics_) could be lesser than that
+    // of output statistics (i.e., results_; e.g., cell index of min value).
+    // Therefore, the output file columns are based on output statistics.
+    const auto& result = results_(fieldName);
+
+    forAllConstIters(result, iter)
+    {
+        const word& name = iter.key();
+        writeTabbed(os, name);
+    }
+    os  << endl;
+
+    writtenHeader_ = true;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::functionObjects::fieldStatistics::fieldStatistics
+(
+    const word& name,
+    const Time& runTime,
+    const dictionary& dict
+)
+:
+    fvMeshFunctionObject(name, runTime, dict),
+    writeFile(mesh_, name, typeName, dict),
+    fieldSet_(mesh_)
+{
+    read(dict);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
+{
+    if (!(fvMeshFunctionObject::read(dict) && writeFile::read(dict)))
+    {
+        return false;
+    }
+
+    mode_ = modeTypeNames_.getOrDefault("mode", dict, modeType::mdMag);
+
+    // Reset and reprepare the input field names
+    fieldSet_.clear();
+    fieldSet_.read(dict);
+    fieldSet_.updateSelection();
+
+    // Reset and reprepare the input statistics
+    statistics_.clear();
+    const wordHashSet stats(dict.get<wordHashSet>("statistics"));
+    for (const word& m : stats)
+    {
+        statistics_.insert(m, createStatistic(m, mode_));
+    }
+
+    // Reset and reprepare the output statistics
+    results_.clear();
+
+    return true;
+}
+
+
+bool Foam::functionObjects::fieldStatistics::execute()
+{
+    // Calculate the specified statistics for the specified fields
+    for (const word& fieldName : fieldSet_.selectionNames())
+    {
+        const bool ok =
+        (
+            calcStat<scalar>(fieldName)
+         || calcStat<vector>(fieldName)
+         || calcStat<symmTensor>(fieldName)
+         || calcStat<tensor>(fieldName)
+        );
+
+        if (!ok)
+        {
+            WarningInFunction
+                << "Unable to find field " << fieldName << endl;
+        }
+    }
+
+    // Store the statistical results into the state containers
+    for (const word& fieldName : fieldSet_.selectionNames())
+    {
+        const auto& results = results_(fieldName);
+
+        forAllConstIters(results, iter)
+        {
+            const word& name = iter.key();
+            const variantOutput& value = iter.val();
+
+            const word variableName(fieldName + "_" + name);
+
+            std::visit
+            (
+                [this, variableName](const auto& v)
+                {
+                    this->setResult(variableName, v);
+                },
+                value
+            );
+        }
+    }
+
+    return true;
+}
+
+
+bool Foam::functionObjects::fieldStatistics::write()
+{
+    // Create an output file per field
+    if (writeToFile() && !writtenHeader_)
+    {
+        for (const word& fieldName : fieldSet_.selectionNames())
+        {
+            filePtrs_.set(fieldName, newFileAtStartTime(fieldName));
+
+            OFstream& file = *filePtrs_(fieldName);
+
+            writeFileHeader(file, fieldName);
+        }
+    }
+
+    // Write the statistical results to the output file if requested
+    if (writeToFile())
+    {
+        for (const word& fieldName : fieldSet_.selectionNames())
+        {
+            const auto& results = results_(fieldName);
+
+            OFstream& file = *filePtrs_(fieldName);
+
+            writeCurrentTime(file);
+
+            forAllConstIters(results, iter)
+            {
+                const variantOutput& value = iter.val();
+
+                std::visit
+                (
+                    [&file](const auto& v)
+                    {
+                        if constexpr (std::is_same_v<std::decay_t<decltype(v)>, scalar>)
+                        {
+                            file<< token::TAB << v;
+                        }
+                        else
+                        {
+                            for (const auto& val : v) file<< token::TAB << val;
+                        }
+                    },
+                    value
+                );
+            }
+            file<< nl;
+        }
+    }
+
+    // Print the statistical results to the standard stream if requested
+    if (log)
+    {
+        for (const word& fieldName : fieldSet_.selectionNames())
+        {
+            const auto& results = results_(fieldName);
+
+            forAllConstIters(results, iter)
+            {
+                const word& name = iter.key();
+                const variantOutput& value = iter.val();
+
+                std::visit
+                (
+                    [name](const auto& v)
+                    {
+                        if constexpr (std::is_same_v<std::decay_t<decltype(v)>, scalar>)
+                        {
+                            Info<< name << " " << v;
+                        }
+                        else
+                        {
+                            Info<< name << " ";
+                            for (const auto& val : v) Info<< val << " ";
+                        }
+                        Info<< nl;
+                    },
+                    value
+                );
+            }
+        }
+    }
+
+    return true;
+}
+
+
+// ************************************************************************* //
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
new file mode 100644
index 00000000000..6b4ec3877d9
--- /dev/null
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -0,0 +1,277 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2025 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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::functionObjects::fieldStatistics
+
+Group
+    grpFieldFunctionObjects
+
+Description
+
+    Operands:
+    \table
+      Operand        | Type | Location
+      input          | -    | -
+      output file    | dat  | \<case\>/postProcessing/\<FO\>/\<time\>/\<file\>
+      output field   | -    | -
+    \endtable
+
+Usage
+    Minimal example by using \c system/controlDict.functions:
+    \verbatim
+    fieldStatistics1
+    {
+        // Mandatory entries
+        type             fieldStatistics;
+        libs             (fieldFunctionObjects);
+        fields           (<wordList>);
+        statistics       (<wordList>);
+
+        // Optional entries
+        mode             <word>;
+
+        // Inherited entries
+        ...
+    }
+    \endverbatim
+
+    where the entries mean:
+    \table
+      Property     | Description                        | Type | Reqd  | Deflt
+      type         | Type name: fieldStatistics         | word | yes   | -
+      libs         | Library name: fieldFunctionObjects | word | yes   | -
+      fields       | List of operand fields             | wordList | yes | -
+      statistics   | List of operand statistics         | wordList | yes | -
+      mode   | Output format of the statistical results | word | no | magnitude
+    \endtable
+
+    Available statistics of the operand field through the \c statistics entry:
+    \verbatim
+      min        | Minimum value
+      max        | Maximum value
+      mean       | Arithmetic mean value
+      variance   | Sample variance value (unbiased)
+    \endverbatim
+
+    Options for the \c mode entry:
+    \verbatim
+      magnitude  | Output statistics magnitude-wise
+      component  | Output statistics separately for each component
+    \endverbatim
+
+    The inherited entries are elaborated in:
+      - \link functionObject.H \endlink
+      - \link writeFile.H \endlink
+
+SourceFiles
+    fieldStatistics.C
+    fieldStatisticsTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef functionObjects_fieldStatistics_H
+#define functionObjects_fieldStatistics_H
+
+#include "fvMeshFunctionObject.H"
+#include "writeFile.H"
+#include "volFieldSelection.H"
+#include <functional>
+#include <variant>
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class fieldStatistics Declaration
+\*---------------------------------------------------------------------------*/
+
+class fieldStatistics
+:
+    public fvMeshFunctionObject,
+    public writeFile
+{
+    // Private Enumerations
+
+        //- Options for the output format of the statistical results
+        enum modeType : char
+        {
+            mdMag = 0,  //!< "Output statistics magnitude-wise"
+            mdCmpt      //!< "Output statistics separately for each component"
+        };
+
+        //- Names for modeType
+        static const Enum<modeType> modeTypeNames_;
+
+
+    // Private Classes
+
+        //- Type-safe union for input field types
+        using variantInput = std::variant
+        <
+            volScalarField,
+            volVectorField,
+            volSymmTensorField,
+            volTensorField
+        >;
+
+        //- Type-safe union for output data types
+        using variantOutput = std::variant
+        <
+            scalar,
+            vector,
+            symmTensor,
+            tensor
+        >;
+
+        //- Class to encapsulate information about specified statistic
+        struct statistic
+        {
+            //- Name of the statistic
+            word name_;
+
+            //- Calculate the value of the specified statistic
+            std::function<variantOutput(variantInput)> calc;
+        };
+
+
+    // Private Data
+
+        //- Output-format mode - only applicable for tensor ranks > 0
+        modeType mode_;
+
+        //- Operand fields on which statistics are computed
+        volFieldSelection fieldSet_;
+
+        //- List of file pointers; one file per field
+        HashPtrTable<OFstream> filePtrs_;
+
+        //- Hash table containing all specified statistics
+        HashTable<statistic> statistics_;
+
+        //- Hash table containing all statistical results per field
+        HashTable<HashTable<variantOutput>> results_;
+
+
+    // Private Member Functions
+
+        //- Return the statistic container
+        statistic createStatistic(const word& statName, const modeType& mode);
+
+        //- Compute the specified statistics of a given field
+        template<class T>
+        bool calcStat(const word& fieldName);
+
+
+        // Central tendency statistics
+
+        //- Return the arithmetic mean of the given input field
+        template<class T>
+        T calcMean(const VolumeField<T>& field);
+
+
+        // Dispersion statistics
+
+        //- Return the minimum value of the given input field
+        //  Store the processor index, cell index and location of the minimum
+        template<class T>
+        T calcMin(const VolumeField<T>& field);
+
+        //- Return the maximum value of the given input field
+        //  Store the processor index, cell index and location of the maximum
+        template<class T>
+        T calcMax(const VolumeField<T>& field);
+
+        //- Return the sample variance of the given input field
+        template<class T>
+        T calcVariance(const VolumeField<T>& field);
+
+
+        //- Output the file header information
+        void writeFileHeader(Ostream& os, const word& fieldName);
+
+public:
+
+    //- Runtime type information
+    TypeName("fieldStatistics");
+
+
+    // Generated Methods
+
+        //- No copy construct
+        fieldStatistics(const fieldStatistics&) = delete;
+
+        //- No copy assignment
+        void operator=(const fieldStatistics&) = delete;
+
+
+    // Constructors
+
+        //- Construct from name, Time and dictionary
+        fieldStatistics
+        (
+            const word& name,
+            const Time& runTime,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~fieldStatistics() = default;
+
+
+    // Member Functions
+
+        //- Read function object settings
+        virtual bool read(const dictionary&);
+
+        //- Execute function object
+        virtual bool execute();
+
+        //- Write function object results
+        virtual bool write();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace functionObjects
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "fieldStatisticsTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C b/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
new file mode 100644
index 00000000000..760532be33b
--- /dev/null
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
@@ -0,0 +1,183 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2025 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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 "fieldStatistics.H"
+#include "volFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
+{
+    typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+
+    if (!obr_.foundObject<VolFieldType>(fieldName))
+    {
+        return false;
+    }
+
+    const VolFieldType& field = lookupObject<VolFieldType>(fieldName);
+
+    HashTable<variantOutput> result;
+    for (const auto& iter : statistics_.csorted())
+    {
+        const statistic& stat = iter.val();
+
+        // Assign a new entry, overwriting existing entries
+        result.set(stat.name_, stat.calc(field));
+    }
+
+    results_.set(fieldName, result);
+
+    return true;
+}
+
+
+template<class T>
+T Foam::functionObjects::fieldStatistics::calcMean(const VolumeField<T>& field)
+{
+    return gAverage(field);
+}
+
+
+template<class T>
+T Foam::functionObjects::fieldStatistics::calcMin(const VolumeField<T>& field)
+{
+    const label proci = Pstream::myProcNo();
+
+    // Find min internal field value info
+
+    List<T> minVs(Pstream::nProcs(), pTraits<T>::max);
+
+    labelPair minMaxIds = findMinMax(field);
+
+    label minId = minMaxIds.first();
+    if (minId != -1)
+    {
+        minVs[proci] = field[minId];
+    }
+
+    // Find min boundary field info
+    const auto& fieldBoundary = field.boundaryField();
+
+    forAll(fieldBoundary, patchi)
+    {
+        const Field<T>& fp = fieldBoundary[patchi];
+        if (fp.size())
+        {
+            minMaxIds = findMinMax(fp);
+
+            minId = minMaxIds.first();
+            if (minVs[proci] > fp[minId])
+            {
+                minVs[proci] = fp[minId];
+            }
+        }
+    }
+
+    // Collect info from all processors and output
+    Pstream::allGatherList(minVs);
+
+    minId = findMin(minVs);
+
+    return minVs[minId];  // minValue
+}
+
+
+template<class T>
+T Foam::functionObjects::fieldStatistics::calcMax(const VolumeField<T>& field)
+{
+    const label proci = Pstream::myProcNo();
+
+    // Find max internal field value info
+
+    List<T> maxVs(Pstream::nProcs(), pTraits<T>::min);
+
+    labelPair minMaxIds = findMinMax(field);
+
+    label maxId = minMaxIds.second();
+    if (maxId != -1)
+    {
+        maxVs[proci] = field[maxId];
+    }
+
+
+    // Find max boundary field info
+    const auto& fieldBoundary = field.boundaryField();
+
+    forAll(fieldBoundary, patchi)
+    {
+        const Field<T>& fp = fieldBoundary[patchi];
+        if (fp.size())
+        {
+            minMaxIds = findMinMax(fp);
+
+            maxId = minMaxIds.second();
+            if (maxVs[proci] < fp[maxId])
+            {
+                maxVs[proci] = fp[maxId];
+            }
+        }
+    }
+
+    // Collect info from all processors and output
+    Pstream::allGatherList(maxVs);
+
+    maxId = findMax(maxVs);
+
+    return maxVs[maxId];  // maxValue
+}
+
+
+template<class T>
+T Foam::functionObjects::fieldStatistics::calcVariance
+(
+    const VolumeField<T>& field
+)
+{
+    label n = field.size();
+    reduce(n, sumOp<label>());
+
+    const T average(calcMean(field));
+
+    T var = Zero;
+    for (const auto& elem : field)
+    {
+        var += (elem - average);
+    }
+    reduce(var, sumOp<T>());
+
+    if (n <= 1)
+    {
+        return T{};
+    }
+
+    return 1/(n-1)*var;
+}
+
+
+// ************************************************************************* //
-- 
GitLab


From 5f2d55e07b466cf49b788b03ba9712b203e3360e Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Tue, 11 Mar 2025 15:43:38 +0000
Subject: [PATCH 02/31] WIP: fieldStatistics: introduce flag to process
 internal fields only

---
 .../field/fieldStatistics/fieldStatistics.C   |  2 +
 .../field/fieldStatistics/fieldStatistics.H   | 28 ++++--
 .../fieldStatisticsTemplates.C                | 95 +++++++++++--------
 3 files changed, 75 insertions(+), 50 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index c54d581f0e2..4e6d159b2e5 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -153,6 +153,8 @@ bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
         return false;
     }
 
+    internal_ = dict.getOrDefault("internal", false);
+
     mode_ = modeTypeNames_.getOrDefault("mode", dict, modeType::mdMag);
 
     // Reset and reprepare the input field names
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 6b4ec3877d9..866433d3339 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -52,6 +52,7 @@ Usage
 
         // Optional entries
         mode             <word>;
+        internal         <bool>;
 
         // Inherited entries
         ...
@@ -66,6 +67,8 @@ Usage
       fields       | List of operand fields             | wordList | yes | -
       statistics   | List of operand statistics         | wordList | yes | -
       mode   | Output format of the statistical results | word | no | magnitude
+      internal | Flag to use internal fields only in computing statistics <!--
+               -->                                      | bool | no | false
     \endtable
 
     Available statistics of the operand field through the \c statistics entry:
@@ -135,10 +138,10 @@ class fieldStatistics
         //- Type-safe union for input field types
         using variantInput = std::variant
         <
-            volScalarField,
-            volVectorField,
-            volSymmTensorField,
-            volTensorField
+            scalarField,
+            vectorField,
+            symmTensorField,
+            tensorField
         >;
 
         //- Type-safe union for output data types
@@ -163,6 +166,9 @@ class fieldStatistics
 
     // Private Data
 
+        //- Flag to use internal fields only in computing statistics
+        bool internal_;
+
         //- Output-format mode - only applicable for tensor ranks > 0
         modeType mode_;
 
@@ -193,7 +199,7 @@ class fieldStatistics
 
         //- Return the arithmetic mean of the given input field
         template<class T>
-        T calcMean(const VolumeField<T>& field);
+        T calcMean(const Field<T>& field);
 
 
         // Dispersion statistics
@@ -201,17 +207,23 @@ class fieldStatistics
         //- Return the minimum value of the given input field
         //  Store the processor index, cell index and location of the minimum
         template<class T>
-        T calcMin(const VolumeField<T>& field);
+        T calcMin(const Field<T>& field);
 
         //- Return the maximum value of the given input field
         //  Store the processor index, cell index and location of the maximum
         template<class T>
-        T calcMax(const VolumeField<T>& field);
+        T calcMax(const Field<T>& field);
 
         //- Return the sample variance of the given input field
         template<class T>
-        T calcVariance(const VolumeField<T>& field);
+        T calcVariance(const Field<T>& field);
 
+        //-
+        template<class GeoField>
+        tmp<Field<typename GeoField::value_type>> flatten
+        (
+            const GeoField& field
+        );
 
         //- Output the file header information
         void writeFileHeader(Ostream& os, const word& fieldName);
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C b/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
index 760532be33b..48e7581974e 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
@@ -30,6 +30,51 @@ License
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+template<class GeoField>
+Foam::tmp<Foam::Field<typename GeoField::value_type>>
+Foam::functionObjects::fieldStatistics::flatten(const GeoField& fld)
+{
+    typedef typename GeoField::value_type value_type;
+    typedef Field<value_type> FieldType;
+
+
+    label n = fld.size();
+
+    if (!internal_)
+    {
+        for (const auto& pfld : fld.boundaryField())
+        {
+            if (!pfld.coupled())
+            {
+                n += pfld.size();
+            }
+        }
+    }
+
+    auto tflatFld = tmp<FieldType>::New(n);
+    auto& flatFld = tflatFld.ref();
+
+    // Insert internal values
+    SubList<value_type>(flatFld, fld.size(), 0) = fld.primitiveField();
+
+    if (!internal_)
+    {
+        // Insert boundary values
+        n = fld.size();
+        for (const auto& pfld : fld.boundaryField())
+        {
+            if (!pfld.coupled())
+            {
+                SubList<value_type>(flatFld, pfld.size(), n) = pfld;
+                n += pfld.size();
+            }
+        }
+    }
+
+    return tflatFld;
+}
+
+
 template<class Type>
 bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
 {
@@ -42,13 +87,16 @@ bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
 
     const VolFieldType& field = lookupObject<VolFieldType>(fieldName);
 
+    tmp<Field<Type>> tfld = flatten(field);
+    const Field<Type> fld = tfld.cref();
+
     HashTable<variantOutput> result;
     for (const auto& iter : statistics_.csorted())
     {
         const statistic& stat = iter.val();
 
         // Assign a new entry, overwriting existing entries
-        result.set(stat.name_, stat.calc(field));
+        result.set(stat.name_, stat.calc(fld));
     }
 
     results_.set(fieldName, result);
@@ -58,14 +106,14 @@ bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
 
 
 template<class T>
-T Foam::functionObjects::fieldStatistics::calcMean(const VolumeField<T>& field)
+T Foam::functionObjects::fieldStatistics::calcMean(const Field<T>& field)
 {
     return gAverage(field);
 }
 
 
 template<class T>
-T Foam::functionObjects::fieldStatistics::calcMin(const VolumeField<T>& field)
+T Foam::functionObjects::fieldStatistics::calcMin(const Field<T>& field)
 {
     const label proci = Pstream::myProcNo();
 
@@ -81,24 +129,6 @@ T Foam::functionObjects::fieldStatistics::calcMin(const VolumeField<T>& field)
         minVs[proci] = field[minId];
     }
 
-    // Find min boundary field info
-    const auto& fieldBoundary = field.boundaryField();
-
-    forAll(fieldBoundary, patchi)
-    {
-        const Field<T>& fp = fieldBoundary[patchi];
-        if (fp.size())
-        {
-            minMaxIds = findMinMax(fp);
-
-            minId = minMaxIds.first();
-            if (minVs[proci] > fp[minId])
-            {
-                minVs[proci] = fp[minId];
-            }
-        }
-    }
-
     // Collect info from all processors and output
     Pstream::allGatherList(minVs);
 
@@ -109,7 +139,7 @@ T Foam::functionObjects::fieldStatistics::calcMin(const VolumeField<T>& field)
 
 
 template<class T>
-T Foam::functionObjects::fieldStatistics::calcMax(const VolumeField<T>& field)
+T Foam::functionObjects::fieldStatistics::calcMax(const Field<T>& field)
 {
     const label proci = Pstream::myProcNo();
 
@@ -125,25 +155,6 @@ T Foam::functionObjects::fieldStatistics::calcMax(const VolumeField<T>& field)
         maxVs[proci] = field[maxId];
     }
 
-
-    // Find max boundary field info
-    const auto& fieldBoundary = field.boundaryField();
-
-    forAll(fieldBoundary, patchi)
-    {
-        const Field<T>& fp = fieldBoundary[patchi];
-        if (fp.size())
-        {
-            minMaxIds = findMinMax(fp);
-
-            maxId = minMaxIds.second();
-            if (maxVs[proci] < fp[maxId])
-            {
-                maxVs[proci] = fp[maxId];
-            }
-        }
-    }
-
     // Collect info from all processors and output
     Pstream::allGatherList(maxVs);
 
@@ -156,7 +167,7 @@ T Foam::functionObjects::fieldStatistics::calcMax(const VolumeField<T>& field)
 template<class T>
 T Foam::functionObjects::fieldStatistics::calcVariance
 (
-    const VolumeField<T>& field
+    const Field<T>& field
 )
 {
     label n = field.size();
-- 
GitLab


From 40eda5738983cd7e6d7ceb0446c23c378f561619 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Tue, 11 Mar 2025 16:56:55 +0000
Subject: [PATCH 03/31] WIP: fieldStatistics: add volume-weighted average to
 the options

---
 .../field/fieldStatistics/fieldStatistics.C   | 11 ++++++++++
 .../field/fieldStatistics/fieldStatistics.H   | 22 +++++++++++++++++++
 .../fieldStatisticsTemplates.C                |  6 +++++
 3 files changed, 39 insertions(+)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 4e6d159b2e5..3271e641a64 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -50,6 +50,16 @@ Foam::functionObjects::fieldStatistics::modeTypeNames_
     { modeType::mdCmpt, "component" },
 });
 
+const Foam::Enum
+<
+    Foam::functionObjects::fieldStatistics::meanType
+>
+Foam::functionObjects::fieldStatistics::meanTypeNames_
+({
+    { meanType::ARITHMETIC, "arithmetic" },
+    { meanType::VOLUMETRIC, "volumetric" },
+});
+
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -156,6 +166,7 @@ bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
     internal_ = dict.getOrDefault("internal", false);
 
     mode_ = modeTypeNames_.getOrDefault("mode", dict, modeType::mdMag);
+    mean_ = meanTypeNames_.getOrDefault("mean", dict, meanType::ARITHMETIC);
 
     // Reset and reprepare the input field names
     fieldSet_.clear();
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 866433d3339..f8f6ca5d91d 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -53,6 +53,7 @@ Usage
         // Optional entries
         mode             <word>;
         internal         <bool>;
+        mean             <word>;
 
         // Inherited entries
         ...
@@ -69,6 +70,7 @@ Usage
       mode   | Output format of the statistical results | word | no | magnitude
       internal | Flag to use internal fields only in computing statistics <!--
                -->                                      | bool | no | false
+      mean     | Type of the mean operation             | word | no | arithmetic
     \endtable
 
     Available statistics of the operand field through the \c statistics entry:
@@ -85,6 +87,12 @@ Usage
       component  | Output statistics separately for each component
     \endverbatim
 
+    Options for the \c meanType entry:
+    \verbatim
+      arithmetic  | Arithmetic mean (average)
+      volumetric  | Volume-weighted arithmetic mean
+    \endverbatim
+
     The inherited entries are elaborated in:
       - \link functionObject.H \endlink
       - \link writeFile.H \endlink
@@ -133,6 +141,17 @@ class fieldStatistics
         static const Enum<modeType> modeTypeNames_;
 
 
+        //- Options for the mean type of the specified fields
+        enum meanType : char
+        {
+            ARITHMETIC = 0,  //!< "Arithmetic mean (average)"
+            VOLUMETRIC       //!< "Volume-weighted arithmetic mean"
+        };
+
+        //- Names for meanType
+        static const Enum<meanType> meanTypeNames_;
+
+
     // Private Classes
 
         //- Type-safe union for input field types
@@ -172,6 +191,9 @@ class fieldStatistics
         //- Output-format mode - only applicable for tensor ranks > 0
         modeType mode_;
 
+        //- Type of the mean of the specified fields
+        meanType mean_;
+
         //- Operand fields on which statistics are computed
         volFieldSelection fieldSet_;
 
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C b/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
index 48e7581974e..b55bd359a7b 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
@@ -108,6 +108,12 @@ bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
 template<class T>
 T Foam::functionObjects::fieldStatistics::calcMean(const Field<T>& field)
 {
+    if (internal_ && (mean_ == VOLUMETRIC))
+    {
+        const auto& V = mesh_.V();
+        return (gSum(V*field)/gSum(V));
+    }
+
     return gAverage(field);
 }
 
-- 
GitLab


From fa260b5c2d5d1c7e623089ed923a1f934bf98daf Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 10:09:08 +0000
Subject: [PATCH 04/31] SQUASH: 970449: use inplace value-count reduce

---
 .../field/fieldStatistics/fieldStatisticsTemplates.C      | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C b/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
index b55bd359a7b..795d90101d9 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
@@ -176,9 +176,6 @@ T Foam::functionObjects::fieldStatistics::calcVariance
     const Field<T>& field
 )
 {
-    label n = field.size();
-    reduce(n, sumOp<label>());
-
     const T average(calcMean(field));
 
     T var = Zero;
@@ -186,7 +183,10 @@ T Foam::functionObjects::fieldStatistics::calcVariance
     {
         var += (elem - average);
     }
-    reduce(var, sumOp<T>());
+
+    label n = field.size();
+
+    sumReduce(var, n);
 
     if (n <= 1)
     {
-- 
GitLab


From 829d32b7be6b08911bbfd2d05f86171e3f88c254 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 10:11:57 +0000
Subject: [PATCH 05/31] SQUASH: 970449: use more useful naming convention for
 the template file

---
 src/functionObjects/field/fieldStatistics/fieldStatistics.C | 6 ++++++
 src/functionObjects/field/fieldStatistics/fieldStatistics.H | 6 ------
 .../{fieldStatisticsTemplates.C => fieldStatisticsImpl.cxx} | 0
 3 files changed, 6 insertions(+), 6 deletions(-)
 rename src/functionObjects/field/fieldStatistics/{fieldStatisticsTemplates.C => fieldStatisticsImpl.cxx} (100%)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 3271e641a64..488484a9d18 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -61,6 +61,12 @@ Foam::functionObjects::fieldStatistics::meanTypeNames_
 });
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Implementation
+#include "fieldStatisticsImpl.cxx"
+
+
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 Foam::functionObjects::fieldStatistics::statistic
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index f8f6ca5d91d..81af225e693 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -300,12 +300,6 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-#ifdef NoRepository
-    #include "fieldStatisticsTemplates.C"
-#endif
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
 #endif
 
 // ************************************************************************* //
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
similarity index 100%
rename from src/functionObjects/field/fieldStatistics/fieldStatisticsTemplates.C
rename to src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
-- 
GitLab


From 653feb6820f5f009e2ff16fb6817e0ed8e4f6e32 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 10:13:55 +0000
Subject: [PATCH 06/31] SQUASH: 970449: pass the enum 'modeType' by value

---
 src/functionObjects/field/fieldStatistics/fieldStatistics.C | 2 +-
 src/functionObjects/field/fieldStatistics/fieldStatistics.H | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 488484a9d18..887ee68b541 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -73,7 +73,7 @@ Foam::functionObjects::fieldStatistics::statistic
 Foam::functionObjects::fieldStatistics::createStatistic
 (
     const word& statName,
-    const modeType& mode
+    const modeType mode
 )
 {
     statistic m;
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 81af225e693..08a4066db31 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -210,7 +210,7 @@ class fieldStatistics
     // Private Member Functions
 
         //- Return the statistic container
-        statistic createStatistic(const word& statName, const modeType& mode);
+        statistic createStatistic(const word& statName, const modeType mode);
 
         //- Compute the specified statistics of a given field
         template<class T>
-- 
GitLab


From 798b3f4d2d2b31b6c5ff918bdc4037f1a40a2b80 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:09:39 +0000
Subject: [PATCH 07/31] SQUASH: 970449: retrieve the field in a more consistent
 and efficient way

---
 .../field/fieldStatistics/fieldStatisticsImpl.cxx          | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index 795d90101d9..543bc733065 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -85,7 +85,12 @@ bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
         return false;
     }
 
-    const VolFieldType& field = lookupObject<VolFieldType>(fieldName);
+    const auto* fieldp = obr_.cfindObject<VolFieldType>(fieldName);
+    if (!fieldp)
+    {
+        return false;
+    }
+    const auto& field = *fieldp;
 
     tmp<Field<Type>> tfld = flatten(field);
     const Field<Type> fld = tfld.cref();
-- 
GitLab


From 90ee449c8f3f64b2f51a17b7fcb31d11b341100f Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:10:31 +0000
Subject: [PATCH 08/31] SQUASH: 970449: add missing reference

---
 .../field/fieldStatistics/fieldStatisticsImpl.cxx               | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index 543bc733065..f49ff106b81 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -93,7 +93,7 @@ bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
     const auto& field = *fieldp;
 
     tmp<Field<Type>> tfld = flatten(field);
-    const Field<Type> fld = tfld.cref();
+    const auto& fld = tfld.cref();
 
     HashTable<variantOutput> result;
     for (const auto& iter : statistics_.csorted())
-- 
GitLab


From 3c5cd38f5262c13f66a392a9bdf71fe8cfb414a3 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:11:52 +0000
Subject: [PATCH 09/31] SQUASH: 3876b5d: avoid dimension mixing in mesh.V

---
 .../field/fieldStatistics/fieldStatisticsImpl.cxx               | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index f49ff106b81..368e8a4b70d 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -115,7 +115,7 @@ T Foam::functionObjects::fieldStatistics::calcMean(const Field<T>& field)
 {
     if (internal_ && (mean_ == VOLUMETRIC))
     {
-        const auto& V = mesh_.V();
+        const Field<scalar>& V = mesh_.V();
         return (gSum(V*field)/gSum(V));
     }
 
-- 
GitLab


From ed4bbc4631633340ed35e049fa408a48ad3b2797 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:13:20 +0000
Subject: [PATCH 10/31] SQUASH: 970449: simplify the calcMin/calcMax routines
 (they were there for the metadata)

---
 .../fieldStatistics/fieldStatisticsImpl.cxx   | 42 +------------------
 1 file changed, 2 insertions(+), 40 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index 368e8a4b70d..424ea685b60 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -126,52 +126,14 @@ T Foam::functionObjects::fieldStatistics::calcMean(const Field<T>& field)
 template<class T>
 T Foam::functionObjects::fieldStatistics::calcMin(const Field<T>& field)
 {
-    const label proci = Pstream::myProcNo();
-
-    // Find min internal field value info
-
-    List<T> minVs(Pstream::nProcs(), pTraits<T>::max);
-
-    labelPair minMaxIds = findMinMax(field);
-
-    label minId = minMaxIds.first();
-    if (minId != -1)
-    {
-        minVs[proci] = field[minId];
-    }
-
-    // Collect info from all processors and output
-    Pstream::allGatherList(minVs);
-
-    minId = findMin(minVs);
-
-    return minVs[minId];  // minValue
+    return gMin(field);
 }
 
 
 template<class T>
 T Foam::functionObjects::fieldStatistics::calcMax(const Field<T>& field)
 {
-    const label proci = Pstream::myProcNo();
-
-    // Find max internal field value info
-
-    List<T> maxVs(Pstream::nProcs(), pTraits<T>::min);
-
-    labelPair minMaxIds = findMinMax(field);
-
-    label maxId = minMaxIds.second();
-    if (maxId != -1)
-    {
-        maxVs[proci] = field[maxId];
-    }
-
-    // Collect info from all processors and output
-    Pstream::allGatherList(maxVs);
-
-    maxId = findMax(maxVs);
-
-    return maxVs[maxId];  // maxValue
+    return gMax(field);
 }
 
 
-- 
GitLab


From 2732ad35cf4e06ddab0b897b476fc00be74ea17b Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:17:36 +0000
Subject: [PATCH 11/31] SQUASH: f17efd1: use more compact form for field
 slicing

---
 .../field/fieldStatistics/fieldStatisticsImpl.cxx             | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index 424ea685b60..6f5d9f73abd 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -55,7 +55,7 @@ Foam::functionObjects::fieldStatistics::flatten(const GeoField& fld)
     auto& flatFld = tflatFld.ref();
 
     // Insert internal values
-    SubList<value_type>(flatFld, fld.size(), 0) = fld.primitiveField();
+    flatFld.slice(0, fld.size()) = fld.primitiveField();
 
     if (!internal_)
     {
@@ -65,7 +65,7 @@ Foam::functionObjects::fieldStatistics::flatten(const GeoField& fld)
         {
             if (!pfld.coupled())
             {
-                SubList<value_type>(flatFld, pfld.size(), n) = pfld;
+                flatFld.slice(n, pfld.size()) = pfld;
                 n += pfld.size();
             }
         }
-- 
GitLab


From 060f37e91295c3408c8a909ca229bf6de8a2b1fb Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:22:49 +0000
Subject: [PATCH 12/31] SQUASH: replace the for-loop with a modern version

---
 .../field/fieldStatistics/fieldStatistics.C               | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 887ee68b541..0b441a84d73 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -132,7 +132,7 @@ void Foam::functionObjects::fieldStatistics::writeFileHeader
     // Therefore, the output file columns are based on output statistics.
     const auto& result = results_(fieldName);
 
-    forAllConstIters(result, iter)
+    for (const auto& iter : result.csorted())
     {
         const word& name = iter.key();
         writeTabbed(os, name);
@@ -219,7 +219,7 @@ bool Foam::functionObjects::fieldStatistics::execute()
     {
         const auto& results = results_(fieldName);
 
-        forAllConstIters(results, iter)
+        for (const auto& iter : results.csorted())
         {
             const word& name = iter.key();
             const variantOutput& value = iter.val();
@@ -267,7 +267,7 @@ bool Foam::functionObjects::fieldStatistics::write()
 
             writeCurrentTime(file);
 
-            forAllConstIters(results, iter)
+            for (const auto& iter : results.csorted())
             {
                 const variantOutput& value = iter.val();
 
@@ -298,7 +298,7 @@ bool Foam::functionObjects::fieldStatistics::write()
         {
             const auto& results = results_(fieldName);
 
-            forAllConstIters(results, iter)
+            for (const auto& iter : results.csorted())
             {
                 const word& name = iter.key();
                 const variantOutput& value = iter.val();
-- 
GitLab


From a879f47980b9938292ff773f43aecf63275a91ef Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:48:22 +0000
Subject: [PATCH 13/31] SQUASH: various style changes

---
 .../field/fieldStatistics/fieldStatistics.C         | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 0b441a84d73..ec14558f3c8 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -243,6 +243,8 @@ bool Foam::functionObjects::fieldStatistics::execute()
 
 bool Foam::functionObjects::fieldStatistics::write()
 {
+    Log << type() << " " << name() << " write:" << endl;
+
     // Create an output file per field
     if (writeToFile() && !writtenHeader_)
     {
@@ -298,6 +300,8 @@ bool Foam::functionObjects::fieldStatistics::write()
         {
             const auto& results = results_(fieldName);
 
+            Info<< tab << "Field" << tab << fieldName << nl;
+
             for (const auto& iter : results.csorted())
             {
                 const word& name = iter.key();
@@ -309,18 +313,19 @@ bool Foam::functionObjects::fieldStatistics::write()
                     {
                         if constexpr (std::is_same_v<std::decay_t<decltype(v)>, scalar>)
                         {
-                            Info<< name << " " << v;
+                            Info<< tab << name << tab << v << nl;
                         }
                         else
                         {
-                            Info<< name << " ";
-                            for (const auto& val : v) Info<< val << " ";
+                            Info<< tab << name << tab;
+                            for (const auto& val : v) Info<< val << tab;
+                            Info<< nl;
                         }
-                        Info<< nl;
                     },
                     value
                 );
             }
+            Info<< endl;
         }
     }
 
-- 
GitLab


From 0edb5ea6b41f0f9f6e75010b0a886cbff3acdcef Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 15:27:50 +0000
Subject: [PATCH 14/31] STYLE

---
 src/functionObjects/field/fieldStatistics/fieldStatistics.C | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index ec14558f3c8..7c3e40df2ea 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -300,7 +300,7 @@ bool Foam::functionObjects::fieldStatistics::write()
         {
             const auto& results = results_(fieldName);
 
-            Info<< tab << "Field" << tab << fieldName << nl;
+            Info<< '    Field' << tab << fieldName << nl;
 
             for (const auto& iter : results.csorted())
             {
@@ -313,11 +313,11 @@ bool Foam::functionObjects::fieldStatistics::write()
                     {
                         if constexpr (std::is_same_v<std::decay_t<decltype(v)>, scalar>)
                         {
-                            Info<< tab << name << tab << v << nl;
+                            Info<< '    ' << name << tab << v << nl;
                         }
                         else
                         {
-                            Info<< tab << name << tab;
+                            Info<< '    ' << name << tab;
                             for (const auto& val : v) Info<< val << tab;
                             Info<< nl;
                         }
-- 
GitLab


From 7765382f13a83f7964526e7b52ab5834fa03d9ad Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:50:41 +0000
Subject: [PATCH 15/31] SQUASH: dd6d51b6e: remove redundant template file name

---
 src/functionObjects/field/fieldStatistics/fieldStatistics.H | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 08a4066db31..98e7bf35bde 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -99,7 +99,6 @@ Usage
 
 SourceFiles
     fieldStatistics.C
-    fieldStatisticsTemplates.C
 
 \*---------------------------------------------------------------------------*/
 
-- 
GitLab


From 864c29710495797bd51aaf05a5253982a8d32e79 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:58:10 +0000
Subject: [PATCH 16/31] SQUASH: 970449: use more convenient type trait checks

---
 .../field/fieldStatistics/fieldStatistics.C   | 22 ++++++++++++-------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 7c3e40df2ea..094c03a5cfb 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -277,13 +277,16 @@ bool Foam::functionObjects::fieldStatistics::write()
                 (
                     [&file](const auto& v)
                     {
-                        if constexpr (std::is_same_v<std::decay_t<decltype(v)>, scalar>)
+                        if constexpr
+                        (
+                            is_vectorspace_v<std::decay_t<decltype(v)>>
+                        )
                         {
-                            file<< token::TAB << v;
+                            for (const auto& val : v) file<< token::TAB << val;
                         }
                         else
                         {
-                            for (const auto& val : v) file<< token::TAB << val;
+                            file<< token::TAB << v;
                         }
                     },
                     value
@@ -311,16 +314,19 @@ bool Foam::functionObjects::fieldStatistics::write()
                 (
                     [name](const auto& v)
                     {
-                        if constexpr (std::is_same_v<std::decay_t<decltype(v)>, scalar>)
-                        {
-                            Info<< '    ' << name << tab << v << nl;
-                        }
-                        else
+                        if constexpr
+                        (
+                            is_vectorspace_v<std::decay_t<decltype(v)>>
+                        )
                         {
                             Info<< '    ' << name << tab;
                             for (const auto& val : v) Info<< val << tab;
                             Info<< nl;
                         }
+                        else
+                        {
+                            Info<< tab << name << tab << v << nl;
+                        }
                     },
                     value
                 );
-- 
GitLab


From 79ba2ccdd4b881472b68a21bb6e39b411784f30d Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 15:52:19 +0000
Subject: [PATCH 17/31] STYLE

---
 .../field/fieldStatistics/fieldStatistics.C            | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 094c03a5cfb..350bcfc8a66 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -303,7 +303,7 @@ bool Foam::functionObjects::fieldStatistics::write()
         {
             const auto& results = results_(fieldName);
 
-            Info<< '    Field' << tab << fieldName << nl;
+            Info<< nl << "    Field " << fieldName << nl;
 
             for (const auto& iter : results.csorted())
             {
@@ -319,20 +319,20 @@ bool Foam::functionObjects::fieldStatistics::write()
                             is_vectorspace_v<std::decay_t<decltype(v)>>
                         )
                         {
-                            Info<< '    ' << name << tab;
-                            for (const auto& val : v) Info<< val << tab;
+                            Info<< "    " << name << " ";
+                            for (const auto& val : v) Info<< val << " ";
                             Info<< nl;
                         }
                         else
                         {
-                            Info<< tab << name << tab << v << nl;
+                            Info<< "    " << name << " " << v << nl;
                         }
                     },
                     value
                 );
             }
-            Info<< endl;
         }
+        Info<< endl;
     }
 
     return true;
-- 
GitLab


From 6d43ee2034ee5c48fcdf9cbbeeb813746c969f8f Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 16:58:10 +0000
Subject: [PATCH 18/31] WIP: collect the data writer routines into functions

---
 .../field/fieldStatistics/fieldStatistics.C   | 150 ++++++++++--------
 .../field/fieldStatistics/fieldStatistics.H   |   6 +
 2 files changed, 89 insertions(+), 67 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 350bcfc8a66..ad39bdc8569 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -143,6 +143,87 @@ void Foam::functionObjects::fieldStatistics::writeFileHeader
 }
 
 
+void Foam::functionObjects::fieldStatistics::writeStatData()
+{
+    for (const word& fieldName : fieldSet_.selectionNames())
+    {
+        const auto& results = results_(fieldName);
+
+        if (!results.size()) break;
+
+        OFstream& file = *filePtrs_(fieldName);
+
+        writeCurrentTime(file);
+
+        for (const auto& iter : results.csorted())
+        {
+            const variantOutput& value = iter.val();
+
+            std::visit
+            (
+                [&file](const auto& v)
+                {
+                    if constexpr
+                    (
+                        is_vectorspace_v<std::decay_t<decltype(v)>>
+                    )
+                    {
+                        for (const auto& val : v) file<< token::TAB << val;
+                    }
+                    else
+                    {
+                        file<< token::TAB << v;
+                    }
+                },
+                value
+            );
+        }
+        file<< nl;
+    }
+}
+
+
+void Foam::functionObjects::fieldStatistics::logStatData()
+{
+    for (const word& fieldName : fieldSet_.selectionNames())
+    {
+        const auto& results = results_(fieldName);
+
+        if (!results.size()) break;
+
+        Info<< nl << "    Field " << fieldName << nl;
+
+        for (const auto& iter : results.csorted())
+        {
+            const word& name = iter.key();
+            const variantOutput& value = iter.val();
+
+            std::visit
+            (
+                [name](const auto& v)
+                {
+                    if constexpr
+                    (
+                        is_vectorspace_v<std::decay_t<decltype(v)>>
+                    )
+                    {
+                        Info<< "    " << name << " ";
+                        for (const auto& val : v) Info<< val << " ";
+                        Info<< nl;
+                    }
+                    else
+                    {
+                        Info<< "    " << name << " " << v << nl;
+                    }
+                },
+                value
+            );
+        }
+    }
+    Info<< endl;
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::functionObjects::fieldStatistics::fieldStatistics
@@ -261,78 +342,13 @@ bool Foam::functionObjects::fieldStatistics::write()
     // Write the statistical results to the output file if requested
     if (writeToFile())
     {
-        for (const word& fieldName : fieldSet_.selectionNames())
-        {
-            const auto& results = results_(fieldName);
-
-            OFstream& file = *filePtrs_(fieldName);
-
-            writeCurrentTime(file);
-
-            for (const auto& iter : results.csorted())
-            {
-                const variantOutput& value = iter.val();
-
-                std::visit
-                (
-                    [&file](const auto& v)
-                    {
-                        if constexpr
-                        (
-                            is_vectorspace_v<std::decay_t<decltype(v)>>
-                        )
-                        {
-                            for (const auto& val : v) file<< token::TAB << val;
-                        }
-                        else
-                        {
-                            file<< token::TAB << v;
-                        }
-                    },
-                    value
-                );
-            }
-            file<< nl;
-        }
+        writeStatData();
     }
 
     // Print the statistical results to the standard stream if requested
     if (log)
     {
-        for (const word& fieldName : fieldSet_.selectionNames())
-        {
-            const auto& results = results_(fieldName);
-
-            Info<< nl << "    Field " << fieldName << nl;
-
-            for (const auto& iter : results.csorted())
-            {
-                const word& name = iter.key();
-                const variantOutput& value = iter.val();
-
-                std::visit
-                (
-                    [name](const auto& v)
-                    {
-                        if constexpr
-                        (
-                            is_vectorspace_v<std::decay_t<decltype(v)>>
-                        )
-                        {
-                            Info<< "    " << name << " ";
-                            for (const auto& val : v) Info<< val << " ";
-                            Info<< nl;
-                        }
-                        else
-                        {
-                            Info<< "    " << name << " " << v << nl;
-                        }
-                    },
-                    value
-                );
-            }
-        }
-        Info<< endl;
+        logStatData();
     }
 
     return true;
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 98e7bf35bde..5c20cb348e7 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -249,6 +249,12 @@ class fieldStatistics
         //- Output the file header information
         void writeFileHeader(Ostream& os, const word& fieldName);
 
+        //-
+        void writeStatData();
+
+        //-
+        void logStatData();
+
 public:
 
     //- Runtime type information
-- 
GitLab


From 6282fefe5b9649bedbed46a2d21d156ee208afde Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 11:52:51 +0000
Subject: [PATCH 19/31] WIP: ensure backward-compatibility for fieldMinMax

---
 .../field/fieldStatistics/fieldStatistics.C   | 147 +++++++++++++++++-
 .../field/fieldStatistics/fieldStatistics.H   |  41 +++++
 .../fieldStatistics/fieldStatisticsImpl.cxx   | 105 +++++++++++++
 3 files changed, 291 insertions(+), 2 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index ad39bdc8569..0c2801836ae 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -138,8 +138,6 @@ void Foam::functionObjects::fieldStatistics::writeFileHeader
         writeTabbed(os, name);
     }
     os  << endl;
-
-    writtenHeader_ = true;
 }
 
 
@@ -224,6 +222,97 @@ void Foam::functionObjects::fieldStatistics::logStatData()
 }
 
 
+void Foam::functionObjects::fieldStatistics::writeExtremaFileHeader
+(
+    Ostream& os,
+    const word& fieldName
+)
+{
+    writeHeader(os, word("Field Extrema Data: " + fieldName));
+    writeCommented(os, "Time");
+    writeTabbed(os, "min");
+    writeTabbed(os, "min_procID");
+    writeTabbed(os, "min_cellID");
+    writeTabbed(os, "min_position");
+    writeTabbed(os, "max");
+    writeTabbed(os, "max_procID");
+    writeTabbed(os, "max_cellID");
+    writeTabbed(os, "max_position");
+    os  << endl;
+}
+
+
+void Foam::functionObjects::fieldStatistics::writeExtremaData()
+{
+    for (const word& fieldName : fieldSet_.selectionNames())
+    {
+        const auto& min = extremaMetaData_(fieldName).first();
+        const auto& max = extremaMetaData_(fieldName).second();
+
+        OFstream& efile = *extremaFilePtrs_(fieldName);
+
+        writeCurrentTime(efile);
+
+        efile<< token::TAB;
+
+        std::visit([&efile](const auto& v){ efile<< v; }, min.value_);
+
+        efile<< token::TAB
+            << min.procID_ << token::TAB
+            << min.cellID_ << token::TAB
+            << min.position_ << token::TAB;
+
+        std::visit([&efile](const auto& v){ efile<< v; }, max.value_);
+
+        efile<< token::TAB
+            << max.procID_ << token::TAB
+            << max.cellID_ << token::TAB
+            << max.position_ << nl;
+    }
+}
+
+
+void Foam::functionObjects::fieldStatistics::logExtremaData()
+{
+    for (const word& fieldName : fieldSet_.selectionNames())
+    {
+        const auto& min = extremaMetaData_(fieldName).first();
+        const auto& max = extremaMetaData_(fieldName).second();
+
+        const word outputName =
+            (mode_ == mdMag)
+        ? word("mag(" + fieldName + ")")
+        : fieldName;
+
+        std::visit
+        (
+            [outputName](const auto& v)
+            {
+                Info<< "    min(" << outputName << ") = " << v;
+            },
+            min.value_
+        );
+
+        Info<< " in cell " << min.cellID_
+            << " at location " << min.position_
+            << " on processor " << min.procID_;
+
+        std::visit
+        (
+            [outputName](const auto& v)
+            {
+                Info<< nl << "    max(" << outputName << ") = " << v;
+            },
+            max.value_
+        );
+
+        Info<< " in cell " << max.cellID_
+            << " at location " << max.position_
+            << " on processor " << max.procID_ << endl;
+    }
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::functionObjects::fieldStatistics::fieldStatistics
@@ -251,6 +340,7 @@ bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
     }
 
     internal_ = dict.getOrDefault("internal", false);
+    extrema_ = dict.getOrDefault("extrema", false);
 
     mode_ = modeTypeNames_.getOrDefault("mode", dict, modeType::mdMag);
     mean_ = meanTypeNames_.getOrDefault("mean", dict, meanType::ARITHMETIC);
@@ -271,6 +361,9 @@ bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
     // Reset and reprepare the output statistics
     results_.clear();
 
+    // Reset and reprepare the output statistics
+    extremaMetaData_.clear();
+
     return true;
 }
 
@@ -316,6 +409,35 @@ bool Foam::functionObjects::fieldStatistics::execute()
                 value
             );
         }
+
+        if (extrema_)
+        {
+            const auto& min = extremaMetaData_(fieldName).first();
+            std::visit
+            (
+                [this, fieldName](const auto& v)
+                {
+                    this->setResult(word(fieldName + "_min"), v);
+                },
+                min.value_
+            );
+            this->setResult(word(fieldName + "_min_procID"), min.procID_);
+            this->setResult(word(fieldName + "_min_cellID"), min.cellID_);
+            this->setResult(word(fieldName + "_min_position"), min.position_);
+
+            const auto& max = extremaMetaData_(fieldName).second();
+            std::visit
+            (
+                [this, fieldName](const auto& v)
+                {
+                    this->setResult(word(fieldName + "_max"), v);
+                },
+                max.value_
+            );
+            this->setResult(word(fieldName + "_max_procID"), max.procID_);
+            this->setResult(word(fieldName + "_max_cellID"), max.cellID_);
+            this->setResult(word(fieldName + "_max_position"), max.position_);
+        }
     }
 
     return true;
@@ -337,17 +459,38 @@ bool Foam::functionObjects::fieldStatistics::write()
 
             writeFileHeader(file, fieldName);
         }
+
+        if (extrema_)
+        {
+            for (const word& fieldName : fieldSet_.selectionNames())
+            {
+                extremaFilePtrs_.set
+                (
+                    fieldName,
+                    newFileAtStartTime(word("fieldMinMax_" + fieldName))
+                );
+
+                OFstream& file = *extremaFilePtrs_(fieldName);
+                writeExtremaFileHeader(file, fieldName);
+            }
+        }
+
+        writtenHeader_ = true;
     }
 
     // Write the statistical results to the output file if requested
     if (writeToFile())
     {
+        if (extrema_) writeExtremaData();
+
         writeStatData();
     }
 
     // Print the statistical results to the standard stream if requested
     if (log)
     {
+        if (extrema_) logExtremaData();
+
         logStatData();
     }
 
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 5c20cb348e7..5cdf0b99bd6 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -54,6 +54,7 @@ Usage
         mode             <word>;
         internal         <bool>;
         mean             <word>;
+        extrema          <bool>;
 
         // Inherited entries
         ...
@@ -71,6 +72,7 @@ Usage
       internal | Flag to use internal fields only in computing statistics <!--
                -->                                      | bool | no | false
       mean     | Type of the mean operation             | word | no | arithmetic
+      extrema | Flag to enable extrema metadata calculations | bool | no | false
     \endtable
 
     Available statistics of the operand field through the \c statistics entry:
@@ -181,12 +183,31 @@ class fieldStatistics
             std::function<variantOutput(variantInput)> calc;
         };
 
+        //- Class to encapsulate metadata about minima and maxima
+        struct extremaMetaData
+        {
+            //- Value of the extremum
+            variantOutput value_;
+
+            //- Processor index of the extremum
+            label procID_;
+
+            //- Cell index of the extremum
+            label cellID_;
+
+            //- Position vector of the extremum
+            vector position_;
+        };
+
 
     // Private Data
 
         //- Flag to use internal fields only in computing statistics
         bool internal_;
 
+        //- Flag to enable extrema metadata calculations
+        bool extrema_;
+
         //- Output-format mode - only applicable for tensor ranks > 0
         modeType mode_;
 
@@ -199,12 +220,18 @@ class fieldStatistics
         //- List of file pointers; one file per field
         HashPtrTable<OFstream> filePtrs_;
 
+        //- List of file pointers for extrema data; one file per field
+        HashPtrTable<OFstream> extremaFilePtrs_;
+
         //- Hash table containing all specified statistics
         HashTable<statistic> statistics_;
 
         //- Hash table containing all statistical results per field
         HashTable<HashTable<variantOutput>> results_;
 
+        //- Hash table containing the metadata of the extrema per field
+        HashTable<Pair<extremaMetaData>> extremaMetaData_;
+
 
     // Private Member Functions
 
@@ -246,6 +273,10 @@ class fieldStatistics
             const GeoField& field
         );
 
+        //- Return the extrema metadata of the specified field
+        template<class GeoField>
+        Pair<extremaMetaData> calcExtremaMetaData(const GeoField& field);
+
         //- Output the file header information
         void writeFileHeader(Ostream& os, const word& fieldName);
 
@@ -255,6 +286,16 @@ class fieldStatistics
         //-
         void logStatData();
 
+        //- Output the extrema-data file header information
+        void writeExtremaFileHeader(Ostream& os, const word& fieldName);
+
+        //- Write extrema data to the specified file
+        void writeExtremaData();
+
+        //- Write extrema data to the standard stream
+        void logExtremaData();
+
+
 public:
 
     //- Runtime type information
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index 6f5d9f73abd..34240d6b240 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -106,6 +106,8 @@ bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
 
     results_.set(fieldName, result);
 
+    if (extrema_) extremaMetaData_.set(fieldName, calcExtremaMetaData(field));
+
     return true;
 }
 
@@ -164,4 +166,107 @@ T Foam::functionObjects::fieldStatistics::calcVariance
 }
 
 
+template<class GeoField>
+Foam::Pair<Foam::functionObjects::fieldStatistics::extremaMetaData>
+Foam::functionObjects::fieldStatistics::calcExtremaMetaData
+(
+    const GeoField& field
+)
+{
+    typedef typename GeoField::value_type value_type;
+
+    const label proci = Pstream::myProcNo();
+
+    // Find the extrema metadata of the specified internal field
+
+    List<value_type> minVs(Pstream::nProcs(), pTraits<value_type>::max);
+    List<label> minCells(Pstream::nProcs(), Zero);
+    List<vector> minCs(Pstream::nProcs(), Zero);
+
+    List<value_type> maxVs(Pstream::nProcs(), pTraits<value_type>::min);
+    List<label> maxCells(Pstream::nProcs(), Zero);
+    List<vector> maxCs(Pstream::nProcs(), Zero);
+
+    labelPair minMaxIds = findMinMax(field);
+
+    label minId = minMaxIds.first();
+    if (minId != -1)
+    {
+        minVs[proci] = field[minId];
+        minCells[proci] = minId;
+        minCs[proci] = mesh_.C()[minId];
+    }
+
+    label maxId = minMaxIds.second();
+    if (maxId != -1)
+    {
+        maxVs[proci] = field[maxId];
+        maxCells[proci] = maxId;
+        maxCs[proci] = mesh_.C()[maxId];
+    }
+
+    if (!internal_)
+    {
+        // Find the extrema metadata of the specified boundary fields
+        const auto& fieldBoundary = field.boundaryField();
+        const auto& CfBoundary = mesh_.C().boundaryField();
+
+        forAll(fieldBoundary, patchi)
+        {
+            const Field<value_type>& fp = fieldBoundary[patchi];
+            if (fp.size())
+            {
+                const vectorField& Cfp = CfBoundary[patchi];
+
+                const labelList& faceCells =
+                    fieldBoundary[patchi].patch().faceCells();
+
+                minMaxIds = findMinMax(fp);
+
+                minId = minMaxIds.first();
+                if (minVs[proci] > fp[minId])
+                {
+                    minVs[proci] = fp[minId];
+                    minCells[proci] = faceCells[minId];
+                    minCs[proci] = Cfp[minId];
+                }
+
+                maxId = minMaxIds.second();
+                if (maxVs[proci] < fp[maxId])
+                {
+                    maxVs[proci] = fp[maxId];
+                    maxCells[proci] = faceCells[maxId];
+                    maxCs[proci] = Cfp[maxId];
+                }
+            }
+        }
+    }
+
+    // Collect info from all processors and output
+    Pstream::allGatherList(minVs);
+    Pstream::allGatherList(minCells);
+    Pstream::allGatherList(minCs);
+
+    Pstream::allGatherList(maxVs);
+    Pstream::allGatherList(maxCells);
+    Pstream::allGatherList(maxCs);
+
+    extremaMetaData min;
+    minId = findMin(minVs);
+    min.value_ = minVs[minId];
+    min.procID_ = minId;
+    min.cellID_ = minCells[minId];
+    min.position_ = minCs[minId];
+
+    extremaMetaData max;
+    maxId = findMax(maxVs);
+    max.value_ = maxVs[maxId];
+    max.procID_ = maxId;
+    max.cellID_ = maxCells[maxId];
+    max.position_ = maxCs[maxId];
+
+    return Pair<extremaMetaData>(min, max);
+}
+
+
 // ************************************************************************* //
-- 
GitLab


From 4b88d5e1537d50dd72e6bf086c7a0adba12cc4b6 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 13 Mar 2025 17:21:06 +0000
Subject: [PATCH 20/31] SQUASH: 39000e8e1b: remove Info duplications

---
 .../field/fieldStatistics/fieldStatistics.C               | 8 ++++----
 .../field/fieldStatistics/fieldStatistics.H               | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 0c2801836ae..3490dbf66e8 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -196,26 +196,26 @@ void Foam::functionObjects::fieldStatistics::logStatData()
             const word& name = iter.key();
             const variantOutput& value = iter.val();
 
+            Info<< "    " << name << " ";
             std::visit
             (
-                [name](const auto& v)
+                [](const auto& v)
                 {
                     if constexpr
                     (
                         is_vectorspace_v<std::decay_t<decltype(v)>>
                     )
                     {
-                        Info<< "    " << name << " ";
                         for (const auto& val : v) Info<< val << " ";
-                        Info<< nl;
                     }
                     else
                     {
-                        Info<< "    " << name << " " << v << nl;
+                        Info<< v;
                     }
                 },
                 value
             );
+            Info<< nl;
         }
     }
     Info<< endl;
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 5cdf0b99bd6..ec116a3e9b5 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -280,10 +280,10 @@ class fieldStatistics
         //- Output the file header information
         void writeFileHeader(Ostream& os, const word& fieldName);
 
-        //-
+        //- Write the statistical data to the specified file
         void writeStatData();
 
-        //-
+        //- Write the statistical data to the standard stream
         void logStatData();
 
         //- Output the extrema-data file header information
-- 
GitLab


From b594deee65513482bd3da90eab2c4d3a941226cf Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Fri, 14 Mar 2025 09:23:24 +0000
Subject: [PATCH 21/31] SQUASH: 970449: update the copyright statement

---
 src/functionObjects/field/fieldStatistics/fieldStatistics.C    | 3 ++-
 src/functionObjects/field/fieldStatistics/fieldStatistics.H    | 3 ++-
 .../field/fieldStatistics/fieldStatisticsImpl.cxx              | 3 ++-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 3490dbf66e8..8f9b37d9609 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -5,7 +5,8 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2025 OpenCFD Ltd.
+    Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2015-2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index ec116a3e9b5..14531671e86 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -5,7 +5,8 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2025 OpenCFD Ltd.
+    Copyright (C) 2011-2017 OpenFOAM Foundation
+    Copyright (C) 2015-2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index 34240d6b240..ebbdef80574 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -5,7 +5,8 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2025 OpenCFD Ltd.
+    Copyright (C) 2011-2017 OpenFOAM Foundation
+    Copyright (C) 2015-2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
-- 
GitLab


From d0a6d71ae74dee0720c7323f5b5827bcbe2ac1cd Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Fri, 14 Mar 2025 09:29:15 +0000
Subject: [PATCH 22/31] SQUASH: 970449: documentation updates

---
 .../field/fieldStatistics/fieldStatistics.C   |  8 ++++----
 .../field/fieldStatistics/fieldStatistics.H   | 19 +++++++++++--------
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 8f9b37d9609..ba9bbccbe4a 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -128,9 +128,9 @@ void Foam::functionObjects::fieldStatistics::writeFileHeader
     writeHeader(os, word("Field Statistics: " + fieldName));
     writeCommented(os, "Time");
 
-    // Number of input statistics (i.e., statistics_) could be lesser than that
-    // of output statistics (i.e., results_; e.g., cell index of min value).
-    // Therefore, the output file columns are based on output statistics.
+    // Number of input statistics (i.e., statistics_) should be the same with
+    // that of output statistics (i.e., results_). However, for consistency,
+    // the output file columns are based on output statistics.
     const auto& result = results_(fieldName);
 
     for (const auto& iter : result.csorted())
@@ -359,7 +359,7 @@ bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
         statistics_.insert(m, createStatistic(m, mode_));
     }
 
-    // Reset and reprepare the output statistics
+    // Reset the output-statistics container
     results_.clear();
 
     // Reset and reprepare the output statistics
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 14531671e86..3c8bdf1319b 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -31,15 +31,18 @@ Group
     grpFieldFunctionObjects
 
 Description
+    Calculates various statistics of the specified fields.
 
     Operands:
     \table
-      Operand        | Type | Location
-      input          | -    | -
-      output file    | dat  | \<case\>/postProcessing/\<FO\>/\<time\>/\<file\>
-      output field   | -    | -
+      Operand      | Type                          | Location
+      input        | vol\<Type\>Field(s)           | Registry
+      output file  | dat | \<case\>/postProcessing/\<FO\>/\<time\>/\<file\>
+      output field | -                             | -
     \endtable
 
+    where \c \<Type\>=Scalar/Vector/SymmTensor/Tensor.
+
 Usage
     Minimal example by using \c system/controlDict.functions:
     \verbatim
@@ -53,9 +56,9 @@ Usage
 
         // Optional entries
         mode             <word>;
-        internal         <bool>;
         mean             <word>;
         extrema          <bool>;
+        internal         <bool>;
 
         // Inherited entries
         ...
@@ -70,10 +73,10 @@ Usage
       fields       | List of operand fields             | wordList | yes | -
       statistics   | List of operand statistics         | wordList | yes | -
       mode   | Output format of the statistical results | word | no | magnitude
+      mean     | Type of the mean operation             | word | no | arithmetic
       internal | Flag to use internal fields only in computing statistics <!--
                -->                                      | bool | no | false
-      mean     | Type of the mean operation             | word | no | arithmetic
-      extrema | Flag to enable extrema metadata calculations | bool | no | false
+      extrema | Flag to enable extrema data calculations | bool | no | false
     \endtable
 
     Available statistics of the operand field through the \c statistics entry:
@@ -180,7 +183,7 @@ class fieldStatistics
             //- Name of the statistic
             word name_;
 
-            //- Calculate the value of the specified statistic
+            //- Return the value of the specified statistic
             std::function<variantOutput(variantInput)> calc;
         };
 
-- 
GitLab


From 02959dc870411ea33af6f8b73adcdfd5e002f9dd Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Fri, 14 Mar 2025 09:38:20 +0000
Subject: [PATCH 23/31] SQUASH: 56377ad: documentation updates

---
 .../field/fieldStatistics/fieldStatistics.C   | 30 +++++++++----------
 .../field/fieldStatistics/fieldStatistics.H   | 14 ++++-----
 .../fieldStatistics/fieldStatisticsImpl.cxx   | 16 +++++-----
 3 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index ba9bbccbe4a..50a3a3dff2a 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -247,25 +247,25 @@ void Foam::functionObjects::fieldStatistics::writeExtremaData()
 {
     for (const word& fieldName : fieldSet_.selectionNames())
     {
-        const auto& min = extremaMetaData_(fieldName).first();
-        const auto& max = extremaMetaData_(fieldName).second();
+        const auto& min = extremaData_(fieldName).first();
+        const auto& max = extremaData_(fieldName).second();
 
-        OFstream& efile = *extremaFilePtrs_(fieldName);
+        OFstream& file = *extremaFilePtrs_(fieldName);
 
-        writeCurrentTime(efile);
+        writeCurrentTime(file);
 
-        efile<< token::TAB;
+        file<< token::TAB;
 
-        std::visit([&efile](const auto& v){ efile<< v; }, min.value_);
+        std::visit([&file](const auto& v){ file<< v; }, min.value_);
 
-        efile<< token::TAB
+        file<< token::TAB
             << min.procID_ << token::TAB
             << min.cellID_ << token::TAB
             << min.position_ << token::TAB;
 
-        std::visit([&efile](const auto& v){ efile<< v; }, max.value_);
+        std::visit([&file](const auto& v){ file<< v; }, max.value_);
 
-        efile<< token::TAB
+        file<< token::TAB
             << max.procID_ << token::TAB
             << max.cellID_ << token::TAB
             << max.position_ << nl;
@@ -277,8 +277,8 @@ void Foam::functionObjects::fieldStatistics::logExtremaData()
 {
     for (const word& fieldName : fieldSet_.selectionNames())
     {
-        const auto& min = extremaMetaData_(fieldName).first();
-        const auto& max = extremaMetaData_(fieldName).second();
+        const auto& min = extremaData_(fieldName).first();
+        const auto& max = extremaData_(fieldName).second();
 
         const word outputName =
             (mode_ == mdMag)
@@ -362,8 +362,8 @@ bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
     // Reset the output-statistics container
     results_.clear();
 
-    // Reset and reprepare the output statistics
-    extremaMetaData_.clear();
+    // Reset the extrema-data container
+    extremaData_.clear();
 
     return true;
 }
@@ -413,7 +413,7 @@ bool Foam::functionObjects::fieldStatistics::execute()
 
         if (extrema_)
         {
-            const auto& min = extremaMetaData_(fieldName).first();
+            const auto& min = extremaData_(fieldName).first();
             std::visit
             (
                 [this, fieldName](const auto& v)
@@ -426,7 +426,7 @@ bool Foam::functionObjects::fieldStatistics::execute()
             this->setResult(word(fieldName + "_min_cellID"), min.cellID_);
             this->setResult(word(fieldName + "_min_position"), min.position_);
 
-            const auto& max = extremaMetaData_(fieldName).second();
+            const auto& max = extremaData_(fieldName).second();
             std::visit
             (
                 [this, fieldName](const auto& v)
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 3c8bdf1319b..dc8f38d0fcc 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -187,8 +187,8 @@ class fieldStatistics
             std::function<variantOutput(variantInput)> calc;
         };
 
-        //- Class to encapsulate metadata about minima and maxima
-        struct extremaMetaData
+        //- Class to encapsulate the data about minima and maxima
+        struct extremaData
         {
             //- Value of the extremum
             variantOutput value_;
@@ -209,7 +209,7 @@ class fieldStatistics
         //- Flag to use internal fields only in computing statistics
         bool internal_;
 
-        //- Flag to enable extrema metadata calculations
+        //- Flag to enable extrema data calculations
         bool extrema_;
 
         //- Output-format mode - only applicable for tensor ranks > 0
@@ -233,8 +233,8 @@ class fieldStatistics
         //- Hash table containing all statistical results per field
         HashTable<HashTable<variantOutput>> results_;
 
-        //- Hash table containing the metadata of the extrema per field
-        HashTable<Pair<extremaMetaData>> extremaMetaData_;
+        //- Hash table containing the data of the extrema per field
+        HashTable<Pair<extremaData>> extremaData_;
 
 
     // Private Member Functions
@@ -277,9 +277,9 @@ class fieldStatistics
             const GeoField& field
         );
 
-        //- Return the extrema metadata of the specified field
+        //- Return the extrema data of the specified field
         template<class GeoField>
-        Pair<extremaMetaData> calcExtremaMetaData(const GeoField& field);
+        Pair<extremaData> calcExtremaData(const GeoField& field);
 
         //- Output the file header information
         void writeFileHeader(Ostream& os, const word& fieldName);
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index ebbdef80574..7b5cd8d1cf6 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -107,7 +107,7 @@ bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
 
     results_.set(fieldName, result);
 
-    if (extrema_) extremaMetaData_.set(fieldName, calcExtremaMetaData(field));
+    if (extrema_) extremaData_.set(fieldName, calcExtremaData(field));
 
     return true;
 }
@@ -168,8 +168,8 @@ T Foam::functionObjects::fieldStatistics::calcVariance
 
 
 template<class GeoField>
-Foam::Pair<Foam::functionObjects::fieldStatistics::extremaMetaData>
-Foam::functionObjects::fieldStatistics::calcExtremaMetaData
+Foam::Pair<Foam::functionObjects::fieldStatistics::extremaData>
+Foam::functionObjects::fieldStatistics::calcExtremaData
 (
     const GeoField& field
 )
@@ -178,7 +178,7 @@ Foam::functionObjects::fieldStatistics::calcExtremaMetaData
 
     const label proci = Pstream::myProcNo();
 
-    // Find the extrema metadata of the specified internal field
+    // Find the extrema data of the specified internal field
 
     List<value_type> minVs(Pstream::nProcs(), pTraits<value_type>::max);
     List<label> minCells(Pstream::nProcs(), Zero);
@@ -208,7 +208,7 @@ Foam::functionObjects::fieldStatistics::calcExtremaMetaData
 
     if (!internal_)
     {
-        // Find the extrema metadata of the specified boundary fields
+        // Find the extrema data of the specified boundary fields
         const auto& fieldBoundary = field.boundaryField();
         const auto& CfBoundary = mesh_.C().boundaryField();
 
@@ -252,21 +252,21 @@ Foam::functionObjects::fieldStatistics::calcExtremaMetaData
     Pstream::allGatherList(maxCells);
     Pstream::allGatherList(maxCs);
 
-    extremaMetaData min;
+    extremaData min;
     minId = findMin(minVs);
     min.value_ = minVs[minId];
     min.procID_ = minId;
     min.cellID_ = minCells[minId];
     min.position_ = minCs[minId];
 
-    extremaMetaData max;
+    extremaData max;
     maxId = findMax(maxVs);
     max.value_ = maxVs[maxId];
     max.procID_ = maxId;
     max.cellID_ = maxCells[maxId];
     max.position_ = maxCs[maxId];
 
-    return Pair<extremaMetaData>(min, max);
+    return Pair<extremaData>(min, max);
 }
 
 
-- 
GitLab


From b34dc2a5a3465e3ad2cc2d2cade2c0fffbcaf429 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Fri, 14 Mar 2025 10:12:39 +0000
Subject: [PATCH 24/31] SQUASH: 970449: update the fields during the execution

Update the fields at the execution stage instead of the 'read' stage.
Otherwise, various fields which are registered after the 'read' stage
will be missed.
---
 .../field/fieldStatistics/fieldStatistics.C     | 17 +++++++++++------
 .../fieldStatistics/fieldStatisticsImpl.cxx     |  2 +-
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 50a3a3dff2a..f239a161c6d 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -91,22 +91,23 @@ Foam::functionObjects::fieldStatistics::createStatistic
 
                 if (statName == "min")
                 {
-                    if (mode == mdMag) return mag(calcMin<BaseType>(arg));
+                    // if (mode == mdMag) return mag(calcMin<BaseType>(arg));
+                    if (mode == mdMag) return calcMin<scalar>(mag(arg));
                     else return calcMin<BaseType>(arg);
                 }
                 else if (statName == "max")
                 {
-                    if (mode == mdMag) return mag(calcMax<BaseType>(arg));
+                    if (mode == mdMag) return calcMax<scalar>(mag(arg));
                     else return calcMax<BaseType>(arg);
                 }
                 else if (statName == "mean")
                 {
-                    if (mode == mdMag) return mag(calcMean<BaseType>(arg));
+                    if (mode == mdMag) return calcMean<scalar>(mag(arg));
                     else return calcMean<BaseType>(arg);
                 }
                 else if (statName == "variance")
                 {
-                    if (mode == mdMag) return mag(calcVariance<BaseType>(arg));
+                    if (mode == mdMag) return calcVariance<scalar>(mag(arg));
                     else return calcVariance<BaseType>(arg);
                 }
                 else return scalar{};  // Default case (for compiler)
@@ -190,7 +191,10 @@ void Foam::functionObjects::fieldStatistics::logStatData()
 
         if (!results.size()) break;
 
-        Info<< nl << "    Field " << fieldName << nl;
+        const word outputName =
+            (mode_ == mdMag) ? word("mag(" + fieldName + ")") : fieldName;
+
+        Info<< nl << "    Field " << outputName << nl;
 
         for (const auto& iter : results.csorted())
         {
@@ -349,7 +353,6 @@ bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
     // Reset and reprepare the input field names
     fieldSet_.clear();
     fieldSet_.read(dict);
-    fieldSet_.updateSelection();
 
     // Reset and reprepare the input statistics
     statistics_.clear();
@@ -371,6 +374,8 @@ bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
 
 bool Foam::functionObjects::fieldStatistics::execute()
 {
+    fieldSet_.updateSelection();
+
     // Calculate the specified statistics for the specified fields
     for (const word& fieldName : fieldSet_.selectionNames())
     {
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index 7b5cd8d1cf6..58ed6f6a0dc 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -163,7 +163,7 @@ T Foam::functionObjects::fieldStatistics::calcVariance
         return T{};
     }
 
-    return 1/(n-1)*var;
+    return 1.0/(n - 1.0)*var;
 }
 
 
-- 
GitLab


From 4e287cec4cdc40c9a788a969ac4b741bdec5cf9a Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Fri, 14 Mar 2025 12:03:53 +0000
Subject: [PATCH 25/31] SQUASH: 56377ad: various changes to the extrema
 functionality

---
 .../field/fieldStatistics/fieldStatistics.C    | 18 ++++++++----------
 .../field/fieldStatistics/fieldStatistics.H    |  4 ++--
 .../fieldStatistics/fieldStatisticsImpl.cxx    | 11 ++++++++++-
 3 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index f239a161c6d..4b449ee7d5f 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -251,8 +251,8 @@ void Foam::functionObjects::fieldStatistics::writeExtremaData()
 {
     for (const word& fieldName : fieldSet_.selectionNames())
     {
-        const auto& min = extremaData_(fieldName).first();
-        const auto& max = extremaData_(fieldName).second();
+        const auto& min = extremaResults_(fieldName).first();
+        const auto& max = extremaResults_(fieldName).second();
 
         OFstream& file = *extremaFilePtrs_(fieldName);
 
@@ -281,13 +281,11 @@ void Foam::functionObjects::fieldStatistics::logExtremaData()
 {
     for (const word& fieldName : fieldSet_.selectionNames())
     {
-        const auto& min = extremaData_(fieldName).first();
-        const auto& max = extremaData_(fieldName).second();
+        const auto& min = extremaResults_(fieldName).first();
+        const auto& max = extremaResults_(fieldName).second();
 
         const word outputName =
-            (mode_ == mdMag)
-        ? word("mag(" + fieldName + ")")
-        : fieldName;
+            (mode_ == mdMag) ? word("mag(" + fieldName + ")") : fieldName;
 
         std::visit
         (
@@ -366,7 +364,7 @@ bool Foam::functionObjects::fieldStatistics::read(const dictionary& dict)
     results_.clear();
 
     // Reset the extrema-data container
-    extremaData_.clear();
+    extremaResults_.clear();
 
     return true;
 }
@@ -418,7 +416,7 @@ bool Foam::functionObjects::fieldStatistics::execute()
 
         if (extrema_)
         {
-            const auto& min = extremaData_(fieldName).first();
+            const auto& min = extremaResults_(fieldName).first();
             std::visit
             (
                 [this, fieldName](const auto& v)
@@ -431,7 +429,7 @@ bool Foam::functionObjects::fieldStatistics::execute()
             this->setResult(word(fieldName + "_min_cellID"), min.cellID_);
             this->setResult(word(fieldName + "_min_position"), min.position_);
 
-            const auto& max = extremaData_(fieldName).second();
+            const auto& max = extremaResults_(fieldName).second();
             std::visit
             (
                 [this, fieldName](const auto& v)
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index dc8f38d0fcc..94cf7e41dc1 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -233,8 +233,8 @@ class fieldStatistics
         //- Hash table containing all statistical results per field
         HashTable<HashTable<variantOutput>> results_;
 
-        //- Hash table containing the data of the extrema per field
-        HashTable<Pair<extremaData>> extremaData_;
+        //- Hash table containing the results of the extrema per field
+        HashTable<Pair<extremaData>> extremaResults_;
 
 
     // Private Member Functions
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index 58ed6f6a0dc..aaa5d9ac63b 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -107,7 +107,16 @@ bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
 
     results_.set(fieldName, result);
 
-    if (extrema_) extremaData_.set(fieldName, calcExtremaData(field));
+    if (extrema_)
+    {
+        extremaResults_.set
+        (
+            fieldName,
+            (mode_ == mdMag)
+          ? calcExtremaData(mag(field)())
+          : calcExtremaData(field)
+        );
+    }
 
     return true;
 }
-- 
GitLab


From 92ddaf6755c253326bee2dc9a9131eb57b25c54b Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Fri, 14 Mar 2025 17:10:36 +0000
Subject: [PATCH 26/31] SQUASH: 970449: add the spherical tensor

---
 .../field/fieldStatistics/fieldStatistics.C                | 4 ++--
 .../field/fieldStatistics/fieldStatistics.H                | 7 ++++---
 .../field/fieldStatistics/fieldStatisticsImpl.cxx          | 3 +--
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
index 4b449ee7d5f..590e6105ee6 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.C
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.C
@@ -5,8 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2015-2025 OpenCFD Ltd.
+    Copyright (C) 2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -381,6 +380,7 @@ bool Foam::functionObjects::fieldStatistics::execute()
         (
             calcStat<scalar>(fieldName)
          || calcStat<vector>(fieldName)
+         || calcStat<sphericalTensor>(fieldName)
          || calcStat<symmTensor>(fieldName)
          || calcStat<tensor>(fieldName)
         );
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.H b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
index 94cf7e41dc1..eb5c7bfbc9f 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.H
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.H
@@ -5,8 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2015-2025 OpenCFD Ltd.
+    Copyright (C) 2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -41,7 +40,7 @@ Description
       output field | -                             | -
     \endtable
 
-    where \c \<Type\>=Scalar/Vector/SymmTensor/Tensor.
+    where \c \<Type\>=Scalar/Vector/SphericalTensor/SymmTensor/Tensor.
 
 Usage
     Minimal example by using \c system/controlDict.functions:
@@ -164,6 +163,7 @@ class fieldStatistics
         <
             scalarField,
             vectorField,
+            sphericalTensorField,
             symmTensorField,
             tensorField
         >;
@@ -173,6 +173,7 @@ class fieldStatistics
         <
             scalar,
             vector,
+            sphericalTensor,
             symmTensor,
             tensor
         >;
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index aaa5d9ac63b..a2719307b84 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -5,8 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2015-2025 OpenCFD Ltd.
+    Copyright (C) 2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
-- 
GitLab


From 31deb5f3be3138dc893578bff043eea6d0ac3338 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Fri, 14 Mar 2025 17:12:34 +0000
Subject: [PATCH 27/31] SQUASH: rename .C as .cxx

---
 src/functionObjects/field/Make/files                            | 2 +-
 .../fieldStatistics/{fieldStatistics.C => fieldStatistics.cxx}  | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename src/functionObjects/field/fieldStatistics/{fieldStatistics.C => fieldStatistics.cxx} (100%)

diff --git a/src/functionObjects/field/Make/files b/src/functionObjects/field/Make/files
index 060eb3e1685..bd6b60b3736 100644
--- a/src/functionObjects/field/Make/files
+++ b/src/functionObjects/field/Make/files
@@ -154,6 +154,6 @@ resolutionIndex/resolutionIndexModels/CelikEtaIndex/CelikEtaIndex.C
 age/age.C
 comfort/comfort.C
 
-fieldStatistics/fieldStatistics.C
+fieldStatistics/fieldStatistics.cxx
 
 LIB = $(FOAM_LIBBIN)/libfieldFunctionObjects
diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.C b/src/functionObjects/field/fieldStatistics/fieldStatistics.cxx
similarity index 100%
rename from src/functionObjects/field/fieldStatistics/fieldStatistics.C
rename to src/functionObjects/field/fieldStatistics/fieldStatistics.cxx
-- 
GitLab


From 883d5ed971e2a1c14e66690ed063b05402a83d3a Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Fri, 14 Mar 2025 17:17:15 +0000
Subject: [PATCH 28/31] STYLE: avoid any trailing spaces

---
 .../field/fieldStatistics/fieldStatistics.cxx               | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatistics.cxx b/src/functionObjects/field/fieldStatistics/fieldStatistics.cxx
index 590e6105ee6..27fbd003967 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatistics.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatistics.cxx
@@ -200,7 +200,7 @@ void Foam::functionObjects::fieldStatistics::logStatData()
             const word& name = iter.key();
             const variantOutput& value = iter.val();
 
-            Info<< "    " << name << " ";
+            Info<< "    " << name;
             std::visit
             (
                 [](const auto& v)
@@ -210,11 +210,11 @@ void Foam::functionObjects::fieldStatistics::logStatData()
                         is_vectorspace_v<std::decay_t<decltype(v)>>
                     )
                     {
-                        for (const auto& val : v) Info<< val << " ";
+                        for (const auto& val : v) Info<< " " << val;
                     }
                     else
                     {
-                        Info<< v;
+                        Info<< " " << v;
                     }
                 },
                 value
-- 
GitLab


From 188bce8c38c276182f8f65e9fde06cd9b2ba0afd Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Mon, 31 Mar 2025 09:12:44 +0100
Subject: [PATCH 29/31] SQUASH: remove the duplicate logic

---
 .../field/fieldStatistics/fieldStatisticsImpl.cxx            | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index a2719307b84..142f1248f9e 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -80,11 +80,6 @@ bool Foam::functionObjects::fieldStatistics::calcStat(const word& fieldName)
 {
     typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
 
-    if (!obr_.foundObject<VolFieldType>(fieldName))
-    {
-        return false;
-    }
-
     const auto* fieldp = obr_.cfindObject<VolFieldType>(fieldName);
     if (!fieldp)
     {
-- 
GitLab


From d5764cee628948c3c51460f0e2a0e9633ed0a3e5 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Mon, 31 Mar 2025 11:15:51 +0100
Subject: [PATCH 30/31] SQUASH: simplify the weighted average routine

---
 .../field/fieldStatistics/fieldStatisticsImpl.cxx              | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index 142f1248f9e..b5c410402bd 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -121,8 +121,7 @@ T Foam::functionObjects::fieldStatistics::calcMean(const Field<T>& field)
 {
     if (internal_ && (mean_ == VOLUMETRIC))
     {
-        const Field<scalar>& V = mesh_.V();
-        return (gSum(V*field)/gSum(V));
+        return gWeightedAverage(mesh_.V(), field);
     }
 
     return gAverage(field);
-- 
GitLab


From dc2792d0f1bad5e35dbf4a8c2974eb7a1bf8c3c1 Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Mon, 31 Mar 2025 11:24:51 +0100
Subject: [PATCH 31/31] SQUASH: modernize the calcExtremaData routine

---
 .../fieldStatistics/fieldStatisticsImpl.cxx   | 40 +++++++++----------
 1 file changed, 18 insertions(+), 22 deletions(-)

diff --git a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
index b5c410402bd..7499b6c742c 100644
--- a/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
+++ b/src/functionObjects/field/fieldStatistics/fieldStatisticsImpl.cxx
@@ -192,20 +192,18 @@ Foam::functionObjects::fieldStatistics::calcExtremaData
 
     labelPair minMaxIds = findMinMax(field);
 
-    label minId = minMaxIds.first();
-    if (minId != -1)
+    if (label celli = minMaxIds.first(); celli >= 0)
     {
-        minVs[proci] = field[minId];
-        minCells[proci] = minId;
-        minCs[proci] = mesh_.C()[minId];
+        minVs[proci] = field[celli];
+        minCells[proci] = celli;
+        minCs[proci] = mesh_.C()[celli];
     }
 
-    label maxId = minMaxIds.second();
-    if (maxId != -1)
+    if (label celli = minMaxIds.second(); celli >= 0)
     {
-        maxVs[proci] = field[maxId];
-        maxCells[proci] = maxId;
-        maxCs[proci] = mesh_.C()[maxId];
+        maxVs[proci] = field[celli];
+        maxCells[proci] = celli;
+        maxCs[proci] = mesh_.C()[celli];
     }
 
     if (!internal_)
@@ -226,20 +224,18 @@ Foam::functionObjects::fieldStatistics::calcExtremaData
 
                 minMaxIds = findMinMax(fp);
 
-                minId = minMaxIds.first();
-                if (minVs[proci] > fp[minId])
+                if (label celli = minMaxIds.first(); minVs[proci] > fp[celli])
                 {
-                    minVs[proci] = fp[minId];
-                    minCells[proci] = faceCells[minId];
-                    minCs[proci] = Cfp[minId];
+                    minVs[proci] = fp[celli];
+                    minCells[proci] = faceCells[celli];
+                    minCs[proci] = Cfp[celli];
                 }
 
-                maxId = minMaxIds.second();
-                if (maxVs[proci] < fp[maxId])
+                if (label celli = minMaxIds.second(); maxVs[proci] < fp[celli])
                 {
-                    maxVs[proci] = fp[maxId];
-                    maxCells[proci] = faceCells[maxId];
-                    maxCs[proci] = Cfp[maxId];
+                    maxVs[proci] = fp[celli];
+                    maxCells[proci] = faceCells[celli];
+                    maxCs[proci] = Cfp[celli];
                 }
             }
         }
@@ -255,14 +251,14 @@ Foam::functionObjects::fieldStatistics::calcExtremaData
     Pstream::allGatherList(maxCs);
 
     extremaData min;
-    minId = findMin(minVs);
+    const label minId = findMin(minVs);
     min.value_ = minVs[minId];
     min.procID_ = minId;
     min.cellID_ = minCells[minId];
     min.position_ = minCs[minId];
 
     extremaData max;
-    maxId = findMax(maxVs);
+    const label maxId = findMax(maxVs);
     max.value_ = maxVs[maxId];
     max.procID_ = maxId;
     max.cellID_ = maxCells[maxId];
-- 
GitLab