Skip to content
Snippets Groups Projects
  • Mark OLESEN's avatar
    c5beee63
    ENH: add isTrue function to RunFunctions · c5beee63
    Mark OLESEN authored
    - check if the first argument corresponds to an OpenFOAM value for
      'true' (as per Switch).
      True == 't', 'y', 'true', 'yes', 'on'. Everything else is not true.
    
    - when the first argument is '-dict', it initializes the value
      with a query via foamDictionary.
      Eg,
           isTrue -dict mydict -entry parallel
    
       ==> value=$(foamDictionary mydict -entry parallel -value)
           isTrue $value
    
       a missing entry is silently treated as false.
    
    ENH: add getNumberOfPatchFaces function in RunFunctions
    
    - simple extraction of nFaces from boundary file for given patch/region
    c5beee63
    History
    ENH: add isTrue function to RunFunctions
    Mark OLESEN authored
    - check if the first argument corresponds to an OpenFOAM value for
      'true' (as per Switch).
      True == 't', 'y', 'true', 'yes', 'on'. Everything else is not true.
    
    - when the first argument is '-dict', it initializes the value
      with a query via foamDictionary.
      Eg,
           isTrue -dict mydict -entry parallel
    
       ==> value=$(foamDictionary mydict -entry parallel -value)
           isTrue $value
    
       a missing entry is silently treated as false.
    
    ENH: add getNumberOfPatchFaces function in RunFunctions
    
    - simple extraction of nFaces from boundary file for given patch/region
RunFunctions 10.15 KiB
#---------------------------------*- sh -*-------------------------------------
# =========                 |
# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
#  \\    /   O peration     |
#   \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
#    \\/     M anipulation  | Copyright (C) 2015-2018 OpenCFD Ltd.
#------------------------------------------------------------------------------
# License
#     This file is part of OpenFOAM, licensed under GNU General Public License
#     <http://www.gnu.org/licenses/>.
#
# Script
#     RunFunctions
#
# Description
#     Miscellaneous functions for running tutorial cases
#
#------------------------------------------------------------------------------

# The normal locations
[ -n "$FOAM_TUTORIALS" ] || export FOAM_TUTORIALS=$WM_PROJECT_DIR/tutorials


#------------------------------------------------------------------------------

#
# 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.
#
isTest()
{
    for i; do [ "$i" = "-test" ] && return 0; done
    return 1
}

#
# Check absence of '-test' in the argument list.
#
notTest()
{
    for i; do [ "$i" = "-test" ] && return 1; done
    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")

    if [ -n "nFaces" ]
    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
#
getNumberOfProcessors()
{
    local dict="${1:-system/decomposeParDict}"

    # Re-use positional parameters for automatic whitespace elimination
    set -- $(foamDictionary -entry numberOfSubdomains -value "$dict" 2>/dev/null)

    if [ "$#" -eq 1 ]
    then
        echo "$1"
    else
        echo "Error getting 'numberOfSubdomains' from '$dict'" 1>&2
        echo 1      # Fallback is 1 proc (serial)
        return 1
    fi
}


#
# Extract 'application' from system/controlDict
#
# On failure:
#    return 'false' which is also a command (ie, shell builtin or /bin/false)
#    exit status 1
#
getApplication()
{
    # Re-use positional parameters for automatic whitespace elimination
    set -- $(foamDictionary -entry application -value system/controlDict 2>/dev/null)

    if [ "$#" -eq 1 ]
    then
        echo "$1"
    else
        echo "Error getting 'application' from system/controlDict" 1>&2
        echo false  # Fallback
        return 1
    fi
}


#
# Run given application in serial with logfile output.
# The preexistence of the log file prevents rerunning.
#
runApplication()
{
    local appRun logFile logMode

    # Any additional parsed arguments (eg, decomposeParDict)
    local appArgs

    # Parse options until executable is encountered
    while [ $# -gt 0 -a -z "$appRun" ]
    do
        case "$1" in
            -a | -append)
                logMode=append
                ;;
            -o | -overwrite)
                logMode=overwrite
                ;;
            -s | -suffix)
                logFile=".$2"
                shift
                ;;
            -decomposeParDict)
                appArgs="$appArgs $1 $2"
                shift
                ;;
            '')
                ;;
            *)
                appRun="$1"
                ;;
        esac
        shift
    done

    local appName="${appRun##*/}"
    logFile="log.$appName$logFile"

    if [ -f "$logFile" -a -z "$logMode" ]
    then
        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
        else
            $appRun $appArgs "$@" > $logFile 2>&1
        fi
    fi
}


