From 42f94ce2c89881cabf628cac442f3ea084f3b266 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Thu, 6 Jul 2023 13:05:34 +0200
Subject: [PATCH] ENH: use sorted order for fieldSelection::selectionNames()
 (#2819)

- return a sorted wordList instead of a wordHashSet to ensure that
  fields will be processed in consistent order in parallel
---
 .../fieldSelection/fieldInfo.H                | 51 ++++++++++---------
 .../fieldSelection/fieldSelection.C           | 49 +++++++++++-------
 .../fieldSelection/fieldSelection.H           | 29 +++++++----
 .../fieldSelection/fieldSelectionI.H          | 28 +++++-----
 .../fieldSelection/fieldSelectionTemplates.C  | 17 +++----
 .../fileFieldSelection/fileFieldSelection.C   | 13 +++--
 .../fileFieldSelection/fileFieldSelection.H   | 10 ++--
 .../solverFieldSelection.C                    |  9 ++--
 .../solverFieldSelection.H                    | 18 +++----
 .../volFieldSelection/volFieldSelection.H     | 18 +++----
 .../field/limitFields/limitFields.C           |  9 ++--
 11 files changed, 129 insertions(+), 122 deletions(-)

diff --git a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldInfo.H b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldInfo.H
index db79172a388..8a8522dc621 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldInfo.H
+++ b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldInfo.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2019-2021 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -32,8 +32,8 @@ Description
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef functionObjects_fieldInfo_H
-#define functionObjects_fieldInfo_H
+#ifndef Foam_functionObjects_fieldInfo_H
+#define Foam_functionObjects_fieldInfo_H
 
 #include "label.H"
 #include "wordRes.H"
@@ -57,7 +57,7 @@ Ostream& operator<<(Ostream&, const fieldInfo&);
 
 class fieldInfo
 {
-    // Pivate Data
+    // Private Data
 
         //- Pattern for the field name(s)
         wordRe name_;
@@ -65,8 +65,8 @@ class fieldInfo
         //- Field component
         label component_;
 
-        //- Found
-        mutable Switch found_;
+        //- Found the field
+        mutable bool found_;
 
 
 public:
@@ -81,9 +81,8 @@ public:
             found_(false)
         {}
 
-
         //- Construct from components
-        fieldInfo(const wordRe& name, const label component = -1)
+        explicit fieldInfo(const wordRe& name, const label component = -1)
         :
             name_(name),
             component_(component),
@@ -91,7 +90,7 @@ public:
         {}
 
         //- Construct from stream
-        fieldInfo(Istream& is)
+        explicit fieldInfo(Istream& is)
         :
             name_(is),
             component_(readLabel(is)),
@@ -105,27 +104,27 @@ public:
 
     // Member Functions
 
-        const wordRe& name() const
-        {
-            return name_;
-        }
+        //- Return the selector pattern for the field name(s)
+        const wordRe& name() const noexcept { return name_; }
 
-        label component() const
-        {
-            return component_;
-        }
+        //- Return the component
+        label component() const noexcept { return component_; }
+
+        //- Return the found state
+        bool found() const noexcept { return found_; }
+
+        //- Set the found state to be 'on'
+        void found(bool on) const noexcept { found_ = on; }
 
-        Switch& found() const
-        {
-            return found_;
-        }
 
         friend bool operator==(const fieldInfo& a, const fieldInfo& b)
         {
             return
-                a.name_ == b.name_
-             && a.component_ == b.component_
-             && a.found_ == b.found_;
+            (
+                a.found() == b.found()
+             && a.component() == b.component()
+             && a.name() == b.name()
+            );
         }
 
         friend bool operator!=(const fieldInfo& a, const fieldInfo& b)
@@ -143,7 +142,9 @@ public:
         }
         friend Ostream& operator<<(Ostream& os, const fieldInfo& fi)
         {
-            os  << fi.name_ << ' ' << fi.component_ << ' ' << fi.found_;
+            os  << fi.name_ << ' '
+                << fi.component_ << ' '
+                << Switch::name(fi.found_);
             return os;
         }
 };
diff --git a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelection.C b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelection.C
index bbe8efc1d8c..a570ebdebd0 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelection.C
+++ b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelection.C
@@ -37,27 +37,28 @@ Foam::functionObjects::fieldSelection::fieldSelection
     const bool includeComponents
 )
 :
-    List<fieldInfo>(),
     obr_(obr),
-    includeComponents_(includeComponents),
-    selection_()
+    includeComponents_(includeComponents)
 {}
 
 
