name = '2016-01-22-string-formatting'
title = 'Writing text files using new Python string formatting'
tags = 'text format'
author = 'Maria Zamyatina'
from nb_tools import connect_notebook_to_post
from IPython.core.display import HTML
html = connect_notebook_to_post(name, title, tags, author)
Sometimes in order to run some programming software we need to prepare an input description file which specifies the model setup (e.g., chemical mechanism, intergration method, desired type of results, etc). If we are planning to run the model several times with different, for example, initial conditions, constracting such a file using a script could be beneficial. During our last meeting we discussed how to assemble such a file with Python, and here is what we did.
Let's assume that we need to construct a file containing the following information:
{!-*- F90 -*-}
#INITVALUES
O3 =7.50e+11;
CH4 =4.55e+13;
CO =2.55e+12;
#INLINE F90_INIT
TSTART = 0*3600
TEND = TSTART + 7*3600
DT = 3600
TEMP = 298
#ENDINLINE
The first line of this file is a header. Since it is not going to change in our model runs, we can store it in a separate file:
header_text = '{!-*- F90 -*-}'
with open('header.inp','w') as header_file:
header_file.write(header_text)
The next four lines define the #INITVALUES section of the file, where the initial concentrations (actually, number densities) of chemical compounds of interest are set. If we want to change only numerical values in this section, it is logical to create a text template which would take into account the syntax of the target sortware and include some sort of 'gaps' to fill in with our initial values. One way of achieving that is to define a function that creates a multline string and has a number of arguments determining the initial concentrations of our chemical species:
def gen_concs_string(O3=7.50e+11, CH4=4.55e+13, CO=2.55e+12):
concs_string = \
"""
#INITVALUES
O3\t={O3_nd:.2e};
CH4\t={CH4_nd:.2e};
CO\t={CO_nd:.2e};"""\
.format(O3_nd=O3, CH4_nd=CH4, CO_nd=CO)
return concs_string
For convinience we can even set default values for each of the arguments (e.g., here default ozone initial concentration is $7.5\times 10^{11}$ molecules per $cm^{3}$).
By the way, we have just used a new style of string formatting in Python! An old way of doing the same would include a '%' sign in front of the function agruments inside the string expression and a line of code starting with '%' afterwards, like this
"""
#INITVALUES
O3\t=%(O3_nd).2e;
CH4\t=%(CH4_nd).2e;
CO\t=%(CO_nd).2e;"""\
%{"O3":O3_nd, "CH4":CH4_nd, "CO_nd":CO_nd}
but using a new style makes your code more readable. For more examples on differences between old and new styles of string formatting in Python follow this link: PyFormat.
Well, let's reinforce our knowledge and apply a new style of string formatting to reproduce the last section of the input file, which specifies model integration time and temperature:
def gen_time_str(tstart, nhours, timestep, temp):
time_string = \
"""
#INLINE F90_INIT
TSTART = {tstart}*{timestep}
TEND = TSTART + {nhours}*3600
DT = {timestep}
TEMP = {temp}
#ENDINLINE"""\
.format(tstart=tstart, nhours=nhours, timestep=timestep, temp=temp)
return time_string
And finally let's assemble our input description file:
# Read header
with open('header.inp','r') as header_file:
header_text = header_file.read()
# Use default inital concentrations and set model integration time and temperature
concstr = gen_concs_string()
timestr = gen_time_str(0,7,3600,298)
# Combine all strings together
full_str = header_text + concstr + timestr
# Create function that writes a string to file
def write_str_to_file(string, filename='model.def'):
with open(filename,'w') as def_file:
def_file.write(string)
# Call this function with your string
write_str_to_file(full_str)
There are plenty of other ways to use a new string formatting in Python to your advantage. For example, you could use it to create file names in a loop:
file_mask = '+{one}hours_{two}UTC.jpg'
for i, j in zip((1,2,3), (4,5,6)):
print(file_mask.format(one=i, two=j))
+1hours_4UTC.jpg +2hours_5UTC.jpg +3hours_6UTC.jpg
HTML(html)
This post was written as an IPython (Jupyter) notebook. You can view or download it using nbviewer.