From 02ec3981e3d7bfaa937b72172fc4df2289b5c743 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Thu, 6 Feb 2020 11:45:49 +0100
Subject: [PATCH] ENH: improve ensightFile output support (#1579)

- indirect lists, lists of labels

- writeString() methods to avoid any ambiguities
---
 src/fileFormats/ensight/file/ensightFile.C    | 119 +++++++++++-------
 src/fileFormats/ensight/file/ensightFile.H    |  74 ++++++++---
 .../ensight/file/ensightFileTemplates.C       |  76 +++++++++++
 src/fileFormats/ensight/file/ensightGeoFile.C |   7 +-
 src/fileFormats/ensight/file/ensightGeoFile.H |   2 +
 src/fileFormats/ensight/part/ensightPart.C    |  24 ----
 6 files changed, 207 insertions(+), 95 deletions(-)
 create mode 100644 src/fileFormats/ensight/file/ensightFileTemplates.C

diff --git a/src/fileFormats/ensight/file/ensightFile.C b/src/fileFormats/ensight/file/ensightFile.C
index 4cdb931fffd..9d24699518c 100644
--- a/src/fileFormats/ensight/file/ensightFile.C
+++ b/src/fileFormats/ensight/file/ensightFile.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2015 OpenFOAM Foundation
-    Copyright (C) 2016-2019 OpenCFD Ltd.
+    Copyright (C) 2016-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -29,7 +29,6 @@ License
 #include "ensightFile.H"
 #include "error.H"
 #include "UList.H"
-
 #include <cstring>
 #include <sstream>
 
@@ -85,6 +84,20 @@ Foam::label Foam::ensightFile::subDirWidth()
 }
 
 
+bool Foam::ensightFile::isUndef(const UList<scalar>& field)
+{
+    for (const scalar& val : field)
+    {
+        if (std::isnan(val))
+        {
+            return true;
+        }
+    }
+
+    return true;
+}
+
+
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 void Foam::ensightFile::initialize()
@@ -153,24 +166,13 @@ Foam::scalar Foam::ensightFile::undefValue(const scalar value)
 }
 
 