-bool Foam::functionObjects::fieldSelection::resetFieldFilters
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Container>
+bool Foam::functionObjects::fieldSelection::resetFieldFiltersImpl
 (
-    const HashSet<wordRe>& names
+    const Container& names
 )
 {
-    static word cmptStr(".component(");
-    static string::size_type len(cmptStr.size());
+    static std::string cmptStr(".component(");
+    static std::string::size_type len(cmptStr.size());
 
     DynamicList<fieldInfo> nameAndComponent(names.size());
 
     for (const wordRe& name : names)
     {
-        string::size_type n = name.find(cmptStr);
-        if (n != string::npos)
+        const auto n = name.find(cmptStr);
+        if (n != std::string::npos)
         {
             // Field should be written <field>.component(i)
 
@@ -76,12 +77,12 @@ bool Foam::functionObjects::fieldSelection::resetFieldFilters
                     << exit(FatalError);
             }
 
-            word baseName = name.substr(0, n);
+            const word baseName(name.substr(0, n));
 
             // Extract the component - number between ()'s
-            string::size_type closei = name.find(')', n);
+            const auto closei = name.find(')', n);
 
-            if (closei == string::npos)
+            if (closei == std::string::npos)
             {
                 FatalErrorInFunction
                     << "Invalid field component specification for "
@@ -90,18 +91,18 @@ bool Foam::functionObjects::fieldSelection::resetFieldFilters
                     << exit(FatalError);
             }
 
-            string::size_type cmptWidth = closei - n - len;
+            const auto cmptWidth = (closei - n - len);
 
             label component
             (
-                readLabel(IStringStream(name.substr(n+len, cmptWidth))())
+                readLabel(name.substr(n+len, cmptWidth))
             );
 
-            nameAndComponent.append(fieldInfo(wordRe(baseName), component));
+            nameAndComponent.emplace_back(wordRe(baseName), component);
         }
         else
         {
-            nameAndComponent.append(fieldInfo(name));
+            nameAndComponent.emplace_back(name);
         }
     }
 
@@ -111,12 +112,23 @@ bool Foam::functionObjects::fieldSelection::resetFieldFilters
 }
 
 
+bool Foam::functionObjects::fieldSelection::resetFieldFilters
+(
+    const HashSet<wordRe>& names
+)
+{
+    return resetFieldFiltersImpl(names);
+}
+
+
 bool Foam::functionObjects::fieldSelection::resetFieldFilters
 (
     const wordRe& name
 )
 {
-    return resetFieldFilters(HashSet<wordRe>({name}));
+    List<wordRe> names(1, name);
+
+    return resetFieldFiltersImpl(names);
 }
 
 
@@ -124,7 +136,8 @@ bool Foam::functionObjects::fieldSelection::resetFieldFilters
 
 bool Foam::functionObjects::fieldSelection::read(const dictionary& dict)
 {
-    HashSet<wordRe> fields(dict.lookup("fields"));
+    HashSet<wordRe> fields(0);
+    dict.readEntry("fields", fields);
 
     return resetFieldFilters(fields);
 }
diff --git a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelection.H b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelection.H
index 31287b2077b..297b854dcfd 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelection.H
+++ b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelection.H
@@ -39,8 +39,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef functionObjects_fieldSelection_H
-#define functionObjects_fieldSelection_H
+#ifndef Foam_functionObjects_fieldSelection_H
+#define Foam_functionObjects_fieldSelection_H
 
 #include "fieldInfo.H"
 #include "DynamicList.H"
