From 6dadd3d33e803221123827bb7beb14818e4a3e97 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Thu, 1 Feb 2024 15:43:42 +0100
Subject: [PATCH] ENH: include cloudFunction results in vtkCloud writing
 (#3094)

- process the contents of the cloud object registry, which enables
  output support for calculated values such as Reynolds, Weber numbers
  etc.

ENH: select any/all clouds by default instead of defaultCloud

- adds robustness
---
 .../lagrangian/dataCloud/dataCloud.C          | 37 +++++++---
 .../lagrangian/dataCloud/dataCloud.H          | 12 ++--
 .../lagrangian/dataCloud/dataCloudTemplates.C |  8 +--
 .../lagrangian/vtkCloud/vtkCloud.C            | 68 +++++++++++++------
 .../lagrangian/vtkCloud/vtkCloud.H            |  8 +--
 .../lagrangian/vtkCloud/vtkCloudTemplates.C   | 20 ++++--
 6 files changed, 102 insertions(+), 51 deletions(-)

diff --git a/src/functionObjects/lagrangian/dataCloud/dataCloud.C b/src/functionObjects/lagrangian/dataCloud/dataCloud.C
index e34be5bc705..8ff65489f56 100644
--- a/src/functionObjects/lagrangian/dataCloud/dataCloud.C
+++ b/src/functionObjects/lagrangian/dataCloud/dataCloud.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -52,12 +52,16 @@ bool Foam::functionObjects::dataCloud::writeCloud
     const word& cloudName
 )
 {
-    const auto* objPtr = mesh_.findObject<cloud>(cloudName);
-    if (!objPtr)
+    applyFilter_ = false;
+
+    const auto* cloudPtr = mesh_.findObject<cloud>(cloudName);
+    if (!cloudPtr)
     {
         return false;
     }
 
+    const auto& currCloud = *cloudPtr;
+
     objectRegistry obrTmp
     (
         IOobject
@@ -71,7 +75,7 @@ bool Foam::functionObjects::dataCloud::writeCloud
         )
     );
 
-    objPtr->writeObjects(obrTmp);
+    currCloud.writeObjects(obrTmp);
 
     const auto* pointsPtr = cloud::findIOPosition(obrTmp);
 
@@ -86,7 +90,10 @@ bool Foam::functionObjects::dataCloud::writeCloud
 
 
     // Number of parcels (locally)
-    label nParcels = (applyFilter_ ? parcelAddr_.count() : pointsPtr->size());
+    const label nParcels
+    (
+        applyFilter_ ? parcelAddr_.count() : pointsPtr->size()
+    );
 
     // Total number of parcels on all processes
     const label nTotParcels = returnReduce(nParcels, sumOp<label>());
@@ -104,9 +111,9 @@ bool Foam::functionObjects::dataCloud::writeCloud
         return false;
     }
 
-    if (Pstream::master())
+    if (UPstream::master())
     {
-        mkDir(outputName.path());
+        Foam::mkDir(outputName.path());
     }
 
     return
@@ -163,12 +170,15 @@ bool Foam::functionObjects::dataCloud::read(const dictionary& dict)
 
     selectClouds_.clear();
     dict.readIfPresent("clouds", selectClouds_);
+    selectClouds_.uniq();
 
     if (selectClouds_.empty())
     {
-        selectClouds_.resize(1);
-        selectClouds_.first() =
-            dict.getOrDefault<word>("cloud", cloud::defaultName);
+        word cloudName;
+        if (dict.readIfPresent("cloud", cloudName))
+        {
+            selectClouds_.push_back(std::move(cloudName));
+        }
     }
 
     dict.readEntry("field", fieldName_);
