From 88b3fb7c2d67a8bd6fa75c5d051f7ed4bfdb00df Mon Sep 17 00:00:00 2001
From: Kutalmis Bercin <kutalmis.bercin@esi-group.com>
Date: Thu, 7 Dec 2023 17:22:57 +0000
Subject: [PATCH] ENH: foamMonitor: modernise and refactor the script (fixes
 #2104)

- enhance POSIX compliance
- apply distinct colours and dash type for each line
- standardize the frame size to 1200x627
- dynamically replace the title with <function-object-name>/<file-name>
- address underscore character issues
- introduce legend components for tensors
- resolve a bug caused by parentheses in tensor files

BUG: particleTrackProperties: correct the typo (fixes #3050)
---
 .../particleTracks/particleTrackProperties    |   2 +-
 bin/foamMonitor                               | 119 +++++++++++++++---
 2 files changed, 101 insertions(+), 20 deletions(-)

diff --git a/applications/utilities/postProcessing/lagrangian/particleTracks/particleTrackProperties b/applications/utilities/postProcessing/lagrangian/particleTracks/particleTrackProperties
index e258f475971..2f040844023 100644
--- a/applications/utilities/postProcessing/lagrangian/particleTracks/particleTrackProperties
+++ b/applications/utilities/postProcessing/lagrangian/particleTracks/particleTrackProperties
@@ -14,7 +14,7 @@ FoamFile
 }
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-cloudName       reactingCloud1;
+cloud           reactingCloud1;
 
 sampleFrequency 1;
 
diff --git a/bin/foamMonitor b/bin/foamMonitor
index 3998fa3a4ce..28923708f18 100755
--- a/bin/foamMonitor
+++ b/bin/foamMonitor
@@ -7,7 +7,7 @@
 #    \\/     M anipulation  |
 #-------------------------------------------------------------------------------
 #    Copyright (C) 2015 OpenFOAM Foundation
-#    Copyright (C) 2019-2021 OpenCFD Ltd.
+#    Copyright (C) 2019-2023 OpenCFD Ltd.
 #------------------------------------------------------------------------------
 # License
 #     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@@ -18,7 +18,7 @@
 # Description
 #     Monitor data with Gnuplot from time-value(s) graphs written by OpenFOAM
 #     e.g. by functionObjects
-#     - requires gnuplot, gnuplot_x11
+#     - requires gnuplot, gnuplot_x11, sed, awk
 #
 #------------------------------------------------------------------------------
 printHelp() {
@@ -58,16 +58,35 @@ die()
 }
 
 
+# Count the number of scalars between ( and ) to deduce the field dimensions
+count_components() {
+    _text="$1"
+
+    # Extract text between the first ( and )
+    _matches="$(echo "$_text" | sed -n 's/^[^(]*(\([^)]*\)).*$/\1/p')"
+
+    # Use grep to find numbers (doubles and 0) between ( and ), then count them
+    _count="$(echo "$_matches" | grep -Eo '\b[0-9]+\.?[0-9]*[eE]?[-+]?[0-9]+\b|\b0\b' | wc -l)"
+
+    echo "$_count"
+}
+
+
 # Set Gnuplot header
 plotFileHeader() {
+    TITLE="$1"
+    NCOLOURS="$2"
+    SIZE="1200,627"
     cat<<EOF
-set term x11 1 font "helvetica,17" linewidth 1.5 persist noraise
+set term x11 1 font "helvetica,17" linewidth 1.5 persist noraise size $SIZE
 $LOGSCALE
 $XRANGE
 $YRANGE
 $GRID
-set title "Data Monitoring"
+set title "$TITLE"
 set xlabel "$XLABEL"
+set key outside
+set linetype cycle "$NCOLOURS"
 plot \\
 EOF
 }
@@ -97,6 +116,8 @@ YRANGE=""
 GRID=""
 GNUPLOT=$(which gnuplot)
 [ ! "$GNUPLOT" = "" ] || die "foamMonitor requires Gnuplot installed"
+command -v sed >/dev/null || die "foamMonitor requires sed installed"
+command -v awk >/dev/null || die "foamMonitor requires awk installed"
 
 #-------------------------------------------------------------------------------
 
@@ -154,63 +175,123 @@ do
     esac
 done
 
+
 [ "$#" -eq 1 ] || die "Incorrect arguments specified"
 [ -f "$1" ]    || die "File $1 does not exit"
 FILE="$1"
 
+
 # Get KEYS from header
 KEYS=$(grep -E '^#' "$FILE" | tail -1)
 
 [ "$KEYS" = "" ] && KEYS="# Step"
 NKEYS=$(howMany "$KEYS")
 NCOLS=$(grep -m 1 '^[^#]' "$FILE" | awk '{ print NF }')
+NCOMPS=$(count_components "$(grep -m 1 '^[^#]' "$FILE")")
 
 # With full column labels, NKEYS = NCOLS + 1, since it includes "#"
 
 # If NKEYS > NCOLS + 1, REMOVE EXCESS KEYS
 NCOLSPONE=$((NCOLS+1))
-[ "$NKEYS" -gt "$NCOLSPONE" ] && KEYS=$(echo $KEYS | cut -d" " -f1-$NCOLSPONE)
+[ "$NKEYS" -gt "$NCOLSPONE" ] && KEYS=$(echo "$KEYS" | cut -d" " -f1-$NCOLSPONE)
+
+# Remove # and Time keys
+XLABEL=$(echo "$KEYS" | cut -d " " -f2)
+KEYS=$(echo "$KEYS" | cut -d " " -f3-)
 NKEYS=$(howMany "$KEYS")
 
-i=0
-while [ "$NKEYS" -le "$NCOLS" ]
+
+# Create the legend items
+TEMPKEYS=""
+
+for i in $KEYS
 do
-    i=$((i+1))
-    KEYS="$KEYS data$i"
-    NKEYS=$(howMany "$KEYS")
+    case "$NCOMPS" in
+        0)  # scalar
+            TEMPKEYS="$TEMPKEYS $i"
+            ;;
+        3)  # vector
+            for j in x y z
+            do
+                TEMPKEYS="$TEMPKEYS ${i}_${j}"
+            done
+            ;;
+        6)  # symmetric tensor
+            for j in xx xy xz yy yz zz
+            do
+                TEMPKEYS="$TEMPKEYS ${i}_${j}"
+            done
+            ;;
+        9)  # tensor
+            for j in xx xy xz yx yy yz zx zy zz
+            do
+                TEMPKEYS="$TEMPKEYS ${i}_${j}"
+            done
+            ;;
+        *)  # handle other cases if needed
+            echo "Unsupported number of components: $NCOMPS"
+            exit 1
+            ;;
+    esac
 done
 