@@ -51,6 +51,7 @@ SourceFiles
 namespace Foam
 {
 
+// Forward Declarations
 class dictionary;
 class objectRegistry;
 
@@ -65,17 +66,19 @@ class fieldSelection
 :
     public List<fieldInfo>
 {
-private:
-
     // Private Member Functions
 
+        //- Reset the field filters to the given field names
+        template<class Container>
+        bool resetFieldFiltersImpl(const Container& names);
+
         //- No copy construct
         fieldSelection(const fieldSelection&) = delete;
 
 
 protected:
 
-    // Protected member data
+    // Protected Member Data
 
         //- Reference to the database
         const objectRegistry& obr_;
@@ -97,7 +100,7 @@ protected:
 public:
 
     //- Construct from object registry
-    fieldSelection
+    explicit fieldSelection
     (
         const objectRegistry& obr,
         const bool includeComponents = false
@@ -110,13 +113,17 @@ public:
 
     // Member Functions
 
-        //- Return the cuurent filters
-        inline HashSet<wordRe> filters() const;
+        //- The current field selection
+        const List<fieldInfo>& selection() const noexcept
+        {
+            return selection_;
+        }
 
-        inline const List<fieldInfo>& selection() const;
+        //- Return the current filters
+        inline HashSet<wordRe> filters() const;
 
-        //- Return the current field selection
-        inline wordHashSet selectionNames() const;
+        //- Return the current field selection, in sorted order
+        inline wordList selectionNames() const;
 
         //- Reset the field filters to the given field names
         virtual bool resetFieldFilters(const HashSet<wordRe>& names);
diff --git a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelectionI.H b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelectionI.H
index 93a703b296c..f08b9f8b8b6 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelectionI.H
+++ b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelectionI.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2019-2020 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,36 +25,34 @@ License
 
 \*---------------------------------------------------------------------------*/
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
 inline Foam::HashSet<Foam::wordRe>
 Foam::functionObjects::fieldSelection::filters() const
 {
-    HashSet<wordRe> f;
+    HashSet<wordRe> values(2*this->size());
     for (const fieldInfo& fi : *this)
     {
-        f.insert(fi.name());
+        values.insert(fi.name());
     }
 
-    return f;
+    return values;
 }
 
-// * * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * //
-
-inline const Foam::List<Foam::functionObjects::fieldInfo>&
-Foam::functionObjects::fieldSelection::selection() const
-{
-    return selection_;
-}
 
-
-inline Foam::wordHashSet
+inline Foam::wordList
 Foam::functionObjects::fieldSelection::selectionNames() const
 {
-    wordHashSet names;
+    DynamicList<word> values(selection_.size());
+
     for (const fieldInfo& fi : selection_)
     {
-        names.insert(fi.name());
+        values.push_uniq(fi.name());
     }
 
+    wordList names(std::move(values));
+    Foam::sort(names);  // Globally consistent order
+
     return names;
 }
 
diff --git a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelectionTemplates.C b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelectionTemplates.C
index cc597c6ea4c..2df442011cb 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelectionTemplates.C
+++ b/src/finiteVolume/functionObjects/fieldSelections/fieldSelection/fieldSelectionTemplates.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2017-2019 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,15 +37,14 @@ void Foam::functionObjects::fieldSelection::addRegistered
 {
     for (const fieldInfo& fi : *this)
     {
-        wordList names(obr_.names<Type>(fi.name()));
-        if (names.size())
+        const wordList names(obr_.sortedNames<Type>(fi.name()));
+        if (!names.empty())
         {
-            for (const word& name : names)
-            {
-                set.append(fieldInfo(wordRe(name), fi.component()));
-            }
-
-            fi.found() = true;
+            fi.found(true);
+        }
+        for (const word& name : names)
+        {
+            set.emplace_back(wordRe(name), fi.component());
         }
     }
 }
diff --git a/src/finiteVolume/functionObjects/fieldSelections/fileFieldSelection/fileFieldSelection.C b/src/finiteVolume/functionObjects/fieldSelections/fileFieldSelection/fileFieldSelection.C
index 308f4c802a4..6aa54f4596e 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/fileFieldSelection/fileFieldSelection.C
+++ b/src/finiteVolume/functionObjects/fieldSelections/fileFieldSelection/fileFieldSelection.C
@@ -51,14 +51,13 @@ void Foam::functionObjects::fileFieldSelection::addFromFile
     {
         const wordList names(objects.sortedNames<Type>(fi.name()));
 
-        if (names.size())
+        if (!names.empty())
         {
-            for (const word& name : names)
-            {
-                set.append(fieldInfo(wordRe(name)));
-            }
-
-            fi.found() = true;
+            fi.found(true);
+        }
+        for (const word& name : names)
+        {
+            set.emplace_back(wordRe(name));
         }
     }
 }
diff --git a/src/finiteVolume/functionObjects/fieldSelections/fileFieldSelection/fileFieldSelection.H b/src/finiteVolume/functionObjects/fieldSelections/fileFieldSelection/fileFieldSelection.H
index 50d4d09df3a..28ab52a7a25 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/fileFieldSelection/fileFieldSelection.H
+++ b/src/finiteVolume/functionObjects/fieldSelections/fileFieldSelection/fileFieldSelection.H
@@ -34,8 +34,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef functionObjects_fileFieldSelection_H
-#define functionObjects_fileFieldSelection_H
+#ifndef Foam_functionObjects_fileFieldSelection_H
+#define Foam_functionObjects_fileFieldSelection_H
 
 #include "fieldSelection.H"
 
@@ -91,11 +91,11 @@ class fileFieldSelection
         ) const;
 
 
-        //- No copy construct
-        fileFieldSelection(const fileFieldSelection&) = delete;
+public:
 
+    //- No copy construct
+    fileFieldSelection(const fileFieldSelection&) = delete;
 
-public:
 
     // Constructors
 
diff --git a/src/finiteVolume/functionObjects/fieldSelections/solverFieldSelection/solverFieldSelection.C b/src/finiteVolume/functionObjects/fieldSelections/solverFieldSelection/solverFieldSelection.C
index e3351cdb63b..0772590deb8 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/solverFieldSelection/solverFieldSelection.C
+++ b/src/finiteVolume/functionObjects/fieldSelections/solverFieldSelection/solverFieldSelection.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2017 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -69,11 +69,8 @@ bool Foam::functionObjects::solverFieldSelection::updateSelection()
         {
             if (fi.name().match(solvedField))
             {
-                newSelection.append
-                (
-                    fieldInfo(wordRe(solvedField), fi.component())
-                );
-                fi.found() = true;
+                fi.found(true);
+                newSelection.emplace_back(wordRe(solvedField), fi.component());
             }
         }
     }
