Skip to content
Snippets Groups Projects
foamLog 10.5 KiB
Newer Older
#!/bin/sh
#------------------------------------------------------------------------------
# =========                 |
# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
#  \\    /   O peration     |
#   \\  /    A nd           | Copyright (C) 2011-2016 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
#     foamLog
#
# Description
#     Extract data for each time-step from a log file for graphing.
#
#------------------------------------------------------------------------------
Script=${0##*/}
toolsDir=${0%/*}/tools
siteDir=${WM_PROJECT_SITE:-${WM_PROJECT_INST_DIR:-<unknown>}/site}
userDir=$HOME/.OpenFOAM
    while [ "$#" -ge 1 ]; do echo "$1"; shift; done
    cat <<USAGE
Usage: $Script [OPTIONS] <log>
  -case <dir>           specify alternate case directory, default is the cwd
  -list | -l            lists but does not extract
  -n                    create single column files with extracted data only
  -quiet | -q           quiet operation
  -local | -localDB     only use the local database file
  -help                 print the usage
$Script - extracts xy files from OpenFOAM logs.
#------------------------------------------------------------------------------
cat <<HELP
-----------------------------------------------------------------------------
    The default is to extract the initial residual, the final residual and
    the number of iterations for all 'Solved for' variables.
    Additionally, a (user editable) database is used to extract data for
    standard non-solved for variables like Courant number, and execution time.

    option -list : lists the possible variables without extracting them.

    The program will generate and run an awk script that writes a set of files,
    logs/<var>_<subIter>, for every <var> specified, for every occurrence inside
    a time step.

    For variables that are 'Solved for', the initial residual name will be
    <var>, the final residual receive the name <var>FinalRes,

    The files are output in a simple xy format with the first column Time
    (default) and the second the extracted values.
    Option -n creates single column files with the extracted data only.

    The query database is a simple text format with three entries per line,
    separated by '/' :
        Column 1 is the name of the variable (cannot contain spaces).
        Column 2 is the extended regular expression (egrep) to select the line.
        Column 3 is the string (fgrep) to select the column inside the line.
    The value taken will be the first (non-space)word after this column.

    The database ($Script.db) will taken from these locations:
        .
        $userDir/$WM_PROJECT_VERSION
        $userDir
        $siteDir/$WM_PROJECT_VERSION
        $siteDir
        $WM_PROJECT_DIR/etc
        $toolsDir

    option -quiet : suppresses the default information and only prints the
    extracted variables.
-----------------------------------------------------------------------------
HELP
caseDir=.
unset optList optQuiet localDB
# Parse options
    -case)
        caseDir="$2"
        shift
        ;;
        optList=true
        ;;
    -q | -quiet | -s | -silent)
        optQuiet=true
    -local | -localDB)
        usage "unknown option: '$1'"
# Requires a single logFile
[ $# -eq 1 ] || usage

logFile=$1

# Change to case directory
cd "$caseDir" 2>/dev/null || {
    echo "$Script: No such case directory '$caseDir'" 1>&2
    exit 1
}

# Find the database file: case-local, from etc dirs, or tools-dir
[ -f "$DBFILE" ] || \
    DBFILE=$(foamEtcFile $Script.db) || \
    DBFILE=$toolsDir/$Script.db
# Need the database file
[ -f "$DBFILE" ] || {
    echo "$Script: Cannot read database $DBFILE" 1>&2
# Verify that logFile is readable
[ -r "$logFile" -a -f "$logFile" ] || usage "Cannot read log $logFile"
# Say is like echo, but -quiet turns it off
say()
    [ "$optQuiet" = true ] || echo "$*"
# getSolvedVars logFile
# Prints names of all 'Solving for ...' variables in the log file.
    [ -f "$1" ] && \
        sed -n -e 's/.* Solving for \([^,]*\)[,:].*/\1/p' "$1" | \
        sed -e 's/\./_/g' | \
        sort -u
}


# getQueries dbFile queryName
# Gets regular expressions for a certain queryName from the database
#
# Sets LINEQ, NUMQ
    local dbFile=$1
    local queryName=$2
        echo "Cannot find dbFile $dbFile" 1>&2
    LINEQ=$(grep -v '^#' $dbFile | awk -F '/' "/$queryName/ {if (\"$queryName\" "'!= $1) next; print $2}')
    NUMQ=$(grep -v '^#'  $dbFile | awk -F '/' "/$queryName/ {if (\"$queryName\" "'!= $1) next; print $3}')
}


# getDbQueryList dbFile
# Echoes list of possible queries
    local dbFile=$1
    grep -v '^#' $dbFile | grep '[^ \t]' | awk -F '/' '{print $1}'
}


# getSolveQueryList logFile
# Echoes list of queries from "solved for" variables in log file
    solvedVars=$(getSolvedVars $1)

    for var in $solvedVars
    do
        echo "${var}"
        echo "${var}FinalRes"
        echo "${var}Iters"
    done
}

