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.
cdtopfr_mesa_example/pfr_test.pyand set the variablesmesa_dirandmesa_dir_printat the top of the script.mesa_dirshould be your main MESA installation.mesa_dir_printis 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.txtwhich 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_fileis the filename of the output.txt file you created in Step 3.output_fileis 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 infileswill 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_filereturns 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_fileto thisi_ignore: (integer) all routines which occur more thani_ignoretimes ininput_filewill 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 -----"