#!/bin/sh
#------------------------------------------------------------------------------
# =========                 |
# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
#  \\    /   O peration     | Website:  https://openfoam.org
#   \\  /    A nd           | Copyright (C) 2015-2026 OpenFOAM Foundation
#    \\/     M anipulation  |
#------------------------------------------------------------------------------
# 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/>.
#
# Script
#     foamSequenceVTKFiles
#
# Description
#     Creates symbolic links to all VTK files in a post-processing directory
#     Links form a sequence like 'patch.0000.vtk', 'patch.0001.vtk', etc.
#
#     If files of the same name exist in different sub-directories of the main
#     directory, e.g. 'inletPatch/0/patch.vtk' and 'outletPatch/0/patch.vtk',
#     a further index is appended to the name in the links, e.g.
#     'patch0.0000.vtk' and 'patch1.0000.vtk'
#
#     Paraview recognises the link names as a sequence which can be opened and
#     played. The sequence of links to images can be used to create a video
#     from the images.
#     - Default directory name for VTK files is 'postProcessing'
#------------------------------------------------------------------------------
error() {
    exec 1>&2
    while [ "$#" -ge 1 ]; do echo "$1"; shift; done
    echo
    usage
    exit 1
}

cat <<EOF

foamSequenceVTKFiles been superseded and replaced by foamVTKSeries.

foamVTKSeries is preferable because it generates fewer files, and it allows
ParaView to correctly maintain the time values corresponding to each file in
the series.

foamVTKSeries has identical usage to foamSequenceVTKFiles, except that the
output directory option ('-out' or '-o') is not available. foamVTKSeries writes
its output into the same directory tree containing the VTK files, rather than
into a separate directory.

EOF

usage() {
    cat <<USAGE
Usage: ${0##*/} [OPTIONS] ...
options:
  -case | -c <dir>    specify case directory (default = local dir)
  -dir  | -d <dir>    post-processing directory <dir> (default = postProcessing)
  -help | -h          print the usage
  -out  | -o <dir>    output links directory <dir> (default = sequencedVTK)

Creates symbolic links to all VTK files in a post-processing directory
Links form a sequence like 'patch.0000.vtk', 'patch.0001.vtk', etc.

If files of the same name exist in different sub-directories of the main
directory, e.g. 'inletPatch/0/patch.vtk' and 'outletPatch/0/patch.vtk', a
further index is appended to the name in the links, e.g. 'patch0.0000.vtk' and
'patch1.0000.vtk'

Paraview recognises the link names as a sequence which can be opened and played.
The sequence of links to images can be used to create a video from the images.
- Default directory name for VTK files is 'postProcessing'
USAGE
}

# If image files of the same name exist in multiple sub-directories,
# list the sub-directory names
multipleSeries () {
    _file_list="$1"
    _depth="$(echo "$file_list" | awk -F'/' '{print NF}' | sort -un | head -1)"

    # List no sub-directories if there are insufficient directory levels
    [ "$_depth" -lt 3 ] && return 1

    # Unique sub-directories
    _dirs="$(echo "$_file_list" | \
        awk -F'/' '{for(i=1; i<NF-1; i++) printf "%s/", $i; printf "\n"}' | \
        sort -u | xargs -n 1)"

    # Only return sub-directories if there is more than one
    [ "$(echo "$_dirs" | wc -l)" -gt 1 ] || return 1

    echo "$_dirs"
}

dir=postProcessing
out=sequencedVTK

while [ "$#" -gt 0 ]
do
   case "$1" in
   -c | -case)
      [ "$#" -ge 2 ] || error "'$1' option requires an argument"
      cd "$2" 2>/dev/null || error "directory does not exist:  '$2'"
      shift 2
      ;;
   -d | -dir)
      [ "$#" -ge 2 ] || error "'$1' option requires an argument"
      dir=$2
      shift 2
      ;;
   -h | -help)
      usage && exit 0
      ;;
   -o | -out)
      [ "$#" -ge 2 ] || error "'$1' option requires an argument"
      out=$2
      shift 2
      ;;
   -*)
      error "invalid option '$1'"
      ;;
   *)
      break
      ;;
    esac
done

[ ! -d "$dir" ] && error "Cannot find postProcessing directory, exiting."

files=$(find "$dir" -type f -name "*vtk" -print0 | xargs -0 -n 1)
names=$(for f in $files; do basename "$f" .vtk; done | sort -u)

if [ -d "$out" ]; then
    echo "$out directory already exists.  Deleting links within it..."
    rm "${out:?}"/* 2>/dev/null
else
    echo "Creating $out directory..."
    mkdir "$out"
fi

for n in $names
do
    echo "Sequencing all VTK files named $n.vtk"

    # Create list of VTK files, ordered by time step
    file_list=$(echo "$files" | \
        grep "/$n\.vtk" | \
        awk -F'/' '{print($(NF-1)" "$0)}' | \
        LC_ALL=C  sort -k 1 -g | \
        cut -d' ' -f2)

    # sub-dirs of files with same name
    dirs="$(multipleSeries "$file_list")" || dirs=SINGLE

    # Series index, required if files with same name exist in multiple sub-dirs
    s=0

    for d in $dirs
    do
        # Image index
        i=0

        [ "$d" = SINGLE ] && unset s

        for f in $file_list
        do
            ! [ "$d" = SINGLE ] && \
                ! echo "$f" | grep -q "$d" && \
                continue

            link=$(printf "${n}${s}.%04d.vtk" $i)
            ln -s "../$f" "$out/$link"

            i=$(( i + 1 )) # Relies on ordered list of files
        done

        s=$(( s + 1 ))
    done
done