-Foam::Ostream& Foam::ensightFile::write
-(
-    const char* buf,
-    std::streamsize count
-)
-{
-    stdStream().write(buf, count);
-    return *this;
-}
-
-
-Foam::Ostream& Foam::ensightFile::write(const char* value)
+Foam::Ostream& Foam::ensightFile::writeString(const char* str)
 {
     // Output 80 chars, but allocate for trailing nul character
     // to avoid -Wstringop-truncation warnings/errors.
 
     char buf[80+1];
-    strncpy(buf, value, 80); // max 80 chars or padded with nul if smaller
+    strncpy(buf, str, 80); // max 80 chars or padded with nul if smaller
 
     if (format() == IOstream::BINARY)
     {
@@ -186,9 +188,38 @@ Foam::Ostream& Foam::ensightFile::write(const char* value)
 }
 
 
-Foam::Ostream& Foam::ensightFile::write(const string& value)
+Foam::Ostream& Foam::ensightFile::writeString(const std::string& str)
+{
+    return writeString(str.c_str());
+}
+
+
+Foam::Ostream& Foam::ensightFile::write(const char* str)
+{
+    return writeString(str);
+}
+
+
+Foam::Ostream& Foam::ensightFile::write(const word& str)
+{
+    return writeString(str);
+}
+
+
+Foam::Ostream& Foam::ensightFile::write(const string& str)
+{
+    return writeString(str);
+}
+
+
+Foam::Ostream& Foam::ensightFile::write
+(
+    const char* buf,
+    std::streamsize count
+)
 {
-    return write(value.c_str());
+    stdStream().write(buf, count);
+    return *this;
 }
 
 
@@ -244,6 +275,14 @@ Foam::Ostream& Foam::ensightFile::write(const scalar value)
 {
     float fvalue(value);
 
+    // TBD: limit range?
+    // #if defined(WM_DP)
+    // if (mag(value) < scalar(floatScalarVSMALL))
+    // {
+    //     fvalue = 0;
+    // }
+    // #endif
+
     if (format() == IOstream::BINARY)
     {
         write
@@ -282,17 +321,17 @@ Foam::Ostream& Foam::ensightFile::writeKeyword(const keyType& key)
 {
     if (allowUndef_)
     {
-        write(string(static_cast<const string&>(key) + " undef"));
+        writeString(key + " undef");
         newline();
         write(undefValue_);
         newline();
     }
     else
     {
-        // ensure we get ensightFile::write(const string&)
-        write(static_cast<const string&>(key));
+        writeString(key);
         newline();
     }
+
     return *this;
 }
 
@@ -301,7 +340,7 @@ Foam::Ostream& Foam::ensightFile::writeBinaryHeader()
 {
     if (format() == IOstream::BINARY)
     {
-        write("C Binary");
+        writeString("C Binary");
     }
 
     return *this;
@@ -314,7 +353,7 @@ Foam::Ostream& Foam::ensightFile::writeBinaryHeader()
 
 void Foam::ensightFile::beginPart(const label index)
 {
-    write("part");
+    writeString("part");
     newline();
     write(index+1); // Ensight starts with 1
     newline();
@@ -323,59 +362,45 @@ void Foam::ensightFile::beginPart(const label index)
 
 void Foam::ensightFile::beginParticleCoordinates(const label nparticles)
 {
-    write("particle coordinates");
+    writeString("particle coordinates");
     newline();
     write(nparticles, 8); // unusual width
     newline();
 }
 
 
-void Foam::ensightFile::writeList(const UList<label>& field)
+void Foam::ensightFile::writeLabels(const UList<label>& list)
 {
-    for (const label val : field)
+    for (const label val : list)
     {
-        write(scalar(val));
+        write(val);
         newline();
     }
 }
 
 
-void Foam::ensightFile::writeList(const UList<scalar>& field)
+void Foam::ensightFile::writeList(const UList<label>& field)
 {
-    for (const scalar& val : field)
+    for (const label val : field)
     {
-        if (std::isnan(val))
-        {
-            writeUndef();
-        }
-        else
-        {
-            write(val);
-        }
-
+        write(scalar(val));
         newline();
     }
 }
 
 
-
-void Foam::ensightFile::writeList
-(
-    const UList<scalar>& field,
-    const labelUList& addr
-)
+void Foam::ensightFile::writeList(const UList<scalar>& field)
 {
-    for (const label id : addr)
+    for (const scalar val : field)
     {
-        if (id < 0 || id >= field.size() || std::isnan(field[id]))
+        if (std::isnan(val))
         {
             writeUndef();
         }
         else
         {
-            write(field[id]);
+            write(val);
         }
-
         newline();
     }
 }
diff --git a/src/fileFormats/ensight/file/ensightFile.H b/src/fileFormats/ensight/file/ensightFile.H
index 6f78b573321..6e4f9cb5c0d 100644
--- a/src/fileFormats/ensight/file/ensightFile.H
+++ b/src/fileFormats/ensight/file/ensightFile.H
@@ -37,11 +37,9 @@ Description
 #define ensightFile_H
 
 #include "OFstream.H"
-#include "IOstream.H"
-
 #include "ensightFileName.H"
 #include "ensightVarName.H"
-#include "UList.H"
+#include "IndirectListBase.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -61,7 +59,7 @@ class ensightFile
         //- Allow undef in results
         static bool allowUndef_;
 
-        //- Value to represent undef in results
+        //- Value to represent undef in results (default: 1e+37, floatVGREAT)
         static scalar undefValue_;
 
         //- The '*' mask appropriate for subDir
@@ -118,6 +116,8 @@ public:
     ~ensightFile() = default;
 
 
+    // Member Functions
+
     // Access
 
         //- Return setting for whether 'undef' values are allowed in results
@@ -150,35 +150,42 @@ public:
 
     // Output
 
-        //- Inherit write from Ostream
-        using Ostream::write;
-
-        //- Binary write
-        virtual Ostream& write(const char* buf, std::streamsize count);
-
-        //- Write element keyword with trailing newline, optionally with undef
+        //- Write element keyword with trailing newline,
+        //- optionally with undef and the value for undefined
         virtual Ostream& writeKeyword(const keyType& key);
 
-        //- Write "C Binary" for binary files (eg, geometry/measured)
+        //- Write "C Binary" string for binary files (eg, geometry/measured)
         Ostream& writeBinaryHeader();
 
+        //- Write C-string as "%79s" or as binary (max 80 chars)
+        Ostream& writeString(const char* str);
+
+        //- Write string as "%79s" or as binary (max 80 chars)
+        Ostream& writeString(const std::string& str);
+
         //- Write undef value
         Ostream& writeUndef();
 
-        //- Write C-string as "%79s" or as binary (max 80 chars)
-        Ostream& write(const char*);
+        //- Binary write
+        virtual Ostream& write(const char* buf, std::streamsize count);
 
-        //- Write string as "%79s" or as binary (max 80 chars)
-        Ostream& write(const string&);
+        //- Write C-string, uses writeString()
+        virtual Ostream& write(const char* str);
+
+        //- Write word, uses writeString()
+        virtual Ostream& write(const word& str);
+
+        //- Write string, uses writeString()
+        virtual Ostream& write(const string& str);
 
         //- Write integer as "%10d" or as binary
-        Ostream& write(const label);
+        Ostream& write(const label value);
 
         //- Write integer with specified width or as binary
-        Ostream& write(const label, const label fieldWidth);
+        Ostream& write(const label value, const label fieldWidth);
 
         //- Write float as "%12.5e" or as binary
-        Ostream& write(const scalar);
+        Ostream& write(const scalar value);
 
         //- Add carriage return to ascii stream
         void newline();
@@ -192,7 +199,17 @@ public:
         //- Begin a "particle coordinates" block (measured data)
         void beginParticleCoordinates(const label nparticles);
 
+        //- Write a list of integers
+        //  With carriage return after each value (ascii stream)
+        void writeLabels(const UList<label>& list);
+
+        //- Write a list of integers
+        //  With carriage return after each value (ascii stream)
+        template<class Addr>
+        void writeLabels(const IndirectListBase<label, Addr>& list);
+
         //- Write a list of integers as float values
+        //  With carriage return after each value (ascii stream)
         void writeList(const UList<label>& field);
 
         //- Write a list of floats as "%12.5e" or as binary
@@ -201,7 +218,18 @@ public:
 
         //- Write an indirect list of scalars as "%12.5e" or as binary
         //  With carriage return after each value (ascii stream)
-        void writeList(const UList<scalar>& field, const labelUList& addr);
+        template<class Addr>
+        void writeList(const IndirectListBase<scalar, Addr>& field);
+
+
+    // Other Methods
+
+        //- Check for any NaN in the field
+        static bool isUndef(const UList<scalar>& field);
+
+        //- Check for any NaN in the field
+        template<class Addr>
+        static bool isUndef(const IndirectListBase<scalar, Addr>& field);
 };
 
 
@@ -211,6 +239,12 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+#ifdef NoRepository
+    #include "ensightFileTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 #endif
 
 // ************************************************************************* //
diff --git a/src/fileFormats/ensight/file/ensightFileTemplates.C b/src/fileFormats/ensight/file/ensightFileTemplates.C
new file mode 100644
index 00000000000..97b00009a30
--- /dev/null
+++ b/src/fileFormats/ensight/file/ensightFileTemplates.C
@@ -0,0 +1,76 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+template<class Addr>
+bool Foam::ensightFile::isUndef(const IndirectListBase<scalar, Addr>& field)
+{
+    for (const scalar val : field)
+    {
+        if (std::isnan(val))
+        {
+            return true;
+        }
+    }
+
+    return true;
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Addr>
+void Foam::ensightFile::writeLabels(const IndirectListBase<label, Addr>& list)
+{
+    for (const scalar val : list)
+    {
+        write(val);
+        newline();
+    }
+}
+
+
+template<class Addr>
+void Foam::ensightFile::writeList(const IndirectListBase<scalar, Addr>& field)
+{
+    for (const scalar val : field)
+    {
+        if (std::isnan(val))
+        {
+            writeUndef();
+        }
+        else
+        {
+            write(val);
+        }
+        newline();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/ensight/file/ensightGeoFile.C b/src/fileFormats/ensight/file/ensightGeoFile.C
index 7b6006f3b38..50b92fbbf12 100644
--- a/src/fileFormats/ensight/file/ensightGeoFile.C
+++ b/src/fileFormats/ensight/file/ensightGeoFile.C
@@ -82,8 +82,7 @@ Foam::ensightGeoFile::ensightGeoFile
 
 Foam::Ostream& Foam::ensightGeoFile::writeKeyword(const keyType& key)
 {
-    // Ensure we get ensightFile::write(const string&)
-    write(static_cast<const string&>(key));
+    writeString(key);
     newline();
 
     return *this;
@@ -101,14 +100,14 @@ void Foam::ensightGeoFile::beginPart
 )
 {
     beginPart(index);
-    write(description);
+    writeString(description);
     newline();
 }
 
 
 void Foam::ensightGeoFile::beginCoordinates(const label npoints)
 {
-    write("coordinates");
+    writeString("coordinates");
     newline();
     write(npoints);
     newline();
diff --git a/src/fileFormats/ensight/file/ensightGeoFile.H b/src/fileFormats/ensight/file/ensightGeoFile.H
index 1415ecf69f8..77a735a9c85 100644
--- a/src/fileFormats/ensight/file/ensightGeoFile.H
+++ b/src/fileFormats/ensight/file/ensightGeoFile.H
@@ -97,6 +97,8 @@ public:
     ~ensightGeoFile() = default;
 
 
+    // Member Functions
+
     // Output
 
         //- Write keyword with trailing newline
diff --git a/src/fileFormats/ensight/part/ensightPart.C b/src/fileFormats/ensight/part/ensightPart.C
index 1a2ec97c985..2092a33f396 100644
--- a/src/fileFormats/ensight/part/ensightPart.C
+++ b/src/fileFormats/ensight/part/ensightPart.C
@@ -36,30 +36,6 @@ namespace Foam
 }
 
 
-// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
-
-// TODO - move elsewhere
-#if 0
-bool Foam::ensightPart::isFieldDefined
-(
-    const List<scalar>& field
-    // const labelUList& addr = cellIds() or faceIds()
-) const
-{
-    forAll(addr, elemI)
-    {
-        const label id = addr[i];
-
-        if (id >= field.size() || std::isnan(field[id]))
-        {
-            return false;
-        }
-    }
-    return true;
-}
-#endif
-
-
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::ensightPart::ensightPart(const string& description)
-- 
GitLab