-# Remove # and Time keys
-XLABEL=$(echo $KEYS | cut -d " " -f2)
-KEYS=$(echo $KEYS | cut -d " " -f3-)
+KEYS=$TEMPKEYS
 
+
+# Create plots
 GPFILE=$(mktemp)
-plotFileHeader > "$GPFILE"
+PLOT_TITLE="$(echo "$FILE" | awk -F'/' '{print $(NF-2) "/" $NF}')"
+NUM_ELEMENTS="$((NKEYS * NCOMPS))"
+
+plotFileHeader "$PLOT_TITLE" "$NUM_ELEMENTS" > "$GPFILE"
+
 i=1
+j=1
 for field in $KEYS
 do
     i=$((i+1))
-    PLOTLINE="\"$FILE\" using 1:${i} with lines title \"$field\""
-    if [ $i -lt $NCOLS ]
+
+    # Reject any keys consisting of 'iter|converged|solver' words
+    case "$field" in
+        *"iter"*|*"converged"*|*"solver"*)
+            continue
+            ;;
+    esac
+
+    # Reject any parentheses, and configure gnuplot for the underscore character
+    PLOTLINE="\"< sed 's/[()]//g' $FILE\" u 1:${i} w l dt ${j} t \"$(echo "$field" | sed 's/_/\\\\_/g')\""
+    if [ "$i" -lt "$NCOLS" ]
     then
        PLOTLINE="$PLOTLINE, \\"
     fi
-    echo $PLOTLINE >> "$GPFILE"
+    echo "$PLOTLINE" >> "$GPFILE"
+
+    # Change the dash type after every 5 non-rejected lines
+    [ $(((i-1) % 5)) -eq 0 ] && j=$((j+1))
 done
+
+# Scrap ', \' characters from the tail of plot command, if necessary
+if tail -n 1 "$GPFILE" | grep -q ', \\$'; then
+    { head -n -1 "$GPFILE"; tail -n 1 "$GPFILE" | sed 's/, \\$//'; } > tmp.gp
+    mv -f -- tmp.gp "$GPFILE"
+fi
+
 plotFileFooter >> "$GPFILE"
 
+
 touch "$FILE"
 $GNUPLOT "$GPFILE" &
 PID=$!
 
 while true
 do
-    MODTIME=$(stat --format=%Y $FILE)
+    MODTIME="$(stat --format=%Y "$FILE")"
     IDLEAGO=$(($(date +%s)-IDLE))
     test "$MODTIME" -gt "$IDLEAGO" || break
-    sleep $REFRESH
+    sleep "$REFRESH"
 done
 
+
 kill -9 $PID
 rm -f "$GPFILE"
 
-- 
GitLab