#---------------------------------*- sh -*------------------------------------- # ========= | # \\ / F ield | OpenFOAM: The Open Source CFD Toolbox # \\ / O peration | # \\ / A nd | www.openfoam.com # \\/ M anipulation | #------------------------------------------------------------------------------ # Copyright (C) 2011-2016 OpenFOAM Foundation # Copyright (C) 2015-2020 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 #------------------------------------------------------------------------------ # # 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 } # # Test for wmake and compiler suite or emit warning # canCompile() { if ! command -v wmake >/dev/null then echo "No 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") 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 appName appRun logFile logMode # Any additional parsed arguments (eg, decomposeParDict) local appArgs # Parse options until executable is encountered while [ "$#" -gt 0 ] && [ -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 appName="${appRun##*/}" logFile="log.$appName$logFile" if [ -f "$logFile" ] && [ -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 appName appRun logFile logMode nProcs # Any additional parsed arguments (eg, decomposeParDict) local appArgs="-parallel" local mpirun="mpirun" if [ "$FOAM_MPI" = msmpi ] then mpirun="mpiexec" fi # Parse options until executable is encountered while [ "$#" -gt 0 ] && [ -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) appName="${appRun##*/}" logFile="log.$appName$logFile" if [ -f "$logFile" ] && [ -z "$logMode" ] then 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' if [ "$logMode" = append ] then ( $mpirun -n $nProcs $appRun $appArgs "$@" > $logFile 2>&1 ) else ( $mpirun -n $nProcs $appRun $appArgs "$@" $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 } #------------------------------------------------------------------------------