From b0b1d0f8b20fc0d9b6e37f52cbd86ea93f295cff Mon Sep 17 00:00:00 2001
From: Andrew Heather <>
Date: Wed, 18 Dec 2024 15:06:11 +0000
Subject: [PATCH] ENH: fieldAverage - allow averaging on internal fields - see
 #3242

BUG: fieldAverage - handle duplicate entries
---
 .../field/fieldAverage/fieldAverage.C         |  25 ++-
 .../field/fieldAverage/fieldAverage.H         |  16 +-
 .../fieldAverage/fieldAverageTemplates.C      | 205 ++++++++++++------
 3 files changed, 173 insertions(+), 73 deletions(-)

diff --git a/src/functionObjects/field/fieldAverage/fieldAverage.C b/src/functionObjects/field/fieldAverage/fieldAverage.C
index ab2cf923bcf..1c5441f7a87 100644
--- a/src/functionObjects/field/fieldAverage/fieldAverage.C
+++ b/src/functionObjects/field/fieldAverage/fieldAverage.C
@@ -308,14 +308,31 @@ bool Foam::functionObjects::fieldAverage::read(const dictionary& dict)
     dict.readIfPresent("restartOnRestart", restartOnRestart_);
     dict.readIfPresent("restartOnOutput",  restartOnOutput_);
     dict.readIfPresent("periodicRestart",  periodicRestart_);
-    dict.readEntry("fields", faItems_);
 
-    for (auto& item : faItems_)
+    List<fieldAverageItem> faItems0;
+    dict.readEntry("fields", faItems0);
+
+    DynamicList<fieldAverageItem> faItems(faItems0.size());
+
+    wordHashSet names;
+    for (auto& item : faItems0)
     {
-        item.setMeanFieldName(scopedName(item.meanFieldName()));
-        item.setPrime2MeanFieldName(scopedName(item.prime2MeanFieldName()));
+        if (names.insert(item.fieldName()))
+        {
+            item.setMeanFieldName(scopedName(item.meanFieldName()));
+            item.setPrime2MeanFieldName(scopedName(item.prime2MeanFieldName()));
+            faItems.push_back(item);
+        }
+        else
+        {
+            WarningInFunction
+                << "Duplicate entry found: " << item.fieldName()
+                << " (ignored)" << endl;
+        }
     }
 
+    faItems_.transfer(faItems);
+
     const scalar currentTime = obr().time().value();
 
     if (periodicRestart_)
diff --git a/src/functionObjects/field/fieldAverage/fieldAverage.H b/src/functionObjects/field/fieldAverage/fieldAverage.H
index 868bed61479..3081085188a 100644
--- a/src/functionObjects/field/fieldAverage/fieldAverage.H
+++ b/src/functionObjects/field/fieldAverage/fieldAverage.H
@@ -233,19 +233,19 @@ protected:
 
             //- Add mean average field to database
             template<class Type>
-            void addMeanFieldType(fieldAverageItem& item);
+            bool addMeanFieldType(fieldAverageItem& item);
 
             //- Add mean average field to database
             template<class Type>
-            void addMeanField(fieldAverageItem& item);
+            bool addMeanField(fieldAverageItem& item);
 
             //- Add prime-squared average field to database
             template<class Type1, class Type2>
-            void addPrime2MeanFieldType(fieldAverageItem& item);
+            bool addPrime2MeanFieldType(fieldAverageItem& item);
 
             //- Add prime-squared average field to database
             template<class Type1, class Type2>
-            void addPrime2MeanField(fieldAverageItem& item);
+            bool addPrime2MeanField(fieldAverageItem& item);
 
 
         // Calculation functions
@@ -263,20 +263,20 @@ protected:
 
             //- Add mean-squared field value to prime-squared mean field
             template<class Type1, class Type2>
-            void addMeanSqrToPrime2MeanType(const fieldAverageItem& item) const;
+            bool addMeanSqrToPrime2MeanType(const fieldAverageItem& item) const;
 
             //- Add mean-squared field value to prime-squared mean field
             template<class Type1, class Type2>
             void addMeanSqrToPrime2Mean() const;
 
             template<class Type>
-            void storeWindowFieldType(fieldAverageItem& item);
+            bool storeWindowFieldType(fieldAverageItem& item);
 
             template<class Type>
             void storeWindowFields();
 
             template<class Type>
-            void restoreWindowFieldsType(const fieldAverageItem& item);
+            bool restoreWindowFieldsType(const fieldAverageItem& item);
 
             template<class Type>
             void restoreWindowFields(const fieldAverageItem& item);
