Runana - Run programs and analyse their results¶
Utility library for running programs and analysing their results.
Useful for convergence testing. Integrates well with Fortran programs.
Documentation: http://runana.readthedocs.org/en/latest/
Installation¶
runana
can be installed from pypi:
$ pip install runana
The latest version of runana
can be installed from source:
$ git clone https://github.com/jenssss/runana.git
$ cd runana
$ python setup.py install
Users without install privileges can append the --user
flag to
setup.py
:
$ python setup.py install --user
Example usage¶
A number of examples are included in the examples
directory of the
source code. The subfolder f90nml
uses configuration files in the
fortran namelist format, while upname
uses a configuration name format
in which the names and values of variables are given on consequtive
lines with entries seperated by white space.
Here follows one of the examples from the f90nml
folder. A simple
program for performing a numerical integration is given in
examples/f90nml/integrate_test.py
. The main content of this file is:
#!/usr/bin/env python
from sys import argv
import numpy as np
import f90nml
config = f90nml.read(argv[1])
npoints = config['nlIntegrate']['npoints']
x = np.linspace(0, 2, npoints)
y = 10*x**2
I = np.trapz(y, x)
print('Integral of 10*x**2 from 0 to 2: ', I)
The program can be configured through a namelist configuration, which
should be given as the first argument when calling the program
./intergrate_test.py config.nml
. An example of such a configuration
is located at examples/f90nml/config.nml
and contains entries of the
form:
&nlGroup
var = 1
&end
&nlIntegrate
npoints = 10
&end
We want to run this program for a number of different values of the
npoints
parameter, and compare the results. For this we can use
runana
. The file examples/f90nml/run_integrate.py
contains a
script showing how this can be run:
from os import path, getcwd
from runana.run import execute, print_time, generate_list
def setup_programs():
programs = ['integrate_test.py',]
programs = [path.join(getcwd(), program) for program in programs]
return programs
def setup_replacers():
nvar_values = 10
chain_iters = {('nlIntegrate', 'npoints'): generate_list(
start=10, incr=10, incr_func='add', nvalues=nvar_values),
}
return chain_iters
input_file = 'config.nml'
chain_iters = setup_replacers()
scratch_base = path.expanduser('~/test_run/runana/integrate_test')
programs = setup_programs()
print('Running in ', scratch_base)
with print_time():
execute(programs, input_file, scratch_base,
chain_iters=chain_iters)
Running this script will run the integration program with 10 values of
the npoints
parameter in increments of 10 starting from 10. The
results of the calculations will be stored in
~/test_run/runana/integrate_test
, specified in the scratch_base
variable. For each parameter, a seperate run of the program will be
performed, and the results stored in separate subdirectories of
~/test_run/runana/integrate_test
. This script can be run by running
python run_integrate.py
in the examples/f90nml/
directory.
Finally, the results can be analyzed using the script in
examples/f90nml/analyse_integrate.py
, which contains:
from os import path
from runana import analyse
from runana import analyse_pandas
from runana import read_numbers
workdir = path.expanduser('~/test_run/runana/integrate_test')
params_to_dirs = analyse.read_input_files(workdir)
params_to_dirs.diff()
panda_data = analyse_pandas.make_a_seq_panda(params_to_dirs)
read_var = analyse.make_collector_function(
workdir,
read_numbers.read_last_number_from_file,
fname="integrate_test.py.stdout",
pattern="Integral",
)
panda_var = panda_data.applymap(read_var)
print("Values of integral")
print(panda_var)
panda_conv = panda_var.calc_convergence()
print("Estimated difference between current and fully converged value")
print(panda_conv)
param_panda = panda_data.applymap(
analyse_pandas.return_dict_element(params_to_dirs)
)
panda_var.plot_("plot_test_integral_var.pdf", param_panda=param_panda)
panda_conv.plot_("plot_test_integral_conv.pdf", logy=True, param_panda=param_panda)
Running this script should print out:
Values of integral:
0
NumParam NumParamValue
npoints 10.0 26.831276
20.0 26.703601
30.0 26.682521
40.0 26.675433
50.0 26.672220
60.0 26.670497
70.0 26.669467
80.0 26.668803
90.0 26.668350
100.0 26.668027
Estimated difference between current and fully converged value:
0_conv
NumParam NumParamValue
npoints 10.0 NaN
20.0 0.009562
30.0 0.002370
40.0 0.001063
50.0 0.000602
60.0 0.000388
70.0 0.000270
80.0 0.000199
90.0 0.000153
100.0 0.000121
The script collects the values calculated by the integration program and
puts them into a pandas DataFrame
, indexed by the value of the
varying numerical parameter. It also calculates an estimate for how well
converged the calculation is. Finally the script plots these values to the files
plot_test_integral_var.pdf
and plot_test_integral_conv.pdf
.
Similar software¶
Welcome to runana’s documentation!¶
Run API¶
-
runana.run.
execute
(programs, input_file, dirs, chain_iters={}, product_iters={}, co_iters={}, just_replace={}, filter_func='f90nml', use_stdin=False, calc_all=<function calc_all>, **kwargs)[source]¶ Run sequence of programs with different parameters defined by iters.
Parameters: - programs (list) – List of strings with names of programs. Should contain absolute paths. Could alternately contain functions
- input_file (str) – Input file
- dirs (str or runana.run.Dirs) – Base directory in which programs will be run
- chain_iters (dict) – Entries of the form {‘Name of parameter’:[values to replace with]}
- product_iters (dict) – Like chain_iters, but runs all combinations
- co_iters (dict) – Runs with several parameters changing simultanously
- just_replace (dict) – Entries of the form {‘Name of parameter’:value to replace with}
- filter_func (str) – Which filter function to use. Options are listed as keys in the INPUT_FILE_FILTERS dictionary
- use_stdin (bool) – send in the content of the filtered input file through stdin rather passing the name of the input file as the first command line argument
- calc_all (func) – Hook for the parallel decorator, please ignore this argument
-
runana.run.
execute_lock_par
(lock, parallel, *args, **kwargs)[source]¶ Convenience function for running execute with a lock and/or in parallel
-
runana.run.
generate_seq
(start, incr, nvalues=0, incr_func=<built-in function add>)[source]¶ Iterator that returns a sequence of numbers
Parameters: incr_func (func or str) – function used to increment the return value. Can be one of the strings ‘add’, ‘mul’ or ‘div’
-
runana.run.
generate_list
(*args, **kwargs)[source]¶ Wrap of generate_seq that returns a list instead of an iterator
-
class
runana.run.
Dirs
(scratch_base, local_scratch_base=None, copy_2_scratch=['*.txt', '*.nml', '*.stdout', '*.dat'])[source]¶ Container class for names of directories
Parameters: - scratch_base (str) – Directory prefix
- local_scratch_base (str) – Prefix for directory in which programs are run. If None then scratch_base is used
- copy_2_scratch (list) – List of strings that are globbed and copied from the local scratch directory to scratch directory
-
runana.run.
print_time
(file_=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>)[source]¶ Contextmanager that prints how much time was spent in it
-
runana.input_file_handling.
filter_inp_file_upname
(inp_file_in, inp_file_out, replace_with_these)[source]¶ Replaces elements in inp_file_in and places the result in inp_file_out
replace_with_these is a dict with entries of the form {‘Name of parameter’:value to replace with}
This version replaces entries that is one line below a string matching Name of parameter, in the same position as the string
-
runana.input_file_handling.
filter_inp_file_f90nml
(inp_file_in, inp_file_out, replace_with_these)[source]¶ Replaces elements in inp_file_in and places the result in inp_file_out
replace_with_these is a dict with entries of the form {‘Name of parameter’:value to replace with}
This version works on namelist files using the f90nml package
-
runana.input_file_handling.
INP_FILE_FILTERS
= {'f90nml': <function filter_inp_file_f90nml>, 'positional': <function filter_inp_file_positional>, 'upname': <function filter_inp_file_upname>}¶ Available input file filter functions
Extra functions¶
Automated convergence testing¶
-
class
runana.run.
ConvCrit
(data_read, eps=0.001, conv_func=<function rel_err_rel_var>, itermax=10, common_start=False)[source]¶ Contains information on how to check for convergence.
Parameters: - data_read (func) – Function which will be executed in the directory in which the programs was run. It should return the observable in terms of which convergence is sought
- eps (float) – Desired precision
- conv_funv (func) – Function that calculates convergence criterion. It should take 4 arguments, f(O1,O2,x1,x2), where x1 and x2 are the values of the numerical parameter at the current and previous calculation and O1 and O2 are the corresponding observable values
-
runana.run.
rel_err_rel_var
(O1, O2, x1, x2)[source]¶ Estimate of relative error abs(x2/(x2-x1)*(O1-O2)/O2)
-
runana.run.
auto_conv
(programs, inp_file, dirs, conv_crit, chain_iters, product_iters={}, co_iters={}, just_replace={}, auto_converge_var=<function auto_converge_var>, auto_conv_sub=<function auto_conv_sub>)[source]¶ Run programs until converged or chain_iters is exhausted.
Parameters: - programs (list) – List of strings with names of programs. Should contain absolute paths. Could alternately contain functions
- input_file (str) – Input file
- dirs (str or runana.run.Dirs) – Base directory in which programs will be run
- conv_crit (runana.run.ConvCrit) – Object specifying type of convergence
- chain_iters (dict) – Entries of the form {‘Name of parameter’:[values to replace with]}
- product_iters (dict) – Like chain_iters, but runs all combinations
- co_iters (dict) – Runs with several parameters changing simultanously
- use_stdin (bool) – send in the content of the filtered input file through stdin rather passing the name of the input file as the first command line argument
-
runana.run.
auto_conv_rerun
(fun)[source]¶ Decorator for rerunning
auto_conv()
, until convergence is achieved in the first two calculations for each parameter. This is useful for cases where parameters are strongly correlated
Analyse API¶
Get data¶
Get parameters¶
-
runana.analyse.
read_input_files
(workdir, indices=[], read_func=<function read_input_files_f90nml>)[source]¶ Read information from input files.
Recursively searches through all subdirectories of workdir. read_func is run in any directory containing a file named ‘hostname.txt’, and the result is stored in a
ParamDict
, with the path in tuple-form as key. ThisParamDict
is returned.If indices is given as a non-empty list, the indices in this argument will be used instead of recursive search
Subdirectories of a directory with a ‘hostname.txt’ file are not searched.
-
ParamDict.
diff
()[source]¶ Call
dictdiff()
on ParamDict object
-
ParamDict.
unpack_list_values
()[source]¶ Takes any numerical parameter value in ParamDict object that is a list and packs it into individual slots with name numparam_name + idx
Works in-place
-
class
runana.analyse.
ChangedParams
(param_dicts, *args, **kwargs)[source]¶ Parameters that changed. Derived from dict
Parameters: param_dicts (dict) – Dictionary containing dictionaries of parameters, in the form returned from e.g. collect_from_all()
-
ChangedParams.
groupby_varname
()[source]¶ Groups elements according to the name of the variable.
Returns a dictionary containing the values of the variables, and another with all the pairs of runs
-
class
runana.analyse.
Seqs
(param_dicts, *args, **kwargs)[source]¶ Seqeunces of related runs
Parameters: param_dicts (dict) – Dictionary containing dictionaries of parameters, in the form returned from e.g. collect_from_all()
-
runana.input_file_handling.
read_input_files_f90nml
(patterns=['*.nml'], read_one_file=<function read_and_flatten_namelist>)[source]¶ Read the all files matching patterns with
f90nml.read()
The namelists are flattened and supersetted, the resulting dict is returned
-
runana.input_file_handling.
read_input_files_upname
(patterns=['*.inp'])[source]¶ Read the all files matching patterns with
read_upname_file()
The data from all the files is supersetted and the resulting dict is returned
-
runana.input_file_handling.
read_input_files_positional
(patterns=['*.inp'])[source]¶ Read the all files matching patterns with
read_positional_file()
The data from all the files is supersetted and the resulting dict is returned
-
runana.input_file_handling.
read_upname_file
(filename)[source]¶ Reads file in upname format
In this format the names of variables are given on a line, with the values on the following line. Each variable/name should be seperated by at least two whitespaces or a tab. Each set of names/values lines should be seperated by at least one blank line
Get other stuff¶
-
runana.analyse.
make_collector_function
(workdir, read_func, *args, **kwargs)[source]¶ Returns a function that runs read_func(*args,**kwargs) in the directory that is the join of workdir and the argument to the function
-
runana.analyse.
prepend_dir
(workdir)[source]¶ Returns a function that takes a tuple of directories and returns the combination of those into a path, with workdir prepended
-
runana.analyse.
read_from_dir
(read_func, workdir)[source]¶ Composes read_func with
prepend_dir(workdir)
Analyse with pandas API¶
This module requires the pandas
package
-
class
runana.analyse_pandas.
SeqsDataFrame
(data=None, index: Axes | None = None, columns: Axes | None = None, dtype: Dtype | None = None, copy: bool | None = None)[source]¶
-
SeqsDataFrame.
import_from_seq
(seqsnew, varvals, inplace=False)[source]¶ Converts the seqs object into a SeqsDataFrame
-
SeqsDataFrame.
calc_convergence
()[source]¶ Calculate an estimate for relative convergence error.
Calculates (O2-O1)/O2*x2/(x2-x1) where O are values and x are numerical parameters, which is an estimate of the difference between the value calculated at the given numerical parameter and the “true” value of the fully converged limit.
All numerical parameter values have to be scalar and numeric.
Returns a new SeqsDataFrame.
-
SeqsDataFrame.
plot_
(outfile, logx=False, logy=False, grid=False, param_panda=None)[source]¶ Requires
numpy
andmatplotlib
Read numbers API¶
Matplotlib managers¶
Context managers for using matplotlib
. Use these together with pythons with statement
-
class
runana.matplotlib_managers.
plot_manager
(outfile, print_outfile=True, *args, **kwargs)[source]¶ Creates pdf file using
matplotlib.backends.backend_pdf.PdfPages()
and returns the handle to this pdf.*args and *kwargs are passed to PdfPages
-
class
runana.matplotlib_managers.
single_fig_manager
(pp, *args, **kwargs)[source]¶ Create a
matplotlib.figure.Figure
args and kwargs are passed to the
Figure
constructorParameters: pp (matplotlib.backends.backend_pdf.PdfPages) – handle that has a savefig method
-
class
runana.matplotlib_managers.
single_ax_manager
(pp, *args, **kwargs)[source]¶ Create an axis with a single subplot in a Figure object.
Subclassed from
single_fig_manager
, and all the arguments are the same