@@ -209,7 +219,12 @@ bool Foam::functionObjects::dataCloud::execute()
 
 bool Foam::functionObjects::dataCloud::write()
 {
-    const wordList cloudNames(mesh_.sortedNames<cloud>(selectClouds_));
+    const wordList cloudNames
+    (
+        selectClouds_.empty()
+      ? mesh_.sortedNames<cloud>()
+      : mesh_.sortedNames<cloud>(selectClouds_)
+    );
 
     if (cloudNames.empty())
     {
diff --git a/src/functionObjects/lagrangian/dataCloud/dataCloud.H b/src/functionObjects/lagrangian/dataCloud/dataCloud.H
index 4943ccf1c70..33b2791b6bb 100644
--- a/src/functionObjects/lagrangian/dataCloud/dataCloud.H
+++ b/src/functionObjects/lagrangian/dataCloud/dataCloud.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2018-2020 OpenCFD Ltd.
+    Copyright (C) 2018-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -48,10 +48,10 @@ Description
     \heading Basic Usage
     \table
         Property     | Description                      | Required | Default
-        type         | Type name: dataCloud             | yes   |
+        type         | Type name: dataCloud             | yes |
         clouds       | List of clouds (name or regex)   | no  |
-        cloud        | Cloud name                       | no  | defaultCloud
-        field        | Name of the field                | yes   |
+        cloud        | Cloud name                       | no  |
+        field        | Name of the field                | yes |
         selection    | Parcel selection control         | no  | empty-dict
     \endtable
 
@@ -103,7 +103,7 @@ class dataCloud
     public fvMeshFunctionObject,
     public Foam::Detail::parcelSelection
 {
-    // Private data
+    // Private Data
 
         //- The printf format for zero-padding names
         string printf_;
@@ -177,7 +177,7 @@ class dataCloud
         bool writeField
         (
             const fileName& outputName,
-            const objectRegistry& obrTmp
+            const objectRegistry& obr
         ) const;
 
 
diff --git a/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C b/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C
index d2b6e16b130..67319c08efe 100644
--- a/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C
+++ b/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C
@@ -171,10 +171,10 @@ template<class Type>
 bool Foam::functionObjects::dataCloud::writeField
 (
     const fileName& outputName,
-    const objectRegistry& obrTmp
+    const objectRegistry& obr
 ) const
 {
-    const auto* pointsPtr = cloud::findIOPosition(obrTmp);
+    const auto* pointsPtr = cloud::findIOPosition(obr);
 
     if (!pointsPtr)
     {
@@ -185,8 +185,8 @@ bool Foam::functionObjects::dataCloud::writeField
     // Fields are not always on all processors (eg, multi-component parcels).
     // Thus need to resolve between all processors.
 
-    const List<Type>* fldPtr = obrTmp.findObject<IOField<Type>>(fieldName_);
-    const List<Type>& values = (fldPtr ? *fldPtr : List<Type>());
+    const List<Type>* fldPtr = obr.findObject<IOField<Type>>(fieldName_);
+    const List<Type>& values = (fldPtr ? *fldPtr : List<Type>::null());
 
     if (!returnReduceOr(fldPtr != nullptr))
     {
diff --git a/src/functionObjects/lagrangian/vtkCloud/vtkCloud.C b/src/functionObjects/lagrangian/vtkCloud/vtkCloud.C
index 08557fd4014..223fa2feab4 100644
--- a/src/functionObjects/lagrangian/vtkCloud/vtkCloud.C
+++ b/src/functionObjects/lagrangian/vtkCloud/vtkCloud.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -101,12 +101,16 @@ bool Foam::functionObjects::vtkCloud::writeCloud
     const word& cloudName
 )
 {
-    const auto* objPtr = mesh_.findObject<cloud>(cloudName);
-    if (!objPtr)
+    applyFilter_ = false;
+
+    const auto* cloudPtr = mesh_.cfindObject<cloud>(cloudName);
+    if (!cloudPtr)
     {
         return false;
     }
 
+    const auto& currCloud = *cloudPtr;
+
     objectRegistry obrTmp
     (
         IOobject
@@ -120,7 +124,7 @@ bool Foam::functionObjects::vtkCloud::writeCloud
         )
     );
 
-    objPtr->writeObjects(obrTmp);
+    currCloud.writeObjects(obrTmp);
 
     const auto* pointsPtr = cloud::findIOPosition(obrTmp);
 
@@ -135,7 +139,10 @@ bool Foam::functionObjects::vtkCloud::writeCloud
 
 
     // Number of parcels (locally)
-    label nParcels = (applyFilter_ ? parcelAddr_.count() : pointsPtr->size());
+    const label nParcels
+    (
+        applyFilter_ ? parcelAddr_.count() : pointsPtr->size()
+    );
 
     // Total number of parcels on all processes
     const label nTotParcels = returnReduce(nParcels, sumOp<label>());
@@ -163,9 +170,9 @@ bool Foam::functionObjects::vtkCloud::writeCloud
             << exit(FatalError);
     }
 
-    if (Pstream::master())
+    if (UPstream::master())
     {
-        mkDir(file.path());
+        Foam::mkDir(file.path());
         os.open(file);
 
         format = writeOpts_.newFormatter(os);
@@ -238,7 +245,7 @@ bool Foam::functionObjects::vtkCloud::writeCloud
     }
 
 
-    if (Pstream::master())
+    if (UPstream::master())
     {
         format().flush();
         format().endDataArray();
@@ -270,7 +277,7 @@ bool Foam::functionObjects::vtkCloud::writeCloud
 
     // Write fields
 
-    if (Pstream::master())
+    if (UPstream::master())
     {
         if (useVerts_)
         {
@@ -282,13 +289,28 @@ bool Foam::functionObjects::vtkCloud::writeCloud
         }
     }
 
-    DynamicList<word> written(obrTmp.size());
+    DynamicList<word> written(obrTmp.size() + currCloud.objectRegistry::size());
 
-    written.append(writeFields<label>(format, obrTmp, nTotParcels));
-    written.append(writeFields<scalar>(format, obrTmp, nTotParcels));
-    written.append(writeFields<vector>(format, obrTmp, nTotParcels));
+    written.push_back
+    (
+        writeFields<label>(format, obrTmp, nTotParcels)
+    );
+    written.push_back
+    (
+        writeFields<scalar>(format, obrTmp, nTotParcels)
+    );
+    written.push_back
+    (
+        writeFields<vector>(format, obrTmp, nTotParcels)
+    );
+
+    // Any cloudFunctions results
+    written.push_back
+    (
+        writeFields<scalar>(format, currCloud, nTotParcels)
+    );
 
-    if (Pstream::master())
+    if (UPstream::master())
     {
         if (useVerts_)
         {
@@ -415,12 +437,15 @@ bool Foam::functionObjects::vtkCloud::read(const dictionary& dict)
 
     selectClouds_.clear();
     dict.readIfPresent("clouds", selectClouds_);
+    selectClouds_.uniq();
 
     if (selectClouds_.empty())
     {
-        selectClouds_.resize(1);
-        selectClouds_.first() =
-            dict.getOrDefault<word>("cloud", cloud::defaultName);
+        word cloudName;
+        if (dict.readIfPresent("cloud", cloudName))
+        {
+            selectClouds_.push_back(std::move(cloudName));
+        }
     }
 
     selectFields_.clear();
@@ -463,7 +488,12 @@ bool Foam::functionObjects::vtkCloud::execute()
 
 bool Foam::functionObjects::vtkCloud::write()
 {
-    const wordList cloudNames(mesh_.sortedNames<cloud>(selectClouds_));
+    const wordList cloudNames
+    (
+        selectClouds_.empty()
+      ? mesh_.sortedNames<cloud>()
+      : mesh_.sortedNames<cloud>(selectClouds_)
+    );
 
     if (cloudNames.empty())
     {
@@ -498,7 +528,7 @@ bool Foam::functionObjects::vtkCloud::write()
             Log << "    cloud  : "
                 << time_.relativePath(outputName) << endl;
 
-            if (Pstream::master())
+            if (UPstream::master())
             {
                 // Add to file-series and emit as JSON
                 fileName seriesName(vtk::seriesWriter::base(outputName));
diff --git a/src/functionObjects/lagrangian/vtkCloud/vtkCloud.H b/src/functionObjects/lagrangian/vtkCloud/vtkCloud.H
index 9511de0db04..648414eb2c3 100644
--- a/src/functionObjects/lagrangian/vtkCloud/vtkCloud.H
+++ b/src/functionObjects/lagrangian/vtkCloud/vtkCloud.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2018-2020 OpenCFD Ltd.
+    Copyright (C) 2018-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -81,7 +81,7 @@ Description
         Property     | Description                      | Required | Default
         type         | Type name: vtkCloud              | yes |
         clouds       | List of clouds (name or regex)   | no  |
-        cloud        | Cloud name                       | no  | defaultCloud
+        cloud        | Cloud name                       | no  |
         fields       | List of fields (name or regex)   | no  |
         selection    | Parcel selection control         | no  | empty-dict
     \endtable
@@ -160,7 +160,7 @@ class vtkCloud
     public fvMeshFunctionObject,
     public Foam::Detail::parcelSelection
 {
-    // Private data
+    // Private Data
 
         //- Writer options
         vtk::outputOptions writeOpts_;
@@ -209,7 +209,7 @@ class vtkCloud
         wordList writeFields
         (
             autoPtr<vtk::formatter>& format,
-            const objectRegistry& obrTmp,
+            const objectRegistry& obr,
             const label nTotParcels
         ) const;
 
diff --git a/src/functionObjects/lagrangian/vtkCloud/vtkCloudTemplates.C b/src/functionObjects/lagrangian/vtkCloud/vtkCloudTemplates.C
index c28bc1fe4c7..f61c1de41e6 100644
--- a/src/functionObjects/lagrangian/vtkCloud/vtkCloudTemplates.C
+++ b/src/functionObjects/lagrangian/vtkCloud/vtkCloudTemplates.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -33,7 +33,7 @@ template<class Type>
 Foam::wordList Foam::functionObjects::vtkCloud::writeFields
 (
     autoPtr<vtk::formatter>& format,
-    const objectRegistry& obrTmp,
+    const objectRegistry& obr,
     const label nTotParcels
 ) const
 {
@@ -55,16 +55,22 @@ Foam::wordList Foam::functionObjects::vtkCloud::writeFields
     // Fields are not always on all processors (eg, multi-component parcels).
     // Thus need to resolve names between all processors.
 
-    wordList fieldNames(obrTmp.names<IOField<Type>>());
+    wordList fieldNames =
+    (
+        selectFields_.size()
+      ? obr.names<IOField<Type>>(selectFields_)
+      : obr.names<IOField<Type>>()
+    );
+
     Pstream::combineReduce(fieldNames, ListOps::uniqueEqOp<word>());
     Foam::sort(fieldNames);  // Consistent order
 
     for (const word& fieldName : fieldNames)
     {
-        const List<Type>* fldPtr = obrTmp.findObject<IOField<Type>>(fieldName);
-        const List<Type>& values = (fldPtr ? *fldPtr : List<Type>());
+        const List<Type>* fldPtr = obr.findObject<IOField<Type>>(fieldName);
+        const List<Type>& values = (fldPtr ? *fldPtr : List<Type>::null());
 
-        if (Pstream::master())
+        if (UPstream::master())
         {
             if (std::is_same<label, typename pTraits<Type>::cmptType>::value)
             {
@@ -93,7 +99,7 @@ Foam::wordList Foam::functionObjects::vtkCloud::writeFields
             vtk::writeListParallel(format.ref(), values);
         }
 
-        if (Pstream::master())
+        if (UPstream::master())
         {
             // Non-legacy
             format().flush();
-- 
GitLab