@@ -288,7 +288,7 @@ protected:
 
             //- Write fields
             template<class Type>
-            void writeFieldType(const word& fieldName) const;
+            bool writeFieldType(const word& fieldName) const;
 
             //- Write fields
             template<class Type>
diff --git a/src/functionObjects/field/fieldAverage/fieldAverageTemplates.C b/src/functionObjects/field/fieldAverage/fieldAverageTemplates.C
index 9b612df9a82..770e96f59ed 100644
--- a/src/functionObjects/field/fieldAverage/fieldAverageTemplates.C
+++ b/src/functionObjects/field/fieldAverage/fieldAverageTemplates.C
@@ -35,16 +35,16 @@ License
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 template<class Type>
-void Foam::functionObjects::fieldAverage::addMeanFieldType
+bool Foam::functionObjects::fieldAverage::addMeanFieldType
 (
     fieldAverageItem& item
 )
 {
-    const word& fieldName = item.fieldName();
+    const Type* fieldPtr = findObject<Type>(item.fieldName());
 
-    if (!foundObject<Type>(fieldName))
+    if (!fieldPtr)
     {
-        return;
+        return false;
     }
 
     // Field has been found, so set active flag to true
@@ -66,7 +66,7 @@ void Foam::functionObjects::fieldAverage::addMeanFieldType
     }
     else
     {
-        const Type& baseField = lookupObject<Type>(fieldName);
+        const Type& baseField = *fieldPtr;
 
         // Store on registry
         obr().store
@@ -88,38 +88,51 @@ void Foam::functionObjects::fieldAverage::addMeanFieldType
                 1*baseField
             )
         );
+
+        return true;
     }
+
+    return false;
 }
 
 
 template<class Type>
-void Foam::functionObjects::fieldAverage::addMeanField
+bool Foam::functionObjects::fieldAverage::addMeanField
 (
     fieldAverageItem& item
 )
 {
     typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+    typedef typename VolFieldType::Internal VolFieldInternalType;
     typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType;
     typedef DimensionedField<Type, polySurfaceGeoMesh> SurfFieldType;
 
+    bool added = false;
+
     if (item.mean())
     {
-        addMeanFieldType<VolFieldType>(item);
-        addMeanFieldType<SurfaceFieldType>(item);
-        addMeanFieldType<SurfFieldType>(item);
+        added =
+        (
+            addMeanFieldType<VolFieldType>(item)
+         || addMeanFieldType<VolFieldInternalType>(item)
+         || addMeanFieldType<SurfaceFieldType>(item)
+         || addMeanFieldType<SurfFieldType>(item)
+        );
     }
+
+    return added;
 }
 
 
 template<class Type>
-void Foam::functionObjects::fieldAverage::restoreWindowFieldsType
+bool Foam::functionObjects::fieldAverage::restoreWindowFieldsType
 (
     const fieldAverageItem& item
 )
 {
     if (restartOnOutput_)
     {
-        return;
+        return false;
     }
 
     const word& fieldName = item.fieldName();
@@ -128,7 +141,7 @@ void Foam::functionObjects::fieldAverage::restoreWindowFieldsType
 
     if (!fieldPtr)
     {
-        return;
+        return false;
     }
 
     const FIFOStack<word>& fieldNames = item.windowFieldNames();
@@ -160,6 +173,8 @@ void Foam::functionObjects::fieldAverage::restoreWindowFieldsType
                 << endl;
         }
     }
+
+    return true;
 }
 
 
@@ -170,29 +185,34 @@ void Foam::functionObjects::fieldAverage::restoreWindowFields
 )
 {
     typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+    typedef typename VolFieldType::Internal VolFieldInternalType;
     typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType;
     typedef DimensionedField<Type, polySurfaceGeoMesh> SurfFieldType;
 
     if (item.window() > 0)
     {
-        restoreWindowFieldsType<VolFieldType>(item);
-        restoreWindowFieldsType<SurfaceFieldType>(item);
-        restoreWindowFieldsType<SurfFieldType>(item);
+        (void)
+        (
+            restoreWindowFieldsType<VolFieldType>(item)
+         || restoreWindowFieldsType<VolFieldInternalType>(item)
+         || restoreWindowFieldsType<SurfaceFieldType>(item)
+         || restoreWindowFieldsType<SurfFieldType>(item)
+        );
     }
 }
 
 
 template<class Type1, class Type2>
