This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.
The file src/dictstring/constants.txt contains a table of the values and
the dimensions of some fundamental constants from physics. We want to
load this table into a dictionary constants
, where the keys are the
names of the constants. For example, constants['gravitational
constant']
holds the value of the gravitational constant
(\( 6.67259\cdot 10^{-11} \)) in Newton's law of gravitation. Make a
function that reads and interprets the text in the file, and
finally returns the dictionary.
Filename: fundamental_constants
.
Consider this code:
t1 = {}
t1[0] = -5
t1[1] = 10.5
Explain why the lines above work fine while the ones below do not:
t2 = []
t2[0] = -5
t2[1] = 10.5
What must be done in the last code snippet to make it work properly?
Filename: list_vs_dict
.
Consider the program density.py
from the section Example: Storing file data in dictionaries. One problem with this program is that
the name of the substance can contain only one or two words, while
more comprehensive tables may have substances with names consisting of
several words. The purpose of this exercise is to use string
operations to shorten the code and make it more general and elegant.
a)
Make a Python function that lets the name substance
consist of all the
words that line
is split into, but not the last (which is the value
of the corresponding density).
Use the join
method in string objects to combine the words that
make up the name of the substance.
b)
Observe that all the density values in the file densities.dat
start in the same column.
Write an alternative function that makes use of
substring indexing to divide line
into two parts (substance
and density
).
Remember to strip the first part such that, e.g.,
the density of ice is obtained as densities['ice']
and not
densities['ice ']
.
c) Make a test function that calls the two other functions and tests that they produce the same result.
Filename: density_improved
.
The program src/funcif/lnsum.py produces, among other things, this output:
epsilon: 1e-04, exact error: 8.18e-04, n=55 epsilon: 1e-06, exact error: 9.02e-06, n=97 epsilon: 1e-08, exact error: 8.70e-08, n=142 epsilon: 1e-10, exact error: 9.20e-10, n=187 epsilon: 1e-12, exact error: 9.31e-12, n=233
Redirect the output to a file (by python lnsum.py > file
).
Write a Python program that reads the file and extracts
the numbers corresponding to epsilon
, exact error
,
and n
. Store the numbers in three arrays and plot
epsilon
and the exact error
versus n
.
Use a logarithmic scale on the \( y \) axis.
The function semilogy
is
an alternative to plot
and gives logarithmic scale on \( y \) axis.
Filename: read_error
.
Based on the stars data in
the
exercise named "Write a sort function for a list of 4-tuples" in the
document Functions and branching
[1],
make a dictionary where the keys contain the names of the stars
and the values correspond to the luminosity.
Filename: stars_data_dict1
.
Store the data about stars from the exercise named "Write a sort
function for a list of 4-tuples" in the document Functions and
branching
[1] in a nested dictionary such that we can
look up the distance, the apparent brightness, and the luminosity of a
star with name N
by
stars[N]['distance']
stars[N]['apparent brightness']
stars[N]['luminosity']
Initialize the data by just copying the stars.txt text into the program.
Filename: stars_data_dict2
.
The file src/dictstring/human_evolution.txt holds information about
various human species and their height, weight, and brain volume.
Make a program that reads this file and stores the tabular data in
a nested dictionary humans
. The keys in humans
correspond
to the specie name (e.g., homo erectus
), and the values are
dictionaries with keys for height
, weight
, brain volume
,
and when
(the latter for when the specie lived).
For example, humans['homo neanderthalensis']['mass']
should
equal '55-70'
. Let the program write out the humans
dictionary in a nice tabular form similar to that in the file.
Filename: humans
.
The viscosity \( \mu \) of gases depends on the temperature. For some gases the following formula is relevant: $$ \mu (T) = \mu_0\frac{T_0-C}{T+C}\left(\frac{T}{T_0}\right)^{1.5},$$ where the values of the constants \( C \), \( T_0 \), and \( \mu_0 \) are found in the file src/dictstring/viscosity_of_gases.dat. The temperature is measured in Kelvin.
a)
Load the file into a nested dictionary mu_data
such that we can
look up \( C \), \( T_0 \), and \( \mu_0 \) for a gas with name name
by
mu_data[name][X]
, where X
is 'C'
for \( C \),
'T_0'
for \( T_0 \), and 'mu_0'
for \( \mu_0 \).
b)
Make a function mu(T, gas, mu_data)
for computing \( \mu(T) \) for a
gas with name gas
(according to the file) and information about
constants \( C \), \( T_0 \), and \( \mu_0 \) in mu_data
.
c) Plot \( \mu(T) \) for air, carbon dioxide, and hydrogen with \( T\in [223, 373] \).
Filename: viscosity_of_gases
.
The purpose of this exercise is to write
an area
function as in
the
exercise named "Compute the area of an arbitrary triangle" in the
document Functions and branching
[1],
but now we assume that the vertices of the triangle is stored in
a dictionary and not a list. The keys in the dictionary correspond to
the vertex number (1, 2, or 3) while the values are 2-tuples with the
\( x \) and \( y \) coordinates of the vertex. For example,
in a triangle with vertices \( (0,0) \), \( (1,0) \), and \( (0,2) \) the
vertices
argument becomes
{1: (0,0), 2: (1,0), 3: (0,2)}
Filename: area_triangle_dict
.
Write a code snippet that uses both a list and a dictionary to represent the polynomial \( -\frac{1}{2} + 2x^{100} \). Print the list and the dictionary, and use them to evaluate the polynomial for \( x=1.05 \).
You can apply the eval_poly_dict
and eval_poly_list
functions from the section Example: Polynomials as dictionaries).
Filename: poly_repr
.
A polynomial can be represented by a dictionary as explained
in the section Example: Polynomials as dictionaries.
Write a function diff
for differentiating such a polynomial.
The diff
function takes the polynomial as a dictionary argument
and returns the dictionary representation
of the derivative.
Here is an example of
the use of the function diff
:
>>> p = {0: -3, 3: 2, 5: -1} # -3 + 2*x**3 - x**5
>>> diff(p) # should be 6*x**2 - 5*x**4
{2: 6, 4: -5}
Recall the formula for differentiation of polynomials:
$$
\begin{equation}
{d\over dx}\sum_{j=0}^n c_jx^j = \sum_{j=1}^{n} jc_jx^{j-1}\tp
\tag{1}
\end{equation}
$$
This means that the coefficient of the \( x^{j-1} \) term in the derivative
equals \( j \) times the coefficient of \( x^j \) term of the original polynomial.
With p
as the polynomial dictionary and dp
as the dictionary representing the derivative, we then have
dp[j-1] = j*p[j]
for j
running over all keys in p
,
except when j
equals 0.
Filename: poly_diff
.
Explain what the following two code snippets do and give an example of how they can be used.
Read about the StringFunction
tool
in the document User input and error handling [2]
and about a variable number of keyword
arguments in the document Variable number of function arguments in Python [3].
a)
import sys
from scitools.StringFunction import StringFunction
parameters = {}
for prm in sys.argv[4:]:
key, value = prm.split('=')
parameters[key] = eval(value)
f = StringFunction(sys.argv[1], independent_variables=sys.argv[2],
**parameters)
var = float(sys.argv[3])
print f(var)
b)
import sys
from scitools.StringFunction import StringFunction
f = eval('StringFunction(sys.argv[1], ' + \
'independent_variables=sys.argv[2], %s)' % \
(', '.join(sys.argv[4:])))
var = float(sys.argv[3])
print f(var)
Filename: cml_functions
.
To specify arbitrary functions \( f(x_1,x_2,\ldots; p_1, p_2, \ldots) \) with independent variables \( x_1, x_2, \ldots \) and a set of parameters \( p_1, p_2, \ldots \), we allow the following syntax on the command line or in a file:
<expression> is function of <list1> with parameter <list2>
where <expression>
denotes the function formula,
<list1>
is a comma-separated list of the independent variables,
and <list2>
is a comma-separated list of name=value parameters. The part
with parameters <list2>
is omitted if there are no parameters.
The names of the independent variables and the parameters can be
chosen freely as long as the names can be used as Python variables.
Here are four different examples of what we can specify on the
command line using this syntax:
sin(x) is a function of x sin(a*y) is a function of y with parameter a=2 sin(a*x-phi) is a function of x with parameter a=3, phi=-pi exp(-a*x)*cos(w*t) is a function of t with parameter a=1,w=pi,x=2
Create a Python function that takes such function specifications as input
and returns an appropriate StringFunction
object.
This object must be created from the function expression and the list
of independent variables and parameters. For example, the last
function specification above leads to the following StringFunction
creation:
f = StringFunction('exp(-a*x)*cos(w*t)',
independent_variables=['t'],
a=1, w=pi, x=2)
Write a test function for verifying the implementation (fill sys.argv
with appropriate content prior to each individual test).
Use string operations to extract the various parts of the string.
For example, the expression can be split out by calling
split('is a function of')
.
Typically, you need to extract <expression>
, <list1>
,
and <list2>
, and create a string like
StringFunction(<expression>, independent_variables=[<list1>],
<list2>)
and sending it to eval
to create the object.
Filename: text2func
.
The tarfile src/misc/city_temp.tar.gz contains a set of files with
temperature data for a large number of cities around the world. The
files are in text format with four columns, containing the month
number, the date, the year, and the temperature, respectively.
Missing temperature observations are represented by the value \( -99 \).
The mapping between the names of the text files and the names of the
cities are defined in an HTML file citylistWorld.htm
.
a)
Write a function that can read the citylistWorld.htm
file and create a dictionary with mapping between city and filenames.
b) Write a function that takes this dictionary and a city name as input, opens the corresponding text file, and loads the data into an appropriate data structure (dictionary of arrays and city name is a suggestion).
c) Write a function that can take a number of data structures and the corresponding city names to create a plot of the temperatures over a certain time period.
Filename: temperature_data
.
The goal of this exercise is to let a program write a report in HTML
format containing the solution to the exercise named "Animate a wave
packet" in the document Arrays and plotting
[4]. First, include the program from that
exercise, with additional explaining text if necessary. Program code
can be placed inside <pre>
and </pre>
tags. Second, insert three
plots of the \( f(x,t) \) function for three different \( t \) values (find
suitable \( t \) values that illustrate the displacement of the wave
packet). Third, add an animated GIF file with the movie of \( f(x,t) \).
Insert headlines (<h1>
tags) wherever appropriate.
Filename: wavepacket_report
.