#
# Run given application in parallel with logfile output.
# The preexistence of the log file prevents rerunning.
#
runParallel()
{
    local appRun logFile logMode nProcs

    # Any additional parsed arguments (eg, decomposeParDict)
    local appArgs="-parallel"

    # Parse options until executable is encountered
    while [ $# -gt 0 -a -z "$appRun" ]
    do
        case "$1" in
            -a | -append)
                logMode=append
                ;;
            -o | -overwrite)
                logMode=overwrite
                ;;
            -s | -suffix)
                logFile=".$2"
                shift
                ;;
            -n | -np)
                nProcs="$2"
                shift
                ;;
            -decomposeParDict)
                appArgs="$appArgs $1 $2"
                nProcs=$(getNumberOfProcessors "$2")
                shift
                ;;
            '')
                ;;
            *)
                appRun="$1"
                ;;
        esac
        shift
    done

    [ -n "$nProcs" ] || nProcs=$(getNumberOfProcessors system/decomposeParDict)

    local appName="${appRun##*/}"
    logFile="log.$appName$logFile"

    if [ -f "$logFile" -a -z "$logMode" ]
    then
        echo "$appName already run on $PWD:" \
             "remove log file '$logFile' to re-run"
    else
        echo "Running $appRun ($nProcs processes) on $PWD "
        if [ "$logMode" = append ]
        then
        (
            mpirun -np $nProcs $appRun $appArgs "$@" </dev/null >> $logFile 2>&1
        )
        else
        (
            mpirun -np $nProcs $appRun $appArgs "$@" </dev/null > $logFile 2>&1
        )
        fi
    fi
}


compileApplication()
{
    echo "Compiling $1 application"
    wmake $1
}


#
# cloneCase srcDir dstDir
#
cloneCase()
{
    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
    elif [ ! -d "$src" ]
    then
        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*)
        do
            srcProc=$src/$proc
            dstProc=$dst/$proc

            mkdir $dstProc
            \cp -r $srcProc/constant $dstProc/

            for time
            do
                [ -d $srcProc/$time ] && \cp -r $srcProc/$time $dstProc/
            done

        done
    fi

    return 0
}


# Overwrite 0/ with the contents of 0.orig/ if it exists.
# The -processor option to do the processor directories instead
#
restore0Dir()
{
    case "$1" in
    -processor | -processors)
        echo "Restore 0/ from 0.orig/ for processor directories"
        [ -d 0.orig ] || echo "    Warning: no 0.orig/ found"

        # do nonetheless
        \ls -d processor* | xargs -I {} \rm -rf ./{}/0
        \ls -d processor* | xargs -I {} \cp -r 0.orig ./{}/0 > /dev/null 2>&1

        # Remove '#include' directives from field dictionaries
        # for collated format
        if [ "$1" = "-processors" ]
        then
        (
            echo "Filter #include directives in processors/0:"
            \cd processors/0 2>/dev/null || exit 0
            for file in $(grep -l "#include" * 2> /dev/null)
            do
                foamDictionary "$file" > "$file.$$." && mv "$file.$$." "$file"
                echo "    $file"
            done | tr -d '\n'
            echo
        )
        fi
        ;;

    *)
        echo "Restore 0/ from 0.orig/"
        if [ -d 0.orig ]
        then
            \rm -rf 0
            \cp -r 0.orig 0 2>/dev/null
        else
            echo "    Warning: no 0.orig/ found"
        fi
        ;;
    esac
}


#------------------------------------------------------------------------------