Computational Physics With Python
Computational Physics With Python
With Python
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi
1 Python Basics 13
1.0 The Python Interpreter . . . . . . . . . . . . . . . . . . . . . 13
1.1 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.2 Simple Input & Output . . . . . . . . . . . . . . . . . . . . . 16
1.3 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4 Mathematical Operators . . . . . . . . . . . . . . . . . . . . . 27
1.5 Lines in Python . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.6 Control Structures . . . . . . . . . . . . . . . . . . . . . . . . 29
1.7 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.8 Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.9 Expanding Python . . . . . . . . . . . . . . . . . . . . . . . . 40
1.10 Where to go from Here . . . . . . . . . . . . . . . . . . . . . . 43
1.11 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5 Chaos 109
5.0 The Real Pendulum . . . . . . . . . . . . . . . . . . . . . . . 110
5.1 Phase Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.2 Poincaré Plots . . . . . . . . . . . . . . . . . . . . . . . . . . 116
5.3 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
A Linux 155
A.0 User Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . 156
A.1 Linux Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
A.2 The Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
CONTENTS v
References 185
vi CONTENTS
In [1]:
In [1]: x = array([1,2,3,4,5])
In [2]: y = x+3
1
In all examples, this book will assume that you are using a Unix-based computer:
either Linux or Macintosh. If you are using a Windows machine and are for some reason
unable or unwilling to upgrade that machine to Linux, you can still use Python on a
command line by installing the Python(x,y) package and opening an “iPython” window.
2
All this terminology will be explained eventually. For now, just use it and enjoy the
results.
2 Useful Introductory Python
In [3]: plot(x,y,’rx’)
Out[3]: [<matplotlib.lines.Line2D at (gibberish)>]
In the end, you should get something that looks like figure 0.
Let’s take a moment to talk about what’s we’ve done so far. For starters,
x and y are variables. Variables in Python are essentially storage bins: x
in this case is an address which points to a memory bin somewhere in the
computer that contains an array of 5 numbers. Python variables can point
to bins containing just about anything: different types of numbers, lists, files
on the hard drive, strings of text characters, true/false values, other bits of
Python code, whatever ! When any other line in the Python script refers to
a variable, Python looks at the appropriate memory bin and pulls out those
contents. When Python gets our second line
In [2]: y = x+3
It pulls out the x array, adds three to everything in that array, puts the
resulting array in another memory bin, and makes y point to that new bin.
The plot command plot(x,y, ’rx’ ) creates a new figure window if none
exists, then makes a graph in that window. The first item in parenthesis is
the x data, the second is the y data, and the third is a description of how
the data should be represented on the graph, in this case red × symbols.
Here’s a more complex example to try. Entering these commands at the
iPython prompt will give you a graph like figure 1:
10 My first graph
8
Distance (furlongs)
00 1 2 3 4 5 6
Time (fortnights)
1.0
damped
0.8 constant amplitude
0.6
0.4
0.2
0.0
0.2
0.4
0.60 2 4 6 8 10
Time (s)
spot. The legend() command was given two parameters. The first parameter
is a list 3 :
[ ’ damped ’ , ’ c o n s t a n t a m p l i t u d e ’ ]
Lists are indicated with square brackets, and the list elements are sepa-
rated by commas. In this list, the two list elements are strings; strings
are sequences of characters delimited (generally) by either single or double
quotes. The second parameter in the legend() call is a labeled option: these
are often built in to functions where it’s desirable to build the functions with
a default value but still have the option of changing that value if needed4 .
3
See section 1.3.
4
See section 1.7.
0.1 Libraries 5
0.1 Libraries
By itself, Python does not do plots. It doesn’t even do trig functions or
square roots. But when you start iPython with the ‘-pylab’ option, you
are telling it to load optional libraries that expand the functionality of the
Python language. The specific libraries loaded by ‘-pylab’ are mathematical
and scientific in nature; but Python libraries are available to read web pages,
create 3D animations, parse XML files, pilot autonomous aircraft, and just
about anything else you can imagine. It’s easy to make libraries in Python,
and you’ll learn how as you work your way through this class. But you
will find that for many problems someone has already written a Python
library that solves the problem, and the quickest and best way of solving
the problem is to figure out how to use their library!
For plotting, the preferred Python library is “matplotlib”. That’s the
library being used for the plots you’ve made in this chapter so far; but we’ve
barely scratched the surface of what the matplotlib library is capable of
doing. Take a look online at the “matplotlib gallery”: http://matplotlib.
org/gallery.html. This should give you some idea of the capabilities of
matplotlib. This page very useful: clicking on a plot that shows something
similar to what you want to create gives example code showing how that
graph was created!
Another extremely useful library for physicists is the ‘LINPACK’ linear
algebra package. This package provides very fast routines for calculating
anything having to do with matrices: eigenvalues, eigenvectors, solutions of
systems of linear equations, and so on. It’s loaded under the name ‘linalg’
when you use ipython −−pylab.
Example 0.1.1
In electronics, Kirchhoff’s laws are used to solve for the currents
through components in circuit networks. Applying these laws
gives us systems of linear equations, which can then be expressed
as matrix equations, such as
−13 2 4 IA 5
2 −11 6 IB = −10 (1)
4 6 −15 IC 5
This can be solved algebraically without too much difficulty, or
one can simply solve it with LINPACK:
B = array([5,-10,5])
linalg.solve(A,B)
--> array([-0.28624535, 0.81040892, -0,08550186])
One can easily verify that the three values returned by linalg . solve ()
are the solutions for IA , IB , and IC .
The loadtxt() function takes one required argument: the file name. (You
may need to adjust the file name (microphones.txt) to reflect the location
of the actual file on your computer, or move the file to a more convenient
location.) There are a number of optional arguments: one we’re using here
is “unpack”, which tells loadtxt() that the file contains columns of data that
should be returnend in separate arrays. In this case, we’ve told Python
to call those arrays ‘frequency’, ‘mic1’, and ‘mic2’. The loadtxt() function
is very handy, and reasonably intelligent. By default, it will ignore any
line that begins with ‘#’, as it assumes that such lines are comments; and
it will assume the columns are separated by tabs. By giving it different
optional arguments you can tell it to only read certain rows, or use commas
as delimiters, etc. It will choke, though, if the number of items in each row
is not identical, or if there are items that it can’t interpret as numbers.
Now that we’ve loaded the data, we can plot it as before:
figure()
plot(frequency, mic1, ’r-’, frequency, mic2, ’b-’)
xlabel(’Frequency (Hz)’)
ylabel(’Amplitude (arbitrary units)’)
legend([’Microphone 1’, ’Microphone 2’])
See figure 2.
8 Useful Introductory Python
4.0
Microphone 1
3.5 Microphone 2
3.0
Amplitude (arbitrary units)
2.5
2.0
1.5
1.0
0.5
0.3 Problems
0-0 Graph both of the following functions on a single figure, with a usefully-
sized scale.
(a)
x4 e−2x
(b)
2
x2 e−x sin(x2 )
Make sure your figure has legend, range, title, axis labels, and so on.
0-1 The data shown in figure 2 is most usefully analyzed by looking at the
ratio of the two microphone signals. Plot this ratio, with frequency
on the x axis. Be sure to clean up the graph with appropriate scales,
axes labels, and a title.
0-2 The file Ba137.txt contains two columns. The first is counts from a
Geiger counter, the second is time in seconds.
0-3 The data in file Ba137.txt is actual data from a radioactive decay
experiment; the first column is the number of decays N , the second is
the time t in seconds. We’d like to know the half-life t1/2 of 137 Ba. It
should follow the decay equation
N = No e−λt
where λ = log 2
t1/2 . Using the techniques you’ve learned in this chapter,
load the data from file Ba137.txt into appropriately-named variables
in an ipython session. Experiment with different values of N and λ
and plot the resulting equation on top of the data. (Python uses exp()
calculate the exponential function: i.e. y = A∗exp(−L∗time) ) Don’t
worry about automating this process yet (unless you really want to!)
just try adjusting things by hand until the equation matches the data
pretty well. What is your best estimate for t1/2 ?
10 Useful Introductory Python
0-4 The normal modes and angular frequencies of those modes for a linear
system of four coupled oscillators of mass m, separated by springs of
equal strength k, are given by the eigenvectors and eigenvalues of M ,
shown below.
2 −1 0 0
−1 2 −1 0
M = 0 −1 2 −1
0 0 −1 2
q
k
(The eigenvalues give the angular frequencies ω in units of m .) Find
those angular frequencies.
0-5 Create a single plot that shows separate graphs of position, velocity,
and acceleration for an object in free-fall. Your plot should have a sin-
gle horizontal time axis and separate stacked graphs showing position,
velocity, and acceleration each on their own vertical axis. (See figure
3.) The online matplotlib gallery will probably be helpful! Print the
graph, with your name in the title.
0.3 Problems 11
8
6
4
2
0
15
10
Velocity, m/s
5
0
5
10
15
15
Acceleration, m/s2
10
5
0
5
10
150.0 0.5 1.0 1.5 2.0 2.5 3.0
Time (s)
Python Basics
You can use Python as a very powerful calculator if you want. It can
also store value in variables. Try this:
x = 4
y = 16
x*y
x**y
y/x
x**y**x
That last one may take a moment or two: Python is actually calculating
4
the value of 4(16 ) , which is a rather huge number.
In addition to taking commands one line at a time, the Python inter-
preter can take a file containing a list of commands, called a program. The
rest of this book, and course, is about putting together programs so as to
solve physics problems.
1.1 Comments
A program is a set of instructions that a computer can follow. As such,
it has to be comprehensible by the computer, or it won’t run at all. The
rest of this chapter is concerned with the specifics of making the program
comprehensible to the computer, but it’s worthwhile to spend a little time
here at the beginning to talk about making the program comprehensible to
humans.
Python is pretty good in terms of comprehensibility. It’s a language that
doesn’t require a lot of obscure punctuation or symbols that mean different
things in different contexts. But there are still two very important things
to keep in mind when you are writing any computer code:
(1) The next person to read the code will not know what you were thinking
when you write the code.
(2) If you are the next person to read the code, rule #1 will still apply.
tenPrimes . py
# I n i t i a l i z e t h e prime c o u n t e r
count = 0
The second program might take less disk space but disk space is cheap
and plentiful. Use the commented version.
Example 1.2.1
name = r a w i n p u t ( ”what i s your name? ” )
After the above line, the variable ’name’ will contain the char-
acters you type, whether they be “King Arthur of Britain” or
“3.141592”.
y = i n p u t ( ”What i s your q u e s t ? ” )
The value of y, after you press enter, will be the computer’s best
guess as to the numeric value of your entry. “3.141592” would
result in y being approximately π. “To find the Holy Grail”
would cause an error.
2
Including Macintosh & Linux, see appendix A
1.2 Simple Input & Output 17
In order to get your carefully calculated results out of the computer and
onto the monitor, you need the print command. This command sends the
value of its arguments to the screen.
Example 1.2.2
e = 2.71828
print ” H e l l o , world ”
−→ Hello world
print e
−→ 2.71828
print ” E u l e r ’ s number i s a p p r o x i m a t e l y ” , e , ” . ”
Note in example 1.2.2 that the comma can be used to concatenate out-
puts. The comma can also be used to suppress the newline character that
would otherwise come automatically at the end of the output. This use of
the comma can allow you to make one print statement ending in a comma,
then another print statement some lines further in the program, and have
the output of both statements appear on one line of the screen.
It is also possible to specify the format of the output, using “string
formatting”. The most common format indicators used for our purposes are
given in table 1.1. To use these format indicators, include them in an output
string and then add a percent sign and the desired value to insert at the end
of the print statement.
Example 1.2.3
pi = 3.141592
print ” Decimal : %d” % p i
−→ 3
print ” F l o a t i n g Point , two d e c i m a l p l a c e s : %0.2 f ” % p i
−→ 3.14
print ” S c i e n t i f i c , two D. P , t o t a l width 1 0 : %10.2 e ” % p i
18 Python Basics
−→ 3.14e00
Note the two extra spaces at the front of the output in that final
example. If we had given the format as “%2.2e”, the output
would have been the same numerically, but without those two
blank spaces at the beginning. The output format expands as
necessary, but always takes up at least as much space as specified.
Should you need to include more than one formatted variable in your
output, go right ahead: just put the variables, grouped with parenthesis,
after the % sign. Put them in the right order, of course: the first value will
go into the first string formatting code, the second into the second, and so
on.
Example 1.2.4
pi = 3.141592
e = 2.718282
sum = p i + e
print ”The sum o f %0.3 f and %0.3 f i s %0.3 f . ” % ( pi , e , sum )
String formatting can be used for any strings, not just print statements.
You can use string formatting to build up strings you want to use later, or
send to a file, or whatever:
1.3 Variables 19
C o m p l i c a t e d S t r i n g = ” Student %s s c o r e d %d on t h e f i n a l exam ,
f o r a g r a d e o f %s . ” % ( name , FinalExamScore , FinalGrade )
1.3 Variables
It’s worth our time to spend a bit of time discussing how Python handles
variables. When Python interprets a line such as x=5, it starts from the
right hand side and works its way towards the left. So given the statement
x=5, the Python interpreter takes the “5”, recognizes it as an integer, and
stashes it in an integer-sized “box” in memory. It then takes the label x and
uses it as a pointer to that memory location. (See figure 1.0.)
Figure 1.0: Variable assignment statements, and how Python handles them.
The boxes represent locations in the computer’s memory.
The statement y=x is analyzed the same way. Python starts from the
right (x) and, recognizing x as a pointer to a memory location, makes y a
pointer to the same memory location. At this point, both x and y are point-
ing to the same location in memory, and you could change the value of both
if you could change the contents of that location. You can’t, generally. . .
Continuing the example shown in figure 1.0, you now give Python the
statement x=3. As always, this is analyzed from right to left: “3” is placed
in some memory location, and x becomes a pointer to that location. This
doesn’t change y, though, since y is a pointer to the location containing “5”.
Finally, if you now give Python the command y=3, y will end up pointing
at some third memory location containing yet another “3”. It will not be
the same memory location as x, since from Python’s perspective there is no
reason it should be the same location. At this point, nothing is pointing at
the memory location containing “5”, and that location is free to be used for
something else.
20 Python Basics
Example 1.3.1
You want to swap two variable values.
x,y = y,x
Example 1.3.2
If you start with a = b = 1, what would be the result of repeated
uses of this command?
a , b = b , a+b
Variable Names
Variable names can contain letters, numbers, and the underscore character.
They must start with a letter. Names are case sensitive, so “Time” is not
the same as “time”.
3
Technically, it sees both pairs as “tuples”. See page 22.
1.3 Variables 21
It’s good practice when naming variables to choose your names so that
the code is “self-commenting”. The variable names r and R are legal, and
someone reading your computer code might guess that they refer to radii;
but the names CylinderRadius and SphereRadius are much better. The
extra time you spend typing those more descriptive variable names will be
more than made up by the time you save debugging your code!
Variable Types
There are many different types of variables in Python. The two broad
divisions in these types are numeric types and sequence types. Numeric
types hold single numbers, such as “42”, “3.1415”, and 2 − 3i. Sequence
types hold multiple objects, which may be single numbers, or individual
characters, or even collections of different types of things.
One of the strengths (and pitfalls) of Python is that it automatically
converts between types as necessary, if possible.
Numeric Types
Integer The integer is the simplest numeric type in Python. Integers are
perfect for counting items, or keeping track of how often you’ve done
something.
The maximum integer is 231 − 1 = 2, 147, 483, 647.
Integers don’t divide quite like you’d expect, though! In Python,
1/2 = 0, because 2 goes into 1 zero times.
Python will convert the integer 2 to the float 2.0 and then do the
math.There is a trade-off in speed for this convenience, though.
√
Complex Complex numbers are built-in in Python, which uses j ≡ −1.
It is perfectly legal to say x = 0.5 + 1.2j in Python, and it does complex
arithmetic correctly.
Sequence Types
Sequence types in Python are collections of items which are referred to by
one variable name. Individual items within the sequence are separated by
commas, and referred to by an index in square brackets after the sequence
name. This is easier to demonstrate than explain, so. . .
Example 1.3.3
Pythons = ( ” C l e e s e ” , ” P a l i n ” , ” I d l e ” , ”Chapman” ,
” Jones ” , ” G i l l i a m ” )
print Pythons [ 2 ]
−→ Idle
Note that the index starts counting from zero:
print Pythons [ 0 ]
−→ Cleese
Negative numbers start counting from the end, backwards:
print Pythons [ − 1 ] , Pythons [ −2]
−→ Gilliam Jones
One can also specify a “slice” of the sequence:
print Pythons [ 1 : 3 ]
−→ (’Palin’, ’Idle’)
Note that in that last example, what is printed is another (shorter)
sequence. Note also that the range [1:3] tells Python to start with
item 1 and go up to item 3. Item 3 is not included.
List Lists are indicated by square brackets: [ ]. Lists are pretty much the
same as tuples, but they are mutable: individual items in a list may be
changed. Lists can contain any other data type, including other lists.
Example 1.3.4
matrix = [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] , [ 7 , 8 , 9 ] ]
matrix [ 1 ] [ 0 ] = 0
Example 1.3.5
matrix1 = [ [ 1 , 2 ] , [ 3 , 4 ] ]
matrix2 = [ [ 0 , 0 ] , [ 1 , 1 ] ]
print matrix1 + matrix2
The best way of doing matrices in Python is to use the SciPy or NumPy
packages, which we will introduce later.
Sequence Tricks
If you are calculating a list of N numbers, it’s often handy to have the list
exist first, and then fill it with numbers as you do the calculation. One easy
way to create an empty list with the length needed is multiplication:
LongList = [ ] ∗N
After the above command, LongList will be a list of N blank elements, which
you can refer to as you figure out what those elements should be.
Sometimes you may not know exactly how many list elements you need
until you’ve done the calculation, though. Being able to add elements to the
end of a list, thus making the list longer, would be ideal in this case; and
Python provides for this with list .append(). Here’s an example:
Example 1.3.6
You want a list of calculated values, but you don’t know exactly
how many you need ahead of time.
1.3 Variables 25
# S t a r t by c r e a t i n g t h e f i r s t l i s t e l e m e n t .
# Even an empty e l e m e n t w i l l do −− t h e r e j u s t must
# be s o m e t h i n g t o t e l l Python t h a t t h e v a r i a b l e
# i s a l i s t r a t h e r than s o m e t h i n g e l s e .
Values = [ ]
# Now do your c a l c u l a t i o n s ,
NewValue = MuchCalculation ( YadaYadaYada )
# and each time you f i n d a n o t h e r v a l u e j u s t append
# i t to the l i s t :
Values . append ( NewValue )
# This w i l l i n c r e a s e t h e l e n g t h o f Values [ ] by one ,
# and t h e new e l e m e n t a t t h e end o f Values [ ] w i l l
# be NewValue .
Another handy trick is sorting. If, for example, in the previous example
you wanted to sort your list of values numerically after you’d calculated
them all, this would do it:
Values . s o r t ( )
After that, the list Values would contain the same information but in numeric
order.
Generally speaking, the sort operation only works if all the elements of
the list are the same type. Trying to sort a mix of numbers and strings and
other sequences is a recipe for disaster, and Python will just give you an
error and stop.
Sequences have many other useful built-in operations, more than can
be covered here. Google is my preferred way of finding what they are:
If there’s something you think you should be able to do with a sequence,
Google “Python list (or string, or tuple) <action>”, whatever that action
might be. This will usually come up with something! There are operations
for finding substrings in strings, changing case in strings, removing non-
printing characters, etc. . .
Ranges
It is often necessary to create a list of numbers for the computer to use. If
you’re making a graph, for example, it’d be nice to quickly generate a list of
numbers to put along the bottom axis. Python has a built-in function to do
this for us: “range()”. The range() function takes up to three parameters:
Start (optional), Stop (required), and Step (optional). It generates a list of
26 Python Basics
integers beginning with Start (or zero if Start is omitted) and ending just
before Stop, incrementing by Step along the way.
Example 1.3.7
Create a list of 100 numbers for a graph axis.
a x i s = range (100)
print a x i s
−→ [ 0, 1, 2, . . . 98, 99 ]
Create a list of even numbers from 6 up to 17.
Evens = r a n g e ( 6 , 1 7 , 2 )
List Comprehensions
The range() function only creates integers, and the spacing between the
integers is always exactly the same. We often need something more flexible
than that: what if we needed a list of squares of the first 100 integers, or a
range that went up by 0.1 each step?
Python provides one very useful trick for doing just this thing: List
Comprehensions. Again, this is most easily shown by example:
Example 1.3.8
Create a list of 100 evenly-spaced numbers for a graph axis which
goes from a minimum of zero to a maximum of 2.
Axis = [ 0 . 0 2 ∗ i f or i in r a n g e ( 1 0 0 ) ]
Let’s look at that bit by bit. The square brackets indicate that
the result is a list. The formuala (0.02 * i) is how it calculates
each item in the list. The “for i in range(100)” tells Python to
take each number in the list “range(100)”, call that number “i”,
and apply the formula given.
List comprehensions work for any list, not just range(). So if you have a
list of experimental measurements that were taken in inches, and you needed
to convert them all to centimeters, then the line
m e t r i c = [ 2 . 5 4 ∗ measure f or measure in ListOfMeasurements ]
would do what you need.
1.4 Mathematical Operators 27
Example 1.4.1
print 10/4
−→ 2
print 1/2
−→ 0
print 1 . / 2 .
−→ 0.5
Shortcut Operators
The statement x = x + y and other similar statements are so common in
programming that many languages (including Python) allow shortcut oper-
ators for these statements. The most common of these is +=, which means
“Take what’s to the right and add to it whatever is on the left”. In other
words, x += 1 is exactly equivalent to x = x + 1. Similarly, − =, ∗ =, and
/ = do the same thing for subtraction, multiplication, and division.
These shortcut operators do not make your program run faster, and they
do make the code harder for humans to read. Use them sparingly.
Example 1.5.1
print ” t h i s l i n e i s a p h y s i c a l l i n e and a l o g i c a l l i n e . ”
x = [ ” t h i s ” , ” l i n e ” , ” i s ” , ” both ” , ” a l s o ” ]
Indentation like this helps make programs clear and easier for
humans to read. Python ignores extra whitespace inside a logical
line, so it’s not a problem to put it there.
4
Whether this is one of the best or worst features of Python is a matter of some debate.
1.6 Control Structures 29
Conditionals
A conditional is anything that can be evaluated as either true or false. In
Python, the following things are always false:
• 0, 0L, or 0.0
• “False” (This is true, because it’s a string that is not empty. Python
doesn’t look inside the string to see what it’s about!)
• [0, False , (), ””] (This is true, even though it’s a list of false things,
because it is a non-empty list, and if a list is not empty then it is true.)
== Equal to
! = Not equal to
Note that “=” is an assignment, and “==” is a conditional. FavoriteColor = ‘‘Blue’’
assigns the string “Blue” to the variable FavoriteColor, but FavoriteColor == ‘‘Blue’’
is a conditional that evaluates to either true or false depending on the con-
tents of the variable FavoriteColor. Using = instead of == is one of the
most common and hard-to-find bugs in Python programs!
There are also the boolean operators and, or, and not.
Example 1.6.1
i f ( Animal == ‘ ‘ P a r r o t ’ ’ ) and ( not I s A l i v e ( Animal ) ) :
Complain ( )
If . . . Elif . . . Else
The most basic control statement in Python, or any other computer lan-
guage, is the if statement. It allows you to tell the computer what to do if
some condition is met. The syntax is as follows:
i f C o n d i t i o n a l : # The : i s needed a t t h e end o f t h i s l i n e .
DoThis ( ) # This l i n e must be i n d e n t e d .
AndThis ( ) # Any o t h e r l i n e s t h a t a r e p a r t o f t h e i f
# s t a t e m e n t must a l s o be i n d e n t e d t h e same
# amount . ( comments a r e i g n o r e d , o f c o u r s e ! )
ThisAlso ( )
AlwaysDoThis ( ) # This l i n e i s not i n d e n t e d , so i t i s not
# part of the i f statement ’ s action .
1.6 Control Structures 31
While
The while statement is used to repeat a block of commands until a condition
is met.
while C o n d i t i o n : # The : i s r e q u i r e d , a g a i n .
DoThis ( ) # The b l o c k o f t h i n g s t h a t s h o u l d be done
DoThat ( ) # i s i n d e n t e d , as a l w a y s .
DoTheOther ( )
UpdateCondition ( )
# I f n o t h i n g happens t o change t h e c o n d i t i o n ,
# t h e w h i l e l o o p w i l l go f o r e v e r !
DoThisAfterwards ( ) # This s t a t e m e n t i s done a f t e r C o n d i t i o n
# becomes f a l s e .
There are a few extra keywords that can be used with the while loop.
pass The pass keyword does exactly nothing. Its sole purpose is to create
an indented line if you want the program to do nothing but there’s a
structural need for an indented line. I know this seems crazy, but I
have actually found a situation in which the pass command was the
simplest way to make something work!
32 Python Basics
break The break keyword moves execution of the loop directly to the line
following the while block. It “breaks out” of the loop, in other words.
Confusing enough for you? This is probably a good time for an example
that uses these features.
Example 1.6.2
You need to write a program that tests whether a number is
prime or not. The program should ask for the integer to test,
then print a message giving either the first factor found or stating
that the number is prime.
#! / u s r / b i n / env python
”””
This Python program d e t e r m i n e s w h e t h e r a number
i s prime or not . I t i s NOT t h e most e f f i c i e n t
way o f d e t e r m i n i n g w h e t h e r a l a r g e i n t e g e r i s
prime !
”””
TestNumber = 2
# Main l o o p t o t e s t each number
while TestNumber < Number :
i f Number % TestNumber == 0 :
# The remainder i s z er o , so TestNumber i s a f a c t o r
# o f Number and Number i s not prime .
print Number , ” i s d i v i s i b l e by” , TestNumber , ” . ”
# There i s no need t o t e s t f u r t h e r f a c t o r s .
break
else :
# The remainder i s NOT z er o , so i n c r e m e n t
# TestNumber t o c h e c k t h e n e x t p o s s i b l e f a c t o r .
1.6 Control Structures 33
TestNumber += 1
else :
# We g o t h e r e w i t h o u t f i n d i n g a f a c t o r , so
# Number i s prime .
print Number , ” i s prime . ”
For
The for loop iterates over items in a sequence, repeating the loop block once
per item. The most basic syntax is as follows:
f or Item in Sequence : # The : i s r e q u i r e d
DoThis ( ) # The b l o c k o f commands t h a t s h o u l d
DoThat ( ) # be done r e p e a t e d l y i s i n d e n t e d .
Each time through the loop, the value of Item will be the value of the
next element in the Sequence. There is nothing special about the names Item
and Sequence, they can be whatever variable names you want to use. In
the case of Sequence, you can even use something that generates a sequence
rather than a sequence, such as range().
Example 1.6.3
You need a program to greet the cast of a humorous skit.
Cast = ( ’ John ’ , ’ E r i c ’ , ’ Terry ’ , ’ Graham ’ , ’ Terry ’ , ’ Michael ’ )
f or Member in Cast :
print ’ H e l l o ’ , member # Each time t h r o u g h t h e l o o p
# one c a s t member i s g r e e t e d .
print ’ Thank you f o r coming today ! ’ # This l i n e i s o u t s i d e t h e l o o p
# so i t i s done once , a f t e r
# the loop .
Hello John
Hello Eric
Hello Terry
Hello Graham
Hello Terry
Hello Michael
Thank you for coming today!
34 Python Basics
In numeric work, it’s more common to use the for command over a
numeric range:
f or j in r a n g e (N ) :
etc ()
Since the range() function returns a list, the for command is perfectly happy
with that arrangement.
The for command also allows the same extras as while: continue goes
straight to the next iteration of the for loop, break causes Python to aban-
don the loop, else at the end of the loop marks code that is done only if the
for loop exits normally, and pass does nothing at all.
One caution about for loops: it’s quite possible to change the list that
is controlling the loop during the loop! This is not recommended, as the
results may be unpredictable.
1.7 Functions
A function is a bit of code that is given its own name so that it may be
used repeatedly by various parts of a program. A function might be a bit
of mathematical calculation, such as sin () or sqrt () . It might also be code
to do something, such as draw a graph or save a list of numbers.
Functions are defined with the def command. The function name must
start with a leter, and may contain letters, numbers, and the underscore
character just like any other Python variable name. In parentheses after
the function name should be a list of variables that should be passed to the
function. The def line should end with a colon, and the indented block after
the def should contain the function code.
Generally, a function should return some value, although this is not re-
quired. For mathematical functions, the return value should be the result of
the calculation. For functions that don’t calculate a mathematical value, the
return should be True or False depending on whether the function managed
to do what it was supposed to do or not.
Example 1.7.1
Write a function that calculates the factoral of a positive integer.
def f a c t o r a l ( n ) :
””” f a c t o r a l ( n )
This f u n c t i o n c a l c u l a t e s n ! by t h e s i m p l e s t and
1.7 Functions 35
most d i r e c t method i m a g i n a b l e .
”””
f = 1
f or i in r a n g e ( 2 , n +1):
f = f ∗ i
return f
Once this definition has been made, any time you need to know
the value of a factorial, you can just use factoral (x).
print ’%10s %10s ’ % ( ’ n ’ , ’ n ! ’ )
f or j in r a n g e ( 1 0 ) :
print ’%10d %10d ’ % ( j , f a c t o r a l ( j ) )
Functions can also be used to break the code up into more understand-
able chunks. Your morning ritual might look something like this, in Python
code:
i f ( Time >= Morning ) :
GetUp ( )
GetDressed ( )
E a t B r e a k f a s t (Spam , eggs , Spam , Spam , Spam , Spam , bacon )
else :
ContinueSleeping ()
The functions GetDressed() and EatBreakfast() may entail quite a bit of
code; but writing them as separate functions allows one to bury the details
(socks first, then shoes) elsewhere in the program so as to make this code
more readable. Writing the program as a set of functions also allows you to
change the program easily, if for example you needed to eat breakfast before
getting dressed.
The variables that are passed to the function exist for the duration of
that function only. They may (or may not) have the same name(s) as other
variables elsewhere in the program.
Example 1.7.2
def sq ( x ) :
# Returns t h e s q u a r e o f a number x
x = x∗x # Note t h a t s q ( ) c h a n g e s t h e l o c a l v a l u e o f x h e r e !
return x
print sq ( x ) # p r i n t s 9 ,
print x # prints 3.
Note that the value of x is changed within the function sq() , but
that change doesn’t “stick”. The reason for this is that sq() does
not receive x, but instead receives some value which it then calls
x for the duration of the function. The x within the function is
not the same as the x in the main program.
Functions can have default values built-in, which is often handy. This is
done by putting the value directly into the definition line, like this:
def answer (A = 4 2 ) :
# Put your f u n c t i o n h e r e
# etc .
# main program
answer ( 6 ) # For t h i s c a l l t o answer ( ) , A w i l l be 6 .
answer ( ) # But t h i s time , A w i l l be t h e d e f a u l t , 4 2 .
Global variables
If a Python function can’t find the value of some variable, it looks outside
the function. This is handy: you can define π once at the beginning of the
program and then use it inside any functions in the program. Values used
throughout the program like this are called global variables.
If you re-define the value of a variable inside your function, though, then
that new value is valid only within the function. To change the value of a
global variable and make it stick outside the function, refer to that variable
in the function as a global. The following example may help clarify this.
Example 1.7.3
a = 4
b = 5
c = 6
def f n ( a ) :
d = a # d i s a new l o c a l v a r i a b l e , and has t h e
# v a l u e o f w h a t e v e r was p a s s e d t o f n ( ) .
a = b # ’ f n ’ d o e s not know ’ b ’ , so Python l o o k s
# o u t s i d e f n and f i n d s b =5. So t h e l o c a l
1.7 Functions 37
# v a l u e o f ’ a ’ i s 5 now .
global c = 9 # I n s t e a d o f making a new l o c a l ’ c ’ , t h i s
# l i n e changes the value of the g l o b a l
# variable ’c ’.
print a , b , c # −−> 4 5 6
fn (b) # The v a l u e o f d i n s i d e f n ( ) w i l l be 5 .
# The v a l u e o f a i n s i d e f n ( ) w i l l a l s o be 5 .
print a , b , c # −−> 4 5 9
# The v a l u e s o u t s i d e f n ( ) d i d n ’ t change ,
# o t h e r than c .
print d # −−> ERROR! d i s o n l y d e f i n e d i n s i d e f n ( ) .
Passing functions
Python treats functions just like any other variable. This means that you
can store functions in other variables or sequences, and even pass those
functions to other functions. The following program is somewhat contrived,
but it serves to give a good example of how this can be useful. The output
is shown in figure 1.1.
#! / u s r / b i n / env python
’ ’ ’ p a s s t r i g . py
Demonstrates Python ’ s a b i l i t y t o s t o r e f u n c t i o n s an v a r i a b l e s and
pass those functions to other functions .
’’’
def p l o t t r i g ( f ) :
# t h i s f u n c t i o n t a k e s one argument , which must be a f u n c t i o n
# t o be p l o t t e d on t h e range −p i . . p i .
x v a l u e s = l i n s p a c e (− pi , pi , 1 0 0 )
plot ( xvalues , f ( xvalues ) ) # y v a l u e s a r e computed d e p e n d i n g on f .
xlim (− pi , p i ) # s e t x l i m i t s t o x range
ylim ( −2 , 2 ) # s e t t h e y l i m i t s so t h a t tan ( x ) doesn ’ t
# ruin the v e r t i c a l s c a l e .
f or f u n c t i o n in t r i g f u n c t i o n s :
# t r i g f u n c t i o n s i s a l i s t o f f u n c t i o n s , so t h i s f o r l o o p d o e s t h i n g s
38 Python Basics
# w i t h each f u n c t i o n i n t h e l i s t .
print f u n c t i o n ( p i / 6 . 0 ) # returns t h i s function value .
plottrig ( function ) # p a s s e s t h i s f u n c t i o n t o be p l o t t e d .
show ( )
2.0
1.5
1.0
0.5
0.0
0.5
1.0
1.5
2.0
3 2 1 0 1 2 3
As you can see, functions here are put into lists, referred to as elements
in lists, and passed to other functions. This is particularly useful in the next
chapter, where we will develop (among other things) ways of finding roots
of equations. We can write functions that find roots, then pass functions to
be solved to those root-finding functions. This allows us to use one general-
purpose root-finding function for just about any function for which we need
to find a root.
1.8 Files 39
1.8 Files
More often than not in computational physics, the inputs and outputs of
a project are large sets of data. Rather than re-enter these large data sets
each time we run the program, we load and save the data in the form of text
files.
When working with files, we start by “opening” the file. the open()
function tells the computer operating system what file we will be working on,
and what we want to do with the file. The function requires two parameters:
the file name and the desired mode.
F i l e H a n d l e = open ( FileName , Mode )
FileName should be a string describing the location and name of the file,
including any directory information if the file is not in the working directory
for the Python program. The mode can be one of three things:
’r’ Read mode allows you to read the file. You can’t change it, only read it.
’w’ Write mode will create the file if it does not exist. If the file does exist,
opening it in ’w’ mode will re-write it, destroying the current contents.
’a’ Append mode allows you to write onto the end of a previously-existing
file without destroying what was there already.
Once the file is open for reading, we can read it by one of several methods.
We can read the entire text file into one string:
s t r i n g = FileHandle . read ( )
Each time you invoke this command, the variable Line will become a string
containing the next line of the file indicated by FileHandle. We could also
read all of the lines at once into a list:
Lines = FileHandle . r e a d l i n e s ()
After this command, Lines[0] will be a string containing the first line of the
file, Lines[1] will contain the second line, and so on.
When we’re done reading the file, it’s best to close the file.
FileHandle . c l o s e ()
40 Python Basics
If you don’t close the file, it will close automatically when the program is
done, but it’s still good practice to close it yourself.
Notice that all of these methods of reading a file result in strings of char-
acters. This is to be expected, since the file itself is a string of characters
on the drive. Python makes no effort to try figuring out what those charac-
ters mean, so if you want to change the strings to numeric values you must
convert them yourself by specifying what type of numbers you expect them
to be. The float () and int () functions are the standard way of doing this.
For example if the string S = ’3.1415’, then x=float(S) takes that string and
changes it to the appropriate floating-point value.
If you wish to write to a file, you must indicate so when you open the
file.
F i l e H a n d l e = open ( FileName , ’w ’ )
After the file is open for writing, the write operation saves string information
to the file:
FileHandle . write ( s t r i n g )
The write() operation is much more literal than the print command: it sends
to the file exactly the contents of the string. If the string does not have a
newline character at the end, then there will be no newline character written
to the file, so if you want to write a single line be sure to include ’\n’ as the
last character in the string. The write() operation can use any of the string
formatting techniques described earlier.
F i l e H a n d l e . w r i t e ( ” p i = %6.4 f \ t e =%6.4 f \n” % ( pi , e ) )
When you are done writing to the file, it is very important to close the
file.
FileHandle . c l o s e ()
Closing the file flushes the write buffer and ensures that all of the written
matter is actually on the hard drive. The file will be closed automatically
at the end of the program, but it’s better to close it yourself.
import math
import commands are generally placed at the beginning of the program,
although that’s just for convenience to the reader. Once the import com-
mand has been run by the program, all of the functions in the “math”
package are available as “math.(function-name)”.
import math
x = math . p i / 3 . 0
print x , math . s i n ( x ) , math . c o s ( x ) , math . tan ( x )
There are many other functions and constants in the math package.5 It is
often useful to just import individual elements of a package rather than the
entire package, so that we could refer to “sin(x)” rather than math.sin(x).
from math import s i n
You can also import everything from a package, each with its own name:
from math import ∗
x = pi / 3.0
print x , s i n ( x ) , c o s ( x ) , tan ( x )
There are numerous other packages that add useful functionality to
Python. In this book we’ll be using the “scipy”, “pylab”, “matplotlib”,
and “numpy” packages extensively. These will be discussed later, but one
package that deserves mention here is the “sys” package, which allows access
to some of the system underpinnings of a unix-based system. The part of
the sys package we use most often is the variable sys.argv. When you invoke
a Python program from the command line, it is possible to enter parameters
directly at time of invocation.
$ add.py 35 7
In the case shown above, the variable sys.argv will be a list containing
the program name and whatever came after on the line:
s y s . argv = [ ’ add . py ’ , ’ 35 ’ , ’ 7 ’ ]
So we can use this to enter values directly into a program.
Example 1.9.1
import s y s
x = f l o a t ( s y s . argv [ 1 ] ) # Note t h a t t h e i t e m s i n a r g v [ ]
y = f l o a t ( s y s . argv [ 2 ] ) # are s t r i n g s !
You can also build your own packages. This is easier than you might
imagine, since every Python program is a package already! Any Python
program ending with a ’.py’ suffix on its filename (and they all should
end with .py) can be imported by any other Python program. Just use
from <filename> import <function(s)>.
Example 1.9.2
You’ve written a program called “area.py” that includes an inte-
gration routine “integrate()”, and you’d like to use that routine
in your next program.
from a r e a import i n t e g r a t e
It’s a good idea, as you work through the exercises in this course, to
put any useful functions you may develop into a “tools.py” file. Then all of
those functions are easily accessible from new programs with the command
from t o o l s import ∗
One thing to consider, though: any time you import a package, it over-
writes anything with the same name. This can cause problems. The pylab
package has trig functions, for example, that are capable of operating on
entire arrays at once. The math package trig functions have much more
basic capabilities. So if you use this code:
from pylab import ∗
from math import ∗
x = sin ([0.1 , 0.2 , 0.3 , 0.4 , 0.5])
then the basic trig functions from math.py overwrite the pylab.py trig func-
tions, and the sin () function will crash when you give it the array.
A better way to do it, if you must have both pylab and math packages,
would be to import the packages with their “full names” intact.
1.10 Where to go from Here 43
import pylab
import math
x = pylab . s i n ( [ 0 . 1 , 0 . 2 , 0 . 3 , 0 . 4 , 0 . 5 ] )
y = math . s i n ( p i / 2 )
There’s another thing to consider when dealing with Python packages:
any Python program can be imported as a package into any other Python
program. A Python program can even import itself, which will cause nothing
but trouble. Problems arise if you happen to name your program “math.py”
and them import math, for example. Python will happily import the first
“math.py” it finds, which will not be the one you expect and nothing will
work right and the error messages you get will be completely unhelpful.
1.11 Problems
1-0 Use a list comprehension to create a list of squares of the numbers
between 10 and 20, including the endpoints.
1-1 Write a Python program to print out the first N numbers in the Fi-
bonacci sequence. The program should ask the user for N , and should
require that N be greater than 2.
1-2 For the model used in introductory physics courses, a projectile thrown
vertically at some initial velocity vi has position y(t) = yi + vi t − 12 gt2 ,
where g = 9.8 m/s2 . Write a Python program that creates two lists,
one containing time data (50 data points over 5 seconds) and the other
containing the corresponding vertical position data for this projectile.
The program should ask the user for the initial height yi and initial
velocity vi , and should print a nicely-formatted table of the list values
after it has calculated them.
where the n’s are integers greater than or equal to one. Write a pro-
gram that will calculate, and list in order of increasing energy, the
values of the n’s for the 10 lowest different energy levels, given a box
for which L2 = 2L1 and L3 = 4L1 .
1-5 Write a function that calculates the value of the nth triangular number.
Triangular numbers are formed by adding a series of integers from 1
to n: i.e. 1 + 2 + 3 + 4 = 10 so 10 is a triangular number, and 15 is
the next triangular number after 10.
1-8 Write a program that takes a multi-digit integer and prints out its
digits in English. Bonus point if the program takes care of ones/
tens/hundreds/thousands properly.
46 Python Basics
Chapter 2
v 2 sin(2θ)
R=
g
vo
Lau
nch
θ
ow
Wind ition
in e.
Pos Ball
w
BandRang mm of
Yello ates
25
e
Indic
Us !
RT N LY
SHO GE O
RAN lls
ba
ER
CH
IUM
MED GE
RAN
! !
K E
UN
IONLOOOK !
TION
NG
UT T LO
CAU EL
REL.
G CANO NOT RR BAR
T RA
LON GE
RAN
DO BA
DO WNN
THE
OR
LA
DODOW
SH LE
CTI
OJE
PR
0
-680
90
ME
80
70
0
60
50 10
40 30 20
AR TY S E.
WE FE SE US
SA AS IN
GL EN
WH
yo
Plugging equation 2.3 into equation 2.1 gives us our general range equa-
tion:
vo cos θ
q
x(θ) = vo sin θ + vo2 sin2 θ + 2yo g (2.4)
g
Now we have a problem. It’s easy enough to calculate the range x, given θ,
but the problem is to find θ to reach a given range x. It is possible to find
an algebraic expression for θ from equation 2.4, but it’s not easy, or pretty.
One way of solving equation 2.4 is to graph the right-hand side versus t
and see where that graph reaches the desired value of x. Or more generally,
graph the right-hand side minus the left-hand side, and see where the result
crosses the θ axis. (See figure 2.1.) We’re going to introduce three methods
of solving equations numerically. You may not think of graphing as the
most precise method of finding numeric solutions, but it is helpful to keep
the graphical model in mind when considering how these numeric methods
actually work.
One other factor to keep in mind is that these methods will give you
an approximately correct answer in all but some special cases. The level
of approximation depends on how much computer time you’re willing to
2.0 Numeric Solution 49
1.0
0.5
0.0
x(θ)
0.5
Target distance -
1.0
1.5
2.0
2.5
3.0
0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6
θ (radians)
devote to the problem. You, as the computer user, must decide what level
of approximation is good enough.
Bisection Method
To use the bisection method of finding a root, start with two guesses on either
side of the root. They don’t have to be exact guesses, or even particularly
good guesses, but they have to be on either side of the root. We’ll call the
guess to the left of the root a and the guess to the right of the root b, as
shown in figure 2.2.
Next, find the value of the function at the midpoint x between a and b.
Compare the signs of f (x) and f (a): if the signs are different, then the root
must be between a and x, so let b = x. If the signs are the same, then the
root must be between x and b, so let a = x. Now a and b are such that the
solution is still between the two, but they’re half as far apart! Repeat this
50 Basic Numerical Tools
0) a x b
1) a x b
2) a b
Figure 2.2: Bisection method of finding a root. At step 0, a and b are initial
guesses, with a root between them. x is the initial halfway point: since the
root is between a and b the new value of b is x. These new values of a and
b are used in step 1, and so on.
process until the distance between a and b is less than the desired tolerance
for your solution.
Here’s a program to solve f (x) = 0, in Python code:
Example 2.0.1
#! / u s r / b i n / env python
”””
This program u s e s t h e b i s e c t i o n method t o f i n d t h e r o o t
o f f ( x ) = exp ( x )∗ l n ( x ) −x ∗ x = 0 .
”””
# Get t h e i n i t i a l g u e s s e s
a , b = i n p u t ( ” Enter two g u e s s e s , s e p a r a t e d by commas : ” )
dx = abs ( b−a ) # i n i t i a l v a l u e o f dx
Note that in the bisection program above, the function could be any
function that returns a numeric value. In the example it’s a relatively sim-
ple numeric function, but it doesn’t have to be a numeric function in the
mathematical sense. You could just as well have a function that — for ex-
ample — runs a complete simulation and returns the final result. If you can
write a function that returns a continuous numeric result, you can use that
function with the bisection method.
With this in mind, it would be very handy to have a bisection-method
root-finding function that could be used in any general case. Something that
you could call like this would be ideal:
answer = r o o t b i s e c t i o n ( Equation , F i r s t G u e s s , SecondGuess )
Example 2.0.2
def r o o t b i s e c t i o n ( f , a , b , t o l e r a n c e =1.0 e −6):
”””
Uses t h e b i s e c t i o n method t o f i n d a v a l u e x bet w een a and b
f o r which f ( x ) = 0 , t o w i t h i n t h e t o l e r a n c e g i v e n .
52 Basic Numerical Tools
D e f a u l t t o l e r a n c e i s 1 . 0 e −6, i f no t o l e r a n c e i s s p e c i f i e d i n
the function c a l l .
”””
dx = abs ( b−a ) # i n i t i a l v a l u e o f dx
while dx > t o l e r a n c e : # Repeat u n t i l dx < t o l e r a n c e
x = ( a+b ) / 2 . 0
i f ( f ( a )∗ f ( x ) ) < 0 : # root i s in l e f t h a l f
b = x
else : # root i s in r i g h t h a l f
a = x
dx = abs ( b−a ) # update uncer tai nty in root l o c a t i o n
You can then include this function in any Python program, and
use it to find the root of any function you define. Just pass the
name of that function to root bisection () .
Example 2.0.3
You want to find the value of θ for which cos θ = 0.
from math import ∗
from r o o t b i s e c t i o n import ∗
t h e t a 0 = r o o t b i s e c t i o n ( cos , 0 , p i )
The bisection method is simple and very robust. If there is a root be-
tween the two initial guesses, bisection will find it. Bisection is not particu-
larly fast, though. Each step improves the accuracy only by a factor of two,
so if you start with a and b separated by something on the order of 1, and
you have a desired tolerance on the order of 10−6 , it will take roughly 20
steps. There are faster methods for finding roots.
Newton’s Method
Newton’s method of rootfinding requires that one know both the function
f (x) and its derivative f ′ (x) = dfdx
(x)
.
Start with a guess a, and calculate the values of f (a) and f ′ (a). (see
figure 2.3.) Use the point-slope form of a line to find the new point b at
2.0 Numeric Solution 53
a d c b
Figure 2.3: Newton’s method of finding a root. a is the initial guess. The
value of the function at a and the slope of the function at a leads us to
the next approximate solution at b. The function value and slope at b lead
to the approximate solution at c, and so on until the change between two
successive approximations is less than the desired tolerance.
Example 2.0.4
def r o o t n e w t o n ( f , df , g u e s s , t o l e r a n c e =1.0 e −6):
”””
Uses Newton ’ s method t o f i n d a v a l u e x near ” g u e s s ”
f o r which f ( x ) = 0 , t o w i t h i n t h e t o l e r a n c e g i v e n .
54 Basic Numerical Tools
D e f a u l t t o l e r a n c e i s 1 . 0 e −6, i f no t o l e r a n c e i s
s p e c i f i e d in the function c a l l .
I t i s r e q u i r e d t o p a s s t h i s f u n c t i o n b o t h f ( x ) and f ’ ( x ) .
”””
dx = 2∗ t o l e r a n c e # i n i t i a l dx > d e l t a
while dx > t o l e r a n c e : # main l o o p −− l o o p u n t i l
# dx < t o l e r a n c e
x1 = x − f ( x ) / d f ( x ) # Point−s l o p e form o f l i n e
dx = abs ( x−x1 ) # how much have t h i n g s changed ?
x = x1 # Here ’ s t h e new v a l u e
return x # Best v a l u e so f a r
Secant Method
The secant method is a modification of Newton’s method which has the
advantage of not needing the derivative function.
Start with two guesses, a and b. These should be near the desired solu-
tion, as with Newton’s method, but they don’t have to bracket the solution
like they do with the bisection method. Use the values of f (a) and f (b) to
approximate the slope of the curve, instead of using a function f ′ (x) to find
the slope exactly, as was done in Newton’s method. (see figure 2.4.)
Find the value of x at which the line through points (a, f (a)) and (b, f (b))
hits the x axis. Next, repeat the process with the new point and the initial
guess that is closest to the new point. Keep repeating until the change from
one iteration to the next is less than the desired tolerance.
Like Newton’s method, the secant method is not as robust as the bisec-
tion method. It can be unpredictable when used on discontinuous functions,
and the initial guesses should be relatively close to the desired root. It is
nearly as fast as Newton’s method, though, and it has the advantage of not
2.0 Numeric Solution 55
a b d c
Figure 2.4: Secant method of finding a root. a and b are the initial guesses.
The line through (a, f (a)) and (b, f (b)) leads us to the next approximate so-
lution at c. The process is repeated until the change between two successive
approximations is less than the desired tolerance.
Example 2.0.5
from pylab import ∗
from s c i p y . o p t i m i z e import b r e n t q
x = brentq ( sin , 2 , 4) # w i l l f i n d v a l u e o f x be t w een 2 and 4
# f o r which s i n ( x ) = 0
print x , x−p i
=⇒ 3.141592653589793, 0.0
Simple Method
The simplest method of estimating the integral shown in figure 2.5 is to
divide the integration range into N slices of width dx. Calculate the value
2.1 Numeric Integration 57
f(x)
x
a b
Figure 2.5: Some function f (x), integrated from a to b. The exact value of
the integral is the shaded region.
of f (xi ) at some point on each slice, and find the area Ai = f (xi )∆x for
each slice, as shown in figure 2.6. The integral is then approximately
Z b X
f (x) dx ≈ f (xi )∆x
a i
Example 2.1.1
A python implimentation of the simple integration method could
look something like this:
def i n t s i m p l e ( fn , a , b , N ) :
”””
A r o u t i n e t o do a s i m p l e a r e c t a n g u l a r −s l i c e a p p r o x i m a t i o n
o f an i n t e g r a l .
58 Basic Numerical Tools
f(x)
x0 x1 x2 x3
Δx
x
a b
fn : the function to i n t e g r a t e
a , b : l i m i t s of integration
N: number o f s l i c e s t o t a k e
”””
I = 0 # The v a l u e o f t h e i n t e g r a l
dx = ( b−a ) / f l o a t (N) # t h e s t e p s i z e , or w i d t h o f s l i c e
f or j in r a n g e (N ) :
x = a + dx ∗ j # The x v a l u e f o r t h i s s l i c e
I = I + f n ( x ) ∗ dx # add t h e area o f t h i s s l i c e
return I
This method is very simple to use and to understand, but as you can
see from figure 2.6 it’s not particularly good. If you increase the number of
2.1 Numeric Integration 59
slices, the estimate becomes better: in fact the exact value of the integral is
Z X
f (x) dx = lim f (xi )∆x
∆x→0
i
so if you use a slice width of zero, the answer is exact. The problem, of
course, is summing the infinite number of slices that accompany a slice
width of zero!
There is a limited return on investment with an increasing number of
slices. The error in each slice is the approximately triangular piece at the
top. If you use twice as many slices, each of half the width, of the original
slice, then that triangle becomes two triangles, each one roughly half the
linear size of the original. The area of the smaller triangles is each 1/4 the
area of the original, but there are two of them, so the area that is missed is
cut by half overall.
There are more precise methods of doing that rough error calculation,
but the results are the same: The precision of the result for the simple
method goes as N . Doubling the number of slices takes you twice as long,
since you must calculate f (x) for twice as many points, and the uncertainty
in your result is half what it was.
There are better ways of approximating the integral, but before we go on
to them let’s take a moment or two to improve the way we call an integrating
function. In example 2.1.1, there were actually two different things that took
place: calculation of the function to obtain the function values at regular
intervals, and summing of those values to calculate the approximate value
of the integral. Although these two seem to be parts of the same process,
there are two significant advantages to treating them separately. First, not
all integrations are integrations of functions. It is often necessary to integrate
data, in which case there is no function to call to find the next value of f (x).
Instead, the most likely form of f (x) is that of a list of data values. Second,
the simple integration method shown in example 2.1.1 is somewhat unusual
in that it uses the value of the function at any point only once. The more
precise methods described in the next few pages use the function values more
than once.
Because of these two reasons, it’s best to design our integration routines
to accept a list of function values and the spacing ∆x between those values.
This way the routine can be used more generally. For data sets, the calling
program passes the list of values to the integration routine. For functions,
the calling program calculates a list of function values once, then passes that
list to the same integration routine.
60 Basic Numerical Tools
Example 2.1.2
def i n t s i m p l e ( f , dx ) :
”””
S i m p l e s t i n t e g r a t i o n p o s s i b l e , u s i n g uniform r e c t a n g u l a r
s l i c e s . Gives a r a t h e r poor r e s u l t , w i t h e r r o r on t h e
o r d e r o f dx .
f [ ] s h o u l d be a l i s t o f f u n c t i o n v a l u e s a t x v a l u e s
s e p a r a t e d by t h e i n t e r v a l dx . The l i m i t s o f i n t e g r a t i o n
a r e x [ 0 ] −> x [ 0 ] + dx ∗ l e n ( f ) .
N = 100 # number o f s l i c e s .
# Hi gher N g i v e s b e t t e r r e s u l t s .
a = 0.0
b = pi
i n t e r v a l = ( b−a ) / f l o a t (N)
# C a l c u l a t e t h e v a l u e s o f x t o use .
x = [ a + i n t e r v a l ∗ i f or i in r a n g e (N+1)]
# n o t i c e t h a t i t t a k e s N+1 f u n c t i o n v a l u e s t o d e f i n e N s l i c e s !
print ”The v a l u e o f t h e i n t e g r a l i s a p p r o x i m a t e l y ” ,
print i n t s i m p l e ( FunctionValues , i n t e r v a l )
Trapezoid Method
We can greatly improve the efficiency of our integration by approximating
the slices as trapezoids instead of as rectangles, as shown in figure 2.7.
2.1 Numeric Integration 61
f(x)
x0 x1 x2 x3 x4
Δx
x
a b
The area each trapezoid is the width ∆x times the average height of the
slice sides:
Z b N
X f (xi ) + f (xi−1 )
f (x) dx ≈ ∆x (2.5)
a 2
i=1
If you look at the right hand side of equation 2.5 closely, you can convince
yourself that it works out to
N −1
" #
b
f (x0 ) + f (xN ) X
Z
f (x) dx ≈ + f (xi ) ∆x (2.6)
a 2
i=1
This is probably the most efficient way to code the trapezoid method, al-
though the actual function is left as an exercise.
62 Basic Numerical Tools
Simpson’s Method
The simple method approximates the function as a constant for the slices.
The trapezoid method approximates the function as a linear equation for
each slice. The next level of approximation, called Simpson’s method after
its inventor, is to approximate the function as a collection of parabolas,
with each pair of slices providing the three points necessary to define the
parabola for that region. (See figure 2.8.) The value of the integral is then
approximately
N −1
Z b 2
XZ x2i+1
f (x) dx ≈ gi (x) dx (2.7)
a i=1 x2i−1
where the gi (x) are the parabolas through the sets of three points described
previously.
The derivation of Simpson’s method is somewhat complicated, but worth
considering carefully. Start with the equation for a parabola which goes
through the three points (xk−1 , f (xk−1 )), (xk , f (xk )), and (xk+1 , f (xk+1 )):
(x − xk )(x − xk+1 )
gk (x) = f (k − 1) (2.8)
(xk−1 − xk )(xk−1 − xk+1 )
(x − xk−1 )(x − xk+1 )
+ f (k)
(xk − xk−1 )(xk − xk+1 )
(x − xk−1 )(x − xk )
+ f (k + 1)
(xk+1 − xk−1 )(xk+1 − xk )
f(x)
x0 x1 x2 x3 x4
Δx
x
a b
Each of the terms [A], [B], and [C] depend only on the numeric values at
the edges of the slices for the integrations.
The integral of gk (x) is just
Z k+1
1 1
gk (x) dx = [A](x3k+1 − x3k−1 ) + [B](x2k+1 − x2k−1 ) + [C](xk+1 − xk−1 )
k−1 3 2
(2.10)
After a few pages of careful algebra, the combination of equations 2.7–2.10
gives us a final result:
b N −1
∆x X
Z
f (x) dx ≈ (f (xk−1 ) + 4f (xk ) + f (xk+1 )) (2.11)
a 3
k=odd
Example 2.1.3
def i n t s i m p s o n ( f , dx ) :
”””
Simpson ’ s r u l e , u s i n g uniform s l i c e s .
f [ ] s h o u l d be a l i s t o f f u n c t i o n v a l u e s , s e p a r a t e d on t h e
x a x i s by t h e i n t e r v a l dx . The l i m i t s o f i n t e g r a t i o n a r e
x [ 0 ] −> x [ 0 ] + dx ∗ l e n ( f ) .
This p a r t i c u l a r a l g o r i t h m d o e s not r e q u i r e t h a t t h e r e be
an even number o f i n t e r v a l s ( odd number o f p o i n t s ) : i n s t e a d ,
i t adds t h e l a s t s e c t i o n s e p a r a t e l y i f n e c e s s a r y .
”””
# number o f p o i n t s
N = len ( f )
# i n i t i a l value of i n te g r a l
integral = 0.0
# add up terms
2.1 Numeric Integration 65
f or i in r a n g e ( 1 , N−1, 2 ) :
i n t e g r a l = i n t e g r a l + f [ i −1] + 4 . 0 ∗ f [ i ] + f [ i +1]
# m u l t i p l y by dx , and d i v i d e by 3
i n t e g r a l = i n t e g r a l ∗ dx / 3 . 0
return i n t e g r a l
Other Methods
The error of the simple measure goes as ∆x, as we showed previously, so
doubling the number of slices decreases the error in the result at a cost of
twice the computation time. The error of the trapezoid method goes as
∆x2 , so doubling the number of slices decreases the error by a factor of
four but only costs twice as much in terms of computation time. That’s
a nice gain, but Simpson’s method is even better. The error in Simpson’s
method goes as ∆x4 [11], so doubling the number of slices decreases the
error by a factor of sixteen. Doubling the slices doubles the time, of course,
but Simpson’s method is considerably more complicated than the trapezoid
or simple method so there’s an additional time cost to Simpson’s method
compared to others.
Intuition might tell you that next method in the series would approxi-
mate the integral as a cubic over each set of three slices, and that this method
would give you an error that went as some even higher power of ∆x. While
in theory that intuitive answer is correct, in practice it’s not practical to im-
plement the method. The amount of calculation for this third-order method
is so high that you can get better results for less work by increasing the
number of points on Simpson’s method rather than using a cubic method.
There are methods of numeric integration that are specialized for certain
classes of functions, and if you are curious about these I encourage you to
read more about Gaussian Quadrature (and other methods) in Numerical
Methods in C [13] or some similarly advanced text. For general use, though,
Simpson’s method is usually a good place to start.
66 Basic Numerical Tools
2.2 Differentiation
One of the tools commonly used in an introductory physics laboratory is the
“sonic ranger”. This uses pulses of sound to determine the distance between
a sensor and some object, typically a dynamics cart. The sonic ranger
measures distance only, but we would like to know velocity and acceleration.
This is an example where numeric differentiation becomes useful.
One way of finding a numeric derivative is to start from the definition of
a derivative:
f (x + xo ) − f (x)
f ′ (x) = lim
∆x→0 ∆x
So we could approximate the derivative by taking the difference between
two successive data points and dividing by the distance between them:
fi+1 − fi
fi′ ≈ (2.13)
∆x
where the notation fi ≡ f (xi ) is used to indicate the discrete nature of our
data and simplify the expression. This simple approach works, but there
are better methods.
To find some of these better methods, let’s start with the Taylor expan-
sion:
(x − xo )2 ′′ (x − xo )3 (3)
f (x) = f (xo ) + (x − xo )f ′ (x) + f (x) + f (x) + · · ·
2! 3!
or in discrete notation,
∆x3 (3)
fi+1 − fi−1 = 2∆xfi′ + 2 f + ··· (2.16)
6 i
If we take the ∆x3 and smaller terms as negligible and solve for fi′ , we obtain
the “three-point derivative” approximation:
fi+1 − fi−1
fi′ ≈ (2.17)
2∆x
The error in equation 2.17 goes as the power of ∆x in the last term we
didn’t just ignore, which is ∆x2 . Computationally, this gives us a much
better result than the simplest method for very little extra computational
cost.
We can obtain higher precision by taking the expansion of fi±2 :
8∆x3 (3)
fi+2 − fi−2 = 4∆xfi′ + 2 fi + · · · (2.18)
6
Now multiply equation 2.16 by 8 and subtract equation 2.18 to obtain the
“five-point derivative” formula:
1
fi′ = (fi−2 − 8fi−1 + 8fi+1 − fi+2 ) (2.19)
12∆x
The error in this “five-point derivative” formula goes as ∆x4 , since the 4th -
order term in the Taylor expansion cancels in each of equations 2.16 and
2.18, so our first neglected term is 5th order.
We can continue the process to obtain higher-order approximations, at
the cost of increased complexity. A disadvantage of higher-order approxi-
mations, in addition to complexity, is that derivatives near the edges of the
initial data set are lost. The five-point derivative formula can only calculate
derivatives at points 3 through N − 2.
Higher-order derivatives are available by the same process. For example,
adding equations 2.14 and 2.15 gives us
so
fi−1 − 2fi + fi+1
fi′′ ≈ (2.21)
∆x2
where the error is on the order of ∆x3 , since the third-derivative terms
cancel perfectly in equation 2.20. This is the “three-point second-derivative
68 Basic Numerical Tools
1
http://docs.scipy.org/doc/scipy/reference/generated/scipy.misc.
derivative.html
2.3 Problems 69
2.3 Problems
2-0 Write a generalized function implementing the secant method of root-
finding, similar to example 2.0.2.
2-1 Write a program that uses the trapezoid method to return the integral
of a function over a given range, using a given number of sample points.
The actual calculation should be a function of the form int trap ( f ,dx),
where f is a list of function values and dx is the slice width.
2-2 Compare the results of the simple integration method, the trapezoid
integration method from problem 1, and Simpson’s method of integra-
tion for the following integrals:
(a)
Z π/2
cos x dx
0
(b)
3
1
Z
dx
1 x2
(c)
Z 4
x2 + x + 1 dx
2
(d)
Z 6.9 π
cos x2 dx
0 2
For each part, try it with more and with fewer slices to determine
how many slices are required to give an ‘acceptable’ answer. (If you
double the number of slices and still get the same answer, then try half
as many, etc.) Parts (c) and (d) are particularly interesting in this
regard. In your submitted work, describe roughly how many points
were required, and explain.
Note: The function in (d) is the Fresnel Cosine Integral, used in op-
tics. It may be helpful in understanding what’s going on with your
integration if you make a graph of the function. For more information
on this function, see [13].
2-4 Write a program that can calculate double integrals. Use the simple
method, but instead of using rectangular slices use square prisms with
volume f (x, y)∆x∆y Check your program by using it to calculate the
volume of a hemisphere.
2-5 The Simpson’s method program developed in this chapter requires
uniform slice width. It’s sometimes convenient to integrate using slices
of varying width, for example if one needs to integrate data sets that
are taken at irregular time intervals. Write a Simpson’s method routine
that integrates over non-constant-width slices. The routine should
take two arrays as its arguments: the first array should be an array of
function values f (x), and the second an array of values of x.
2-6 The Fermi-Dirac distribution describes the probability of finding a
quantum particle with half-integer spin ( 21 , 32 , · · · ) in energy state E:
1
fF D =
e(E−µ)/kT + 1
The µ in the Fermi-Dirac distribution is called the Fermi energy, and
in this case we want to adjust µ so that the total probability of finding
the particle somewhere is exactly one.
Z Emax
fF D dE = 1
Emin
3.0 Numpy
Python lists are quite powerful, but they have limitations. Take matrices,
for example: a two-dimensional array can be expressed as a list of lists.
M = [ [1 ,2] , [3 ,4] ]
The result is something that is very much like the matrix
1 2
M= .
3 4
Addressing elements in this “matrix” is clumsy: the top-right element
would be addressed as M[0][1] instead of the more intuitive M[0,1]. More
bothersome to us in a computational physics course, though, is that although
a list of lists looks something like a matrix it doesn’t behave like a matrix
mathematically!
print M∗3
[[1 , 2] , [3 , 4] , [1 , 2] , [3 , 4] , [1 , 2] , [3 , 4]]
print M+M
[[1 , 2] , [3 , 4] , [1 , 2] , [3 , 4]]
print M∗M
TypeError : can ’ t m u l t i p l y s e q u e n c e by non−i n t o f type ’ l i s t ’
There is, of course, a package to provide real matrices to Python. Numpy,
short for “Numerical Python”, provides everything we need and much more,
in the form of numpy “arrays”. Setting up an array is similar to what you’d
do for a list of lists, but with the specification that the item is an array:
74 Numpy, Scipy, and MatPlotLib
As does addition:
print M+M
[ [ 2 4]
[6 8 ] ]
There are at least three different ways of multiplying matrices: the default
is scalar multiplication of matrix elements:
print M∗M
[ [ 1 4]
[ 9 16]]
But of course one can also do dot and cross product multiplications with
numpy:
print dot (M,M)
[ [ 7 10]
[15 22] ]
print c r o s s (M,M)
[0 0]
Example 3.0.1
Calculate sine of {π/6, π/5, π/4, π/3, π/2}.
x = array ( [ pi /6 , pi /5 , pi /4 , pi /3 , pi / 2 ] )
print s i n ( x )
[ 0.5 0.58778525 0.70710678 0.8660254 1.
]
Example 3.0.2
You are given a system of linear equations as follows, and need
to find the values of w, x, y, and z:
w + 3x − 5y + 2z = 0
4x − 2y + z = 6
2w − x + 3y − z = 5
w + x + y + z = 10
arange() Creates an “Array Range”. This is just like the range() function
built into python, except it returns a numpy array and the step doesn’t
have to be an integer.
print a r a n g e ( 0 , 1 , 0 . 2 5 )
[ 0. 0.25 0.5 0.75]
print a r a n g e ( 0 , 1 . 0 1 , 0 . 2 5 )
[ 0. 0.25 0.5 0.75 1. ]
logspace() Just like linspace () but the values are spaced so that they are
evenly distributed on a logarithmic scale. The stop and start values
should be given as the powers of 10 that are desired.
print l o g s p a c e ( 1 , 3 , 4 )
[ 1. 10. 100. 1000.]
zeros() Produces a numpy array filled with zeros of the specified type. This
is useful for setting up an empty array that your program can then fill
with calculated values. The “type” can be float or int or double (or
others) and specifies what format should be used for storing values.
The default type is float.
print z e r o s ( [ 2 , 3 ] , i n t )
[ [ 0 0 0]
[0 0 0 ] ]
3.1 Scipy 77
Numpy arrays are the standard format for any numeric work in Python,
and are the expected format for Scipy and MatPlotLib.
3.1 Scipy
As one might guess, “Scipy” is short for “Scientific Python” and it is a pack
of extensions to Python that provides numerous scientific tools. Where
numpy provides basic numeric tools such as the ability to do nice things
with matrices, Scipy provides higher-level tools such as numeric integration,
differential equation solvers, and so on.
In the previous chaptor we derived a method for calculating integrals
using Simpson’s method: Simpson’s method is included in Scipy.
from s c i p y . i n t e g r a t e import simps
The documentation for this function shows that it has some extra features
not discussed previously: pydoc scipy.integrate.simps to see these features.
Scipy also provides the ability to integrate functions (rather than lists of
y values) using Gaussian Quadrature.
from s c i p y . i n t e g r a t e import quad
print quad ( s i n , 0 , p i )
( 2 . 0 , 2 . 2 2 0 4 4 6 0 4 9 2 5 0 3 1 3 1 e −14)
The quad() function takes any function (sine, in this case) and integrates
over the range given (0, pi). It returns a tuple containing the value of the
integral (2.0) and the uncertainty in that value.
If you need to integrate to infinity, scipy provides for that also:
from s c i p y . i n t e g r a t e import i n f
print quad (lambda x : exp(−x ) , 0 , i n f )
( 1 . 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 , 5 . 8 4 2 6 0 6 7 4 2 9 0 6 0 0 4 1 e −11)
3.2 MatPlotLib
“A picture is worth a thousand words,” as the saying goes, and nowhere
is that more true than in this field. For all but the most simple numeric
problems, graphs are the best way of showing your results. The MatPlotLib
78 Numpy, Scipy, and MatPlotLib
library provides a powerful and easy set of tools for two-dimensional graph-
ing.
Example 3.2.1
Plot sine and cosine over the range {−π, π}.
from pylab import ∗
x = a r a n g e (− pi , pi , p i / 1 0 0 )
p l o t ( x , s i n ( x ) , ’ b− ’ , l a b e l= ’ s i n e ’ )
p l o t ( x , c o s ( x ) , ’ g−− ’ , l a b e l= ’ c o s i n e ’ )
xlabel ( ’x value ’ )
ylabel ( ’ t r i g function value ’ )
xlim (− pi , p i )
ylim ( −1 ,1)
l e g e n d ( l o c= ’ upper l e f t ’ )
show ( )
1.0
Sine
Cosine
0.5
trig function value
0.0
0.5
1.0
3 2 1 0 1 2 3
x value
’o’ circle
’ˆ’ upward-pointing triangle
’s’ square
’+’ plus
’x’ cross
’D’ diamond
Character Color
’b’ blue
’c’ cyan
’g’ green
’k’ black
’m’ magenta
’r’ red
’w’ white
’y’ yellow
and ylim() function calls set the range displayed on the graphs. These are
optional, and matplotlib is pretty good at selecting reasonable values if you
don’t specify any. The legend() call sets various characteristics of the legend
— in this case it is used to set the location.
The final function call in the example is show(), which draws the graph
on-screen and halts program execution until that window is closed. If in-
stead you wish to save the figure to a file, use savefig ( ’filename’ ), where the
filename should end with the type of file you wish to save. The most com-
mon filetypes are .ps, .png, and .pdf. If you wish to save the figure and show
the results, call savefig () before show() since show() halts program execution.
3.3 Problems
3-0 Solve this system of equations for a through f .
a/5 + b + c + d − e − f = 24.1312
a + c − d + 5e + f = 46.2798
−a − 3b + 2c − d − e − f = −61.8372
5b − c + d + 2e = 31.1466
a − 2b + 3c + d/2 = 51.2106
a/2 − 2b − 2c − d + e − 6f = −5.7008
3-1 A ball is thrown upwards with initial velocity vo = 5m/s and an initial
height yo = 3 m. Write a Python program to plot y(t) from t = 0
until the ball hits the ground.
3-3 For the previous problem, plot a phase-space plot. The horizontal axis
should be position, and the vertical axis velocity.
3-4 Repeat the previous two problems, but add damping to the spring-
mass system. In other words, the equation of motion for the system
is
k
ÿ = − y − β ẏ .
m
p
Assume that β < 2 k/m.
82 Numpy, Scipy, and MatPlotLib
Chapter 4
Ordinary Differential
Equations
If you give a large wooden rabbit some initial vertical velocity v over a
castle wall, you will note that the vertical component of velocity gradually
decreases. Eventually the vertical velocity component becomes negative,
and the wooden rabbit comes back to the ground with a speed roughly
equal to the speed it had when it left.
This phenomenon of “constant-acceleration motion” was probably dis-
cussed in your introductory physics course, although less Python-oriented
courses tend to use more standard projectiles. Ignoring for the moment the
fact that the exact solution to constant-acceleration motion is well-known,1
let’s use numeric techniques to approximate the solution.
To find the velocity v of the projectile, we use the definition of acceler-
ation:
dv
a≡
dt
Rearranging this a bit gives us
dv = a dt
or since we’re going to need to work with finite-sized steps,
∆v = a∆t
Knowing the initial velocity vi and the change ∆v in the velocity we can
estimate the new velocity:
d
v = vi + a∆t =⇒ vi+1 = vi + [v] ∆t (4.1)
dt
1
v(t) = vi + at, x(t) = xi + vi t + 21 at2
84 Ordinary Differential Equations
d
xi+1 = xi + [x]∆t (4.2)
dt
This method does not give an exact result, but for small ∆t it’s reasonably
close. It may seem ridiculous to use it, given that we know the answer in
exact form already, but for many problems we do not know the exact form of
the answer. If we consider air resistance, for example, then the acceleration
of a projectile depends on the temperature, altitude, and projectile velocity.
In such a case, we may have no option other than this sort of approximation.
Example 4.0.1
The equation for damped harmonic motion is given by
ẍ = −ω 2 x − β ẋ (4.4)
4.0 Euler’s Method 85
x(t)
x3
x4
x2
x1
Δt
τ
t
t1 t2 t3 t4
Figure 4.0: Euler’s method: The slope at each point xi is used to find
the new point xi+1 . The smooth curve is the actual function, and the small
circles are the approximation to the function determined by Euler’s method.
v̇ = −ω 2 x − βv (4.6)
ẋ = v (4.8)
v̇ = −g
There is a symmetry in equations 4.9 that just makes you want to write
them as a single vector equation:
where
x
y= (4.11)
v
Equations 4.8 could be written with the same vector notation:
v
ẏ = (4.12)
−g
Now here’s the critical thing: Equations 4.11 and 4.12 define the problem.
Equation 4.11 defines how things are arranged in the vector y, which holds
everything we know about the system at some instant. Equation 4.12 defines
the differential equation we’re solving.
Now if only Python could do vector math correctly. . . Lists and tuples
just don’t work at all here, since multiplying a list by a number n just gives
4.1 Standard Method for Solving ODE’s 87
us a list containing n copies of the original list. But the numpy package
provides just this vector-math functionality. (See Chapter 3.)
This vector notation allows us to break the process into two parts: defin-
ing the problem and solving the problem. We define the problem with a
function that returns the derivatives of each element in y, as in equation
4.12.
Example 4.1.1
Define a function that will return the derivatives necessary to
calculate the motion of a large wooden rabbit in free-fall.
def F r e e F a l l ( s t a t e , time ) :
”””
This f u n c t i o n d e f i n e s t h e ODE d ˆ2 x / d t ˆ2 = −g .
I t t a k e s t h e v e c t o r y and r e t u r n s a n o t h e r v e c t o r
c o n t a i n i n g t h e d e r i v a t i v e s o f each e l e m e n t i n
t h e c u r r e n t s t a t e o f t h e system .
The f i r s t e l e m e n t i n s t a t e i s p o s i t i o n x , and t h e
d e r i v a t i v e o f x i s v e l o c i t y , v . So t h e f i r s t
e l e m e n t i n t h e r e t u r n v e c t o r i s v , which i s t h e
second e l e m e n t i n s t a t e .
The r e s u l t i s r e t u r n e d as a numpy a r r a y so t h e
r e s t o f t h e program can do v e c t o r math .
”””
g0 = s t a t e [ 1 ]
g1 = −9.8
return numpy . a r r a y ( [ g0 , g1 ] )
Notice that we’ve passed “time” to the function in example 4.1.1, but we
haven’t used it. Time does not enter into the problem, since gravitational
force is a constant. We’ve included time since we’re developing a general
method for ODE’s and our method should include capability of dealing with
time-dependent equations.
Now that the problem is defined, we need a general method of calculating
the next “state” of the system.
88 Ordinary Differential Equations
Example 4.1.2
Write a general Euler’s-method routine that will calculate the
next state of the system from the current state, the derivatives,
and the desired time step.
def e u l e r ( y , t , dt , d e r i v s ) :
”””
A r o u t i n e t h a t i m p l i m e n t s E u l e r ’ s method o f f i n d i n g
t h e new ’ s t a t e ’ o f y , g i v e n t h e c u r r e n t s t a t e , time ,
and d e s i r e d time s t e p . ’ d e r i v s ’ must be a f u n c t i o n
t h a t r e t u r n s t h e d e r i v a t i v e s o f y and t h u s d e f i n e s
the d i f f e r e n t i a l equation .
”””
y n e x t = y + d e r i v s ( y , t ) ∗ dt
return y n e x t
Again, this routine thinks it needs to know the time, just to ensure
that the general method works for time-dependent ODE’s. If time does not
matter, just give it something to keep it happy. The Euler routine will pass
the time along to the derivs function, which will ignore it if it’s not needed.
Note that the code in example 4.1.1 is specific to the problem at hand,
but the code in example 4.1.2 is generally applicable any time we want to
use Euler’s method. It would be a good idea to save the definition in 4.1.2
somewhere handy so that you can just import it when needed.2
In the next example, let’s take everything we’ve done so far and put it
together.
Example 4.1.3
Write a program that plots the motion of a mass oscillating at
the end of a spring. The force on the mass should be given by
F = −mg + kx.
#! / u s r / b i n / env python
”””
Program t o p l o t t h e motion o f a mass h a n g i n g on t h e
end o f a s p r i n g . The f o r c e on t h e mass i s g i v e n by
F = −mg − kx .
”””
2
I personally keep a file called “tools.py” that contains all of the generally-handy func-
tions developed in this course, such as the secant method for rootfinding and Simpson’s
method of integrating.
4.1 Standard Method for Solving ODE’s 89
N = 1000 # number o f s t e p s t o t a k e
xo = 0 . 0 # i n i t i a l position , spring
# unstretched .
vo = 0 . 0 # initial velocity
tau = 3 . 0 # t o t a l time f o r t h e
# simulation , in seconds .
dt = tau / f l o a t (N−1) # time s t e p
k = 3.5 # s p r i n g c o n s t a n t , i n N/m
m = 0.2 # mass , i n kg
gravity = 9.8 # g , i n m/ s ˆ2
# S i n c e we ’ r e p l o t t i n g v s t , we need time f o r t h a t p l o t .
time = l i n s p a c e ( 0 , tau , N)
”””
C r ea t e a Nx2 a r r a y f o r s t o r i n g t h e r e s u l t s o f our
c a l c u l a t i o n s . Each 2−e l e m e n t row w i l l be used f o r
t h e s t a t e o f t h e system a t one i n s t a n t , and each
i n s t a n t i s s e p a r a t e d by time d t . The f i r s t e l e m e n t
i n each row w i l l be p o s i t i o n , t h e second v e l o c i t y .
”””
y = z e r o s ( [ N, 2 ] )
y [ 0 , 0 ] = xo # set i n i t i a l state
y [ 0 , 1 ] = vo
We b r e a k t h i s second−o r d e r DE i n t o two f i r s t −
o r d e r DE ’ s by i n t r o d u c i n g v :
dx / d t = v
dv / d t = k /m x − g
”””
g0 = s t a t e [ 1 ]
g1 = −k/m ∗ s t a t e [ 0 ] − g r a v i t y
return a r r a y ( [ g0 , g1 ] )
90 Ordinary Differential Equations
# Now we do t h e c a l c u l a t i o n s .
# Loop o n l y t o N−1 so t h a t we don ’ t run i n t o a
# problem a d d r e s s i n g y [N+1] on t h e l a s t p o i n t .
f or j in r a n g e (N−1):
# We g i v e t h e e u l e r r o u t i n e t h e c u r r e n t s t a t e
# y [ j ] , t h e time ( which we don ’ t c a r e a b o u t
# a t a l l i n t h i s ODE) t h e time s t e p dt , and
# t h e d e r i v a t i v e s f u n c t i o n SHO ( ) .
y [ j +1] = e u l e r ( y [ j ] , time [ j ] , dt , SHO)
p l o t ( time , xdata )
p l o t ( time , vdata )
x l a b e l ( ” time ” )
ylabel (” position , velocity ”)
show ( )
The output of the program in example 4.1.3 is shown in figure 4.1. Note
that the position is always negative, while the velocity is either positive or
negative.
1
position, velocity
80
60
40
20
position, velocity
20
40
60
800 5 10 15 20
time
Figure 4.2: Output of program in example 4.1.3, with total time 20.0 seconds
and N = 1000. Note the vertical scale!
4.3 Euler-Cromer Method 93
1
position, velocity
40 5 10 15 20
time
Figure 4.3: Output of program in example 4.1.3, with total time 20.0 seconds
and N changed to 10,000. Despite the very large number of points in this
approximation, the energy is still visibly increasing with time.
94 Ordinary Differential Equations
The most popular and stable general technique of solving ODE’s is a set of
methods known as “Runge-Kutta” methods.
I’ll start the explanation of these methods with a bit of notation. We
define y as the function we’re looking for, and g as the derivative of y. Now
g is in general a function of both y and t, so the second derivative of y is,
using the chain rule,
d
ÿ = [ẏ]
dt
d
= [g(y, t)]
dt
∂g ∂g dy
= +
∂t ∂y dt
= gt + gy g
∂g
where gξ ≡ ∂ξ . Similarly,
...
y = gtt + 2ggty + g 2 gyy + ggy2 + gt gy
where
k1 = ∆tg(y, t)
k2 = ∆tg(y + ν21 k1 , t + ν21 ∆t)
k3 = ∆tg(y + ν31 k1 + ν32 k2 , t + ν31 ∆t + ν32 ∆t)
..
.
n−1 n−1
!
X X
kn = ∆tg y + νnℓ kℓ , t + ∆t νnℓ (4.15)
ℓ=1 ℓ=1
y(t + ∆t) = y + α1 k1 + α2 k2
= y + α1 [∆tg(y, t)] + α2 [∆tg(y + ν21 k1 ), t + ν21 ∆t] (4.16)
The first and second terms in 4.16 are exact already, so we expand only the
third term:
α1 + α2 = 1
1
α2 ν21 = (4.19)
2
There are three unknowns in 4.19, and only two equations, so the system
is underspecified. We can pick one value, then. If we choose ν21 = 1, then
α1 and α2 are each 21 . These values, applied to equation 4.14, give us a
second-order Runge-Kutta method:
1 1
y(t + ∆t) = y + k1 + k2 + O(∆t3 ) (4.20)
2 2
96 Ordinary Differential Equations
where
k1 = ∆tg(y, t)
k2 = ∆tg(y + k1 , t + ∆t)
Conceptually, this second-order Runge-Kutta method is equivalent to
taking the average of the slope at t and at t + ∆t and using that average
slope in Euler’s method to find the new value y(t + ∆t).
The error in second-order Runge-Kutta method is on the order of ∆t3 per
τ
step, so after N = ∆t steps the total error is on the order of ∆t2 . This total
error is a significant improvement over Euler’s method, even considering the
roughly 2× increase in computational effort. If ∆t τ ≈ 0.01, then the error
(compared to Euler’s method) goes down by about 100, for a cost increase
of about 2. Alternately, one can use this method to get the same accuracy
as with Euler’s method for a fifth of the effort.
An important consideration is that the solution to 4.19 given by 4.20 is
one of the possible second-order Runge-Kutta methods. We could just as
easily set α1 = 0 in 4.19, in which case α2 = 1 and ν21 = 21 . In that case,
the resulting second-order method becomes
1 1
y(t + ∆t) = y(t) + ∆tg(y + k1 , t + ∆t) (4.21)
2 2
where k1 = ∆tg(y, t). This second-order Runge-Kutta method is equivalent
to taking the slope at the midpoint between t and t + ∆t, and using that
slope in Euler’s method.
Example 4.4.1
Here is a second-order Runge-Kutta method routine:
def rk2 ( y , time , dt , d e r i v s ) :
”””
This f u n c t i o n moves t h e v a l u e o f ’ y ’ f o r w a r d by a s i n g l e
s t e p o f s i z e ’ d t ’ , u s i n g a second−o r d e r Runge−Kutta
a l g o r i t h m . This p a r t i c u l a r a l g o r i t h m i s e q u i v a l e n t t o
f i n d i n g t h e a v e r a g e o f t h e s l o p e a t time t and a t time
( t+d t ) , and u s i n g t h a t a v e r a g e s l o p e t o f i n d t h e new
value of y .
”””
k0 = dt ∗ d e r i v s ( y , time )
k1 = dt ∗ d e r i v s ( y + k0 , time + dt )
y n e x t = y + 0 . 5 ∗ ( k0 + k1 )
return y n e x t
4.4 Runge-Kutta Methods 97
Example 4.4.2
A spring and mass system is shown in figure 4.4. The coefficient
of friction µ is not negligible. Generate a position vs. time plot
for the motion of the mass, given an initial displacement x = 0.2
98 Ordinary Differential Equations
k x
m
xo μ
N = 500 # number o f s t e p s t o t a k e
xo = 0 . 2 # i n i t i a l position
vo = 0 . 0 # initial velocity
tau = 3 . 0 # t o t a l time f o r t h e
# simulation , in seconds .
dt = tau / f l o a t (N−1) # time s t e p
k = 42.0 # s p r i n g c o n s t a n t , i n N/m
m = 0.25 # mass , i n kg
gravity = 9.8 # g , i n m/ s ˆ2
mu = 0 . 1 5 # friction coefficient
”””
C r ea t e a Nx2 a r r a y f o r s t o r i n g t h e r e s u l t s o f our
c a l c u l a t i o n s . Each 2−e l e m e n t row w i l l be used f o r
4.4 Runge-Kutta Methods 99
y [ 0 , 0 ] = xo # set i n i t i a l state
y [ 0 , 1 ] = vo
We b r e a k t h i s second−o r d e r DE i n t o two f i r s t −
o r d e r DE ’ s by i n t r o d u c i n g v :
dx / d t = v
dv / d t = k /m x +/− mu g
Note t h a t t h e d i r e c t i o n o f t h e f r i c t i o n a l
f o r c e changes , d e p e n d i n g on t h e s i g n o f v .
We h a n d l e t h i s w i t h an i f s t a t e m e n t .
”””
g0 = s t a t e [ 1 ]
i f g0 > 0 :
g1 = −k/m ∗ s t a t e [ 0 ] − g r a v i t y ∗ mu
else :
g1 = −k/m ∗ s t a t e [ 0 ] + g r a v i t y ∗ mu
return a r r a y ( [ g0 , g1 ] )
# Now we do t h e c a l c u l a t i o n s .
# Loop o n l y t o N−1 so t h a t we don ’ t run i n t o a
# problem a d d r e s s i n g y [N+1] on t h e l a s t p o i n t .
f or j in r a n g e (N−1):
# We g i v e t h e e u l e r r o u t i n e t h e c u r r e n t s t a t e
# y [ j ] , t h e time ( which we don ’ t c a r e a b o u t
# a t a l l i n t h i s ODE) t h e time s t e p dt , and
# t h e d e r i v a t i v e s f u n c t i o n SHO ( ) .
y [ j +1] = rk4 ( y [ j ] , 0 , dt , SpringMass )
x l a b e l ( ” time ” )
ylabel (” position ”)
show ( )
0.25
0.20
0.15
0.10
0.05
position
0.00
0.05
0.10
0.15
4.5 Scipy
As you might expect, Scipy has a routine that solves differential equations.
This function is avalable as scipy.integrate.odeint(), and it uses variable step-
sizes and error-checking methods to return very precise results, efficiently.
Call this routine with a derivs function, an initial state value (which may
be an array, as usual) and an array of times (rather than a time step.) The
odeint() function will return an array of state values corresponding to those
times.
Let’s use odeint() to look at a more complex example:
Example 4.5.1
A mass m is attached to a spring with spring constant k, which
is attached to a support point as shown in figure 4.6. The length
of the resulting pendulum at any given time is the spring rest-
length xo plus the stretch (or compression) x, and the angle of the
pendulum with respect to the vertical is θ. This is an example
Lo
θ
m L
mix of both. The differential equations for this system are given
by3
k
L̈ = (Lo + L)θ̇2 − L + g cos θ
m
1 h i
θ̈ = − g sin θ + 2L̇θ̇
Lo + L
Write a program that plots the motion of the mass for some
initial θ =
6 0.
#! / u s r / b i n / env python
”””
Program t o p l o t t h e motion o f a ” s p r i n g y pendulum ” .
”””
N = 1000 # number o f s t e p s t o t a k e
”””
We a c t u a l l y have FOUR p a r a m e t e r s t o t r a c k , h e r e :
L , L dot , t h e t a , and t h e t a d o t .
So i n s t e a d o f t h e u s u a l Nx2 array , make i t Nx4 .
Each 4−e l e m e n t row w i l l be used f o r t h e s t a t e o f
t h e system a t one i n s t a n t , and each i n s t a n t i s
s e p a r a t e d by time d t . I ’ l l use t h e o r d e r g i v e n a bove .
”””
y = zeros ( [ 4 ] )
time = l i n s p a c e ( 0 , 2 5 , N)
3
The easiest way of deriving these is via Lagrangian Dynamics, see [7].
4.5 Scipy 103
k = 3.5 # s p r i n g c o n s t a n t , i n N/m
m = 0.2 # mass , i n kg
gravity = 9.8 # g , i n m/ s ˆ2
def s p r i n g p e n d u l u m ( y , time ) :
”””
This d e f i n e s t h e s e t o f d i f f e r e n t i a l e q u a t i o n s
we a r e s o l v i n g . Note t h a t t h e r e a r e more than
j u s t t h e u s u a l two d e r i v a t i v e s !
”””
g0 = y [ 1 ]
g1 = ( L o+y [ 0 ] ) ∗ y [ 3 ] ∗ y [ 3 ] − k/m∗y [ 0 ] + g r a v i t y ∗ c o s ( y [ 2 ] )
g2 = y [ 3 ]
g3 = −( g r a v i t y ∗ s i n ( y [ 2 ] ) + 2 . 0 ∗ y [ 1 ] ∗ y [ 3 ] ) / ( L o + y [ 0 ] )
return a r r a y ( [ g0 , g1 , g2 , g3 ] )
# Now we do t h e c a l c u l a t i o n s .
answer = o d e i n t ( spring pendulum , y , time )
# Now graph t h e r e s u l t s .
# r a t h e r than graph i n terms o f t , I ’m g o i n g
# t o graph t h e t r a c k t h e mass t a k e s i n 2D.
# This w i l l r e q u i r e t h a t I change L , t h e t a d a t a
# to x , y data .
xdata = ( L o + answer [ : , 0 ] ) ∗ s i n ( answer [ : , 2 ] )
ydata = −(L o + answer [ : , 0 ] ) ∗ c o s ( answer [ : , 2 ] )
p l o t ( xdata , ydata , ’ r− ’ )
xlabel (” Horizontal position ”)
ylabel (” Vertical position ”)
show ( )
Note that in previous examples the size of our state vector y has
always been 2, but there’s nothing magic about that. We can
make it contain as many (or as few) parameters as necessary to
solve the problem.
The path of the pendulum for one set of initial conditions is
shown in figure 4.7. Changing the parameters results in very
interesting paths — feel free to explore the results with different
m, k, and initial conditions!
104 Ordinary Differential Equations
1.1
1.2
1.3
1.4
Vertical position
1.5
1.6
1.7
1.8
1.9
2.0
1.0 0.5 0.0 0.5 1.0
Horizontal position
Figure 4.7: Path of the spring-pendulum in example 4.5.1, with initial con-
ditions given in the program listing.
Let’s look at one more example, this one with a time-dependent differ-
ential equation.
Example 4.5.2
Write a “derivs” function for a damped driven pendulum:
g
θ̈ = − sin θ − bθ̇ + β cos ωt
L
elsewhere .
”””
g0 = y [ 1 ]
g1 = −g r a v i t y / l e n g t h ∗ s i n ( y [ 0 ] ) − b∗y [ 1 ] +
b e t a ∗ c o s ( omega ∗ time )
4.6 Problems
4-0 Express each of these differential equations as a set of first-order dif-
ferential equations
(a)
mẍ = f (x, t)
(b)
Aẍ + B ẋ + Cx = D
(c) r
g
mθ̈ = − sin θ − β θ̇ + γ sin ωt
L
(d)
...
y + ÿ + ẏ + y = 0
4-1 The number of radioactive atoms that decay in a given time period is
proportional to the number of atoms in the sample:
dN
= −λN
dt
Write a program that uses Euler’s method to plot N (t). Have your
program also plot the exact solution, N (t) = No e−λt , for comparison.
4-2 Write an appropriate “derivs” function for each of the differential equa-
tions in problem 0.
4-3 Write a function that impliments the 4th -order Runge-Kutta method
described in equation 4.22. Make sure it works by testing it for some
previous problem or example that used Euler’s method or second-order
Runge-Kutta.
4-4 Write a function that solves ODEs for each point on an array of time
values, such as is described on page 100. You may use whatever
individual-step routine you wish (Euler, 4th -order Runge-Kutta, etc.)
Test your routine on a differential equation with a known solution, and
show that it works.
dNSr
= −λSr NSr
dt
dNY dNSr
= −λY NY −
dt dt
Plot the relative activity of a sample of 90 Sr as a function of time. (A
logrithmic time scale will be helpful.)
Write a program that plots θ1 and θ2 vs. time for a total time τ = 20
seconds, with b = 0.1 and β = 5.0.
4-7 Redo problem 6 with damping that depends on θ̇2 instead of on θ̇. Be
careful about the sign of the damping term! You may also have to
change the size of b to obtain interesting results.
4-8 A spring-mass system with friction, such as that in figure 4.4, is driven
by an external force F (t) = A cos ωt.
a) Plot the frequency response of this system. In other words, for some
constant value of A, what is the resulting amplitude of oscillation
of the mass as a function of the driving frequency ω? Choose your
parameters so as to span the “interesting” frequency region, and
note that a logrithmic graph axis might be helpful on one or both
axes.
b) How does the frequency response change with driving amplitude
A? Write a program to make a graph that answers the question.
4-9 The rate at which a finite resource (such as oil) is gathered depends
on the difficulty and on the demand. Assume that the demand D
increases with the amount extracted E:
d
[D] = αE
dt
Assume that the difficulty of extraction W is inversely dependent on
the fraction remaining:
1
W =
1−E
Finally, assume that the rate of extraction R is the ratio of demand
to difficulty:
d D
R = [E] =
dt W
Assume also that the cost C of the resource depends on the extraction
rate and on the demand:
D
C= ξ
R
where ξ is some scale factor.
Write a program that plots the extraction rate and the cost as a func-
tion of time, for this simple model. Good starting values are Do = 0.1,
α = 2.0, and ξ = 0.01, plotted over a total time range of 0 to 5.
Chapter 5
Chaos
Let’s take a break from learning new computer techniques and algorithms
for a bit, and spend some time using what we’ve learned so far to investi-
gate something interesting. We’ll start with something familiar: the simple
pendulum.
A simple pendulum, as you probably remember from introductory physics,
consists of a point mass on a massless string as shown in figure 5.0. If the
mass is released from some initial angle θo , the torque restoring the pendu-
lum to the center is
τ = Iα = −mgL sin θ
The rotational inertia is I = mL2 , so the equation of motion for this pen-
dulum is
g
θ̈ = − sin θ (5.1)
L
At this point in your introductory physics class, you almost certainly
were told to keep the angle θ small, in which case sin θ ≈ θ. For this
approximation,
d2 θ g
2
=− θ
dt L
q
g
which is simple harmonic motion, with a known solution θ(t) = θo cos Lt .
If we plotted θ vs time, we’d get a graph something like figure 5.1. You can
see in figure 5.1 that the small-angle approximation gives a noticeably differ-
ent result from the numeric solution to equation 5.1, even at this relatively
small initial angle of 30◦ . At larger angles, the small-angle approximation
becomes progressively worse.
To make our pendulum more realistic, let’s add a damping term to equa-
tion 5.1.
g
θ̈ = − sin θ − β θ̇ (5.2)
L
5.0 The Real Pendulum 111
0.6
0.4
0.2
Amplitude
0.0
0.2
0.4
0.60 5 10 15 20 25 30 35 40 45
Time
Figure 5.1: Angular position vs time for a simple pendulum. The red curve
is obtained using scipy.integrate.odeint() on equation 5.1, the green curve is
the result of the small-angle approximation. Lg = 1.
This damping depends on the angular velocity θ̇, which would be consistent
with viscous damping or magnetic braking. The modified “derivs” function
would look like this:
def pendulum ( s t a t e , time ) :
”””
D i f f e r e n t i a l e q u a t i o n f o r a damped pendulum .
s t a t e [ 0 ] s h o u l d be a n g u l a r p o s i t i o n , s t a t e [ 1 ]
s h o u l d be a n g u l a r v e l o c i t y .
g r a v i t y , l e n g t h , and damping parameter b e t a
are g l o b a l v a r i a b l e s .
”””
g0 = s t a t e [ 1 ]
g1 = −g r a v i t y / l e n g t h ∗ s i n ( s t a t e [ 0 ] ) − b e t a ∗ s t a t e [ 1 ]
return numpy . a r r a y ( [ g0 , g1 ] )
112 Chaos
And the resulting graph of position vs time would be as shown in figure 5.2.
0.6
0.4
0.2
Amplitude
0.0
0.2
0 5 10 15 20 25 30 35
Time
g
Figure 5.2: Damped simple pendulum, with L = 1 and damping parameter
β = 0.5.
This motion is more realistic, but eventually everything just stops, which
is boring. Let’s add in a driving term as well, just to keep things going.
g
θ̈ = − sin θ − β θ̇ + A cos(ωt) (5.3)
L
This equation now represents a pendulum with a time-varying torque with
strength A and driving frequency ω. It’s trivial to add this term to our
previous “dervis” definition for the pendulum, and the resulting graph looks
like figure 5.3. As you can see, the pendulum quickly reaches a steady-state
motion. On the way to that steady-state motion, however, it actually loops
completely over the top so its new equilibrium position is around θ = 2π
rather than around θ = 0. Zero and 2π are exactly the same place, so it’s
5.1 Phase Space 113
10
4
Angle
40 10 20 30 40 50 60 70
Time
helpful to “wrap” the data: any time the data is more than π (or less than
−π) we subtract (add) 2π so that the data range is limited to the range ±π.
It’s also easiest at this point to switch the plot from lines to dots so that
you don’t get lines across the graph any time the pendulum loops around:
see figure 5.4.
1
Angle
3
0 10 20 30 40 50 60 70
Time
Figure 5.4: Same calculation as for figure 5.3, but with data “wrapped” to
the range {−π : π}
Although a phase plot lacks the time information of the type of plots
we’ve been using so far, it gives additional insight into the overall long-term
behavior of the system. For example, if we just look at the data after the
initial “transient” behavior dies out (after t = 40 in figure 5.5, for example)
we see the attractor for this system. (figure 5.6.)
The attractor is the motion at which the system eventually arrives, in-
dependent of its starting conditions. As a trivial example, consider the
undriven pendulum, figure 5.2. Regardless of the initial conditions, the pen-
dulum eventually reaches the state (0,0) on the phase plot: hanging at θ = 0,
with angular velocity θ̇ = 0. The attractor in figure 5.6 is more complicated,
but not by much.
As we lower the drive frequency, we reach a frequency at which the at-
tractor splits into a double loop instead of a single loop. We call this a
“period-2” oscillation: the period of the oscillation is twice the period of the
5.1 Phase Space 115
3 3
2 2
1 1
Angular Velocity
Angle
0 0
1 1
2 2
3 3 3
0 10 20 30 40 50 60 70 2 1 0 1 2 3
Time Angle
Figure 5.5: Plots of position (and velocity) vs. time, with corresponding
phase plot. These two plots show the same system, undergoing the same
motion.
driving force. (See figure 5.7b.) This process continues with exponentially-
rapid splits into period-4 (figure 5.7c), period-8, and so on until at some
frequency (see figure 5.7d) the motion is chaotic. Note that the initial tran-
sient behavior has been omitted from figure 5.7: what is shown is just the
attractor. Figure 5.7d is a strange attractor.
It is very important to understand that the motion shown in figure 5.7d
is not random. It repeats itself, but the period of that repetition may be
longer than the age of the universe! The motion is still deterministic: if
the pendulum is re-started in the exact same conditions, it will undergo the
exact same motion. But if the pendulum is started in even slightly different
conditions, the motion will be different although the attractor will be the
same. This sensitive dependence on initial conditions is the hallmark of
chaotic behavior.
116 Chaos
1
Angular Velocity
3
3 2 1 0 1 2 3
Angle
ω = 0.724 ω = 0.715
3
Angular Velocity 2 a b
1
0
1
2
3
ω = 0.713 ω = 0.667
3
2 c d
Angular Velocity
1
0
1
2
3
3 2 1 0 1 2 3 3 2 1 0 1 2 3
Angle Angle
ω = 0.724 ω = 0.715
3
2 a b
Angular Velocity
1
0
1
2
3
ω = 0.713 ω = 0.667
3
2 c d
Angular Velocity
1
0
1
2
3
3 2 1 0 1 2 3 3 2 1 0 1 2 3
Angle Angle
E r i c Ayars
Figure 5.9: Poincaré plot for the damped driven pendulum in chaotic motion,
at phase angle 0.
N = 300 # number o f d r i v e l a p s t o c a l c u l a t e
s k i p = 100 # don ’ t p l o t t h e s e , l e t t r a n s i e n t d i e .
# s e t up i n i t i a l c o n d i t i o n s
i n i t i a l s t a t e = array ( [ t h e t a i n i t i a l , v i n i t i a l ] )
time = a r a n g e ( 0 . 0 , N∗ ( 2 . 0 ∗ p i ) / omega d , t i m e s t e p )
# Wrap t h e s o l u t i o n s i n t o range −p i . . p i
f or i , p o s i t i o n in enumerate ( answer [ : , 0 ] ) :
while p o s i t i o n > p i :
position = position − (2.0 ∗ pi )
# There −−− t h a t s h o u l d t a k e c a r e o f too−l a r g e a n g l e s .
while p o s i t i o n < −p i :
position = position + (2.0 ∗ pi )
# And t h a t s h o u l d t a k e c a r e o f too−s m a l l a n g l e s .
# now r e p l a c e t h e v a l u e i n answer w i t h t h i s wrapped v e r s i o n
answer [ i , 0 ] = p o s i t i o n
# P u l l o u t one ” s n a p s h o t ” p e r l a p f o r Poincare p l o t
o f f s e t = 50 # ph a se o f Poincare p l o t , 0 −99.
max index = (N−s k i p ) ∗ s t e p s − o f f s e t # Don ’ t t r y g o i n g p a s t h e r e .
P thetas = [ ] # b u i l d up t h e s e l i s t s
P omegas = [ ]
f or j in r a n g e ( o f f s e t , max index , s t e p s ) :
# This l o o p p u l l s o u t a s n a p s h o t o f t h e system once p e r d r i v e c y c l e .
# I t adds t h i s s n a p s h o t t o t h e l i s t s x t h e t a s and x omegas f o r
# a l a t e r Poincare p l o t .
P t h e t a s . append ( answer [ j , 0 ] )
P omegas . append ( answer [ j , 1 ] )
# now p l o t t h e r e s u l t s
p l o t ( answer [ : , 0 ] , answer [ : , 1 ] , ’ c , ’ )
p l o t ( P t h e t a s , P omegas , ’ b . ’ )
x l a b e l ( ’ Angle ’ )
y l a b e l ( ’ Angular V e l o c i t y ’ )
xlim (− pi , p i )
show ( )
5.3 Problems 121
5.3 Problems
5-0 The Duffing oscillator is given by
ẍ + δ ẋ + βx + αx3 = γ cos ωt
Monte Carlo is a small town on the French Riviera most famous for its
casino. Because of this fame in the field of random events, the name “Monte
Carlo techniques” is given to random (or pseudo-random) methods of solving
problems on a computer.
Here’s an example. Say you have an odd shape, and you want to find
its area. One Monte Carlo technique for finding this area would be to
surround the shape with a shape of known area (a rectangle, perhaps) and
then generate a large number of random points within the known area. The
area of the shape is (approximately) the fraction of the points that fall within
the shape, times the known area surrounding the shape. (See figure 6.0.)
For this method to work, it’s necessary that our random numbers meet
three criteria:
c
Figure 6.1:
Scott Adams
Example 6.0.1
Let a = 5, b = 3, and c = 8. For a starting “seed” x0 = 1, this
generates the sequence 0, 3, 2, 5, 4, 7, 6, 1. At this point, the
sequence repeats itself.
6.1 Integration
Let’s go back now and take a closer look at the first integration example
in this chapter. The first question you should be asking is, “Why would
anyone do this?” After all, in order for the program to determine whether a
random point is inside or outside of the shape, the program will have to have
an equation for the shape. If the program has an equation for the shape,
shouldn’t it be possible to find the area by numerically integrating, using
the techniques from section 2.1? And shouldn’t direct numerical integration
be faster, by several orders of magnitude, than randomly selecting several
million points?
These objections are entirely valid, for problems with low dimension-
ality. At higher dimensions, though, direct numerical integration becomes
more difficult. The number of function calculations for numeric integration
grows exponentially with dimension. Monte Carlo integrations also increase
in difficulty with dimension, but the increase is linear. This means that
an integral that takes 10 function calls to calculate in one dimension would
take on the order of 1012 function calls in 12 dimensions. The same inte-
grals might take a million function calls in one dimension for Monte Carlo
integration, and a mere 12 million in 12 dimensions. Monte Carlo wins by
a large margin.
1
The only caveat is that the Merseinne Twister is not appropriate for cryptographic
use, as it is possible to calculate the exact state of the system given a large enough sample
of the output. This makes no difference to this course!
6.1 Integration 127
“But where,” you may well ask, “does one get a 12-dimensional inte-
gral?” It takes only two particles. Each particle has three position compo-
nents (x, y, z) and three velocity components (vx , vy , vz ). With two particles,
that’s 12 degrees of freedom.
Monte Carlo methods are still slow, though. (Actually, the problems to
which we apply Monte Carlo methods are slow.) It’s definitely worthwhile
to carefully consider any symmetries in the problem you’re facing and use
them to your advantage. For example, if the shape you are integrating is
symmetric about some axis, find the area on one side only, then double the
result. Make sure your known area is not bigger than it needs to be, and by
all means devise your test for whether the points are within the area or not
to be as efficient as possible.
Example 6.1.1
Use Monte Carlo integration to find the volume of a hemisphere
of radius 1.
We can use the symmetry of the problem to find the volume
of one quarter (the positive {x, y, z} quarter) of the hemisphere,
then multiply by 4 to get our final answer. For the known volume
surrounding our unknown piece, let’s use the unit cube: x, y, and
z range from 0–1. This range of values corresponds exactly to the
evenly-distributed random numbers given by random.random().
Here’s code to do the job:
from random import random
from math import s q r t
# S i n c e t h e r a d i u s i s 1 , we can l e a v e i t o u t o f most c a l c u l a t i o n s .
6.2 Problems
Rπ
6-0 Calculate 0 sin(x) dx using Monte Carlo techniques. Report your
uncertainty in the result, and compare with the known result.
6-1 Find the volume of the intersection of a sphere and a cylinder, using
Monte Carlo techniques. The sphere has radius 1 and is centered at
the origin. The cylinder has radius 1/2, and its axis is perpendicular
to the x axis and goes through the point ( 21 , 0, 0). (See figure 6.2.)
Report your uncertainty, also.
Stochastic Methods
Take a still beaker of water, and drip one drop of dye into the center. Over
time the dye spreads out, and eventually distributes itself evenly throughout
the water. How would we model this behavior computationally?
The direct method would be to calculate ~x and p~ for each molecule in
the beaker, but this poses some computational difficulty. Assuming 1023
molecules, with six degrees of freedom each, and a 4-byte floating-point
number for each degree of freedom, this direct method would require 2.4 ×
1012 Tb just to store the state of the system at any instant.1 In addition
to the storage problem, the direct method has limited usefulness even if it
could be implemented: We could calculate the time it would take for the
dye molecules to evenly spread throughout the water, but then if we wanted
to know how long it would take to distribute through twice the volume we’d
have to do it again! The direct method doesn’t give us any understanding
of what’s going on.
Instead of the direct method, we use stochastic methods. The fundamen-
tal idea behind these methods is that large ensembles act in an “average”
way even if individual elements are random. We lose the details about each
molecule, and only learn the behavior of the ensemble.
west. For the sake of this model, we’ll assume that the probability of either
direction is 0.5, and the step lengths are all the same. The question we’d
like to answer is, “how fast, on average, does this random walk move the
frat boy away from the Bear?”
Here’s a program that models his motion:
#! / u s r / b i n / env python
”””
F r a t b o y . py
Program t o model 1−D random w a l k
”””
N = 200 # number o f s t e p s
# s e t up s t o r a g e s p a c e
x = z e r o s ( [N] )
t = r a n g e (N)
# Do t h e w a l k
f or i in r a n g e ( 1 ,N ) :
i f c h o i c e ( [ ’ f o r w a r d ’ , ’ back ’ ] ) == ’ back ’ :
# take a s t e p back
x [ i ] = x [ i −1] − 1
else :
# take a s t ep forward
x [ i ] = x [ i −1] + 1
RMS = a r r a y ( [ s q r t ( i ∗ i ) f or i in x ] )
p l o t ( t , x , ’ b− ’ )
p l o t ( t ,RMS, ’ g− ’ )
show ( )
This program only tells us one walk, though. We need to know the aver-
age behavior of a drunk frat boy. To calculate this average behavior, we take
several thousand non-interacting drunk frat boys, or —since non-interacting
drunk frat boys don’t exist2 — we run the simulation several thousand times
2
As has been determined experimentally, drunk frat boys in groups tend to all move in
the same general direction, and burn furniture in the middle of the street. While random
7.0 The Random Walk 133
”””
f r a t b o y a v e r a g e . py
Program t o model AVERAGE 1−D random w a l k
”””
def power ( x , a , b ) :
return a ∗x ∗∗b
s t e p s = 200 # number o f s t e p s
boys = 2000 # number o f f r a t b o y s
# s e t up s t o r a g e s p a c e
x = zeros ( [ steps ] )
t = range ( s t e p s )
x sum = z e r o s ( [ s t e p s ] )
x2 sum = z e r o s ( [ s t e p s ] )
# Do t h e w a l k s
f or j in r a n g e ( boys ) :
f or i in r a n g e ( 1 , s t e p s ) :
i f choice ( [ 0 , 1 ] ) :
x [ i ] = x [ i −1] − 1
else :
x [ i ] = x [ i −1] + 1
# add x , x ˆ2 t o running sums
f or i in r a n g e ( s t e p s ) :
x sum [ i ] = x sum [ i ] + x [ i ]
x2 sum [ i ] = x2 sum [ i ] + x [ i ] ∗ ∗ 2
# rescale averages
x avg = [ f l o a t ( i ) / f l o a t ( boys ) f or i in x sum ]
RMS = [ s q r t ( f l o a t ( i ) / f l o a t ( boys ) ) f or i in x2 sum ]
in some sense, this is not the random behavior we’re interested in studying in a physics
course.
134 Stochastic Methods
p l o t ( t ,RMS, ’ g− ’ )
print ”Power f i t : y ( t ) = A ∗ t ˆB : ”
print ”A = %f +/− %f . ” % ( popt [ 0 ] , s q r t ( pcov [ 0 , 0 ] ) )
print ”B = %f +/− %f . ” % ( popt [ 1 ] , s q r t ( pcov [ 1 , 1 ] ) )
# P l o t t h e c u r v e f i t on t o p o f t h a t l a s t graph
p l o t ( t , power ( t , popt [ 0 ] , popt [ 1 ] ) )
show ( )
An RMS displacement graph for this program is shown in figure 7.0. The
RMS displacement goes as the square root of the number of steps. There’s a
good mathematical reason for this: The displacement after n steps is given
by
Xn
xn = si
i=1
where si is the step length for step i, which in this case could be either ±1.
The square of the displacement is given by
n
! n
n n
X X X X
x2n = si sj = si sj .
i=1 j=1 i=1 j=1
The second term (i 6= j) averages to zero, since the direction of the step is
random. We’re left with just the first term, which simplifies nicely to
n
2 X
s2i = n s2 .
xn =
i=1
In our present case si = ±1, so
√
hxn i = n
as is consistent with the program output.
7.1 Diffusion and Entropy 135
14
12
Average and RMS position (Steps)
10
import s y s
from pylab import ∗
from random import r a n d i n t # r a n d i n t ( a , b ) p i c k s a random i n t e g e r i n
# t h e range ( a , b ) , i n c l u s i v e .
# Allow animation
ion ()
# s e t up graph window
f i g u r e ( f i g s i z e =(10 ,10))
# D e f i n e d r o p l e t c o o r d i n a t e s ( a l l d r o p l e t s ) t o be a t p o i n t 1 0 0 , 1 0 0 .
atoms = o n e s ( [ 4 0 0 , 2 ] ) ∗ 1 0 0
# show i n i t i a l c o n f i g u r a t i o n
l i n e , = p l o t ( atoms [ : , 0 ] , atoms [ : , 1 ] , ’ r o ’ )
xlim ( 0 , 2 0 0 )
ylim ( 0 , 2 0 0 )
draw ( )
wait = raw input ( ” Press return to continue ” )
# How many s t e p s t o t a k e ?
N = i n t ( s y s . argv [ 1 ] )
f or i in r a n g e (N ) :
# Go t h r o u g h a l l atoms
f or j in r a n g e ( 4 0 0 ) :
# Check f o r boundary c o l l i s i o n
x , y = ( atoms [ j , 0 ] , atoms [ j , 1 ] )
i f x == 2 0 0 :
atoms [ j , 0 ] = 198
7.1 Diffusion and Entropy 137
e l i f x == 0 :
atoms [ j , 0 ] = 2
i f y == 2 0 0 :
atoms [ j , 1 ] = 198
e l i f y == 0 :
atoms [ j , 1 ] = 2
Figure 7.1: Output of the program diffusion.py, initially and after 5,000
steps. The light grid overlaid on both graphs is for calculation of entropy
by equation 7.1. In the initial state S = 0, and in the final S = 195.
they’re all empty. So Pi = 0 in equation 7.1 for all but the center square.
In the center square, Pi = 1 since all of the particles are there, and ln 1 = 0
so the total entropy is S = 0.
The entropy of the final state is calculated in the same way, but of course
the number of particles in each box is not zero. Writing a program to do
this is left as an exercise, in problem 2.
7.2 Problems 139
7.2 Problems
7-0 We showed in√ section 7.0 that the RMS displacement of the drunk frat-
boy goes as time. That was done for a one-dimensional walk, though.
Diffusion of dye molecule in a liquid would be a three-dimensional ran-
dom walk, instead of one-dimensional. What is the time dependence
of the RMS displacement for a 3-D random walk?
The problem with equation 8.1 is that we rarely know the exact charge
distribution in an area. We’re far more likely to know the potentials at
certain points in the area, which is quite different from knowing the charges
in that area.
Laplace’s equation describes the potential in a charge-free region. That
“charge-free” region can include all the areas between the charges in any
area we want, so we can use it to get beyond the problems in equation 8.1.
The derivation of Laplace’s equation is good material for a different course
than this one, so let’s just start with the equation itself:
We’ll start in the usual way, by breaking our space into a discrete grid
of points. Then we’ll develop a simplified expression of Laplace’s equation,
and use that to solve for the potential V .
142 Partial Differential Equations
∂V V (xi+1 ) − V (xi )
≈ (8.3)
∂x ∆x
Let’s simplify our notation a bit before we go further: we’ll define Vi ≡ V (xi ),
and so on. So Vi+1,j,k would refer to the potential at the point (xi+1 , yj , zk ).
Getting back to equation 8.3, this is actually the derivative at the point
halfway between xi and xi+1 . Let’s call that point xi+ 1 . We could also use
2
∂V
equation 8.3 to find ∂x at xi− 1 :
2
∂V Vi − Vi−1
≈ (8.4)
∂x ∆x
Of course, for equation 8.2 we actually need the second derivative. We
need this second derivative at xi , so we use the difference in the first deriva-
tive at xi+ 1 and xi− 1 in equation 2.13.
2 2
Relaxation Method
The “average” nature of the solution to equation 8.2 suggests the relaxation
method as a way of solving for the potential in charge-free regions.
1
For further discussion of this marvelous result, see [5].
8.0 Laplace’s Equation 143
1 Populate your solution grid with some initial guess of what the solution
should look like. Anything works — zero is fine — but if you have even
a coarse estimate of the solution you can save quite a bit of calculation
time by starting with that.
3 As you go, keep track of how much things change. When the largest
change is less than your solution tolerance, stop.
Of course there are some subtle —or not-so-subtle— points to keep track
of when using the relaxation method. First, you need to make sure that the
area of space in which your calculations take place is actually bounded. In
other words, make sure that the boundary of the area you’re relaxing is set
to some fixed potential. Zero usually works well, and the easiest way of
ensuring this is to initially set your guess to something that has zero on all
the boundaries, then not re-calculating the boundary elements.
Second, your solutions are going to be very boring unless there are some
fixed potential points inside the area. Don’t recalculate the potential at
those points! They’re supposed to be fixed.
A plot of the potential near a “parallel-plate capacitor” on a 100×100
grid is shown in figure 8.0. Note that this is the solution for V in a 2-D
region: in 3-D this is the equivalent to the potental around two infinitely
long parallel plates.
Over-Relaxation
We can speed the relaxation method considerably by using “over-relaxation”[4].
At each point on the grid, calculate the new value of V as before, but in-
stead of assigning the new value to the grid point calculate the change in V :
∆V = Vnew − Vold . Multiply this ∆V by some factor α, and add the result
to the original to get the new value of V at that point. In equation form,
The reason this method is faster is that V moves farther each step. It may
even move past the “correct” value, but then it will just move back the next
step. Overall, the solution converges faster.
The factor α should be between 1 and 2. α = 1 corresponds to the
regular relaxation algorithm, so there’s no benefit. Values of α greater than
2 cause the algorithm to become unstable: V will oscillate from step to step
144 Partial Differential Equations
Figure 8.0: 2-D relaxation solution for V in the region surrounding two
parallel plates held at opposite potentials. Both top and bottom show the
same information in different ways.
∂2y 2
2∂ y
= c . (8.8)
∂t2 ∂x2
We can derive this equation to some degree of plausibility by starting with
a string, as shown in figure 8.1. As you might expect by now, we break the
string into segments of length ∆x and label each segment with an index i.
The mass per length of the string is µ, so the mass of each string segment
8.1 Wave Equation 145
y
x
θi+1
θi-1 T
T
Δx
i-1 i i+1
Figure 8.1: A bit of string for deriving the wave equation. The vertical scale
is greatly exaggerated for clarity.
is µ∆x. Next, bring in Newton’s second law, F = ma, to find the vertical
2
acceleration ddt2y of segment i. The force on the string segment is just the
sum of the vertical components of tension on each side, since the horizontal
components of T must necessarily cancel out. Taking the angles θ to be
positive in the directions shown, Newton’s second law becomes
d2 y
µ∆x = T sin θi+1 − T sin θi−1 . (8.9)
dt2
For small angles, the distance between points is approximately ∆x, so
yi+1 − yi
sin θi+1 ≈ (8.10)
∆x
and
yi − yi−1
sin θi−1 ≈ . (8.11)
∆x
Substituting equations 8.10 and 8.11 into equation 8.9 and rearranging
slightly, we obtain
d2 y
T yi+1 + yi−1 − 2yi
2
≈ . (8.12)
dt µ ∆x2
But the right-hand side of equation 8.12 is just the second derivative of y
with respect to x (See equation 8.5),qso we now have the discrete-particle
T
equivalent of equation 8.8, with c = µ.
146 Partial Differential Equations
yi,n+1 + yi,n−1 − 2yi,n 2 yi+1,n + yi−1,n − 2yi,n
=c . (8.13)
∆t2 ∆x2
where r ≡ c∆t
∆x .
Let’s stop and think what equation 8.14 tells us. Remember that i refers
to position and n refers to time; so it’s saying that the position of the string
for this location at the next time step (yi,n+1 ) depends on where the string
segment is now (yi,n ), where the segment used to be (yi,n−1 ), and where the
segments on each side are at present (yi+1,n , yi−1,n ).
To use equation 8.14, we need two starting configurations. We need to
know the y value of the string at each i for n, and the y value for each i
one time-step in the past, at n − 1. The easiest way of doing this is to start
with the string at some non-equilibrium position, and not moving. Make
two arrays of y values: yold and ynow . Since the string is not moving, their
values should be the same. This produces a wave in a manner equivalent to
plucking a guitar string: the string is pulled to one side, held briefly, and
released.
Another way of generating the required two starting configurations is to
create two slightly different arrays of y values. A simple example would be
to create yold with an equilibrium configuration (zero throughout) and then
create ynew to be also zero but with one element just slightly positive. This
produces a wave in a manner similar to striking a piano string with a felt
hammer.
8.2 Schrödinger’s Equation 147
h̄2 2 ∂
− ∇ ψ + V (r)ψ = −ih̄ ψ (8.15)
2m ∂t
describes the wavefunction ψ for a quantum particle. This wavefunction can
then be used to calculate the probability of finding the particle in a given
location as well as the position, velocity, momentum, and so on.2 We can
solve Schrödinger’s equation analytically for simple cases: particles in boxes,
harmonic oscillators, and hydrogen atoms are examples. But beyond that,
we’re pretty much stuck.
We’re not going to get unstuck in part of one chapter of a book on compu-
tational physics, either! This is a complicated topic. But we can get a short
survey of one useful technique if we limit ourselves to the time-independent
Schrödinger’s equation, and to bound particles in one dimension.
h̄2 d2
− ψ + V (x)ψ = Eψ (8.16)
2m dx2
This looks straightforward enough. V (r) is the potential well in which
the particle is bound, h̄ and m are known, and E is just some constant.
There are conditions on ψ, though: ψ must be continuous, and if V is not
infinite then the derivative of ψ must also be continuous. There is also a
normalization condition: the probability of finding the particle somewhere
is exactly one, so
Z inf
ψ ∗ ψ dx = 1 (8.17)
− inf
The fascinating thing about solutions to this equation — the quantum thing,
if you will — is that these conditions result in valid solutions only for certain
values of E. The usual way of showing this is to work through an actual
solution[12] but this is a computational class, so let’s just take a brute-force
approach and see what happens.
Imagine a square potential well, symmetric about the origin, with width
2L. This well contains a single particle. Since the particle is bound by
the potential, we know that the particle energy E < V for −L < x < L.
By symmetry, we can see that there are two possible classes of solution to
Schrödinger’s equation for this configuration: symmetric and anti-symmetric
2
Take a Quantum class for more details, if you haven’t already.
148 Partial Differential Equations
Vo
V=0
-L L
it to its correct value later by using equation 8.17. For the anti-symmetric
case, the appropriate initial conditions are ψ = 0 and dψ dx = 1. Again, that
dψ
value of dx is almost certainly incorrect, but we can normalize ψ later to
correct it.
Equation 8.16 is a second-order ODE. We can simplify it further without
loss of generality by redefining our system of units so that h̄ = 1 and m = 1:
For the finite square well in figure 8.2, it’s easy to define the potential V (x):
def V( x ) :
”””
P o t e n t i a l i n which t h e p a r t i c l e e x i s t s .
L = 1
”””
i f x <1.0:
return 0 # square w e l l
else :
return Vo
We can then define the ODE for solution with odeint():
def SE( y , x ) :
”””
Returns d e r i v s f o r t h e 1−D TISE , f o r use i n o d e i n t .
R e q u i r e s g l o b a l v a l u e E t o be s e t e l s e w h e r e .
Note t h a t we a r e u s i n g x as time h e r e . . . Python doesn ’ t c a r e !
”””
g0 = y [ 1 ]
g1 = 2 . 0 ∗ (V( x)−E) ∗ y [ 0 ]
return a r r a y ( [ g0 , g1 ] )
And we can plot the resulting wavefunction ψ. If our value of E is too large
or too small, ψ diverges quickly, as shown in figure 8.3. This method is
called the “shooting method”, for reasons which are fairly obvious.
We can automate the process of finding the correct value of E, of course.
In section 2.0 we saw several ways of finding a zero of a function: this is
no different except that the “function” for which we want a zero is just
something that returns the last value of ψ in our odeint solution. Sample
code for this, using the brentq() root-finding function, is shown below.
#! / u s r / b i n / env python
”””
S E s o l v e . py
150 Partial Differential Equations
2.0
1.5
1.0
0.5
0.0
ψ
0.5
1.0
E too small
1.5 E too big
E just right
2.00.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4
x (Units of L)
hbar , m, and L a r e a l l t a k e n as 1 .
S o l u t i o n s a r e not n o r m a l i z e d .
”””
b = 2.0
Vo = 2 0 . 0 # Potential outside square w e l l
s t e p s = 100
E = 0.0 # g l o b a l v a r i a b l e , changed by F i n a l V a l u e ( )
def V( x ) :
”””
P o t e n t i a l i n which t h e p a r t i c l e e x i s t s .
L = 1
”””
i f x <1.0:
return 0 # square w e l l
else :
return Vo
def SE( y , x ) :
”””
Returns d e r i v s f o r t h e 1−D TISE , f o r use i n o d e i n t .
R e q u i r e s g l o b a l v a l u e E t o be s e t e l s e w h e r e .
Note t h a t we a r e u s i n g x as time h e r e . . . Python doesn ’ t c a r e !
”””
g0 = y [ 1 ]
g1 = −2.0∗(E−V( x ) ) ∗ y [ 0 ]
return a r r a y ( [ g0 , g1 ] )
def F i n a l V a l u e ( e n e r g y ) :
”””
C a l c u l a t e s p s i f o r t h i s v a l u e o f E, and
returns the value of p s i at point b to check divergence .
”””
global y
global E
E = energy
y = o d e i n t (SE , yo , x )
return y [ −1 , 0 ] # return f i n a l value ( psi at b )
y = zeros ( [ steps , 2 ] )
yo = a r r a y ( [ 1 . 0 , 0 . 0 ] ) # i n i t i a l p s i and p s i −d o t .
x = linspace (0 , b , steps )
E1 = f l o a t ( s y s . argv [ 1 ] )
E2 = f l o a t ( s y s . argv [ 2 ] )
plot (x , y [ : , 0 ] )
x l a b e l ( ” P o s i t i o n ( U n i t s o f L) ” )
show ( )
It is a simple matter to change this code to find the anti-symmetric so-
lutions, and one can find different solutions by giving the program different
search limits E1 and E2 . One can also easily change the shape of the poten-
tial well from square to just about anything else. With some creativity, it is
also possible to adapt this method to one-sided wells and other asymmetric
cases.
8.3 Problems 153
8.3 Problems
8-0 Write a program that uses the relaxation method to calculate and plot
the potential in a 2-D region bounded by zero potential. There are
three files in /export/250/shared/ that describe a grid of fixed poten-
tials: dipole.txt, plates.txt, and cage.txt. These files contain “0” in
the non-fixed-potential regions, and ± some value on grid points at
which the potential is held fixed. Make sure your program gives sen-
sible results for dipole.txt and plates.txt. (The solution to plates.txt
is shown in figure 8.0.) Save an image file of a plot of your solution to
cage.txt, and turn it in with your program.
8-1 Find all bound energy levels for a particle in a triangular well. The
potential should be V = 0 everywhere except in the well, in which it
drops linearly from zero at x = −L to V = −50 at x = 0 and then
climbs linearly to V = 0 at x = L. Use the simplified unit system from
this chapter: h̄ = 0, etc.
154 Partial Differential Equations
Appendix A
Linux
example, when you log into one of the Linux machines in this lab, you will
start in your “home directory”, /export/home/<username>/. This means
you are in a directory namaed with your username, which is contained in
the directory home, which is contained within export, which is contained
within /. You might have other directories within your home directory,
such as data, papers, homework, and so on. Each of these subdirectories
can contain more subdirectories or files.
Directories within Linux are identical to “Folders” in Windows or Mac
OS X. Each file in a directory must have a unique name, of course. Files
within different directories may have identical names, since their full names
(including the entire directory path) would be different.
Each directory contains a minimum of two files: “.” and “..”. The first
one is the current directory, and the second is the current directory’s parent
directory. So if you were in directory /export/home/<username>/homework/,
and wanted to refer to the file data.txt in /export/home/<username>/,
you could abbreviate it as ../data.txt. Why it would be important to
have a directory item (.) refer to the directory itself will become clear
later. . . Another useful shortcut is the “~/” directory, which is shorthand
for your home directory.
Most Linux filenames come in two parts: the name and the suffix. The
file you are currently reading, for example, is named linux.tex on my com-
puter. This file is a LATEX file, and by convention they end in .tex. Similarly,
Mathematica files are usually named something with .nb at the end, text
files end in .txt, and so on. The suffix is not required for functionality
in Linux, though: they are merely helpful for the user to figure out what
they’re supposed to be. Renaming linux.tex something like Windows.exe
would not change the contents of the file, or how the OS treated it, or any-
thing else.2 It is not uncommon to see multiple suffixes on a file, such as
backup.tar.gz, which would indicate an archive file (.tar) that has been
compressed with gzip (.gz).
One thing to be cautious of when naming files: Linux doesn’t particularly
like spaces in filenames. Spaces are the delimiters between commands, files,
and options in the command line. If you had a file named homework seven,
and wanted to edit it, the command edit homework seven would send the
operating system looking for files named homework and seven to edit. You
can get around this problem by escaping the spaces — putting a \ character
2
One minor change worth noting, though: changing the suffix will change the appear-
ance of the file’s icon if you’re using a GUI. It’s recommended that you use a file suffix
that matches the file type for this reason.
158 Linux
in front of the space to indicate that it is a space rather than a break between
separate filenames. edit homework\ seven would do what you want, there.
The best policy, though, is to avoid spaces in filenames.
man Probably the most important command if you’re new to the command
line: it prints out the MANual pages for the target. Try man ls.
ls LiSt files. Important options include -a for “All” files, and -l for a long
listing that includes size, permissions, owner/group information, and
so on. If no target is given, ls gives the contents of the current directory.
mv MoVe files. This works exactly like copy, except the original will be
removed.
available for use. The information is still there, until those drive sectors
are overwritten.) Be particularly careful with the -r option, which
removes files or directories recursively. rm -r * can be spectacularly
devastating — see the section on wildcards, page 160.
cd Change Directory. This command allows you to move around the direc-
tory tree. Assume you had three folders in your home directory: home-
work, data, and papers. From your home directory, you could give the
command cd homework to move to the homework directory, then cd
set-5 to move to the subdirectory set-5 within homework. Equiva-
lently, you could do both at the same time with cd homework/set-5.
If you then wanted to move to the data directory within your home
directory, you could give the command cd ~/data, or cd ../../data,
or cd /export/home/<username>/data. Note that the .. directory
is particularly useful, here: it is the parent directory of whatever di-
rectory you are currently in.
pwd Print Working Directory. This is useful when you forget where you
are in the directory tree: it tells you your current path.
mkdir MaKe DIRectory. This command creates a folder with the given
target name. For example, if you are in ~/labs/ and want to create a
new folder for your next experimental results, mkdir Nobel will create
an appropriately-named directory within the current directory. This
can also be used with different pathnames, of course: if you want to
make a directory within a different area on the tree, just give mkdir
the path it needs. From ~/labs/nobel/, for example, the command
mkdir ~/homework/set-8/ will create the directory set-8 in your
homework directory.
The -p option will cause mkdir to create all directories in the given
path, not just the last one. mkdir -p ~/this/is/a/long/path will
create —if they don’t exist already— five nested directories within
your home directory.
cat conCATinate files. What this actually does is print the source file(s)
out to the target file. if either source or target is missing, cat uses the
keyboard and screen. So cat file1 > file2 will list the contents
of file1 to the file file2, obliterating what was already in file2 if
anything was there. cat file1 is missing a target, so it will dump the
160 Linux
contents of file1 to the screen. cat > file2 is missing the input
file, so it will happily wait for keyboard input, and copy everything
you type to file2. (Ctrl-d will signal end-of-file in this case.) You can
probably figure out what cat file1 file2 file3 > bigfile would
do.
less Cat is not the best program for looking at what’s in a file, since ev-
erything other than the last page disappears off the top of your screen
almost instantly. The program ‘more’ was written to deal with this: it
would show you more of the file, one page at a time. Eventually, some-
one wrote an improved version of more, with lots of options and so on.
This program was more than more, and since less is more —more or
less— more more was named ‘less’.
Anyway. . . less bigfile will show you the contents of bigfile, one
page at a time.
passwd Set your password. Due to some specifics of the file-sharing sys-
tem in use in the lab, you will have to use yppasswd to change your
password, though.
Wildcards
Wildcard characters are characters that can mean multiple things.
The most common wildcard character is *, which roughly translates,
in the bash shell, as “Any number of any character”. ls *.tex would
list all LATEX files in the current directory, but it would not list texas or
lab-manual.tex.gz.
Another useful wildcard is ?, which means “one of any character”. While
ls ca* would list files like cat, cake, cab, and catastrophe, ls ca? would
list only cat and cab.
A.2 The Shell 161
Example A.2.1
You need to copy all Mathematica notebooks in your homework
directory to the directory ~/notebooks, then delete the originals.
One solution: mv ~/homework/*.nb ~/notebooks/
Although not technically a wildcard, the ‘tab’ key is certainly one you
should know. If you begin typing a command or filename and then press
‘tab’, the shell automatically completes the name for you if it can. If you
had three files in a directory named cat, catalogue, and catastrophe,
and you wanted to look at the contents of catalogue, you could type less
catal(tab) and the shell would fill in the rest of the filename. If the shell
can’t figure out what you mean, it will beep at you when you press ‘tab’.
Pressing ‘tab’ again will cause the shell to list the options it thinks you may
mean, so you can continue typing letters until you have a unique selection.
There are other wildcards also, and entire books on how to use them. [8]
Pipes
Each of the commands explained in this chapter is actually a program:
A small, finely-crafted single-purpose program. The true power of Unix-y
systems comes from the ability to string these small programs together. The
output of one becomes the input of the next, and so on. A single command,
then, can invoke several programs, each of which does its thing and passes
the results to the next.
Two of the important commands regulating this behavior are “|” and
“>”. The first one, “|”, is the “pipe” command. It simply means to take
the output of whatever came before the pipe and give it as input to whatever
comes after. The second, “>”, means “send the output to . . . ”. If you follow
“>” with a filename, or something that the OS interprets as a file name,
then the results will be written to that file.
Some others which are worth brief mention include “>>”, which means
“Append to . . . ”, and “<”, which translates roughly to “Get from . . . ”.
Example A.2.2
You need a text file named “paper-length” that contains a list
of all the LATEX files in a directory and the number of words in
each, sorted by size.
One solution: wc -w *.tex | sort -n > paper-length
162 Linux
Example A.3.1
You need a folder that can be used as a “drop box” for your
fellow 300B students. In other words, a folder into which they
can place files, but can’t get them out or see what’s there. People
not in the phys300B group should have no permissions in this
folder.
Solution:
mkdir dropbox
chgrp phys300B dropbox
chmod go-rx,g+w dropbox
text editor. The better text editors on Windows offer options to save files
with the appropriate line endings, but it may be easiest to use a terminal-
based text editor that runs on the remote machine, such as nano or vim, if
you are forced to work on a Windows machine.
X forwarding
The terminal-based methods described above are limited in that they only
allow one to do (and see) what could be done from within the terminal
window. GUI-based text editors such as bluefish will not work under this
method, and any graphical output of your program will not be displayed.
It is possible to redirect all of the graphical output of the server to your
local machine using “X Forwarding”. On a Macintosh, this would require
that X11 be installed — it is one of the optional installation packages on
the system-install DVD. Start X11, which will give you a terminal window
on the Macintosh, or open a new terminal window if you’re using a Linux
machine. Give the command ssh -X richard.csuchico.edu, and from
then on any graphical windows that would normally open on the Linux
machine are instead sent to your local machine. This requires a relatively
fast internet connection to be usable.
Under Windows, you will need to use PuTTy and either XWin-32 or
XMing. There are good explanations of how to do this on the web: Google
“Windows X forwarding” for a helpful set of instructions.
A.7 Problems
A-0 A good password should be a mix of upper-case, lower-case, numeric,
and symbol characters. It should be at least 8 characters long, and
longer is better. It should not be a word in any known language or a
name, as such passwords are easily cracked by dictionary attacks.
One excellent method of choosing a password is to use a phrase you can
easily remember, then take the first letter of each word in the phrase.
For example, “Four score and seven years ago our forefathers. . . ”
would become “Fsasyaof”. This could be made stronger by replac-
ing letters that looked like numbers with the numbers: “F5a5ya0f”.
“$5a5ya0f” would be even better — replace the “Four” with a “Capi-
talized” 4.
Log in and change the password on your account in the lab. Don’t use
“$5a5ya0f”: it’s no longer a strong password.
A-1 Create a directory called Chapter.1 in your home directory in the lab.
Create a text file called numbers.txt in this directory which contains
the numbers 1–9, spelled out, one number per line.
Now use a single unix command to create a file called bemnrsu.txt
which contains those numbers, alphabetized.
What’s that command? Add that command to the end of the bemnrsu.txt
file, then create a folder named with your last name in the directory
/export/classes/phys312/dropbox/ and move the file to that directory.
A-2 Use the find command to list all files in your home directory that
are less than one day old. (The man command will probably be useful
here!) What’s the command to do this?
A-3 Create the following text file:
#! / u s r / b i n / env python
A-5 Create a file called junk in your home directory. Put some random
text in it, then look carefully at the file’s listing using ls -lh.
Run this command:
chmod 200 junk
Use ls -lh again, and notice the difference. Try viewing the file with
less junk or cat junk. What happens?
Append more lines to the file using cat >> junk. (Use ctrl-d to indi-
cate that you’re done adding lines.) Does this work? (And how would
you tell?)
Run this command:
chmod 400 junk
Try viewing the file again. Try adding to the file again. Delete the file.
What worked, what didn’t work? What were the differences? Why?
Spend whatever time is necessary to figure out what’s going on, here.
The chmod command with three digits afterwards is different than
what’s described in this text, and it’s very useful. What would be
the permissions resulting from chmod 664 <filename>? What 3-digit
number would you use to give a file the permissions rwxr-x--x?
Visual Python
The “Visual Python” package (VPython for short) is a set of routines that
allow easy access to 3-D graphics from within Python. VPython was origi-
nated by David Scherer in 2000, while he was a sophomore Computer Science
major at Carnegie Mellon University, and since then has been used exten-
sively by the physics education community, most notably Bruce Sherwood
and Ruth Chabay. [14, 2] As of this writing, VPython is on version 5 and
is available for Linux, Macintosh, and Windows.1
VPython takes care of all the display management: the drawing of vari-
ous objects, shading, perspective, and so on. All that the programmer has
to do is define the objects and then update their characteristics as needed.
The display is updated automatically as soon as the objects’ characteristics
change.
Example B.-1.1
Write a simulation showing that circular motion is a combination
of two simple harmonic motions.
#! / u s r / b i n / env python
”””
Program showing two s i m p l e harmonic motions a t 90 d e g r e e s
t o each o t h e r , and t h e r e s u l t i n g c i r c u l a r motion o f t h e i r
intersection .
”””
from v i s u a l import ∗
RodWidth = 0 . 1
R = 1.0 # Circle radius
SphereRadius = 0 . 2
theta o = 0.0
omega = 1 . 0
dt = 0 . 0 1 # time s t e p
time = 0 . 0
# I n i t i a l s e t u p o f system
VerticalRod = c y l i n d e r (
pos=(R∗ s i n ( t h e t a o ) , −R, 0 ) ,
c o l o r=c o l o r . red ,
r a d i u s=RodWidth ,
axis =(0 ,2 ,0) ,
o p a c i t y =0.6)
HorizontalRod = c y l i n d e r (
pos=(−R, R∗ c o s ( t h e t a o ) , 0 ) ,
c o l o r=c o l o r . red ,
r a d i u s=RodWidth ,
axis =(2 ,0 ,0) ,
o p a c i t y =0.6)
Dot = s p h e r e (
pos=(R∗ s i n ( t h e t a o ) , R∗ c o s ( t h e t a o ) , 0 ) ,
c o l o r=c o l o r . y e l l o w ,
r a d i u s=SphereRadius ,
o p a c i t y =0.5)
Trace = c u r v e ( c o l o r=c o l o r . y e l l o w )
# Keep d o i n g t h i s i n d e f i n i t e l y
while True :
time = time + dt
# c a l c u l a t e x and y w i t h r e s p e c t t o time .
x = R∗ s i n ( omega∗ time )
y = R∗ c o s ( omega∗ time )
# update p o s i t i o n s of o b j e c t s .
B.0 VPython Coordinates 171
VerticalRod . x = x
HorizontalRod . y = y
Dot . pos = ( x , y , 0 )
# and t h e t r a c e a l s o
Trace . append ( Dot . pos )
box A box has color, position (pos), length (x extent), height (y extent)
and width (z extent). The position of the box refers to the center
of the box. The box can also have an axis, which is the vector de-
scribing the box’s x axis. (by default, the box x axis matches the
window’s x axis.) In addition, the box has an “up”, which is a vector
describing the box’s y axis. (by default, the boy y ayis matches the
window’s y ayis.) Between pos, axis, and up it is possible to put a box
in any orientation in space. In addition to specifying length, width,
and height individually, it is possible to define the size of the box via
size =(length, width, height) .
cone The cone has color, pos, axis, and radius. The position refers to the
center of the cone’s base, and the axis is the vector from the position
to the apex of the cone. The radius is that of the cone’s base.
cylinder Cylinders have position (pos), color, radius, and axis. It helps
to think of a cylinder as a vector: the position of the cylinder is the
location of the tail of the vector, and the axis describes the length and
direction of the cylinder. A short cylinder looks like a disk, of course.
frame A frame allows one to form composite objects that can be moved
and rotated as if they were one object. For example:
pendulum = frame ( )
c y l i n d e r ( frame=pendulum ,
pos = ( 0 , 0 , 0 )
r a d i u s =0.1
c o l o r=c o l o r . b l u e
a x i s =(0 , −1 ,0))
s p h e r e ( frame=pendulum ,
pos =(0 , −1 ,0)
r a d i u s =0.2
c o l o r=c o l o r . cyan )
pendulum . a x i s = ( 0 , 1 , 0 ) # change o r i e n t a t i o n o f e n t i r e frame
pendulum . pos = ( 1 , 2 , 1 ) # change p o s i t i o n o f e n t i r e frame
You can change the parameters of all objects in a frame with a for
loop:
B.1 VPython Objects 173
f or item in pendulum . o b j e c t s :
item . c o l o r=c o l o r . g r e e n
color There are nine built-in colors in VPython: red, green, blue, yellow,
orange, cyan, magenta, black, and white. These are specified by, for
example, “color=color.red”. You can also specify RGB values for any
color you want:
c o l o r=c o l o r (R,G, B)
Once this has been done, it’s important to specify which display each
new object belongs to:
b a l l = s p h e r e ( d i s p l a y=s c e n e 2 , pos= . . . )
materials It’s possible (with an appropriate video card) to specify the ap-
parent material for an object. Currently-available materials include
wood, rough, marble, plastic, earth, diffuse, emmisive (glowing) and
unshaded (unaffected by lighting).
Home = s p h e r e ( m a t e r i a l=m a t e r i a l . e a r t h )
opacity Objects are usually opaque, but the opacity of most objects can
be specified with a number from 0.0 (completely transparent) to 1.0
(completely opaque).
C r y s t a l B a l l = s p h e r e ( o p a c i t y =0.2)
B.2 VPython Controls and Parameters 175
rate When you’re working on a fast computer, the system can update the
picture much faster than you can watch it. The rate(N) function limits
the speed of the loop containing it to N frames/second. (See example
B.-1.1.)
rotate It’s possible to rotate objects around an arbitrary axis using the
rotate () function. The following command would rotate “object” coun-
terclockwise through an angle of 45◦ around a vertical axis located at
(1,0,0):
o b j e c t . r o t a t e ( a n g l e=p i / 4 . 0 , a x i s = ( 0 , 1 , 0 ) , o r i g i n = ( 1 , 0 , 0 ) )
B.3 Problems
B-0 Create a ball and a floor, and write a simulation showing the ball
bouncing on the floor.
Least-Squares Fitting
The simplest non-trivial case is the linear case, and it turns out that if
you solve the linear case you can often solve others with some appropriate
algebraic work, so we’ll start with the linear case and work from there.
Imagine that you have some data set such as the one shown in figure
C.0. Although there’s noise in the data, it’s clear that the data is linear:
y = ax + b. The best line through this data would be the line for which the
sum of the distances between the line and the data points is a minimum.
As it turns out, though, the distance between the line and the points
could be either positive or negative. This means that there are some as-
tonishingly bad lines that would have the same sum of deviations as the
“right” line. Taking the sum of the absolute values of the deviations would
seem to be better, but the absolute value function causes severe mathemat-
ical difficulties when you attempt to take derivatives. The solution to these
problems is to minimize the sum of the squares of the deviations of the data
points from the line.1
1
Thus the name “Least-squares fitting”, as you can probably guess.
178 Least-Squares Fitting
Figure C.0: Somewhat noisy (x, y) data, and the ideal line through that
data.
C.0 Derivation
Now let’s start some math. We want to minimize the sum of the deviations
of the data points from the line. The line is given by
y = ax + b (C.1)
so the vertical deviation2 of the ith data point (xi , yi ) from the line is
δi ≡ yi − (axi + b) . (C.2)
The sum of the squares of all these deviations is then
n
X n
X
δi2 yi2 − 2axi yi − 2byi + a2 x2i + 2abxi + b2 .
∆≡ = (C.3)
i=1 i=1
2
Note of course that this vertical deviation of a data point from the line is not generally
the same as the perpendicular distance between the point and the line. An equivalent
derivation using the perpendicular distance is considerably more complicated, and gives
no significant improvement in results.
C.0 Derivation 179
n n n
∂∆ X X X
= 0 = −2 yi + 2a xi + 2 b. (C.5)
∂b
i=1 i=1 i=1
At this point, it’s helpful to divide both equations by n and make the fol-
lowing substitutions:
n
1X
x≡ xi
n
i=1
n
1X
y≡ yi
n
i=1
n
1X 2
x2 ≡ xi
n
i=1
n
1X
xy ≡ x i yi
n
i=1
ax2 + bx = xy (C.6)
and
ax + b = y . (C.7)
Once the averages x, y, xy, and x2 are calculated, equations C.6 and
C.7 form a system of two equations with two unknowns, a and b. These
equations can be written in matrix form as
x2 x a xy
= . (C.8)
x 1 b y
where3
−1
x2 x 1 1 −x
= ,
x 1 x2 − x2 −x x2
so
xy − x y
a= (C.10)
x2 − x2
and
x2 y − x xy
b= . (C.11)
x2 − x2
We can also calculate our uncertainty in a and b. The deviation of any
point (xi , yi ) from the line y(xi ) is given by
δi = yi − (axi + b) (C.12)
Example C.1.1
You have data for which you believe the equation to be y = AxB ,
and you want to find the values of A and B that best fit this
data.
Take the natural log of both sides of the equation:
ln y = ln A + B ln x
y ′ = b + ax′
A = eb B=a
• Begin by defining the function f (x) that will be fit to the data. The
function should take an array of x values and any adjustable parame-
ters as inputs, and should return an array of y values. For example, a
power fit function of the form
• Make sure you have your x and y data in array form. (Usually these
data arrays are read from a data file.) If you have uncertainties δy in
the data points, have those in another array.
• Call curve fit() with the function name, the x data, the y data, the
initial guess, and (optionally) the uncertainties. The routine will re-
turn two items: the first is an array containing optimal values of the
parameters, the second is a matrix containing the estimated covariance
of those optimal values.
popt , pcov = c u r v e f i t ( power , xdata , ydata , g u e s s , dy )
C.3 Problems
C-0 Write a least-squares fitting function. The function should accept two
lists (or equivalents) containing x and y data points, and should return
a tuple containing the slope, the uncertainty in the slope, the intercept,
and the uncertainty in the intercept for that data.
C-2 Use scipy.optimize.curve fit() to do a linear fit of the same data from
problem 1. Compare your results, and the uncertainties in your results.
184 Least-Squares Fitting
References
[1] Philip R. Bevington and D. Keith Robinson. Data Reduction and Error
Analysis for the Physical Sciences. McGraw-Hill, 1992.
[2] Ruth Chabay and Bruce Sherwood. Matter & Interactions: Electric
and Magnetic Interactions, volume 2. John Wiley and Sons Publishing,
2002.
[6] Mark Lutz and David Ascher. Learning Python. O’Reilly & Associates,
2nd edition, 2004.
[8] Cameron Newham and Bill Rosenblatt. Learning the BASH Shell.
O’Reilly & Associates, 2nd edition, 1998.
[10] Tiara Norris, Brendan Diamond, and Eric Ayars. Magnetically coupled
rotors. American Journal of Physics, 74(9):806–809, September 2006.
[15] Randal L. Schwartz and Tom Phoenix. Learning Perl. O’Reilly and
Associates, 3rd edition, 2001.