diff --git a/src/finiteVolume/functionObjects/fieldSelections/solverFieldSelection/solverFieldSelection.H b/src/finiteVolume/functionObjects/fieldSelections/solverFieldSelection/solverFieldSelection.H
index ce551eb999c..dcfd9c8ffa3 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/solverFieldSelection/solverFieldSelection.H
+++ b/src/finiteVolume/functionObjects/fieldSelections/solverFieldSelection/solverFieldSelection.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2017-2019 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -34,8 +34,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef functionObjects_solverFieldSelection_H
-#define functionObjects_solverFieldSelection_H
+#ifndef Foam_functionObjects_solverFieldSelection_H
+#define Foam_functionObjects_solverFieldSelection_H
 
 #include "fieldSelection.H"
 
@@ -54,18 +54,14 @@ class solverFieldSelection
 :
     public fieldSelection
 {
-private:
-
-    // Private Member Functions
-
-        //- No copy construct
-        solverFieldSelection(const solverFieldSelection&) = delete;
+public:
 
+    //- No copy construct
+    solverFieldSelection(const solverFieldSelection&) = delete;
 
-public:
 
     //- Construct from object registry
-    solverFieldSelection
+    explicit solverFieldSelection
     (
         const objectRegistry& obr,
         const bool includeComponents = false
diff --git a/src/finiteVolume/functionObjects/fieldSelections/volFieldSelection/volFieldSelection.H b/src/finiteVolume/functionObjects/fieldSelections/volFieldSelection/volFieldSelection.H
index cd7a70d9ce7..a84f2e2d56b 100644
--- a/src/finiteVolume/functionObjects/fieldSelections/volFieldSelection/volFieldSelection.H
+++ b/src/finiteVolume/functionObjects/fieldSelections/volFieldSelection/volFieldSelection.H
@@ -34,8 +34,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef functionObjects_volFieldSelection_H
-#define functionObjects_volFieldSelection_H
+#ifndef Foam_functionObjects_volFieldSelection_H
+#define Foam_functionObjects_volFieldSelection_H
 
 #include "fieldSelection.H"
 
@@ -54,14 +54,6 @@ class volFieldSelection
 :
     public fieldSelection
 {
-private:
-
-    // Private Member Functions
-
-        //- No copy construct
-        volFieldSelection(const volFieldSelection&) = delete;
-
-
 protected:
 
     // Protected Member Functions
@@ -73,8 +65,12 @@ protected:
 
 public:
 
+    //- No copy construct
+    volFieldSelection(const volFieldSelection&) = delete;
+
+
     //- Construct from object registry
-    volFieldSelection
+    explicit volFieldSelection
     (
         const objectRegistry& obr,
         const bool includeComponents = false
diff --git a/src/functionObjects/field/limitFields/limitFields.C b/src/functionObjects/field/limitFields/limitFields.C
index c03eb37fcc8..520ef2af85d 100644
--- a/src/functionObjects/field/limitFields/limitFields.C
+++ b/src/functionObjects/field/limitFields/limitFields.C
@@ -157,11 +157,13 @@ bool Foam::functionObjects::limitFields::execute()
 {
     fieldSet_.updateSelection();
 
-    Log << type() << " " << name() << ":" << nl;
+    Log << type() << ' ' << name() << ':' << nl;
+
+    label count = 0, total = 0;
 
-    label count = 0;
     for (const word& fieldName : fieldSet_.selectionNames())
     {
+        ++total;
         if
         (
             limitScalarField(fieldName)
@@ -177,8 +179,7 @@ bool Foam::functionObjects::limitFields::execute()
 
     if (debug)
     {
-        Log << " - limited " << count << '/'
-            << fieldSet_.selectionNames().size() << " fields";
+        Log << " - limited " << count << '/' << total << " fields";
     }
 
     Log << endl;
-- 
GitLab