-void Foam::functionObjects::fieldAverage::addPrime2MeanFieldType
+bool Foam::functionObjects::fieldAverage::addPrime2MeanFieldType
 (
     fieldAverageItem& item
 )
 {
-    const word& fieldName = item.fieldName();
+    const auto* baseFieldPtr = findObject<Type1>(item.fieldName());
 
-    if (!foundObject<Type1>(fieldName))
+    if (!baseFieldPtr)
     {
-        return;
+        return false;
     }
 
     const word& meanFieldName = item.meanFieldName();
@@ -212,7 +232,7 @@ void Foam::functionObjects::fieldAverage::addPrime2MeanFieldType
     }
     else
     {
-        const Type1& baseField = lookupObject<Type1>(fieldName);
+        const auto& baseField = *baseFieldPtr;
         const Type1& meanField = lookupObject<Type1>(meanFieldName);
 
         // Store on registry
@@ -233,24 +253,32 @@ void Foam::functionObjects::fieldAverage::addPrime2MeanFieldType
                 sqr(baseField) - sqr(meanField)
             )
         );
+
+        return true;
     }
+
+    return false;
 }
 
 
 template<class Type1, class Type2>
-void Foam::functionObjects::fieldAverage::addPrime2MeanField
+bool Foam::functionObjects::fieldAverage::addPrime2MeanField
 (
     fieldAverageItem& item
 )
 {
     typedef GeometricField<Type1, fvPatchField, volMesh> VolFieldType1;
+    typedef typename VolFieldType1::Internal VolFieldInternalType1;
     typedef GeometricField<Type1, fvsPatchField, surfaceMesh> SurfaceFieldType1;
     typedef DimensionedField<Type1, polySurfaceGeoMesh> SurfFieldType1;
 
     typedef GeometricField<Type2, fvPatchField, volMesh> VolFieldType2;
+    typedef typename VolFieldType2::Internal VolFieldInternalType2;
     typedef GeometricField<Type2, fvsPatchField, surfaceMesh> SurfaceFieldType2;
     typedef DimensionedField<Type2, polySurfaceGeoMesh> SurfFieldType2;
 
+    bool added = false;
+
     if (item.prime2Mean())
     {
         if (!item.mean())
@@ -261,26 +289,34 @@ void Foam::functionObjects::fieldAverage::addPrime2MeanField
                 << item.fieldName() << nl << exit(FatalError);
         }
 
-        addPrime2MeanFieldType<VolFieldType1, VolFieldType2>(item);
-        addPrime2MeanFieldType<SurfaceFieldType1, SurfaceFieldType2>(item);
-        addPrime2MeanFieldType<SurfFieldType1, SurfFieldType2>(item);
+        added =
+            addPrime2MeanFieldType<VolFieldType1, VolFieldType2>(item)
+         || addPrime2MeanFieldType<VolFieldInternalType1, VolFieldInternalType2>
+            (
+                item
+            )
+         || addPrime2MeanFieldType<SurfaceFieldType1, SurfaceFieldType2>(item)
+         || addPrime2MeanFieldType<SurfFieldType1, SurfFieldType2>(item);
     }
+
+    return added;
 }
 
 
 template<class Type>
-void Foam::functionObjects::fieldAverage::storeWindowFieldType
+bool Foam::functionObjects::fieldAverage::storeWindowFieldType
 (
     fieldAverageItem& item
 )
 {
-    const word& fieldName = item.fieldName();
-    if (!foundObject<Type>(fieldName))
+    const auto* fPtr = findObject<Type>(item.fieldName());
+
+    if (!fPtr)
     {
-        return;
+        return false;
     }
 
-    const Type& baseField = lookupObject<Type>(fieldName);
+    const Type& baseField = *fPtr;
 
     const word windowFieldName = item.windowFieldName(this->name());
 
@@ -306,6 +342,8 @@ void Foam::functionObjects::fieldAverage::storeWindowFieldType
     DebugInfo << "Create and store: " << windowFieldName << endl;
 
     item.addToWindow(windowFieldName, obr().time().deltaTValue());
+
+    return true;
 }
 
 
