Install by cloning or downloading the repository, cd
into it and then execute
python setup.py install
or
pip install .
to install package on your system.
Also available from
pip install print_fortran_routines
Uninstall by executing
pip uninstall py_print_fortran_routines
The motivation behind this package is to track which functions / subroutines are being called in a piece of software written in Fortran. I wrote this to apply specifically to MESA (Modules for Experiments in Stellar Astrophysics), but I have applied it to other software. Barring unusual Fortran syntax that I haven't taken account of, in principle it should work for any code. The way this is done is to insert write(*,*)
statements in the fortran files that contain the functions/subroutines that you would like to keep track of. This means that when each routine is called it will print a statement such as:
'start -- subroutine do_evolve_step_part1 -- evolve.f90'
for a routine with a name of 'do_evolve_step_part1' in a file named evolve.f90. When the routine is complete, it will print a statement such as:
'finsh -- subroutine do_evolve_step_part1 -- evolve.f90'
Note that I intentionally misspell finish so that it has the same number of characters as 'start' which makes the final output files easier to read & interpret. Feel free to change that if you like!
I also include an folder which shows you how to use print_fortran_routines called pfr_mesa_example. It contains a basic MESA work directory, a python script pfr_test.py and a bash script which is called by the python script.
Tested for mesa-r11701 and mesa-r12778, though should in principle work for all versions. Note that the test folder only works for mesa-r12778 due to changes in run_star_extras.f, though you can just apply print_fortran_routines to your own or any MESA model.
- Copy your current installation of MESA and compile it.
cd
topfr_mesa_example/pfr_test.py
and set the variablesmesa_dir
andmesa_dir_print
at the top of the script.mesa_dir
should be your main MESA installation.mesa_dir_print
is the directory you created in step 1.- Run
pfr_test.py
. It will do the following:- Modify a selection of MESA Fortran files
- Run a MESA model for one timestep producing an output file called
'output.txt'
. - Run pfr.modify_mesa_terminal_output producing output files called
'routines_short.txt'
,'routines_medium.txt'
and'routines_long.txt'
.
- Done!
-
Make a (compiled) copy of your current installation of MESA. Make an empty file called skip_test in the main directory of your new copy of MESA (this skips tests when you re-compile with modified .f90 files).
-
Use
pfr.write_mesa_routines(mesa_dir, mesa_dir_print, files)
to insertwrite(*,*)
statements into Fortran Files in MESA where:- mesa_dir is your main installation of MESA
- mesa_dir_print is the new installation of MESA where you want to modify Fortran files
- files is either a list of Fortran files in MESA in which you want to insert write statements or a string (e.g. 'all' for all MESA files, see below for further details)
-
Run a MESA model using
./rn >& output.txt
which pipes the terminal output to a file. Ideally you should run for just one timestep because the output file will become very large very quickly. -
Use
pfr.modify_mesa_terminal_output(input_file, output_file, i_ignore=2, files=[])
to improve the layout of output.txt that you created in Step 3, whereinput_file
is the filename of the output.txt file you created in Step 3.output_file
is the new file that you want to createi_ignore
(optional) - all routines which occur more than this many times will be ignored inoutput_file
. This is to remove routines which occur hundreds of times are uninteresting and just minor check routines.files
: if files is not empty, only routines/functions which originally existed infiles
will be included inoutput_file
.
For more details, see below.
There are three main functions in print_fortran_routines.
modify_fortran_file(input_file, output_file=None, ignore_functions=[], write=True)
Purpose: takes in Fortran filename, inserts write(*,*)
statements at the
start and end of every function & subroutine and writes to output file.
Input Parameters
-
input_file
: .f or .f90 filename which you want to modify -
output_file
: location of the new .f or .f90 file which you want to write to, containing all thewrite(*,*)
statements -
write
: set to True for normal usage. If false,modify_fortran_file
returns a list of strings which contain the modified Fortran file. I use this within the write_mesa_routines function. -
ignore_functions
: list of function/subroutine names that you want to ignore. For example, if you don't want to insert awrite(*,*)
statement in the subroutinedo_evolve_step_part1
, setignore_functions = ['subroutine do_evolve_step_part1']
. Default is empty list.
Returns: None (or list of strings if write
== False)
modify_mesa_terminal_output(input_file, output_file, i_ignore=2,
files=[]):
Purpose: Takes in the output text file from running MESA with the write(*,*)
statements turned on and modifies the layout to make it easier to read and interpret.
Input Parameters:
input_file
: output text file from MESA run withwrite(*,*)
statementsoutput_file
: writes modified version of theinput_file
to thisi_ignore
: (integer) all routines which occur more thani_ignore
times ininput_file
will be excluded fromoutput_file
. This is to remove short routines which are called hundreds or thousands of times or uninteresting and minor check routines.
Returns: None
write_mesa_routines(mesa_dir, new_mesa_dir, files='main', reset=True,
ignore_functions=['subroutine check']):
Purpose: Essentially a helpful wrapper to apply modify_fortran_file to MESA files. This is useful because it:
-
Files that already contain
write(*,*)
statements are not modified. This means MESA won't have to recompile them which speeds things up. -
Automatically resets any Fortran files not included in files to the original unmodified version (i.e. without the write statements). This applies only if
reset
== True. -
Contains useful present lists of fortran files in MESA such
files='all'
which will include all .f90 files in your MESA installation orfiles='star'
which gives a nice overview of the functions used in star/private.
Input Parameters:
mesa_dir
: directory of current installation of MESAnew_mesa_dir
: new directory of MESA installation (where you want the modified Fortran files)files
: can be either a list of Fortran filenames within mesa_dir in which you want to insertwrite(*,*)
statements, or one of the following strings, which is a preset selection of Fortran files:
'all'
: includes all .f90 files in MESA, as well as '/include/standard_run_star_extras.inc'
and '/star/job/run_star.f'
. List of these files can be accessed by
print_fortran_routines.all_mesa_f_files()
'lib'
: includes all of the Fortran files in *lib.f90 files in public directories in MESA as well as evolve.f90
, run_star.f90
, run_star_support.f90
and /include/standard_run_star_extras.inc'
. List of these files can be accessed by
print_fortran_routines.lib_mesa_f_files()
'star'
: includes all of the Fortran files in star/private as well as '/include/standard_run_star_extras.inc'
and '/star/job/run_star.f'
. List of these files can be accessed by
print_fortran_routines.star_mesa_f_files()
'basic'
: includes 'public/star_lib.f90'
, 'job/run_star.f90'
, 'job/run_star.f'
, 'job/run_star_support.f90'
, 'private/evolve.f90'
List of these files can be accessed by
print_fortran_routines.basic_mesa_f_files()
- ignore_functions: list of routines/functions in fortran that will be ignored when going through file. Useful as these subroutines are probably not the ones you are looking for.
The following code shows a simple example of print_fortran_routines and MESA in action. Simply run the following python script in a MESA work directory, with the bash script below saved as compile_run_mesa.sh
.
import print_fortran_routines as pfr
import os
import subprocess
# ----------------------------------------------------- #
# | There are 3 main steps to do a test run: |
# | 1. Insert the write(*,*) statements in the Fortran |
# | files using pfr.write_mesa_routines |
# | 2. Re-compile MESA and run the model for 1 timestep |
# | (or more if you like - that will just make a |
# | huge output file). This can be done with the |
# | bash script called compile_run_mesa.sh. |
# | 3. Improve the layout of the output.txt to make it |
# | easier to interpret. This removes extraneous |
# | output and tabs in corresponding start and |
# | finish statements. |
# | |
# | You need to specify 2 directories - one is the |
# | normal MESA installation and the other is the one |
# | that you want to modify. |
# ----------------------------------------------------- #
# 0. Specifying directories
mesa_dir = '/Users/eoin/mesa-r12778'
mesa_dir_print = '/Users/eoin/mesa-r12778_print'
# ----------------------------------------------------- #
# 1. Modifies Fortran files in mesa_dir_print
pfr.write_mesa_routines(mesa_dir, mesa_dir_print, files='star')
# ----------------------------------------------------- #
# 2. Compiles and runs MESA and the stellar evolution model
subprocess.run(["bash", "compile_run_mesa.sh", mesa_dir_print])
# ----------------------------------------------------- #
# 3. Improve the layout of the output files - doing this 4 different ways just
# to indicate different possibilites
inputf = os.path.abspath('output.txt') # output file from MESA run.
files_v1 = ['run_star.f', 'evolve.f90', 'standard_run_star_extras.inc']
outputf1 = os.path.abspath('routines_short.txt')
pfr.modify_mesa_terminal_output(inputf, outputf1, files=files_v1)
files_v2 = ['net.f90', 'run_star.f', 'standard_run_star_extras.f',
'micro.f90', 'overshoot.f90', 'evolve.f90',
'standard_run_star_extras.inc', 'solve_hydro.f90',
'star_newton.f90', 'struct_burn_mix.f90', 'timestep.f90']
outputf2 = os.path.abspath('routines_medium.txt')
pfr.modify_mesa_terminal_output(inputf, outputf2, files=files_v2)
outputf4 = os.path.abspath('routines_long.txt')
pfr.modify_mesa_terminal_output(inputf, outputf4, i_ignore=10)
# ----------------------------------------------------- #
With the following bash code (assumed to be called 'compile_run_mesa.sh'
by the python script above).
#!/bin/bash
# Runs test MESA file
if [ "$#" -lt 1 ]; then
echo 'Provide MESA directory (the one containing modified Fortran files)'
exit 1
fi
cwd=$PWD
export MESA_DIR=$1
cd $MESA_DIR
if [ ! -f skip_test ]; then
touch skip_test
fi
# Compiling MESA
echo "---------- Compiling MESA ----------"
./install
wait
echo "---------- Compiled MESA -----------"
echo
# Compiling Model
cd $cwd
echo "---------- Compiling model ---------"
./clean
./mk
wait
echo "---------- Compiled model -----------"
echo
# Running Model
echo "---------- Running model --------------"
./rn &> output.txt
wait
echo "---------- Finished running model -----"