2 #-------------------------------------------------------------------------------
4 # | ____| _| |_ / __ \ /\ | \/ |
5 # | |__ _ __ ___ ___ / \| | | | / \ | \ / |
6 # | __| '__/ _ \/ _ ( (| |) ) | | |/ /\ \ | |\/| |
7 # | | | | | __/ __/\_ _/| |__| / ____ \| | | |
8 # |_| |_| \___|\___| |_| \____/_/ \_\_| |_|
10 # FreeFOAM: The Cross-Platform CFD Toolkit
12 # Copyright (C) 2008-2010 Michael Wild <themiwi@users.sf.net>
13 # Gerber van der Graaf <gerber_graaf@users.sf.net>
14 #-------------------------------------------------------------------------------
16 # This file is part of FreeFOAM.
18 # FreeFOAM is free software; you can redistribute it and/or modify it
19 # under the terms of the GNU General Public License as published by the
20 # Free Software Foundation; either version 2 of the License, or (at your
21 # option) any later version.
23 # FreeFOAM is distributed in the hope that it will be useful, but WITHOUT
24 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28 # You should have received a copy of the GNU General Public License
29 # along with FreeFOAM; if not, write to the Free Software Foundation,
30 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 # Extracts info from log file
39 # -solution singularity not handled
40 #------------------------------------------------------------------------------
42 """Usage: freefoam@PY_SCRIPT_SUFFIX@ log [-n] [-s] [-l] [-h, -help] <log>
44 Extracts xy files from Foam logs.
48 -n Produce single-column data files
50 -l Only list extracted variables
51 -h, -help Print this help message
52 <log> Log file from which to extract data
54 The default is to extract for all the 'Solved for' variables the initial
55 residual, the final residual and the number of iterations. On top of this a
56 (user editable) database of standard non-solved for variables is used to
57 extract data like Courant number, execution time.
59 The -l option shows all the possible variables but does not extract them.
61 The program writes a set of files, logs/<var>_<subIter>, for every <var>
62 specified, for every occurrence inside a time step.
64 For variables that are 'Solved for' the initial residual name will be <var>,
65 the final residual will get name <var>FinalRes,
67 The files are a simple xy format with the first column Time (default) and the
68 second the extracted values. Option -n creates single column files with the
71 The query database is a simple text format containing Python regular
72 expressions. The regular expression must capture the queried value in a group
73 with the values name (i.e. using (?P<name>...) syntax). Lines where the first
74 non-blank character is a # will be ignored. The database will either be
75 $HOME/.FreeFOAM/foamLog.db or if not found @FOAM_DATA_DIR@/foamLog.db.
77 Option -s suppresses the default information and only prints the extracted
82 # want to be future proof
83 from FreeFOAM
.compat
import *
91 def __init__(self
, verbose
):
92 self
.verbose
= verbose
93 def __call__(self
, *args
):
97 class InvalidRegex(Exception):
98 """Raised if a regex fails to compile"""
99 def __init__(self
, regex
, i
, msg
):
100 """Initialize with the error message `msg`, thefailed regex `regex` in
102 Exception.__init
__(self
, regex
, i
, msg
)
105 return 'Failed to compile regular expression "%s" in line %d:\n %s'%self
.args
108 def getSolvedForRegex(logf
):
109 """Extracts from the file object `logf` the solved-for variables and
110 generates a list of regular expression objects to extract them or `None`."""
115 m
= re
.search(r
'Solving for\s+(?P<varname>\w+)', l
)
117 vars.add(m
.group('varname'))
123 result
.append(re
.compile((''.join([
124 'Solving for\s+%(var)s,\s+',
125 'Initial residual = (?P<%(var)s>\S+),\s+',
126 'Final residual = (?P<%(var)sFinalRes>\S+),\s+',
127 'No Iterations (?P<%(var)sIters>\S+)']))%{'var': v
}))
131 def getDbRegex(logf
, dbf
):
132 """Extracts from the file object `dbf` the contained regular expression
133 strings and returns a list with regular expression objects that match any of
134 the lines in the file object `logf` at least once."""
145 # try to compile the line (discarding empty and comment lines)
146 if not re
.match(r
'^\s*(#|$)', l
):
148 rc
= re
.compile(l
[:-1])
150 raise InvalidRegex(l
[:-1], i
, str(e
))
153 # try to match the regexes and tranfer the succesful ones into `result`
155 keys
= list(allRegex
.keys())
169 def resetCounters(counters
):
170 """Reset the sub-iter counters"""
171 for i
in counters
.iterkeys():
174 #-----------------------------
176 #-----------------------------
195 elif a
== '-h' or a
== '-help':
199 sys
.stderr
.write('Error: unknown option "%s"\n'%a
)
200 sys
.stderr
.write(__doc__
+'\n')
206 plog
= PrintLog(not silent
)
209 sys
.stderr
.write('Error: No log file specified')
210 sys
.stderr
.write(__doc__
+'\n')
213 if not os
.path
.isfile(logName
):
214 sys
.stderr
.write('Error: No such file "%s"\n'%logName
)
220 os
.path
.expanduser('~/.FreeFOAM'),
221 os
.path
.normpath('@FOAM_DATA_DIR@')
223 n
= os
.path
.join(os
.path
.normpath(n
), 'foamLog.db')
224 if os
.path
.isfile(n
):
228 sys
.stderr
.write('Error: Failed to find foamLog.db\n')
231 # open the db and log file
232 logFile
= open(logName
, 'rt')
233 dbFile
= open(dbName
, 'rt')
235 # fetch all the regexes
236 regex
= getSolvedForRegex(logFile
)
237 regex
.extend(getDbRegex(logFile
, dbFile
))
240 # get all the variable names, create data and counter container
245 for n
in r
.groupindex
.iterkeys():
252 if len(vars) != len(set(vars)):
258 for v
, n
in cnt
.iteritems():
261 'Error: multiple regular expressions for variable "%s"\n'%v
)
264 # if -l specified, list variables
266 print('\n'.join(vars))
270 plog(' log : %s'%logName
)
271 plog(' database : %s'%dbName
)
272 plog(' files to : logs/')
275 if not os
.path
.isdir('logs'):
276 if os
.path
.exists('logs'):
277 sys
.stderr
.write('Error: `logs` exists but is not a directory\n')
281 # loop over lines, extract data
282 splitRegex
= re
.compile(r
'\s*Time\s*=\s*(?P<time>\S+)')
284 resetCounters(counters
)
287 # check for splitting regex
288 m
= splitRegex
.match(l
)
290 time
.append(m
.group('time'))
291 resetCounters(counters
)
294 # check for data regex
297 for n
, v
in m
.groupdict().iteritems():
298 while len(data
[n
]) <= counters
[n
]:
300 data
[n
][counters
[n
]].append(v
)
304 # loop over data and write
305 tLen
= max(map(len, time
))
306 for n
, v
in data
.iteritems():
307 for i
in xrange(len(v
)):
308 f
= open(os
.path
.join('logs', '%s_%d'%(n
, i
)), 'wt')
309 for j
in xrange(len(time
)):
311 f
.write(('%-'+str(tLen
)+'s ')%time
[j
])
312 f
.write('%s\n'%v
[i
][j
])
314 plog('Generated XY files for:')
315 plog('\n'.join(vars))
317 # ------------------- vim: set sw=3 sts=3 ft=python et: ------------ end-of-file