@@ -313,6 +351,7 @@ template<class Type>
 void Foam::functionObjects::fieldAverage::storeWindowFields()
 {
     typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+    typedef typename VolFieldType::Internal VolFieldInternalType;
     typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType;
     typedef DimensionedField<Type, polySurfaceGeoMesh> SurfFieldType;
 
@@ -320,9 +359,13 @@ void Foam::functionObjects::fieldAverage::storeWindowFields()
     {
         if (item.storeWindowFields())
         {
-            storeWindowFieldType<VolFieldType>(item);
-            storeWindowFieldType<SurfaceFieldType>(item);
-            storeWindowFieldType<SurfFieldType>(item);
+            (void)
+            (
+                storeWindowFieldType<VolFieldType>(item)
+             || storeWindowFieldType<VolFieldInternalType>(item)
+             || storeWindowFieldType<SurfaceFieldType>(item)
+             || storeWindowFieldType<SurfFieldType>(item)
+            );
         }
     }
 }
@@ -332,14 +375,21 @@ template<class Type>
 void Foam::functionObjects::fieldAverage::calculateMeanFields() const
 {
     typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+    typedef typename VolFieldType::Internal VolFieldInternalType;
     typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType;
     typedef DimensionedField<Type, polySurfaceGeoMesh> SurfFieldType;
 
+    const auto& obr = this->obr();
+
     for (const fieldAverageItem& item : faItems_)
     {
-        item.calculateMeanField<VolFieldType>(obr());
-        item.calculateMeanField<SurfaceFieldType>(obr());
-        item.calculateMeanField<SurfFieldType>(obr());
+        (void)
+        (
+            item.calculateMeanField<VolFieldType>(obr)
+         || item.calculateMeanField<VolFieldInternalType>(obr)
+         || item.calculateMeanField<SurfaceFieldType>(obr)
+         || item.calculateMeanField<SurfFieldType>(obr)
+        );
     }
 }
 
@@ -348,36 +398,41 @@ template<class Type1, class Type2>
 void Foam::functionObjects::fieldAverage::calculatePrime2MeanFields() const
 {
     typedef GeometricField<Type1, fvPatchField, volMesh> VolFieldType1;
+    typedef typename VolFieldType1::Internal VolFieldInternalType1;
     typedef GeometricField<Type1, fvsPatchField, surfaceMesh> SurfaceFieldType1;
     typedef DimensionedField<Type1, polySurfaceGeoMesh> SurfFieldType1;
 
     typedef GeometricField<Type2, fvPatchField, volMesh> VolFieldType2;
+    typedef typename VolFieldType2::Internal VolFieldInternalType2;
     typedef GeometricField<Type2, fvsPatchField, surfaceMesh> SurfaceFieldType2;
     typedef DimensionedField<Type2, polySurfaceGeoMesh> SurfFieldType2;
 
+    const auto& obr = this->obr();
+
     for (const fieldAverageItem& item : faItems_)
     {
-        item.calculatePrime2MeanField<VolFieldType1, VolFieldType2>(obr());
-        item.calculatePrime2MeanField<SurfaceFieldType1, SurfaceFieldType2>
+        (void)
         (
-            obr()
+            item.calculatePrime2MeanField<VolFieldType1, VolFieldType2>(obr)
+         || item.calculatePrime2MeanField
+            <VolFieldInternalType1, VolFieldInternalType2>(obr)
+         || item.calculatePrime2MeanField
+            <SurfaceFieldType1, SurfaceFieldType2>(obr)
+         || item.calculatePrime2MeanField<SurfFieldType1, SurfFieldType2>(obr)
         );
-        item.calculatePrime2MeanField<SurfFieldType1, SurfFieldType2>(obr());
     }
 }
 
 
 template<class Type1, class Type2>
-void Foam::functionObjects::fieldAverage::addMeanSqrToPrime2MeanType
+bool Foam::functionObjects::fieldAverage::addMeanSqrToPrime2MeanType
 (
     const fieldAverageItem& item
 ) const
 {
-    const word& fieldName = item.fieldName();
-
-    if (!foundObject<Type1>(fieldName))
+    if (!foundObject<Type1>(item.fieldName()))
     {
-        return;
+        return false;
     }
 
     const Type1& meanField = lookupObject<Type1>(item.meanFieldName());
@@ -385,6 +440,8 @@ void Foam::functionObjects::fieldAverage::addMeanSqrToPrime2MeanType
     Type2& prime2MeanField = lookupObjectRef<Type2>(item.prime2MeanFieldName());
 
     prime2MeanField += sqr(meanField);
+
+    return true;
 }
 
 