# getAllQueries dbFile logFile
# Gets all queries from database and from logfile
    local db=$1
    local log=$2
    local q queries

    #-- All solved for queries from log file
    [ "$localDB" = true ] || queries=$(getSolveQueryList $log)

    #-- Add ones from database, present in log file
    # Note: just like awk, line selected with regular expression,
    #       column with string.
    local dbQueries="$(getDbQueryList $db)"
        getQueries $db "$var"
        q=$(egrep "$LINEQ" "$log" | fgrep "$NUMQ")
        [ -n "$q" ] && queries="$queries $var"
#-----------------------------
# Main
#-----------------------------

if [ "$optList" = true ]
    getAllQueries $DBFILE $logFile
outputDir=logs
QUERYNAMES=$(getAllQueries $DBFILE $logFile)
#
# Make logs dir in case directory and place awk file there
#
mkdir -p $outputDir
AWKFILE=$outputDir/$Script.awk
say "Using:"
say "  case     : $(pwd -L)"
say "  log      : $logFile"
say "  database : $DBFILE"
say "  awk file : $AWKFILE"
say "  files to : $outputDir"
say


#-----------------------------
# Generate Awk program
#-----------------------------

rm -f $AWKFILE 2> /dev/null
cat << AWK_CONTENTS > $AWKFILE
# Awk script for OpenFOAM log file extraction
# Reset counters used for variable postfix
function resetCounters() {
AWK_CONTENTS
# ----------

for queryName in $QUERYNAMES
do
    echo "    ${queryName}Cnt=0"
done >> $AWKFILE
cat << AWK_CONTENTS >> $AWKFILE
    # Reset counters for 'Solving for ...'
    for (varName in subIter)
    {
        subIter[varName]=0
    }
}

# Extract value after columnSel
function extract(inLine,columnSel,outVar,a,b)
{
    a=index(inLine, columnSel)
    b=length(columnSel)
    split(substr(inLine, a+b),outVar)
    gsub("[,:]","",outVar[1])
}

#
# Code for iteration separator (increments 'Iteration')
#
getQueries $DBFILE Separator
cat << AWK_CONTENTS >> $AWKFILE
# Iteration separator (increments 'Iteration')
/$LINEQ/ {
    Iteration++
    resetCounters()
}

getQueries $DBFILE Time
cat << AWK_CONTENTS >> $AWKFILE
# Time extraction (sets 'Time')
/$LINEQ/ {
    extract(\$0, "$NUMQ", val)
    Time=val[1]
}

#
# Code for singularity handling.
#
cat << AWK_CONTENTS >> $AWKFILE
# Skip whole line with singularity variable
/solution singularity/ {
    next;
}

#
# Code for extracting solved for quantities
# - note leading tabs for alignment are intentional
[ "$localDB" = true ] || cat <<- AWK_CONTENTS >> $AWKFILE
	# Extract: 'Solving for ...'
	/Solving for/ {
	    extract(\$0, "Solving for ", varNameVal)

	    varName=varNameVal[1]
	    file=varName "_" subIter[varName]++
	    file="$outputDir/" file
	    extract(\$0, "Initial residual = ", val)
	    print $timeName "\t" val[1] > file

	    varName=varNameVal[1] "FinalRes"
	    file=varName "_" subIter[varName]++
	    file="$outputDir/" file
	    extract(\$0, "Final residual = ", val)
	    print $timeName "\t" val[1] > file

	    varName=varNameVal[1] "Iters"
	    file=varName "_" subIter[varName]++
	    file="$outputDir/" file
	    extract(\$0, "No Iterations ", val)
	    print $timeName "\t" val[1] > file
	}
for queryName in $QUERYNAMES
do
    counter=${queryName}Cnt
    getQueries $DBFILE $queryName

    # note leading tabs for alignment are intentional
    [ -n "$LINEQ" -a -n "$NUMQ" ] && cat<<- AWK_CONTENTS
	# Extract: '$queryName'
	/$LINEQ/ {
	    extract(\$0, "$NUMQ", val)
	    file="$outputDir/${queryName}_" ${counter}
	    print $timeName "\\t" val[1] > file
	    ${counter}++
	}

AWK_CONTENTS
# ----------
done >> $AWKFILE

echo "# End" >> $AWKFILE

#-----------------------------
# Run awk program on log
#-----------------------------
say "Executing: awk -f $AWKFILE $logFile"
awk -f $AWKFILE $logFile
say


#-----------------------------
# Print found
#-----------------------------
if [ -z "$optQuiet" ]
then
    echo "Generated XY files for:"

    for queryName in $QUERYNAMES
    do
        echo "    ${queryName}"
    done
    echo "End"
fi

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