Skip to content
Snippets Groups Projects
RunFunctions 12.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • #---------------------------------*- sh -*-------------------------------------
    
    # =========                 |
    # \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    #  \\    /   O peration     |
    
    OpenFOAM bot's avatar
    OpenFOAM bot committed
    #   \\  /    A nd           | www.openfoam.com
    
    #    \\/     M anipulation  |
    #------------------------------------------------------------------------------
    
    OpenFOAM bot's avatar
    OpenFOAM bot committed
    #     Copyright (C) 2011-2016 OpenFOAM Foundation
    
    #     Copyright (C) 2015-2024 OpenCFD Ltd.
    
    #------------------------------------------------------------------------------
    # License
    
    #     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
    
    #
    # Script
    #     RunFunctions
    #
    # Description
    
    #     Miscellaneous functions for running tutorial cases
    
    #------------------------------------------------------------------------------
    
    
    # The normal locations
    
    [ -n "$FOAM_TUTORIALS" ] || export FOAM_TUTORIALS="$WM_PROJECT_DIR"/tutorials
    
    # Basic sanity checks
    [ -d "$FOAM_TUTORIALS" ] || echo "No OpenFOAM tutorials? : $FOAM_TUTORIALS" 1>&2
    
    # Darwin workaround - SIP clearing DYLD_LIBRARY_PATH variable
    if [ -n "$FOAM_LD_LIBRARY_PATH" ] && [ -z "$DYLD_LIBRARY_PATH" ]
    then
        export DYLD_LIBRARY_PATH="$FOAM_LD_LIBRARY_PATH"
    fi
    
    
    
    #------------------------------------------------------------------------------
    
    
    # Check presence of '-parallel' in the argument list.
    
    #
    isParallel()
    {
        for i; do [ "$i" = "-parallel" ] && return 0; done
        return 1
    }
    
    
    # Check presence of '-test' in the argument list.
    
        for i; do [ "$i" = "-test" ] && return 0; done
    
    #
    # Check absence of '-test' in the argument list.
    #
    notTest()
    {
        for i; do [ "$i" = "-test" ] && return 1; done
        return 0
    }
    
    
    # Test for make/wmake, compiler suite or emit warning
    
        # system
        if ! command -v make >/dev/null
        then
            echo "No system 'make' command found ... cannot compile" 1>&2
            return 1
        fi
    
        # OpenFOAM-specific
    
        if ! command -v wmake >/dev/null
        then
    
            echo "No openfoam 'wmake' command found ... cannot compile" 1>&2
    
            return 1
        fi
    
        local cxx_compiler
        cxx_compiler="$(wmake -show-cxx 2>/dev/null)"
    
        if [ -z "$cxx_compiler" ]
        then
    
            echo "No wmake rule for C++ compiler ... cannot compile" 1>&2
    
            return 1
        elif ! command -v "$cxx_compiler"  >/dev/null
        then
            echo "No path to C++ compiler ($cxx_compiler) ... cannot compile" 1>&2
            return 1
        fi
    
        return 0
    }
    
    
    #
    # Check if '$1' corresponds to an OpenFOAM value for 'true' (see Switch.H)
    # - does not handle integers very much, although Switch does
    #
    # Handles -dict as first argument to relay the balance to foamDictionary
    # Eg,
    #     isTrue -dict controls -entry coupling
    # ->
    #     value=$(foamDictionary controls -entry coupling -value)
    #     if value ...
    #
    isTrue()
    {
        local value="$1"
    
        if [ "$value" = "-dict" ]
        then
            shift
            value="$(foamDictionary -value $@ 2>/dev/null)" || return 2
        fi
    
        case "$value" in
            (t | y | true | yes | on)  return 0 ;;
            (f | n | false | no | off) return 1 ;;
        esac
        return 2
    }
    
    
    #
    # Extract 'nFaces' for given patchName from constant/polyMesh/boundary
    # or constant/{region}/polyMesh/boundary
    #
    # On failure:
    #    return '1'
    #    exit status 1
    #
    getNumberOfPatchFaces()
    {
        local patch="${1:-}"
        local file="${2:-}"
    
        file="constant/$file${file:+/}polyMesh/boundary"
    
        [ -n "$patch" ] || {
            echo "No patch name given" 1>&2
            return 1
        }
    
        [ -f "$file" ] || {
            echo "No such file: $file" 1>&2
            return 2
        }
    
        local nFaces
        nFaces=$(sed -ne \
            '/^ *'"$patch"' *$/,/}/{s/^ *nFaces  *\([0-9][0-9]*\) *;.*$/\1/p}' \
            "$file")
    
    
        then
            echo "$nFaces"
        else
            echo "No patch entry found for '$patch' in $file" 1>&2
            echo 0      # Report as 0
            return 2
        fi
    }
    
    
    
    #
    # Extract 'numberOfSubdomains' from system/decomposeParDict
    # (or alternative location).
    #
    # On failure:
    #    return '1'
    #    exit status 1
    #
    
        local dict="${1:-system/decomposeParDict}"
    
    
        case "$dict" in
        (system/*)  # Already qualified
            ;;
        (*)
            # If it does not exist, assume it refers to location in system/
            [ -f "$dict" ] || dict="system/$dict"
            ;;
        esac
    
    
    
        # Re-use positional parameters for automatic whitespace elimination
    
        set -- $(foamDictionary -entry numberOfSubdomains -value "$dict" 2>/dev/null)
    
            echo "Error getting 'numberOfSubdomains' from '$dict'" 1>&2
    
            echo 1      # Fallback is 1 proc (serial)
    
    
    #
    # Extract 'application' from system/controlDict
    #
    # On failure:
    #    return 'false' which is also a command (ie, shell builtin or /bin/false)
    #    exit status 1
    #
    
        # Re-use positional parameters for automatic whitespace elimination
    
        set -- $(foamDictionary -entry application -value system/controlDict 2>/dev/null)
    
            echo "Error getting 'application' from system/controlDict" 1>&2
    
    
    #
    # Run given application in serial with logfile output.
    # The preexistence of the log file prevents rerunning.
    #
    
        local appName appRun optValue logFile logMode
    
    
        # Any additional parsed arguments (eg, decomposeParDict)
        local appArgs
    
        # Parse options until executable is encountered
    
        while [ "$#" -gt 0 ] && [ -z "$appRun" ]
    
            ('') ;;  # Ignore junk
    
            (-a | -append)
                logMode=append
                ;;
            (-o | -overwrite)
                logMode=overwrite
                ;;
            (-s | -suffix)
                logFile=".$2"
                shift
                ;;
    
            (-decompose-dict=*)
                optValue="${1#*=}"
                case "$optValue" in
                ('' | none | false) ;;  ## Ignore
                (*) appArgs="$appArgs -decomposeParDict $optValue" ;;
                esac
                ;;
    
            (-decomposeParDict)
                optValue="$2"
                shift
                case "$optValue" in
                ('' | none | false) ;; ## Ignore
                (*) appArgs="$appArgs -decomposeParDict $optValue" ;;
                esac
                ;;
    
            (*)
                appRun="$1"
                ;;
    
        appName="${appRun##*/}"
    
        if [ -f "$logFile" ] && [ -z "$logMode" ]
    
            echo "$appName already run on $PWD:" \
                 "remove log file '$logFile' to re-run"
    
        else
    
            echo "Running $appRun on $PWD"
            if [ "$logMode" = append ]
            then
                $appRun $appArgs "$@" >> $logFile 2>&1
    
                $appRun $appArgs "$@" > $logFile 2>&1
    
    
    #
    # Run given application in parallel with logfile output.
    # The preexistence of the log file prevents rerunning.
    #
    
        local appName appRun optValue logFile logMode
        local mpiopts nProcs
    
    
        # Any additional parsed arguments (eg, decomposeParDict)
        local appArgs="-parallel"
    
    
        case "$FOAM_MPI" in
        (msmpi*)
    
            ;;
        (*openmpi*)
            mpiopts="--oversubscribe"
            ;;
        esac
    
        # Parse options until executable is encountered
    
        while [ "$#" -gt 0 ] && [ -z "$appRun" ]
    
            ('') ;;  # Ignore junk
    
            (-a | -append)
                logMode=append
                ;;
            (-o | -overwrite)
                logMode=overwrite
                ;;
            (-s | -suffix)
                logFile=".$2"
                shift
                ;;
            (-n | -np)
                nProcs="$2"
                shift
                ;;
            (-decompose-dict=*)
                optValue="${1#*=}"
                case "$optValue" in
                ('' | none | false) ;;  ## Ignore
                (*)
                    appArgs="$appArgs -decomposeParDict $optValue"
                    nProcs="$(getNumberOfProcessors "$optValue")"
    
                esac
                ;;
            (-decomposeParDict)
                optValue="$2"
                shift
                case "$optValue" in
                ('' | none | false) ;;  ## Ignore
                (*)
                    appArgs="$appArgs -decomposeParDict $optValue"
                    nProcs="$(getNumberOfProcessors "$optValue")"
    
        [ -n "$nProcs" ] || nProcs=$(getNumberOfProcessors system/decomposeParDict)
    
        appName="${appRun##*/}"
    
        if [ -f "$logFile" ] && [ -z "$logMode" ]
    
            echo "$appName already run on $PWD:" \
                 "remove log file '$logFile' to re-run"
    
        else
    
            echo "Running $appRun ($nProcs processes) on $PWD "
    
            # Options '-n' and '-np' are synonymous, but msmpi only supports '-n'
    
                "$mpirun" $mpiopts -n "${nProcs:?}" $appRun $appArgs "$@" </dev/null >> $logFile 2>&1
    
                "$mpirun" $mpiopts -n "${nProcs:?}" $appRun $appArgs "$@" </dev/null > $logFile 2>&1
    
    {
        echo "Compiling $1 application"
        wmake $1
    }
    
    
    #
    # cloneCase srcDir dstDir
    #
    
        local src=$1
        local dst=$2
        shift 2
    
        if [ -e "$dst" ]
    
            echo "Case already cloned: remove case directory $dst prior to cloning"
            return 1
        elif [ ! -d "$src" ]
    
            echo "Error: no directory to clone:  $src"
            return 1
        fi
    
        echo "Cloning $dst case from $src"
        mkdir $dst
        # These must exist, so do not hide error messages
        for f in constant system
        do
            \cp -r $src/$f $dst
        done
    
        # Either (or both) may exist, so error messages may be spurious
        for f in 0 0.orig
        do
            \cp -r $src/$f $dst 2>/dev/null
        done
        return 0
    }
    
    
    #
    # cloneParallelCase srcDir dstDir [...times]
    #
    # If any times are specified, they will be used for the cloning.
    # Otherwise the entire processor* directories are cloned
    cloneParallelCase()
    {
        local src=$1
        local dst=$2
        shift 2
    
        if [ -e "$dst" ]
        then
            echo "Case already cloned: remove case directory $dst prior to cloning"
            return 1
        fi
    
        [ -d "$src" ] || {
            echo "Error: no directory to clone: $src"
            return 1
        }
    
        echo "Cloning $dst parallel case from $src"
        mkdir $dst
        # These must exist, so do not hide error messages
        for f in constant system
        do
            \cp -r $src/$f $dst
        done
    
        [ -d $src/processor0 ] || {
            echo "Does not appear to be a parallel case"
            return 1
        }
    
        if [ "$#" -eq 0 ]
        then
            # Copy all processor directories
            echo "    clone processor* directories"
            \cp -r $src/processor* $dst
        else
            # Only copy some time directories
            echo "    clone processor directories with $# times: $@"
    
    
            for proc in $(\cd $src && \ls -d processor*)
    
                srcProc=$src/$proc
                dstProc=$dst/$proc
    
                mkdir $dstProc
    
                \cp -r $srcProc/constant $dstProc/
    
                    [ -d $srcProc/$time ] && \cp -r $srcProc/$time $dstProc/
    
    # If 0.orig/ exists, copy (overwrite) into 0/ [ie, serial case]
    # * -processor : copy into processor directories instead
    # * -all : copy into serial and processor directories
    
        if [ ! -d 0.orig ]
        then
            echo "No 0.orig/ to restore..." 1>&2
            return 0
        fi
    
    
        (-all | -proc | -processor*)
            if [ "$1" = "-all" ]
            then
                echo "Restore 0/ from 0.orig/  [serial/processor dirs]" 1>&2
                \rm -rf 0
                \cp -r 0.orig 0 2>/dev/null
            else
                echo "Restore 0/ from 0.orig/  [processor dirs]" 1>&2
            fi
    
    
            \ls -d processor* | xargs -I {} \rm -rf ./{}/0
    
            \ls -d processor* | xargs -I {} \cp -r 0.orig ./{}/0 > /dev/null 2>&1
    
        (*)
            echo "Restore 0/ from 0.orig/" 1>&2
    
            \rm -rf 0
            \cp -r 0.orig 0 2>/dev/null
    
    #------------------------------------------------------------------------------