@@ -392,10 +449,12 @@ template<class Type1, class Type2>
 void Foam::functionObjects::fieldAverage::addMeanSqrToPrime2Mean() const
 {
     typedef GeometricField<Type1, fvPatchField, volMesh> VolFieldType1;
+    typedef typename VolFieldType1::Internal VolFieldInternalType1;
     typedef GeometricField<Type1, fvsPatchField, surfaceMesh> SurfaceFieldType1;
     typedef DimensionedField<Type1, polySurfaceGeoMesh> SurfFieldType1;
 
     typedef GeometricField<Type2, fvPatchField, volMesh> VolFieldType2;
+    typedef typename VolFieldType2::Internal VolFieldInternalType2;
     typedef GeometricField<Type2, fvsPatchField, surfaceMesh> SurfaceFieldType2;
     typedef DimensionedField<Type2, polySurfaceGeoMesh> SurfFieldType2;
 
@@ -403,28 +462,36 @@ void Foam::functionObjects::fieldAverage::addMeanSqrToPrime2Mean() const
     {
         if (item.prime2Mean())
         {
-            addMeanSqrToPrime2MeanType<VolFieldType1, VolFieldType2>(item);
-            addMeanSqrToPrime2MeanType<SurfaceFieldType1, SurfaceFieldType2>
+            (void)
             (
-                item
+                addMeanSqrToPrime2MeanType<VolFieldType1, VolFieldType2>(item)
+             || addMeanSqrToPrime2MeanType
+                <VolFieldInternalType1, VolFieldInternalType2>(item)
+             || addMeanSqrToPrime2MeanType
+                <SurfaceFieldType1, SurfaceFieldType2>(item)
+             || addMeanSqrToPrime2MeanType
+                <SurfFieldType1, SurfFieldType2>(item)
             );
-            addMeanSqrToPrime2MeanType<SurfFieldType1, SurfFieldType2>(item);
         }
     }
 }
 
 
 template<class Type>
-void Foam::functionObjects::fieldAverage::writeFieldType
+bool Foam::functionObjects::fieldAverage::writeFieldType
 (
     const word& fieldName
 ) const
 {
-    if (foundObject<Type>(fieldName))
+    const auto* fPtr = findObject<Type>(fieldName);
+
+    if (fPtr)
     {
-        const Type& f = lookupObject<Type>(fieldName);
-        f.write();
+        DebugInfo<< "writing " << Type::typeName << ": " << fieldName << endl;
+        return fPtr->write();
     }
+
+    return false;
 }
 
 
@@ -432,6 +499,7 @@ template<class Type>
 void Foam::functionObjects::fieldAverage::writeFields() const
 {
     typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+    typedef typename VolFieldType::Internal VolFieldInternalType;
     typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType;
     typedef DimensionedField<Type, polySurfaceGeoMesh> SurfFieldType;
 
@@ -440,17 +508,27 @@ void Foam::functionObjects::fieldAverage::writeFields() const
         if (item.mean())
         {
             const word& fieldName = item.meanFieldName();
-            writeFieldType<VolFieldType>(fieldName);
-            writeFieldType<SurfaceFieldType>(fieldName);
-            writeFieldType<SurfFieldType>(fieldName);
+
+            (void)
+            (
+                writeFieldType<VolFieldType>(fieldName)
+             || writeFieldType<VolFieldInternalType>(fieldName)
+             || writeFieldType<SurfaceFieldType>(fieldName)
+             || writeFieldType<SurfFieldType>(fieldName)
+            );
         }
 
         if (item.prime2Mean())
         {
             const word& fieldName = item.prime2MeanFieldName();
-            writeFieldType<VolFieldType>(fieldName);
-            writeFieldType<SurfaceFieldType>(fieldName);
-            writeFieldType<SurfFieldType>(fieldName);
+
+            (void)
+            (
+                writeFieldType<VolFieldType>(fieldName)
+             || writeFieldType<VolFieldInternalType>(fieldName)
+             || writeFieldType<SurfaceFieldType>(fieldName)
+             || writeFieldType<SurfFieldType>(fieldName)
+            );
         }
 
         if (item.writeWindowFields())
@@ -459,9 +537,14 @@ void Foam::functionObjects::fieldAverage::writeFields() const
             forAllConstIters(fieldNames, fieldNameIter)
             {
                 const word& fieldName = fieldNameIter();
-                writeFieldType<VolFieldType>(fieldName);
-                writeFieldType<SurfaceFieldType>(fieldName);
-                writeFieldType<SurfFieldType>(fieldName);
+
+                (void)
+                (
+                    writeFieldType<VolFieldType>(fieldName)
+                 || writeFieldType<VolFieldInternalType>(fieldName)
+                 || writeFieldType<SurfaceFieldType>(fieldName)
+                 || writeFieldType<SurfFieldType>(fieldName)
+                );
             }
         }
     }
-- 
GitLab