Computational Modeling and Visualization of Physical Systems With Python
Computational Modeling and Visualization of Physical Systems With Python
http://www.wiley.com/college/wang
Acknowledgments
5.2 Chaos
5.6 Fractals
7 Electromagnetic fields
11 Thermal systems
List of programs
Bibliography
Index
Chapter 1
Introduction
In this book, we will be discussing computational modeling of
physical systems ranging from classical to quantum systems.
The primary factor that makes this possible is the speed of
computation offered by digital computers. In this sense,
computer modeling is simply a tool to get the job done, just like
the abacus or the calculator of the past. It is an important tool,
enabling us to simulate a range of systems from the simple
projectile motion but with added realism such as drag and spin
effects to the complex behaviors of many-body problems or
time-dependent quantum systems. Computational modeling is
important and often indispensable in the study of these
systems.
In [1]: %precision 17
x=0.6
a=(1−x*x)**(0.5)
a
Out[1]: 0.80000000000000004
In [2]: 1−a
Out[2]: 0.19999999999999996
In [4]: 1. + 1.e−15 == 1.
Out[4]: False
In [5]: 1. + 1.e−16 == 1.
Out[5]: True
In [9]: x*x/(1+(1−x*x)**0.5)
Out[9]: 5.0000000000000005e−17
Round-off error
Round-off error can occur in arithmetic operations of floating
point numbers for several reasons (see Section 1.A). The floats
may not be exactly representable, or some significant bits are
lost during shifting. Even if the floats are exactly representable
or no shifting is involved, the intermediate results could
require more mantissa bits to hold the full accuracy than the
working precision could provide, resulting in rounding off.
Truncation error
To produce a concrete result, we normally use a practical
method, or an algorithm, for the calculation. There is usually a
difference between the obtained result and the exact result.
This is known as the truncation error. The size of the error
should be dependent on the method, and unlike round-off
error, it is entirely under our control by the choice of the
method.
Figure 1.1: Approximating the circumference of a circle by polygons.
Table 1.1 lists the ratio of the polygon perimeter to the exact
circumference of the unit circle for several n values. Roughly
with every quadrupling of n, the numerical result gains one
significant digit. The method is stable and allows systematic
improvement of accuracy. Most algorithms in our simulations
are chosen to minimize or control truncation error.
Stability
Often, stability is a factor in controlling truncation error.
Consider the golden mean . It is a
root to the quadratic equation2
We may wonder why the method works well for one series
(ϕ) but fails terribly for another (ϕ_). The reason is that both ϕ
and ϕ_ are present (even a small amount caused by round-off
error) in the recursion since both are solutions of Eq. (1.4). The
growing ϕ series completely overwhelms the vanishing ϕ_
series. A small error is quickly amplified and washes out the
latter in a few steps.3 The behavior is not related to, and cannot
be solved by higher float precisions. It is the property of the
recursion (1.5). There is a silver lining, though: if the upward
recursion is unstable, the reverse direction must be stable. We
can use this fact to accurately obtain the ϕ_ series by
downward recursion (Project P1.3). Stability conditions of
some common recursions can be found in Ref. [1].
1.3.1 PYTHON
Like driving, the only way to learn programming is to just do it.
Let us write a Python program to compute and graph one-
dimensional motion with constant acceleration a. Taking the
initial value to be zero, the position x as a function of time t is
, where v0 is the initial velocity. The program is
given below and results in Figure 1.3 (see Section 1.B on how to
run programs).
As our first full example, Program 1.1 may feel longer than
necessary. It is okay if you do not understand fully what is
going on here. We will explain the program below, but after
working through the rest of this chapter to the middle of
Chapter 2, it will become clear. The program has three basic
blocks: initialization (lines 1 to 5), computation (lines 7 to 10),
and data presentation (lines 12 to end). Most programs
generally follow this template.
Conditional controls
Besides the “for” loop above, Python has a conditional while
loop (see Program 2.1)
while (condition):
……
if (condition):
……
elif (condition):
……
else:
……
Both the elif and else are optional, and there can be
multiple elif statements. There is also an inline if-else
expression that yields a value depending on the condition:
x = a if condition else b
File handling
Among Python file handlers, the easiest way may be to read
from and write data to files via the pickle module. Structured
data records can be loaded or dumped easily (see Program 9.7
for an example). A quick way to handle text files can be found
in Program 4.4.
In [1]: 1/2
Out[1]: 0
In [2]: 2.0**(1/2)
Out[2]: 1.0
Built-in help
Python has an online help system that can provide information
on keywords, modules, etc. It is invoked by
In [7]: help()
help>
1.3.3 MATPLOTLIB
Matplotlib is a Python library for data plotting and graphical
presentation in 2D and 3D. It is easy to make quality graphs
with Matplotlib, interact with them like zooming, and save to
standard file formats. At the same time, almost every aspect of
a Matplotlib plot is customizable, making it possible to do hard
or odd things, such as twin axes with different scales or even
data animation (see Figure 3.16, Programs 8.1 and 10.2, and
Matplotlib gallery for examples).
1.3.4 VPYTHON
VPython is a graphics programming library for Python. It
makes manipulation and dynamic animation of illuminated
three-dimensional objects easy and accessible to the end user.
It offers a rich and interactive environment to render the
simulation process or data sets as dynamic movies on the
screen. Program 2.1 shows a simple example of a bouncing ball
(Figure 2.1). We use VPython extensively. In nearly all cases,
animation can be turned off (commented out) without affecting
the non-visual aspect of the simulations, or replaced with
either Matplotlib output (see Exercise E2.1) or data files for
separate analysis.
Run the example, and interact with the animation. You can
view the scene from different perspectives by right-button drag
(or Ctrl-drag) to change the camera angle. You can also zoom in
or out by middle-button drag (Alt-drag, or left+right on a two-
button mouse).
Chapter summary
General references
PROJECTS
P1.1 Write a program to convert a floating point number to its
bit pattern. The program should take the input from the
user and print out the bit pattern (sign, and the rest in
groups of 4 bits) for the float, assuming single precision.
Test your program with the results shown in Table 1.2.
See if you can break the program into logical modules.
P1.2 Consider the roots of the quadratic equation ax2 + bx + c
= 0,
including 1 bit for the sign, 8 bits for the exponent interpreted
as a signed integer between [−128, 127], and 23 bits for the
mantissa as a fraction according to Eq. (1.6). Since the
mantissa has a lower bound , the first bit (most
significant) of the mantissa in Eq. (1.8) is always 1, and by
convention, it is normally not stored explicitly (so-called
phantom bit). The mantissa actually represents the next 23
bits, for an effective 24-bit length. This means that single
precision floats are accurate to ∈ = 2−24 ~ 6 × 10−8, or about 7
digits. The value ∈ is called the machine accuracy in Eq. (1.2).
The range of single precision floats is [2−128, 2127], or roughly
10−38 to 1038.
.B Python installation
In addition to Python 2.7x, we need the following four
packages: NumPy, SciPy, Matplotlib, and VPython. Optional
packages include IPython, SymPy (both recommended), and
IVisual. IPython is a user-friendly Python shell (see below).
SymPy, a symbolic mathematics library for Python, is not used
in our numerical computation, but is handy nonetheless for
many tasks such as algebra, exercises (see Exercise E2.7 and
Exercise E3.10), etc.
Python distributions
The easiest way to get a full installation up and running quickly
is through all-in-one distributions such as:
Anaconda, http://continuum.io/downloads;
Canopy, https://www.enthought.com/products/canopy/;
Python(x,y), https://code.google.com/p/pythonxy/ (Windows
only);
WinPython, http://sourceforge.net/projects/winpython/.
Custom installation
In general, use binary installers if possible, and stick with one
version (32- or 64-bit) consistently. All required packages have
binary installers at their web sites built for the official
python.org Python (Table 1.3). Binaries built for other Python
installations including all-in-one distributions are usually not
compatible. The online resource of the book has updated
installation instructions and the needed binaries for Windows
at:
You can also use the pip tool to install packages from
Python Package Index, https://pypi.python.org/, for any
platform including Linux. The typical command line is $ pip
install xyz for installing package xyz. Note that pip is in the
Scripts directory of a Python installation, so make sure it is in
the command path (C:\Python27\Scripts\ on Windows).
The pip tool can also install packages in the “wheel” format,
e.g., $ pip install xyz.whl. For Windows, many binaries built
by Christoph Gohlke for the official Python including
Matplotlib dependencies can be found at
M: python-2.7.8-macosx10.6.dmg
M: VPython-Mac-Py2.7-6.10.dmg
NumPy
numpy.org W: numpy-1.8.2-win32-superpack-
python2.7.exe
SciPy
scipy.org W: scipy-0.14.0-win32-superpack-
python2.7.exe
M: scipy-0.14.0-py2.7-python.org-
macosx10.6.dmg
Matplotlib
matplotlib.org W: matplotlib-1.4.0.win32-
py2.7.exe; requires python-
dateutil, pyparsing and six
(binaries at UCI)
M: matplotlib-1.3.1-py2.7-
python.org-macosx10.6.dmg
IPython
ipython.org W: ipython-2.4.0-py27-none-
any.whl (from UCI)
SymPy
sympy.org W: sympy-0.7.5.win32.exe
$ pip list
This will list the locally installed packages. Use pip to install
missing dependencies (if any) or other packages.
Running programs
If you have installed the required packages successfully,
congratulations! You are about to enter the exciting world of
simulations, and you can now run all the programs discussed in
the book.
$ ipython [notebook]
where x and y are the data set, and string is an optional string
specifying the color, line style, or marker type of the curve.
There are also many other optional arguments. The string is
normally a three-character field, ’CMS’, for color, marker, and
line style, respectively. Refer to Table 1.4 for common codes.
The order of the character in the string is unimportant. For
instance, the string ’g-o’ means a green solid line with filled
circle markers.
In [7]: a [ : ]
Out[7]: array([0, 1, 2, 3, 4])
In [8]: a[1:3]
Out[8]: array([1, 2])
In [9]: a[:3]
Out[9]: array([0, 1, 2])
In [10]: a[2:]
Out[10]: array([2, 3, 4])
In [11]: a[::−1]
Out[11]: array([4, 3, 2, 1, 0])
Note that a[:] returns the whole array, but a[] would be
illegal.
Array manipulations
Elements can be inserted or removed from ndarrays. The
following example inserts a “9” in front of the original index “1”
of a, and deletes the element at index “2”:
In [12]: np.insert(a,1,9)
Out[12]: array([0, 9, 1, 2, 3, 4])
In [13]: np.delete(a,2)
Out[13]: array([0, 1, 3, 4])
In [14]: 2*a
Out[14]: array([0, 2, 4, 6, 8])
In [15]: a+3
Out[15]: array([3, 4, 5, 6, 7])
When the scalar “3” is added to the array, it is cast into an array
of the same dimension (called broadcasting) internally and
then the arrays are added element by element. Since no explicit
looping is invoked in Python, the speed gain is considerable for
larger arrays. For explicit looping, Python lists are faster.
In [17]: b=np.copy(a[1:3])
b
Out[17]: array([−1, −2])
In [18]: b[:]=[−3, −4]
b
Out[18]: array([−3, −4])
In [19]: a
Out[19]: array([ 0, −1, −2, 3, 4])
Advanced indexing
Copies of ndarrays can also be obtained with advanced
indexing. This occurs when the index is not simply an integer.
The following code obtains a copy with a list index which
triggers advanced indexing. Again, the source array is not
affected:
In [20]: c=a[ [ 1, 2 ] ]
c
Out[20]: array([−1, −2])
In [21]: c[:]=[−5, −6]
c
Out[21]: array([−5, −6])
In [22]: a
Out[22]: array([ 0, −1, −2, 3, 4])
In [25]: a[a>0]
Out[25]: array([3, 4])
In [26]: a[a<0]
Out[26]: array([−1, −2])
In [27]: a[a==0]
Out[27]: array([0])
In [28]: a[a<0]=0
a
Out[28]: array([0, 0, 0, 3, 4])
All elements of the array less than zero are set to 0 in the above
example.
Multidimensional arrays
Multidimensional arrays can be created and handled similarly.
For instance, zeros((2,5)) will create a 2-row by 5-column
array filled with zeros. Each dimension is called an axis, so axis
0 refers to going down the rows, and axis 1 to going across the
columns.
The array can be accessed with two indices and sliced like
before, but the results may be scalars, one-dimensional arrays
(row or column vectors), or two-dimensional sub-arrays:
In [31]: d[1,2]
Out[31]: 23
In [32]: d[0]
Out[32]: array([11, 12, 13])
In [33]: d[ : , 1 ]
Out[33]: array([12, 22, 32])
In [34]: d[ 1 :, : 2 ]
Out[34]: array([ [21, 22],
[31, 32]])
The target d[:,[0,2]] refers to the first and third columns of all
rows, and the source d[:,[2,0]] specifies the third and first
columns of all rows. Slicing and advanced indexing work
together to enable us to swap the columns in a single
statement. See Program 9.9 for examples in actual codes.
Universal functions
NumPy arrays of the same shape can be added, subtracted,
multiplied, or divided, all element-wise. Python operators like
+, −, *, /, **, etc., are context-aware. When acting on ndarrays,
operations are carried out element-wise transparently and
automatically, irrespective of the type of operands as long as
they can be broadcast into an ndarrary.
2
Another form for Eq. (1.4) is ϕ/1 = (ϕ+1)/ϕ, meaning that the ratio ϕ to 1 is the same
as ϕ + 1 to ϕ. This “perfect” ratio has inspired artists and architects in history.
3
A quantitative von Neumann stability analysis is discussed later (Section 6.5.4).
4
There seems to be a specialized library for any task. Want to fly? Try import
antigravity.
5
Some may prefer to use more descriptive names. We try to use short names if they do
not lead to confusion. Here, ta and xa designate time and position arrays.
6
If the animation does not show in the notebook, restarting the IPython kernel usually
fixes it.
7
In binary arithmetic, dividing by 2 is equivalent to shifting the bits to the right by one
position.
8
On Windows, the keyword “python” can be omitted. Any program entered at command
line (cmd.exe) with .py extension should automatically invoke Python.
9
One can also run most VPython programs without VPython installation in a web
browser via GlowScript (glowscript.org), or capture output to a movie (see vpython.org).
10
There are also online tutorials, e.g., scipy-lectures.github.io.
11
If necessary, we can also make a non-ufunc to a unfunc by vectorizing it with a NumPy
module named, well, you guessed it: vectorize().
Chapter 2
Free fall and ordinary
differential equations
Many problems in physics and engineering are expressed in the
form of either ordinary or partial differential equations
(denoted ODEs, or PDEs). To a large part, this seems to be due
to the fact that mathematical descriptions of problems of
interest, especially the complex ones, simplify significantly
when we consider only infinitesimal changes of the variables
involved. The result is the emergence of differential equations
of one form or another. Take Newton’s second law F = ma, for
example. Since the acceleration a is the second derivative of
position with respect to time, Newtonian mechanics always
involves differential equations, be it free fall on earth, or star
motion in the sky. Another example is wave motion such as a
vibrating string. To describe waves, we must treat the space
and time variables independently. This leads to wave equations
in the form of PDEs. Therefore, solving differential equations is
a major undertaking in scientific computing.
Some ODEs, like those for free fall, yield analytic solutions
in closed-form, known functions. Others do not, so numerical
solutions are needed. Because ODEs are among the single,
most common class of mathematical relations used across
science and engineering including this book, we will devote this
chapter to the discussion of methods of numerical solutions
suitable to the problems we study (PDEs will be discussed
separately starting from Chapter 6). The ODE solvers
developed here will be used throughout this book. We will first
study one ODE at a time, and generalize it to a set of coupled
ODEs. The collection of these methods serves as a toolbox that
will be applied to computer simulations in subsequent chapters
where analytic solutions are rarely known.
The rest of the program sets the step size and the initial
velocity (lines 7 and 8), then enters the while loop. The “rate”
function (line 10) inside the loop is another VPython module
that limits the rate of animation so it will not run too fast on
fast machines. The position of the ball is updated by changing
the variable ball.pos.y by an amount v*h each time (line 11).
Since it is an attribute of the sphere object assigned to ball,
VPython, running in the background and keeping track of all
attributes of objects created, will automatically redraw the ball
at the new position, creating the animated effect. The last if-
else statement checks to see if the ball is above the floor: if it is,
the velocity is updated according to free fall with constant
acceleration −9.8 m/s2 (line 13); otherwise, it is reversed (line
15).
To see how this works out, let us use the Taylor series (2.4)
again, first at the beginning of the step as (using same notation
as in last section)
and then at the end of the step as
Figure 2.4: Illustration of the fourth order Runge method (a), and the
Kutta method (b).
The notations used in Eq. (2.18) are the same as in Eq. (2.16).
Alternatively, we can divide the step size h into three
intervals, and evaluate the derivative at 0, h/3, 2h/3, and h
(Figure 2.4(b)). This leads to the Kutta formula
Both formulas work fine. We will stick with the simpler Runge
formula (2.18). The RK4 method is self-starting and efficient.
There are more elaborate methods around, but a basic RK4
with some step size adjustment as necessary will serve us well
in most situations. Except for certain cases such as
Hamiltonian systems to be discussed later, RK4 is the
recommended method as the general ODE solver in our
simulations. Of course, we will develop appropriate methods
for special problems we encounter going forward.
We might well ask, why stop at the fourth order RK4? Can
we not continue to higher orders? As it turns out, higher than
fourth order will require more function calls to f(y, t) than the
order number. For example, a fifth order Runge-Kutta method
would need six function calls (see Runge-Kutta-Felhberg
method, Section 2.3.2). So the RK4 is a natural place to stop.
to
……
k1 = h*(v0 − g*t) # k1, for clarity only, not needed
k2 = h*(v0 − g*(t+h/2.0)) # k2=f(y+k1/2, t+h/2)
y = y + k2 # RK2 method
……
……
y = RK2(velocity, y, t, h) # call RK2
……
Euler method
To illustrate this point, let us port Euler’s method, Eq. (2.7), for
a single ODE to a system of coupled ODEs, Eq. (2.28). Instead
of using yn, yn+1 for the start and end values in each step, we
adopt a slightly different notation as
RK2 method
Higher order methods like RK2 can be ported over in exactly
the same way. We vectorize the single ODE version (2.16) as
The actual code given in Program 2.3 works for a single
ODE as well as a system of ODEs, provided the derivatives are
returned as vector ndarrays.
def go(v0):
……
y1 = RK2(freefall, y0, t, h)
……
RK4 method
By now we know the routine pretty well. We can vectorize RK4
(2.18) so it becomes applicable to a system of ODEs. This is
shown below.
Implicit methods
All the methods we have discussed so far are explicit: given the
initial conditions, we march forward for solutions at later
times. There are cases where explicit methods are not suitable,
and even fail to produce acceptable solutions. For instance, stiff
differential equations are known to be ill-suited for explicit
methods. To obtain accurate solutions to these equations, the
steps size h needed with explicit methods is often much smaller
than that for non-stiff differential equations. The reason is
usually due to terms varying over very different time scales.
Implicit methods such as the backward Euler method are often
used for such cases. We will encounter one such case in Section
8.3.1.
Figure 2.5: Phase space plot of the harmonic oscillator for two
energies, E2 > E1.
Figure 2.7: Phase space plot of the harmonic oscillator (top), and the
relative error in energy (bottom) for ω = 1 rad/s. The results are
calculated with the Euler (Eul), RK2, and the leapfrog (LF) methods.
Chapter summary
E2.3 Follow through one working cycle of the RK2 method for fr
fall similar to Eq. (2.35) of Euler’s method. Show that in RK
(2.16)
E2.4 Prove that the leapfrog method, Eqs. (2.41) to (2.43), is time
reversible. Use primed variables to represent reversed motio
and let . Show that after one step, the
PROJECTS
P2.1 Simulate free fall using Euler’s method and VPython.
#y = Euler(…)
y = RK2(…)
ball.pos=(y[0],y [1])
(c) Reduce the step size h by half and repeat (b). Discuss
the changes and trends in the results.
(e) Do the same using RK4 and RK45n, but with different
initial conditions of x = 5 and v = −4. You can use the
same derivative function as in (c). Discuss and compare
the performance of the two methods relative to each
other.
The game ends when one side reaches zero, and the other
side is the winner.
(a) Say you are the last one to join, and you are free to
choose either group. The current situation is as follows:
69 Humans with a kill rate 2, and 99 Zombies with a kill
rate 1. There are fewer Humans, but they have twice the
kill rate. If your goal is to win, which group would you
join? Choose wisely (and write it down).
Note that the pre-transformed variables for the second and the
third steps are (x1/2, v0) and (x1/2, v1), respectively.
1
We may also turn Eq. (2.5) around to find the derivative by two-point numerical
differentiation, dy/dt ≈ [y(t + Δt) − y(t)]/Δt. The error term is O(Δt). However, we can do
better with two points using the midpoint method, Eq. (2.13).
2 5
Tests show that creating 10 two-element ndarrays is about 30 times slower than
comparable lists.
3
To validate a program, it is always important to check the results against exact solutions
if available, or against conservation laws such as energy and angular momentum, etc.
4
The use of symplectic methods has completely transformed our understanding of the
stability of the solar system by extending accurate time integrations from millions of years
prior to 1990s to timescales comparable to the age of the solar system (see Ref. [65] and
Chapter 4).
Chapter 3
Realistic projectile motion with
air resistance
One of the most classic and well-known problems in physics is
projectile motion. Tossing a ball in the air, we expect to see it
move in a familiar arched path. Under ideal conditions
assuming constant gravitational acceleration and negligible air
resistance, projectile motion is analytically solvable, i.e., its
solutions are expressible in closed-form, known functions. Its
properties such as the parabolic path are well explained from
introductory physics. Free fall discussed in Chapter 2 is a
special case of one-dimensional ideal projectile motion, while
the general case is three-dimensional.
Linear drag
Physically, the first term in Eq. (3.3) comes from viscosity of
the medium. The linear coefficient b1 can be calculated from
Stoke's law applicable to laminar (smooth) flow. We can
understand qualitatively how b1 comes about from Newtonian
physics.
Figure 3.2: Viscous fluid flow between two moving plates.
Quadratic drag
The second term in Eq. (3.3) arises when the flow is turbulent,
meaning that it is no longer laminar in nature. The
dimensionless Reynolds number defined as
For instance, the drag force of the form (3.7) with constant
Cd is adequate for most projectile problems. We could certainly
fine tune the model, e.g., by including some velocity
dependence in the coefficient Cd. In fact, experimental evidence
shows that Cd is velocity-dependent and not a constant over all
the range of v. This dependence is displayed in Figure 3.4.
Bisection method
The bisection method is a simple and sure way of finding a
root, provided we know in advance that there is at least one
root within an interval (bracket). It relies on the fact that the
function f(x) changes sign when passing through a root. The
basic idea is shown graphically in Figure 3.6.
Figure 3.7: Newton's method of root finding. The left panel shows
the successive steps of the process. In each step, the x-intercept of the
tangent line is found, which is used as the next estimate for the root.
The process is repeated until the change of the intercept is within
allowed accuracy. The right panel shows the unstable nature of this
method. In this case, the intercept cycles between two points
endlessly.
Newton's method
Compared to the bisection method, Newton's method for root
finding requires not only the function f(x) itself, but its
derivative f′(x) as well. It can be a lot faster and more efficient
when it works, but may also be unstable and less robust.
Nonetheless, there are situations when this method is useful
and appropriate, or even preferred.
The results (Figure 3.8) for two initial speeds show a steep
rise from small angles to the maximum, and a shallower falloff
toward larger angles. The maxima occur at angles much earlier
than 45°, and there is no symmetry as there would be for ideal
projectile motion. Achieving the maximum range requires
optimal balancing between the time of flight and the horizontal
velocity. With air resistance, it is more important to have a
larger horizontal velocity and a smaller time of flight because
the former decreases exponentially (3.12), leading to a smaller
angle θmax that maximizes the range.
Figure 3.9: The Lambert W function for real argument x. The two real
branches are: the principal branch W0 (solid line), and the secondary
−1
branch W−1 (dashed line). The branch point is at x = −e and W =
−1.
Evaluation of W
Unlike elementary functions, the Lambert W function has yet
to make its way on a handheld calculator with a dedicated
button. Fortunately, it can be computed efficiently and
accurately using the root finders we have discussed.5 For a
given x, the value of the W function is the root w to
7 for i in range(nmax):
w, v = (w*w + x*ma.exp(−w))/(1.0+w), w # Eq. (3.27)
9 if (abs(w−v) <= 1.e−15*abs(w)): break # to double precision
return w
The module lambertw() accepts an argument x and an
optional branch switch. If the argument is invalid, a type None
is returned. Otherwise, it computes the value by Eq. (3.27) and
checks for convergence in the loop. The convergence is fast,
usually to machine accuracy in just a few iterations in nearly all
cases.
This is the analytic solution for the range in terms of the special
Lambert W function. Since the argument z in Eq. (3.32) is
negative, and W(z) is multivalued with two branches (Figure
3.9), how do we decide which one to use, W0 or W−1?
Mathematically, both are correct solutions. Physically, the valid
choice is the primary branch W0, since W−1 would produce a
negative range. It is understood that W0(z) must be used in Eq.
(3.32).
It is clear from the sketch that as air flows past the aerofoil,
it is bent downward. There must be a net downward force
exerted on the airflow by the aerofoil. By Newton's third law,
the aerofoil experiences an equal magnitude but opposite force
from the airflow, i.e., an upward lift.8
Figure 3.12: The Magnus effect on a spinning ball. Airflow past the
spinning ball (counterclockwise) is bent downward. The direction of
the force on the ball is given by the vector product ,
upward here.
Here, ρ and A are the air density and cross section, respectively
(same as in (3.7)), and r is the radius of the ball. Effects of both
drag and Magnus forces should be included in more realistic
simulations of projectile motion, and are considered next.
Forces on a baseball
With the drag and lift coefficients determined, we can examine
and compare quantitatively the forces acting on a baseball in
flight. They are shown in Figure 3.14.
Figure 3.15: Views of a curveball from the front, behind, and above
(bird's eye). Also shown is the ideal projectile motion (darker/green,
without the ball). The coordinates are such that from the bird's eye, x
axis points to the right, y axis out of page, and z axis down.
A final caveat: in all likelihood, the ball's spin rate (ω) is not
constant, and there is little data at present on how it precisely
changes. If we assume the torque is proportional to angular
velocity, we expect an exponential decay (see Eq. (3.12)) as
with v in m/s.
Ping pong is rather unique due to its small mass and the
compact playing area. Of all ball sports, spin is most important
in ping pong games. Top spin rates can easily reach 6000 to
8000 rpm, and top speeds can be more than 40 m/s. These
factors make ping pong one of the fastest sports where quick
reaction and accurate anticipation of ball movement is crucial
[98].
Soccer corners
Last but not least, we turn our attention to the most popular
sports the world over, soccer. The soccer ball is considerably
bigger and heavier than the cases discussed so far, but the
effects of drag and spin are no less important [97]. Casual
spectators can easily spot the curving of the ball in long passes.
Curving is such an important art in soccer that set plays such as
direct kicks or corner kicks are major scoring opportunities. In
direct kicks, for example, players form a human wall to block
the direct path of the ball to the goal. However, a skilled player
could curve the ball around the wall and score. Direct scoring is
also possible, albeit more difficult, in corner kicks.
Figure 3.20: Drag and lift coefficients for soccer [5, 36]. The data for
the lift coefficient correspond to different Reynolds numbers from
5
3.3 to 4.5 × 10 .
19 theta = rtf. bisect (fy, 0.6, 1.2, 1.e−6) # Step 3: shoot for θ
if (theta != None): print(’ theta(deg)=’,theta*180/np.pi) #
result
Chapter summary
E3.8 (a) Use both the bisection and Newton's methods to find
3
the roots of f(x) = 5x−x3. Investigate what happens
when the initial guess is at ±1 in Newton's method.
PROJECTS
P3.1 (a) Integrate animation into Program 3.2 so that the
projectile and its trail are displayed during flight as in
Program 3.1. Place the camera to capture the scene from
different angles, e.g., forward , reverse , top
Now turn off drag (b1 = 0) and run the program again.
Do the results converge to the ideal case?
Let (x1, y1) and (x2, y2) be the positions of the projectile
at t1 and t2, respectively. Connecting the points by a
straight line, the equation of the line is
(c) Plot the x-t, y-t, and y-x curves calculated with the
drag force and compare each with the respective curve
in the ideal case. Find the range and maximum height of
the baseball.
(e)* Track the work done by the drag force and verify
that the work-energy theorem is satisfied by testing the
relation Wdrag ≈ E − Ei, where
(b) How does θmax scale with large v0? First, make a
qualitative prediction. Now, calculate θmax for different
values of v0, say between 10 and 1000 m/s. Double the
speed each time to space out the data points. Plot the
results on a semilog scale for v0. You should automate
the process of finding θmax. Keep θmax to at least two
significant digits. Does your prediction and the results
agree? Why or why not?
P3.7 Like other ball sports, the American football is also full
of physics [33].9 It is typically thrown with a speed of
80 to 90 km/h. Use the optimum launch angle from
Project P3.6 if available, or else θ = 30°.
(b) Assume you want to hit a golf ball directly over the
tree top which stands at 10 m high and 120 m away.
With an initial speed of 60 m/s and a backspin of 8000
rpm, find the angle (at least two significant figures) so
your shot just clears the tree top. Compare the cases of
constant and changing drag and lift coefficients.
while (True):
10 xmid = 0.5*(a+b)
fmid = f(xmid)
12 if (fa*fmid > 0.0): # root in [xmid, b]
a, fa = xmid, fmid # set a=xmid and save a function call
14 else: b=xmid # root in [a, xmid]
if (fmid == 0.0 or abs(b−a) < eps*gap): break # root found
16
return xmid
5 for i in range(nmax):
delta = fx/df(x)
7 if (i == 0): gap = abs(delta) # save initial gap
x = x − delta # ’improved’ root
9 fx = f(x) # prep for next round
if (fx == 0.0 or abs(delta) < eps*gap): break # root found
11
return x
22 def go(x, y, vx, vy): # motion with full drag and spin effects
h, t, Y = 0.01, 0., np.array ([[x, y, 0.], [vx, vy,0.]]) # initialize
24 while (Y[0,0]<R and Y[0,1]>0.2): # before homeplate&above ground
vp.rate(40)
26 t, Y = t+h, ode.RK4(baseball, Y, t, h) # integrate
ball.pos, spin.pos = Y[0], Y[0]−offset # move ball, arrow
28 spin.rotate(angle=phi), ball.rotate(angle=phi,axis=omega) #spin
trail.append(pos=ball.pos)
30 ideal.append(pos=(x+vx*t, y+vy*t−0.5*g*t*t, 0.)) # ideal case
while (not scene.kb.keys): # check for key press
32 vp.rate(40)
spin.rotate(angle=phi), ball.rotate(angle=phi,axis=omega)
34 scene.kb.getkey() # clear key
trail.append(pos=(0,0,0), retain=0) # reset trails
36 ideal.append(pos=(0,0,0), retain=0)
1
We should not confuse the velocity dependence with kinetic friction which is
independent of velocity. For kinetic friction, the contact surface does not move with the
body.
2
Laminar and turbulent flows can be observed in a column of rising smoke, say from a
burning incense. At first, the column is smooth as silk, and is laminar. As the column rises, it
spreads and starts to develop twirls and twists, and becomes turbulent.
3
To quote the 5th century BC philosopher Laozi: the longest journey starts with a single
step.
4
SciPy also has a general root solver, scipy.optimize.fsolve. See Exercise E3.8.
5
The Lambert W function is also available in the SciPy special function library,
lambertw, and in SymPy as LambertW.
6
It can also be solved more quickly (and opaquely) with SymPy, see Exercise E3.10.
7
Numerical extraction of the scaling law is rather tricky because of the slow-varying
logarithmic term ln β in Eq. (3.33) (see Project P3.2).
8
Another common explanation invokes Bernoulli's principle. The flow velocity is greater
on the top than on the bottom, resulting in a net upward pressure difference, hence the lift.
But we think the third-law argument is more direct.
9
See the so-called “Deflategate” in which the New England Patriots team was alleged of
deflating or under-inflating the football to gain an unfair advantage in a playoff game, and
the science behind it in The New York Times Sports, “Upon scientific review”, January 30,
2015. The team won that year's Super Bowl. See also Section 11.4.4 on pressure and
temperature.
10
Having no root bracketed is not an uncommon error, so type None should be inspected
by the calling program to make sure a legitimate root is found.
Chapter 4
Planetary motion and few-body
problems
In projectile motion discussed in Chapter 3, gravity is
considered to be constant. This is an approximation, valid only
for distances small compared to the size of Earth. Now imagine
we stood atop Mt. Everest and fired a cannon horizontally. At
low speed, the cannonball would travel just like projectile
motion. With greater firing power and ever increasing speed,
the cannonball would travel further and curve less. At some
critical speed, it would fly all the way around Earth and come
back from behind (ignoring drag, of course). This is exactly
how the Moon moves around Earth, or the planets around the
Sun. In a sense, planetary motion is akin to projectile motion in
that a planet falls continuously toward the Sun. We can no
longer treat gravity as a constant force, however.
.1 Motion of a planet
Planetary motion is by and large governed by Newton's theory
of gravity. The force F obeys the inverse-square law
Note that the mass of the planet, m, is canceled out, and the
force components have 1/r3 dependence because of the vector
in the numerator. Assuming the motion is confined in the xy
plane, the vectors have only x and y components.
9 def go():
r = np.array([1.017, 0.0]) # initial x,y position for earth
11 v = np.array([0.0, 6.179]) # initial vx, vy
29 GM = 4*np.pi*np.pi # G*Msun
go()
After setting the time and step size, the program enters the
main loop, which is functionally similar to the loop in Program
2.7. Because this is a Hamiltonian system, the leapfrog
integrator is called to advance the solution in time (line 25).
The position of the planet is updated (line 26) after every step,
leaving a trail automatically. The program pauses if a key has
been pressed (line 27). It then calls scene.kb.getkey() twice,
first to read the key and then to wait for the second key press
before continuing.2 Finally, we define a constant GM=4π2 which
sets the unit of mass (to be discussed shortly) before executing
the main function. Earth should move around the Sun
repeatedly over the same path. In other words, the orbit is
closed.
I encourage you to play around with Program 4.1, e.g.,
change the initial position or velocity slightly, turn off
(commenting out) the sunlight, disable the trail, or add spin to
the planet (see Program 3.8), etc.
We now have two of the three basic units. The third one
should be about mass. Often we need the ratio k/m = GM with
M being the mass of the Sun, as in Eq. (4.3). If we assume
circular motion such as the Earth around the Sun, then
With a mean radius r = 1 AU, the period is 1 year, and the speed
is v = 2π AU/year (29.77 km/s). Using the reduced mass given
by (4.2), we get
.3 Precession of Mercury
Astronomers have long known that the orbits of planets precess
with time [25]. Since observations are carried out on Earth
which wobbles like a gyroscope (called precession of equinoxes,
not our concern here), the data must be analyzed to separate
the kinematic effects from true dynamic effects. This is
equivalent to going to the fixed space frame where the Sun is at
rest. Reduction of measurements of the inner-most planet,
Mercury, indicates a precession rate of 574 seconds of arc per
century in the space frame (1 arcsecond, or ″, is 1/3600°). In
other words, the perihelion (or aphelion, Figure 4.3) of
Mercury slowly rotates through an angle of 0.16 degrees per
century.
The problem is (or was), taking into account all the known
perturbations present on Mercury due to these planets (within
Newtonian theory of gravity), and after careful number
crunching, the precession is expected to be about 531″ for
Mercury per century (Table 4.2). That would leave 43″
unaccounted for, or 0.012 degrees/century. This is a very small
amount, but well beyond observational uncertainties to be
ignored.
Now rewrite Eqs. (4.21) and (4.22) in terms of s using the chain
rule ,
The above equations are in the proper form for the leapfrog
method if we treat and t as the generalized “coordinates”, and
and W as the generalized “velocities”. Equations (4.27a) and
(4.27b) are the exact analogue to Eq. (2.44), and Eqs. (4.27c)
and (4.27d) to Eq. (2.45). We are free to choose any form of
Ω(r). A good choice for planetary motion (and other 1/rn
forces) is
Once we are certain that the oscillations are real, what is the
physical reason for them? We note that there are about four
oscillations per year, or the period is about 1/4 years. This is
just the orbital period of Mercury (Table 4.1). Therefore, the
oscillations might be connected to the orbital period. With
animation turned on and with an artificially large λ ~ 0.01, we
can observe the phenomenon visually. Let us assume that
Mercury starts at the aphelion going counterclockwise, with the
Runge-Lenz vector pointing at the perihelion (Ay = 0). The y-
component, Ay, has two terms from Eq. (4.86), Ay/m2 = −vxL −
GMy/r.
We see from Eq. (4.40) that ψ has the same range as θ, i.e.,
when θ changes from 0 to 2π, so does ψ. Furthermore, the two
variables are equal at 0, π, and 2π, no matter the eccentricity e.
We recognize that the last term means that the center of mass
is the origin. The initial velocities (all along y-axis) are
Let us call the third body of mass m the test body. Its mass
is considered so small compared to the two primaries, i.e.,
m/M1,2 ~ 0, that it has no effect on the motion of the primaries,
which rotate around the center of mass at constant angular
velocity ω and constant separation. We are only concerned with
the motion of the test body. Though the restricted three-body
problem is an idealized situation and no actual systems behave
exactly like it, it is still a very good approximation for many
systems, including the motion of a satellite (test body) in the
Earth-Moon system, or of the asteroids in the Sun-Jupiter
system. The simplification allows us to gain much insight from
studying such systems.
where (x, y) are the coordinates of the test body in the rotating
system. The calculation of velocity or acceleration must take
the rotating coordinates into account. Details are given in
Appendix 4.A. For example, according to Eq. (4.72) the
acceleration is,
Table 4.3: RTB unit system for the restricted three-body problem.
For small α, all five Lagrange points lie close to the unit
circle r = 1. While the locations of L4 and L5 can be found
analytically, the locations of L1, L2 and L3 need to be solved
numerically. But for α 1, the following series expansion can
be used (Exercise E4.11)
The largest orbit (Figure 4.19, bottom) goes all the way
around the C-shaped ridge. Its initial condition is
, . It appears to be periodic with a
period of 33 (~ 390 years). The motion is very delicate,
navigating along the equipotential lines. It does not seem to be
connected to any asteroid motion at present.
The top figure shows the orbit for four Pluto periods.
Starting near L5 and the perihelion, we can see that Pluto's
orbit dips inside Neptune's orbit by a small amount. It is about
0.013 length units when Pluto is closest to the Sun. The length
unit is the distance between Neptune and the Sun, or 30 AU
from Table 4.1. That means Pluto penetrates Neptune's orbit by
about 0.39 AU, or nearly 40% the orbital radius of Earth. After
one Pluto period, Pluto is again closest to the Sun but at the
crossover loop diagonally opposite from the starting position
near L5. It takes two periods for Pluto to return to the starting
position. If we look carefully at the crossover loop near L5, we
find that the orbit is not closed. The loop has rotated to the left.
During this time, Neptune has revolved around the Sun three
times.
We may then ask, how did Pluto end up in its current orbit?
It is possible that Pluto, at the time it was formed, happened to
be right where it is now, locked in a stable configuration due to
Neptune's perturbation. It is also possible, arguably more
likely, that Pluto evolved into its current orbit over a long
period of time (billions of years). There is evidence which
suggests that Pluto's motion may be chaotic [88]. It may well
be that we are seeing a Pluto that has been marching on its
chaotic path all along.
Chapter summary
Starting with an animated motion of a planet, we briefly
reviewed useful properties of central field motion and Kepler's
orbits. We then discussed precession of Mercury due to
corrections of the general theory of relativity. Because the effect
is small, we introduced the Runge-Lenz vector as a sensitive
indicator of precession. An accurate and area-preserving
method, the leapfrog method with time-transformation, was
implemented to simulate this process. We found an interesting
effect that precession is oscillatory, not monotonic. Precession
of classical origin due to other planets was also discussed
within the framework of central field approximation.
reduced to , where is
Hamiltonian given by .
momentum, respectively.
E4.5 Suppose that, instead of Ω(r) = 1/r, we choose Ω(r) = 1/r2 a
the time transformation. Rewrite the corresponding
equations of the leapfrog method to Eqs. (4.29a) to (4.29f).
Discuss the merits and shortcomings of this time
transformation.
E4.6 (a) A total mass M is uniformly distributed over a ring of
radius a. A point particle of mass m is placed at a distance r
from the center and in the plane of the ring. Show that the
potential energy between the particle and the ring is given
by Eq. (4.30).
(b) Expand the potential for r/a < 1 and r/a > 1, keeping fou
terms in each case. Verify Eq. (4.31), and explain why onl
even terms appear. You may wish to use SymPy to expan
the integrand,
(b) Carry out the algebraic details to prove Eq. (4.39) fro
(4.37).
E4.9 (a) The periodic orbit shown in Figure 4.14 is unstable but
reversible. First find its period. One way to do so is to add a
text box to Program 4.5 using the label() function of
VPython, see Program 4.3 for an example. Output the time
information, and record the period T when the three bodies
return to their initial positions (4.51). To make it easier, you
can pause the program by intercepting key presses with
scene.kb.keys and scene.kb.getkey(). The system
should start to come apart after roughly two periods. Wait
until the bodies are well off their orbits, and reverse the
velocities of all three bodies. This may be done as a
conditional statement based on time or by detecting certain
key strokes. You should observe that the bodies retrace thei
paths and go back to the initial positions in the same amoun
of time.
observations.
PROJECTS
P4.1 (a) The artificial precession as observed in Exercise E4.3
above could be eliminated by using a smaller h, which
would lead to slower program speed and more round-off
error. Though speed is not a problem in this case, it could
be crucial in more complex situations. A better choice is
to use a leapfrog method with time transformation.
Repeat part (b) of Exercise E4.3 with leapfrog_tt().
Remember to initialize W0 before entering the loop (see
Program 4.3). Try different step sizes. You should see
that, no matter how large h is, there is no precession.
Explain why.
(b) Note that due to the large Sun-Earth mass ratio, the
Sun barely moves. Now change the mass of the planet,
say 0.4 solar mass. Run the code again and observe the
visible wobbles. You may also need to change the initial
conditions depending on the mass ratio.
(c) Plot the radial velocity of the Sun, v*z, in the actual
Sun-Earth system similar to Figure 4.9, assuming edge-
on view. Discuss the results, such as the shape and
magnitude of the curve.
(b) You should see that the fitted curve is shifted from the
data, e.g., the dip should be at a different location, even
though the overall shapes match very well. If you would
just shift your curve left or right, it would look quite like
the fit in Figure 4.11. Explain the physical reason for the
shift. Adjust the time shift to get the best fit. Write down
the parameters, and calculate the lower limit of the
exoplanet's mass, in Earth and in Saturn masses.
Compare with observed values [30].
(c) Run Program 4.4 in full to obtain a least square fit.
Compare the best results between visual and automatic
fits. Optionally, switch to the reduced dataset of Table 4.5
or the self-generated dataset from Project P4.5, and
discuss any difference in the fit.
Figure 4.21: The space reference frame and the rotating reference
frame.
From Figure 4.21, the relationship between the primed unit
vectors in the rotating frame and the unprimed ones in the
space frame can be written as
The left side refers to the rate of change in the space frame. The
first two terms on the right hand side are the rate of change due
to the change of coordinates x′ and y′ as measured in the
rotating frame, and the last two terms are due to the change of
the primed unit vectors. Let us denote this more clearly by
rewriting Eq. (4.65) as
Applying Eq. (4.69) to each of the two terms on the right hand
side, we have
.B Rotation matrices
Sometimes it is necessary to transform the coordinates from
the rotating frame to the space frame. This can be done using
(x, y) = and Eq. (4.63). The results may be
expressed conveniently in the form of a rotation matrix as
The order is important for finite rotations, and the final matrix
is built from right to left in the order of rotations. The inverse
matrix is .
Let and denote the velocities of the planet and the star
in the center of mass, respectively. Then
. Solving for , we have
46 GM = 4*np.pi*np.pi # G*Msun
# lamb=relativistic correction, global, used in ’mercury()’
The next block reads in the RV dataset from a file. The file is
opened with with…as (line 29), a handy Python construct that
automatically cleans up after operations within the block (e.g.,
closing the file in this case). For each line in the file, after being
stripped of white space, if it is not blank (zero length) or a
comment (“#” as the first character), eval() is called to parse
the data fields assumed to contain three comma-separated
values, namely time, velocity, and error bar, all added to the
respective lists. After processing the file, the time and velocity
lists are converted to ndarrays, time and vel respectively, for
vector operations throughout. Time is also scaled so it is
between 0 and 1.
The pair of numbers in b are closest to the first and the third
elements of a, respectively, so the returned index array is [0,
2].
The function nearest() uses the NumPy outer method,
which turns most functions to work in an outer-product
manner (see Program 8.4 for the outer function). Here (line 9),
the np.subtract function modified by the outer method
computes the difference between every possible pair of
elements in t and time in such a way that a 2D array is formed
such that diff[m,n]=t[m]-time[n]. On the next line we locate
the indices of the nearest data points using np.argmin which
returns the indices of the minimum absolute differences along
axis 0 (down a column). This basically amounts to a table
lookup. On return from nearest(), the variable idx now
contains the indices of t closest to the data points time. Lastly,
depending on the fitting flag in the inline if-else statement
being true or false, only the indexed or all values of time and θ
are returned. The false condition should be used after a
successful fit to evaluate the full results.
body.append(vp.sphere(pos=r[i],radius=R,color=c[i],make_trail
=1))
40
vel.append(vp.arrow(pos=body[i].pos,shaftwidth=R/2,color=c[i]
))
line, com = vp.curve(color=c[3]), vp.sphere(pos=(0,0),
radius=R/4.)
42 return body, vel, line
44 def run_3body(scale):
t, h, ic, cycle, R = 0.0, 0.001, 0, 20, 0.1 # anim
cycle, R=obj size
46 r, v = init_cond(scale)
body, vel, line = set_scene(R, r) # create
objects
48 while True:
vp.rate(1000)
50 r, v = ode.leapfrog(threebody, r, v, t, h)
ic = ic + 1
52 if (ic % cycle == 0): # animate once per
’cycle’
for i in range(3): # move bodies, draw
vel, path, lines
54 body[i]. pos = r[i] # bodies
vel [i].pos, vel [i].axis = body[i].pos, v[i]
56 vel [i].length = R*(1+2*vp.mag(v[i])) #
scale vel vector
line.pos = [body[i].pos for i in [0,1,2]] #
lines
58 m1, m2, m3 = 1., 2., 3. # masses, global
60 run_3body(scale = input(’ enter scale, eg 0.7 :> ’))
def makeplot():
12 n, s = 201, 5 # grid points and stride
x = np.linspace(−1.5, 1.5, n) # same x,y grids
14 x, y = np.meshgrid(x, x) # make meshgrid, ie, 1D −> 2D
16 V = potential(x, y) # compute V, −grad(V)
Fy, Fx = np.gradient(−V) # swap Fx, Fy since V[i,j]=V[x,y]
18 big = Fx*Fx + Fy*Fy > 0.003 # truth array for A[i, j] >.003
Fx[big], Fy[big] = 0, 0 # cut off large values
20
fig = plt.figure () # add surface plot with strides and color map
22 axis=fig.add_subplot(111, projection=’ 3d’) # add subplot
axis.plot_surface (x, y, V, rstride=3, cstride=3,
24 linewidth=0, cmap=plt.cm.spectral)
axis.set_xlabel (’ x’), axis.set_ylabel (’ y’), axis.set_zlabel (’ V’)
26
32 # draw arrows on strided grid to space them out, via array slicing
plt.quiver(x [:: s ,:: s], y [:: s ,:: s], Fx[:: s ,:: s], Fy[:: s ,:: s],
34 width=0.005, minshaft=2, minlength=0) # arrow shape
txt = [’ $L_1$’, ’ $L_2$’, ’ $L_3$’, ’ $L_4$’, ’ $L_5$’] # Lag. pts label
36 loc = [(−1.1, −.07),(.5, −.07),(1.2, −.07),(.3,.8),(.3, −1)] # label pos
for i in range(len(txt)):
38 plt.text(loc [i][0], loc [i][1], txt[i], fontsize=16)
40 plt.show()
1 3
In the calculation of s , instead of the power operator s**3, multiplications ( s*s*s) are
used. It is faster this way (up to power ~ 5), and equally readable.
2
Such keyboard polling is included in the VPython module (VPM) library (Program
S:6.4). The library also defines several classes of objects for use in later chapters, such as the
slinky and mesh surfaces.
3
Another common choice is θ0 = 0. In that case, rmin and rmax would be swapped.
4
Though Pluto was reclassified as a minor planet recently, it does not affect our treatment
below.
5
For readers interested in technical details, see Sec. 3.6 of Ref. [40].
6
A more quantitative explanation of the direction of precession is given in Ref. [61].
7 α
This is a special case of power scaling laws, y = cx , where x is the scaled variable, α
α
the exponent (or power), and c a constant (usually unimportant). If x″ = λx, then y′ = λ y.
8
The latest estimate based on the Kepler mission is that one fifth of Sun-like stars in our
galaxy has an Earth-like planet, totaling to tens of billions habitable exoplanets.
9
As of this writing, 1022 exoplanets have been confirmed, 548 of which were discovered
with the RV method [66].
10
This is not to be confused with the radial velocity in Eq. (4.8) which represents the
orbital velocity of the planet directed radially.
11
Physics is not only interesting but also colorful sometimes, judging by some terms
used.
12
We do this in scattering studies of atomic reactions. See Section S:12.5.
13
There are variations about the labeling of L1, L2 and L3. We sequentially label them
from left to right, agreeing with the convention in Ref. [40].
14
This should not be confused with the ability of a central potential to support closed
orbits discussed in Section 4.2.5. The forces involved here are velocity dependent and not
central, and the orbits are not closed in the space-fixed coordinates.
15
Pluto and Neptune have different inclination angles. We ignore that difference here and
assume they move in the same plane.
16
This amounts to the independent particle approximation. It is a good approximation,
particularly if we are primarily interested in the wobbling motion of the star.
17
The float-to-string conversion works as ’ format’ % (expressions). Here, format is a
string containing the C-style format specifier %W.PT where W is the field length, P the
precision (decimal places), T the number type. All except % and the number type are
optional. In the present case, ’ %8.2f’ specifies a float of length 8 and 2 decimal places.
18
The same problem arises in electrostatic potentials on a grid, see Program 7.2.
Chapter 5
Nonlinear dynamics and chaos
We have thus far dealt with systems whose time evolution is
described by a set of ODEs. Given initial conditions, we can
integrate the ODEs and obtain numerical solutions at any point
in the future. When the outcome is uniquely determined by the
initial condition, we say the system is deterministic. Newtonian
systems such as projectile and planetary motion are
deterministic. For the most part (except unstable few-body
systems alluded to in Section 4.5), we did not have to worry
about any unpredictable results, in the sense that if we
propagate the system from two nearby initial conditions, we
should expect the final results to be close, at least not
catastrophically different.
We will use the short hand f(n) to denote the nth iterate of the
map as
plt.figure()
12 plt.plot(range(n), xn, ’ --o’) # plot dashed line with 'o’ symbol
plt.xlabel(’ $n$’), plt.ylabel(’ $x_n$’)
14 plt .ylim (0,1), plt .text(33, .1, ’ r=’+ repr(r)) # add text
plt.show()
We can rewrite the above relation using the map function (5.2)
and (5.3) to get
Solving the above equation gives us two fixed points for period-
one cycles as
The map functions are drawn as curves for f(x) and f(2)(x),
respectively, for period one and two. Note the double hump in
the period-two curve. The intersections of the diagonal lines
and these curves are the fixed points: 2 for period one, 4 for
period two, both including the point 0.
Figure 5.5: Regions of stability of the fixed points of period one and
two.
For each r, we iterate the map for ntrans steps and discard
these points to get rid of transients. The number of steps it
takes for the transients to pass would depend on r. For
simplicity we use a fixed, large value, as it is adequate for our
purpose. The next nsteps iterates are presumably the
attractors. They are retained and plotted.
Feigenbaum's α number
Another result of renormalization is that we can estimate the
second Feigenbaum number, the α-number which measures
the scaling in the vertical direction in the period doubling
diagram (Figure 5.6).
Figure 5.8: Vertical displacements and the Feigenbaum's α number.
.2 Chaos
As we have seen above, orderly period doubling ceases to exist
for r ≥ r∞ and the bifurcation diagram looks rather “chaotic”.
How does the abrupt change happen? Can we quantify it?
Earlier we gave a general definition of chaos as the sensitive
dependence on initial conditions and loss of long term
predictability. With the logistic map detailed so far, we are in a
position to demonstrate this, and in the process to give an
operational definition of chaos.
While there are some scatter in the data, the overall trend is
that the initial difference shrinks exponentially (note the
semilog scale) for r = 0.8, but grows exponentially for r = 0.9.
In the former case, the difference becomes insignificant, and
we can predict where the system will be even if the initial
conditions are not known precisely. However, in the latter case,
any difference in the initial conditions, no matter how small,
will lead to such exponentially diverging outcomes that any
long term prediction is meaningless. It is for this reason that
we saw the different behaviors in Figure 5.9. We stress that it is
not due to inaccuracies in numerics, it is a characteristic of
nonlinear systems in the chaotic regime.
The results, θ(t) and ω(t), are shown in Figure 5.13 for two
driving amplitudes. For Fd = 0.7, the angular displacement and
angular velocity both undergo an initial transient period.
During this period, the oscillator loses track of where it came
from due to damping, and adjusts the motion to the driving
force. After the transients, it oscillates regularly and
periodically with the same frequency as the driving frequency.
This is akin to pushing a child on a swing at regular intervals.
No matter what the initial conditions were, the final
oscillations are the same. The system has no memory effect (we
will see this again in a linear driven oscillator, Section 6.1).
Figure 5.13: The angular displacement (θ) and angular velocity (ω)
as a function of time for two driving force amplitudes, Fd = 0.7 and
−2 2 −1
1.1 s . The other parameters are ω0 = 1 rad/s , b = 0.5 s , and ωd =
0.6 rad/s.
At Fd = 0.7 the path starts from the initial point and quickly
converges to an ellipse in which the motion repeats
indefinitely. This is not surprising since we know from earlier
discussions that the motion is regular at this driving amplitude.
This ellipse is an attractor, though it is not a single point for a
continuous system. On the other hand, at Fd = 1.1, the path
looks very complex. Here the numerical values of θ have no
limits (see Figure 5.13), although as an observable it should be
within [−π, π]. We thus remap θ whenever it exceeds this range
as
Figure 5.15: Phase space plots for different driving force amplitudes
Fd = 0.7, 1.1, and 1.2. Other parameters are the same as in Figure
5.13.
The path wanders all over the diagram like spaghetti and
there is no stable attractor for it to evolve around. If we
increase Fd to 1.2, the system returns to a simple pattern again,
though it is not obvious from the plot because of the
continuous nature of the variables.
To make more sense out of continuous changes, a better
idea is not to plot every point. Rather, we look at them at
discrete times. The result is a distribution of points taken at
specific time intervals, also known as a Poincaré map. To
produce a Poincaré map, we plot only the points in
synchronization with the driving force, e.g., when it is
maximum or minimum, after the initial transients pass. The
technique is used in Program 5.6. The results are shown in
Figure 5.16.
Figure 5.21: The butterfly trajectory of the Lorenz model, with the
same initial condition and parameters as in Figure 5.20. The camera
points to the negative z-axis (into the page), with the x-axis to the
right and y-axis up.
Figure 5.23: The power spectra of the logistic map at different values
of r.
Power spectra can be obtained via the Fourier transform
defined by
.6 Fractals
Earlier we mentioned that the strange attractor of the Lorenz
model apparently has a fractional dimension, i.e., non-integer
dimensions like 1- or 2-dimensional space that we are used to.
For example, the attractor has a dimension ~ 2.05, so it is
strange. How does this happen? A rough explanation is that the
region around the attractor is chaotic in some directions but
regular in others, i.e., some Lyapunov exponents (λ) are
positive and some negative. So the area is stretched (positive λ)
in some directions but compressed in others (negative λ),
making the area irregular and non-measurable in normal
integer dimensions.
where l is the scale, and N(l) the number of basic units required
to cover the object. The dimension is df, also known as the
Hausdorff dimension. For regular lines, df = 1 and for surfaces,
df = 2 as discussed above.
Figure 5.24: The Koch curve. The last level is enlarged by a factor of
two.
Mandelbrot fractals
There are many kinds of fractals. A common feature among
them is self-similarity. We have seen self-similarity in chaotic
systems as well. Perhaps the most well-known ones are the
Mandelbrot fractals, shown in Figure 5.25. The Mandelbrot
fractals are generated by the equation which defines the
Mandelbrot set,
Figure 5.25: Successive levels (column major) of the Mandelbrot
fractals.
E5.4 Show that the last two fixed points of period-2 (5.10) are
stable for .
PROJECTS
P5.1 We have seen from Figure 5.6 that there is a period-3
stable window embedded in the chaotic region of the
logistic map around ~ 0.96. Why does it not appear at
smaller values of r? Explore this and related questions
of the period-3 orbits.
, respectively.
value. That is .
(d)* Repeat parts (a) and (b) using RK45n (or if you
used it already, switch to RK4n). Compare their
performance, and the values of step size when the
results are first converged.
(b) Take the first point after the transients as our center
point P, with position (X, Y, Z). Let us imagine we make
three spheres of different radii Ri (i = 1, 2, and 3)
centered at P. For example, radii of 1, 2, and 3 work
well. Initialize three counters that will keep track of the
numbers the trajectory has entered the spheres.
(e) Once the above steps are working, try the same
procedure for different center points. Average all the
values, and it should be approaching 2.05.
(a) Sketch the potential, then graph it. Find the natural
frequency for small oscillations without the driving
force.
19 plt.figure()
plt.plot(ra, lyap, ’,’) # ’,’=pixels
21 plt.axhline(0.), plt.ylim(−2, 1) # draw horiz.line, set y limits
plt.xlabel(’r’), plt.ylabel(’λ’)
23 plt.show()
The Lyapunov exponent is computed from the analytic
expression (5.29) in Program 5.4.
1
The factor of 4 in Eq. (5.1) is included to make things tidy. Other sources treat r′ = 4r as
the control parameter (e.g., Ch. 18 of Ref. [4]).
2
Many of the results can be obtained with the aid of SymPy. See Exercise E5.1.
3
Strictly speaking, ω0 is the angular frequency only in this limit. For the nonlinear,
driven oscillator, it is best to view ω0 as parameter, against which the strength of the driving
force is to be compared.
4
Lorenz carried out his calculation on a Royal McBee LGP-30 computer, the size of a
chest freezer weighing 700 pounds, and classified as a “desk” computer. It could perform
one iteration of calculations per second. Its speed was probably around 10 FLOPS. Typical
speed of today's PCs is around 100 GigaFLOPS.
5
The Lorenz model approximates the Rayleigh-Bénard flow. The parameter σ is the
Prandtl number, r the scaled Rayleigh number, and b the scaled dimension of the system.
6
We should take multi-day forecasts such as 10-day planners with a grain of salt,
especially in weather-prone regions like New England.
7
It is a result of the convolution theorem and is also known as the Parseval's relation.
Chapter 6
Oscillations and waves
Periodic motion is ubiquitous in nature, from the obvious like
heart beats, planetary motion, vibrations of a cello string, and
the fluttering of leaves, to the less noticeable such as the
vibrations of a gong or shaking of buildings in the wind.
Oscillations and periodicity are the unifying features in these
problems, including nonlinear systems in Chapter 5. The
motion is back and forth repeating itself over and over, and can
cause waves in a continuous medium.
import visual as vp
2
we obtain
The initial condition was set to (u1, u2, u3) = (−0.2, 0.2, 0)
and zero velocities. Only the displacement u1 is shown (the
other two are qualitatively similar). We see regular, periodic
oscillations, but they are not sinusoidal. The positive and
negative displacements are not symmetric about the
equilibrium. The period appears to be 2π for this set of initial
conditions.
Let λ = ω2 and
Equations (6.19) and (6.20) are the normal modes. They are
the fundamental harmonic oscillations of the triatomic system.
All three particles vibrate in mode 3 (ω3 = 3), with the outer
particles moving in unison, and the center particle vibrating in
the opposite direction. This is the asymmetric stretch. The
amplitudes of the outer particles are the same, but are smaller
than the amplitude of the center particle. Their ratio is such
that the CM is at rest in the middle, the same as in mode 2. Any
oscillation of the triatomic molecule is a linear superposition of
the three normal modes. This is what we have seen in Figure
6.6.
where R(θ) is the rotation matrix (4.75). The rotation R(θ) and
its inverse R(−θ) pair are necessary so the transformation is
orthogonal and preserves the eigenvalues [10].
import numpy as np
2 from scipy.linalg import eigh # Hermitian eigenvalue solver
4 k = 1.0
m1, m2, m3 = 1./4., 2./5., 1./4.
6 A = np.array([[k, −k, 0], [−k, 2*k, −k], [0, −k, k]])
B = np.array([[m1, 0, 0], [0, m2, 0], [0, 0, m3]])
8
The first and the last rows on the LHS have two terms since we
have moved to the RHS the boundary values which are given
and need not to be solved. That is how the boundary conditions
determine the solutions. The other rows have three terms each.
A = np.diag([−2.]*(N−1)) # diagonal
9 A += np.diag([1.]*(N−2),1) + np.diag([1.]*(N−2), −1) # off diagonals
11 B = np.array([−h*h*f/T]*(N−1)) # B matrix
B[0], B[−1] = B[0]−u0, B[−1]−uN # boundary values, just in case
13
u = solve(A, B) # solve
15 u = np.insert(u, [0, N−1], [u0, uN]) # insert BV at 1st and last pos
17 plt.plot(x, u, label=’ $f=-1$’), plt. legend(loc=’ center’) # legend
plt.xlabel(’ $x$’), plt.ylabel(’ $u$’), plt.show()
Now let
Because the basis functions and their derivatives have no
overlap unless they share a common node, we see that Aij = 0
unless i = j or j ± 1. This is the reason the basis functions are
chosen to be compact support, so the matrix Aij is sparse. It is
also symmetric, Aij = Aji.
Here we have again used the fact that φi(x) is nonzero only if
xi−1 ≤ x < xi+1. For constant load f(x) = f0, pi = hf0. Assuming u0
= uN = 0, matrix B is
Once A and B have been prepared, we can obtain the
solutions by solving either Eq. (6.48) for the Neumann
boundary type or (6.52) for the Dirichlet boundary type.
Comparing the system matrices between FDM and FEM in this
case, we find that they are the same (besides the placement of
h), so the solutions are identical. It turns out they are also
identical for linear load, and differences start to develop only
for quadratic and higher order load.
The Dirac δ function (see Section S:5.1 and Figure S:5.1) makes
direct evaluation of f(xn) impossible in FDM. In FEM, however,
it poses no special difficulty for this integrable singularity, as
where we have used the property φn(xn) = 1 from Eq. (6.39). All
elements of B are the same as Eq. (6.56) except at node n,
where it is (hf0 + α)/T. Solving for u using this modified B, we
obtain the results shown in Figure 6.14.
.5 Waves on a string
When a string, held by a point-like force as depicted in Figure
6.14, is released, wave motion will be generated on it. If the
string is coupled to a sound chamber such as that of a cello,
vibration energy of the string will be transferred to the
chamber, and musical notes can be heard. Modeling the energy
loss would be similar to but more complicated than damping in
a harmonic oscillator (Section 6.1). We are interested instead in
describing an ideal vibrating string without dissipation.
Let us consider the case where the two ends of a string are
held fixed at zero, u(0, t) = u(L, t) = 0. Equation (6.68) dictates
that
Let
The terms on the LHS refer to different space grids at the same
time grid, whereas the reverse is true on the RHS.
Physically, this means that the time step must be smaller than
the time it takes for the wave to travel one space grid.
8 def gaussian(x):
return np.exp(−(x−5)**2)
10
20 while(True):
vp.rate(100), vpm.wait(scene) # pause if key press
22 u2 = wavemotion(u0, u1)
u0, u1 = u1, u2 # swap u’s
24 string.move(x, 2*u0, z) # redraw string
We can see from the shaded elements that, except for the
end points, the interior elements (middle row) are lined up
with their neighbors with the shifted arrays. We could
accomplish the conceptual shifting via slicing of NumPy arrays
(Section 1.D). Guided by Figure 6.15, we can find Hj by
.6 Standing waves
Like the normal modes for a systems of particles, standing
waves are the fundamental building blocks of waves on a string.
Any wave can be represented as a linear superposition of these
fundamental harmonics (6.72).
.7 Waves on a membrane
When the vibrating medium is a surface rather than a string,
two-dimensional waves are created. With a slight modification,
we can generalize the one-dimensional wave equation (6.62) to
two dimensions as
In effect, the differential operator ∂2/∂x2 is replaced by the
Laplacian in 2D. Equation (6.88) describes two-dimensional
waves on a membrane such as a drum. Holding either x or y
constant, we recover the 1D wave equation in the other
direction.
1 u2 = 2*(1−b−b)*u1 − u0
u2[1:−1,1:−1] += b*(u1[1:−1,0:−2] + u1[1:−1,2:] # left, right
3 + u1[0:−2,1:−1] + u1[2:,1:−1]) # top, bottom
The waves in the previous two iterations are stored on a 2D
grid as and ( u0 and u1), respectively. Like the 1D case
(Section 6.5.5), the solution for the next step is obtained via
element-wise operations. The first line accounts for the first
two terms in Eq. (6.90). The third term, which is proportional
to the sum of the four nearest neighbors, is computed in the
next two lines via slicing, again bearing striking simplicity and
resemblance to the written form. This is a natural extension of
the 1D case, as illustrated below for a 4 × 4 array.
Slicing on the left side of line 2 in the above code selects the
center subarray (boxed) from the left array in Eq. (6.91). It
contains the interior points to be updated (compare with
Figure 6.15). The boundary points where ui,j = 0 are excluded.
The first term in the brackets on the right side of line 2 is
depicted in the right array of Eq. (6.91). Here, slicing refers to
the boxed subarray, which is shifted to the left by one column
relative to the center box. Therefore, entries in u[1:-1,0:-2]
are the left neighbors to u[1:-1,1:-1]. Similarly, the other
three terms on the right side of the statement (lines 2 and 3)
correspond to the right, top, and bottom neighbors,
respectively. Here, left-to-right refers to moving across
columns and top-to-bottom to running down the rows.
When the waves hit the boundary wall where the membrane
is fixed, they are no longer circular. Instead, an inversion
occurs, similar to that observed in waves on a string at the end
points. But it is more complicated for 2D waves because the
wavefront reaches the boundary at different times. The
wavefront first hits the central portion of the walls (Figure 6.18,
lower left). By the time it spreads toward the corner of the
walls, the central portion has already inverted and started
going toward the center (Figure 6.18, lower right). The
wavefronts are distorted by the boundary walls.
Figure 6.19: Snapshots of animated waves on a membrane.
Chapter summary
PROJECTS
P6.1 Consider the longitudinal oscillations of an N-particle
array, Figure 6.22. Assume the interaction between
neighboring particles obeys Hooke's law, and all the
masses are the same.
(a) Set up the equations of motion for the system, and the
A and B matrices as in Eq. (6.14).
where .
combination of x, θ, , and .
P6.3 This project and the next one (Project P6.4) should
ideally be treated as team projects. Each individual team
member can focus on one primary project, but work as a
team exchanging ideas and results.
(a) Run Program 6.3 for the constant load f(x) = −2.
Compare your results with Figure 6.11 (f = −1), and
discuss the shapes of the strings.
(b) Assume a linear load f(x) = −2x. Work out the exact
solution from Eq. (6.29).
(d) Predict what the shape will look like for a quadratic
load, f(x) = −3x2. Sketch it. Carry out the FDM
calculation. How did your prediction turn out? Explain.
P6.4 Investigate FEM solutions for the displacement of a
string under Dirichlet boundary conditions, u0 = uN = 0.
It is helpful if you had gone through Project P6.3
individually or as a team.
(a) Modify Program 6.3 for the constant load, and make
sure you can reproduce the FDM results shown in Figure
6.11. You can decide whether or not to move the factor h
in Eq. (6.54) to the RHS of Eq. (6.52). Verify that doing
so does not alter the solutions.
u1 = gaussian(x+h) or u1 = gaussian(x-h)
3 def accel(u):
return −k*np.array([u[0]−u[1], 2*u[1]−u[0]−u[2], u[2]−u[1]])/m
5
23 while(True):
vp.rate (40), vpm.wait(scene) # pause if key press
25 u2 = wave2d(u0, u1)
u0, u1 = u1, u2 # swap u’s
27 mesh.move(x, y, 2*u0) # redraw mesh
37 while (1):
vp.rate(100), vpm.wait(scene) # pause if key pressed
39 Y = ode.RK4(cloth, Y, 0, h)
x, y, z = Y [0,:,:,0], Y [0,:,:,1], Y [0,:,:,2]
41 net.move(x, y, z), mesh.move(x, y, z)
1
The Millennium Bridge in London had to be closed just two days after opening in June,
2000 due to resonant swaying. The bridge swayed laterally when crowds walked over it,
causing them to sway in step to keep balance, and leading to resonant vibrations. Fixed with
more damping, it reopened 20 months later, nicknamed the “wobbly bridge”.
2
The time and length scales are determined by the choice of units for k and mi. We can
set them to arbitrary units without loss of generality. If they are in SI units, for example, then
time and length would be in seconds and meters, respectively.
3
This would be the case if the particles have the same, unity mass, and the couplings
between them are neglected.
4
You may also use SymPy's symbolic matrix manipulation to verify the results.
5
The rotation matrix would be an N × N identity matrix except for rows i and j: aii = ajj =
cosθ, aij = −aji = sinθ.
6
Aside from efficiency derived from special algorithms for sparse matrices, we can also
reduce memory bandwidth of the program, making it more efficient by minimizing the
amount of data being moved, which may be as important as computational speed.
7 ±
We use the shorthand for x = x ± ∈ where ∈ is a positive infinitesimal.
8
For instance, the speed on the thickest string of a cello (C string) is v ~ 100 m/s.
−2
Assuming a mass density of ρ ~ 1.5 × 10 kg/m for a metal string, the tension is T ~ 150 N,
a strongly-strung string!
9
The same phenomenon exists in quantum mechanics. See Section 9.6.2.
Chapter 7
Electromagnetic fields
In the simulation of few-body problems in Chapter 4, gravity
was the sole interaction at large distances. If the particles are
charged, they will interact via electromagnetic forces which are
much stronger than gravity at the same distance. For example,
the ratio of the Coulomb force to gravity between a proton and
an electron is about 1039 at a given separation, making gravity
utterly negligible. In fact, macroscopic properties of all
ordinary matter are determined by electromagnetic
interactions. Forces such as tension in a string (Section 6.3),
spring forces, friction, etc., are all manifestation of
electromagnetic forces between atoms.
Figure 7.1 shows three shots, two misses and one score. The
success rate depends on the initial condition (skill) and the
underlying physics for a given charge configuration. The
configuration in Figure 7.1 consists of seven charges: five are
positive, one at each corner and one at the center; two negative
ones are placed in the middle of each side. In this example, the
puck is negatively charged, so the forces on the puck are
repulsive from the two negative charges on the sides and
attractive from the corners and the center.
In the first instance, the puck was aimed at the lower side.
When it got close to the negative charge, the repulsive force
slowed it down, and turned it back up, resulting in a miss. The
other instances had the same speed but different launching
angles. In each case, the puck moved toward the center charge,
orbiting around it once under its attractive force. The puck with
the smaller angle suffered a greater pull, over rotated, and went
out of bound from below, another miss. The third one had just
the right pull, was catapulted toward the goal, and a score.
The five positive charges at the corners and the center act
like sink holes the puck is attracted to. There are two saddle
points, one on each side of the playing field, situated
approximately in the middle of each half. Therefore, there is a
minimum energy threshold for the puck to overcome the saddle
point. Once over the threshold, the puck must navigate through
the repulsive and attractive fields, and the trajectory can
become very complex, as some in Figure 7.1 illustrate. This is
true especially at lower energies when the puck must orbit
around the center charge in order to escape to the other side.
Occasionally, the particle can even become trapped to the
center of the field, orbiting indefinitely. At higher energies, it is
possible to deflect directly off the negative charge in the middle
of the side and score a goal.
Figure 7.2: The potential and forces corresponding to the
configuration in Figure 7.1.
or equivalently,
As before, h is the grid size (we assume the same h for x and
y), and we have used the following convention
Equation (7.6) states that the correct, self-consistent
solution at any point is just the average of its four nearest
neighbors. It is independent of the grid size h (though the
accuracy is). Its simplicity is strikingly similar to Eq. (6.85) for
an exact wave on a string.
Here, V0 is the old solution of the last iteration, and V1 the new
solution. The function not_on_plates() checks that the point (i,
j) is not on the plates (boundary) before updating. Because
V1[i-1, j] and V1[i, j-1] (previous row and column of the
current iteration) are available by the time the grid point (i, j) is
being calculated, we make use of them. It mixes old and new
values, and should converge faster. Indeed, it is faster than the
Jacobi scheme by about a factor of two. However, its advantage
does not stop there.
To see FEM in action first, you can skip ahead to Section 7.4
for a worked example and sample Program 7.3. You may also
switch back and forth between FEM development and
application.
This is true for all points except those on the ridges and the
exact node point for which the tent function is defined. To
avoid double counting, we require that only one term in the
sum (7.12) is actually selected: the basis function of the first
element determined to contain the point. The value of the tent
function at the node is unity by definition.
Likewise, tent functions at other nodes can be built in the
same way. For example, the tent function at node 3 (Figure 7.8,
bottom) has two basis functions, one each from elements e1 and
e2. There are six such tent functions, one for each node. We
note that two tent functions overlap each other only if the two
nodes are directly connected by an edge. For instance, the two
tent function shown in Figure 7.8 overlap because nodes 1 and
3 are connected by the common edge between e1 and e2. In
contrast, the tent functions at node 3 and node 5 would not
overlap.
Let
The sums on the LHS and the RHS involve internal and
boundary nodes only, respectively.
After e1 has been processed, entries A12 and A23 and their
symmetric pairs are complete. No contributions will come from
other elements (besides e1) because node 2 is connected only to
nodes 1 and 3. By the same token, after processing e2, all
entries associated with e1 (plus A34 with e2) are complete with
the exception of A11 which awaits further contribution from
elements e3 and e4. For example, the entry A13 will be complete
to become . We see that after going through
every element, all entries of matrix A will be complete.
The two inner loops cycle through the nodes of a given element,
assigning the contribution to the appropriate entry of A, and
taking advantage of symmetry about the diagonal.
Figure 7.11: The mesh over a rectangular domain. Solid symbols are
boundary nodes, and open symbols are internal nodes.
Table 7.1: FEM variables and data structure of the mesh in Figure
7.11.
The routine goes through the element list elm. For each
element, the coordinates of the vertices are extracted from the
node list, and the parameters β0−2, γ0−2 and Ae are calculated
according to Eq. (7.11). The contributions to matrix A, ,
where m and n are the nodes of the current element, are
computed from Eq. (7.27). Three of the six off-diagonal entries
are computed, the other three are obtained via symmetry.
Figure 7.12: The system matrix for a mesh like Figure 7.11 with N =
10.
The electric field near the top and right sides initially points
away from the sides near the highest point. Further left and
down, it becomes weaker and its directions turn toward each
side. By the midpoint, they are parallel to the respective sides,
but eventually point into the sides past the midpoint. On the
left and bottom sides, however, the electric fields are
perpendicular to the boundaries because the potentials are
constant on these sides. As the contour lines extend closer to
the bottom-left corner, they start to mimic the shape of the
walls, running nearly parallel to them and bending more
sharply near the origin.
Figure 7.13: The potential and fields by FEM of a unit square with
boundary conditions (7.28).
Figure 7.15: The difference between the analytic and FEM solutions
for boundary conditions (7.29).
where uexact is the analytic solution (7.30), and uFEM the FEM
solution (Figure 7.14). The parameter N = 40 is used in the
FEM calculation, corresponding to grid spacing of 0.025, and
3, 200 finite elements. The error is displayed as a color-coded
image using plt.imshow() (see Program 7.4).
.6 Visualization of electromagnetic
fields
We have discussed electrostatic problems where the electric
charges are stationary. In this section we are interested in
visualization of electromagnetic vector fields produced by
either steadily moving charges or accelerating charges. The
vector fields can be effectively visualized using the tools and
techniques we have employed so far.
Figure 7.21: Left: magnetic dipole fields; right: zoom-in around the
wire.
A way from the dipole in the radiation zone (kr 1), the
electromagnetic fields have particularly simple expressions
[50],
Chapter summary
PROJECTS
P7.1 Generate the potential surface (Figure 7.2) of the hockey
field. Use Program 4.6 and replace the effective potential
by the Coulomb potentials between the puck and
stationary charges. What would the potential surface look
like if the charge of the puck is positive? Is it possible to
score a goal?
P7.2 (a) Implement the Gauss-Seidel acceleration and
overrelaxation methods discussed in Section 7.2.2, using
Program 7.2 as the basis. Verify that your program
produces the same results as the standard self-consistent
method for the parallel plates.
domain size.
(d) Explain why the entries A13 and A15 are zero. Indicate
what nodes are involved. The entry A55 = 8/2 = 4 is the
largest. What is the reason?
P7.8 Solve the Poisson equation with FEM for a point charge
inside a unit square that is kept at zero potential. Treat
the point charge at (x0, y0) as a Dirac charge distribution
f(x, y) = δ(x − x0)δ(y − y0).
(a) Assume the charge is just off the center of the square,
v, theta = input( ’enter speed, theta; eg, 2.2, 19:’) # try 2.2, 18.5
24 v, theta = min(4, v), max(1,theta)*np.pi/180. # check valid input
Y = np.array([[−a,0], [v*np.cos(theta), v*np.sin(theta )]])
26 while True:
vp.rate(200)
28 Y = ode.RK45n(hockey, Y, t=0., h=0.002)
x, y = Y[0][0], Y[0][1]
30 if (abs(x) > a or abs(y) >b):
txt = ’Goal!’ if (x > 0 and abs(y) < w) else ’Miss!’
32 vp.label (pos=(x, y+.2), text=txt, box=False)
break
34 puck.pos = Y[0]
The speed and launching angle are read from the user, with
an upper speed limit and a lower cutoff for the angle. The latter
is to prevent the puck from falling into the sink hole at the
center of the field. The main loop integrates the motion with
the RK45n solver for improved accuracy. Because hockey()
returns a list of vectors, RK45n can be readily used, because
vector objects represented by NumPy arrays can be
manipulated like scalars in arithmetics (addition, subtraction,
and multiplication). The rest of the loop checks collisions with
the wall, decides if a goal has been scored, and the outcome is
labeled at the end.
The main program sets the grid size, the parallel plates
dimensions, and visually represents the grid by square points
(line 39). It then initializes the potential array and applies the
boundary values. The boundary conditions include the two
parallel plates held at values of ±1 (in arbitrary units), and the
four sides of the box held at zero. The plates run horizontally
from M/3 to 2M/3. The vertical positions of the bottom and top
plates are (N −d)/2 respectively, with separation d. The unit
of distance is also arbitrary since it is scalable.
22
def rbf_mat(ni, nt ): # fills matrix or ϕij
24 A = np.zeros((nt, nt))
for j in range(nt):
26 f, df = phi(np.arange(nt), node[j ]) # vector operation
A[j,:] = df if j < ni else f
28 return A
46 plt. figure ()
img = plt.imshow(u, cmap=plt.cm.jet) # plot as image
48 plt.colorbar(img), plt. axis( ’off’)
plt.show()
The main code sets the parameters including the box size,
radius of the disk, and the shape parameter ε. Then it generates
the nodes and boundary values, the system matrix, and solves
the linear system to obtain the expansion coefficients a. The
potential is calculated over a grid for plotting. The result is
shown as a color-coded image via imshow() on line 47, with a
color bar and the axis (frame) turned off.
8 return b
m, n = 6, 30 # r, phi intervals
4 r = np.linspace(0.15, 0.4, m)
phi = np.linspace (0., 2*np.pi, n+1)
6 r, phi = np.meshgrid(r, phi) # n x m grid
20 E = vp.cross(B, rvec)/r #
1 import numpy as np
import matplotlib.pyplot as plt
3 from mpl_toolkits.mplot3d import Axes3D
plt. figure ()
13 ax = plt.subplot(111, projection= ’3d’, aspect=.5)
ax. plot_surface (x, y, z, rstride=1, cstride=1, color= ’w’)
15 plt. axis( ’off’)
plt.show()
1
Accurate to within the discretization scheme, of course, which in the present case is of
second-order accuracy (6.89).
2
We assumed one basis function in 1D for each node (tent function, Figure 6.12).
Technically, we could split the tent into two, so we would also have two basis functions for
each element.
3
This is the reason we must reduce second-order PDEs to an integral form involving only
first derivatives.
4
Other meshfree methods are discussed in solutions of quantum systems in Chapters 8
and 9.
5
Unlike electric fields, the basic units producing magnetic fields are magnetic dipoles.
There is at present no evidence of magnetic monopoles equivalent to electric charges.
6
The power in an electromagnetic field is given by the Poynting vector, ,
with units of power/area.
Chapter 8
Time-dependent quantum
mechanics
Can a particle be at two places simultaneously? Could a cat be
dead and alive at the same time? If we asked these questions in
previous chapters on classical physics, the answer would seem
to be obviously silly. However, in the context of quantum
physics, the answer is neither obvious nor as silly as it may
seem. Enter the fascinating world of quantum physics at the
atomic scale where classical physics breaks down, and where
few classical beings like us really have any intuitive experience.
Even now, quantum mechanics is still somewhat mysterious,
though its validity bas been confirmed by available experiments
for almost a century since its firm establishment.
Figure 8.1: The wave function (solid curves: real and imaginary
parts) and probability density (dashed) of a free particle. Dotted line:
a wavefront.
ATOMIC UNITS
Given the small constants such as ħ in the TDSE, it would be
cumbersome to use SI units in actual calculations. For
quantum systems in atomic, molecular, or solid state physics, a
natural unit system is the atomic units (a.u.). It is based on the
Bohr model of the hydrogen atom.
In the a.u. system, the units for mass and charge are the
electron mass me and basic charge e, respectively. The length is
measured in Bohr radius a0, and energy is chosen equal to the
magnitude of the potential energy of the electron at the radius
a0 in the Bohr atom (Hartree). They can be most conveniently
expressed in terms of the universal fine structure constant α
and speed of light c as
Given the chosen units for mass, charge, length, and energy,
all other units can be derived from these four. Their
relationship and numerical values (in SI) are summarized in
Table 8.1.
Table 8.1: The atomic units (a.u.) system.
Comparing Eqs. (8.2) and (8.4), we see that the net effect in
switching to atomic units is dropping all constants, equivalent
to setting ħ = me = e = 1 in the equations.3 In the rest of this
chapter, we will use atomic units unless otherwise noted. We
also assume the particles to be electrons.
.2 Direct simulation
We first consider a direct method for solving the TDSE (and
other time-dependent PDEs alike) by converting it to a set of
ODEs.4 This will enable us to start simulating quantum
systems with minimum delay using standard ODE solvers.
8.2.1 SPACE DISCRETIZED LEAPFROG
METHOD
We discretize space into grid points xj = jh, where h is the grid
size, and j = 0, 1, …, N. The second-order differential operator
∂2/∂x2 is approximated the same way as before, Eq. (6.73a),
such that
Besides being real, Eqs. (8.8a) and (8.8b) are in the proper
form for leapfrog integration. The derivative of the real part
depends only on the imaginary part, and vice versa. If we
regard Rj as the general “coordinates”, and Ij as the general
“velocities”, these equations mirror exactly the pair of
equations (2.44) and (2.45), with Rj corresponding to rj and Ij
to vj.
Let
The matrix A is tridiagonal, so it is a band, sparse matrix.
8.2.2 IMPLEMENTATION
We have everything in place to start implementing the direct
simulation method. We need to write a derivative function,
similar to Program 4.3, appropriate to the leapfrog integrator.
First we declare two arrays, R and I, to hold the real and
imaginary parts of the wave function over the spatial grid. They
will be initialized to the wave function at t = 0, and stepped
forward according to Eqs. (8.8a) to (8.8b).
The middle and bottom graphs in Figure 8.2 show the real
and imaginary parts, R and I respectively, of the wave function
at three positions (left end, center, and right end). Initially,
there is only the real part. With increasing t, both parts
develop, and become more oscillatory toward the center. The
peaks of R and the nodes of I coincide with each other (vice
versa), making the probability density smooth throughout.
Surprisingly, the real part does not vanish at the right end,
where the imaginary part dominates. We would not have
suspected this behavior based on the appearance of the
probability density graph alone.
The evolution of the probability density is shown in Figure
8.3 as a function of space and time simultaneously. We can see
more clearly from the surface plot the periodic motion of the
wavepacket as it zigzags back and forth in time. The width of
the wavepacket also oscillates periodically. We can observe in
the contour plot the periodicities of both the probability density
and the width more clearly. The period is close to 2π, which
matches very well with the classical period of the SHO, 2π/ω
from Eq. (6.11), when the mass and spring constant are unity.
We can also understand these oscillations as a result of
quantum revival, discussed in Section 8.5.
The last expressions in Eqs. (8.17) and (8.18) are useful for
numerical calculations (see Exercise E8.5 and Project P8.2). For
time-dependent systems, the above expectation values are generally a
function of t.
We need to evaluate the integral (8.16) numerically. Like solving
ODEs, numerical integration is a common procedure in scientific
computing. We discuss several integration techniques in Section 8.A.
Figure 8.4: The expectation value of position (solid line) and the
maximum of the probability density (dashed line).
2
Figure 8.5: The normalization error, 1 −∫ |ψ| dx.
This is Euler's method for the TDSE. But, this form turns out to be
numerically unusable, because it is nonunitary and unstable no matter
how small Δt is (Exercise E8.3).
Substituting Eq. (8.25) into (8.23) and acting on both sides by the
operator in the denominator, we obtain
Let
and assuming fixed-end boundary conditions, we can express Eq.
(8.29) in matrix form as
Next, we prepare the RHS of Eq. (8.31). Rather than direct matrix
multiplication, we obtain it from the RHS of Eq. (8.29) because
SciPy does not yet have a banded matrix multiplication routine. Line
5 computes the first term on the RHS of Eq. (8.29), i.e., the diagonal
elements of Bu0 in Eq. (8.31). This is why we did not need the full
matrix B above. The next line subtracts the last two terms, the left
and right neighbors, respectively, using the same shift-slicing
technique as before (Section 8.2.2). For fixed ends, we neglect the
boundary points, since . Now, we have completed the
RHS of Eq. (8.31).
The last line (line 7) calls the SciPy band matrix solver,
solve_banded(), to obtain the solution ψ1 at t + Δt. The function
requires a minimum of three parameters as
solve_banded((l,u), A, b)
Figure 8.7 shows the results from Program 8.3. The initial wave
function is again a Gaussian (8.15), and the acceleration is a = 2. The
center of the wavepacket falls toward the negative x direction as
expected. It also broadens as before, but unlike the SHO potential,
there is no refocusing effect in the linear potential, and the
wavepacket just keeps broadening.
Just like |ψ|2 giving the probability in position space, |ϕ(k)|2 gives
the probability of finding the particle with momentum k. And ϕ(k) is
normalized if ψ(x) is as well, i.e., ∫|ϕ(k, t)|2dk = ∫|ψ(x, t)|2dx = 1.
Since our wave function ψ(x, t) is discrete over the space grid, it
is efficient and straightforward to evaluate Eq. (8.33a) with the FFT
method (if you have not done so already, now would be a good time
to review Section S:5.B).
Suppose we sample M points at equal intervals δx = h over the
spatial range (i.e., period) d = Mh. From Eqs. (S:5.18) and (S:5.20),
and according to Section S:5.B.3, the momentum grid points are
determined by
Both figures show that, at the beginning, the profile keeps its
initial shape with no apparent broadening, in stark contrast to
position space where broadening happens rather quickly. Imagine the
wavepacket was in free space. Since there would be no force, the
momentum as well as the kinetic energy of the particle must be
conserved, and we would expect no spreading at all.
Figure 8.10: The momentum density of a quantum particle in free
fall. The dashed line shows the classical relation v = v0 − at (a = 2).
To solve for a1(t) and a2(t), we substitute ψ(x, t) of Eq. (8.38) into
the Schrödinger equation iħ∂ψ/∂t = (H0 + V (x, t))ψ, where V (x, t)
represents the interaction with the laser field (see Eq. (S:8.40)). After
some algebra and using Eq. (8.36) for cancellations (see Section
S:8.2), we obtain
Equation (8.40) is valid for all space and time. To extract the
coefficients, we project it to the eigenstates u1 and u2. For instance,
we can multiply both sides of Eq. (8.40) by , and integrate over x.
Using the orthogonality relation (8.37), the 2 term drops out. The
same can be done with . The final result after projection is
where ω = (E2−E1)/ħ is the transition frequency, and the matrix
elements Vmn are defined as
Figure 8.11: State population for a laser duration τ = 600. The dotted
2
line shows a shifted Rabi flopping function cos (ΩRt + φ), Eq.
(8.49a).
This form of the field will help us see more clearly the core idea of
Rabi flopping. In numerical calculations such as Figure 8.11 we still
use realistically enveloped pulses like Eq. (S:8.41).
where ϕ1,2 = u1,2 exp(−iE1,2t/ħ) (see Eq. (8.38)). At any given time,
the wave function is a coherent sum of the two states, i.e., both states
exist simultaneously within ψ. The probabilities of finding the states
are cos2(ΩRt) and sin2(ΩRt), respectively. Quantum mechanics
prescribes exactly, and deterministically, how the probabilities
change with time.
.5 Quantum waves in 2D
As seen from above, we can create a superposition of states, or a
coherent state, with external perturbations like laser excitation. After
the external interaction is turned off, the coherent state will continue
to evolve but with different characteristics than single stationary
states. The numerical methods we discussed above also enable us to
study coherent states in higher dimensions. Below we will explore an
example in 2D and examine the evolution in both coordinate and
momentum spaces.
Let us consider a coherent state prepared at t = 0 in a 2D box
(infinite potential well) as
The basis functions um and un are the same as Eq. (S:8.39), and the
eigenenergies are Emn = Em + En, the sum of individual eigenenergies
Em and En from Eq. (S:8.39). We can determine the amplitudes amn
from the wave function at t = 0 as (see Exercise E8.9)
QUANTUM REVIVAL
A coherent state of an isolated, finite quantum system has an
interesting property: periodic revival of its wave function. We
have seen an example of this from Figures 8.12 and 8.13. Let us
consider a coherent state expanded in the basis functions for a
particle in a box (S:8.39)
We see that 〈x〉 oscillates with a period 2πħ/ |Em − En|, which is
different than the revival period (8.55). What is more, the
energies of the states enter the equation. It shows that the
oscillation period is inversely proportional to the difference of
eigenenergies, not the eigenenergies themselves.7
The period tsc can be much smaller than tR. We leave further
exploration of quantum revival to Project P8.7.
Chapter summary
E8.2 (a) Fill in the steps from Eq. (8.6) to Eqs. (8.8a) and
(8.8b). (b) Prove Eq. (8.11) by explicit differentiation.
E8.3 Analyze the stability condition of the space discretized
TDSE. Assume the potential is zero in this exercise.
(b) Repeat the above with the leapfrog method to find the
stability criterion for the SDLF.
is
The results show that if the wave function is purely real
or imaginary aside from an overall multiplication
constant, then 〈p〉 = 0 and J = 0. Stationary states are in
this category. For nontrivial time-dependent processes
we are dealing with in this chapter, they are nonzero.
PROJECTS
P8.1 Explore the evolution of a wavepacket in the SHO
potential, and use Program 8.2 as the base program. In
this and other projects below, assume the wavepacket
describes an electron.
xexp = h*np.sum(x*pb)
This is the trapezoid rule, exact for a linear function. The local
error in Eq. (8.66) is O(h3), and the overall error is O(h2), or
O(1/N2).
Except for the end points f0 and fN that have a coefficient ,
the interior points appear twice in the sum (8.67), so their
coefficients are 1. We can rewrite Eq. (8.67) a little differently
as (dropping the error)
I = integral.simpson(f, h)
def f(x):
return np.sin(x)
I = itg.gauss(f, 0, np.pi)
print (I)
It means that
Three line objects are created and stored in the list plot
(line 13). The Matplotlib animation function (line 14) calls
updatefig() at regular intervals (in ms) to update the figure,
passing the frame number in the arguments by default. In
updatefig(), we scale the frame number as time, and update
the (x, y) data set for each of the lines in plot.
19 h, x, V, R, I = initialize (a, b, N) #
initialization
scene = vp.display(background=(1,1,1), ambient=1) # set
scene
21 bars = vpm.bars(x, z, z, z, h, 0.05, (1,0,1)) # wave
function
line = vpm.line(x, z, z, (1,0,1), 0.02)
23 pot = vpm.line(x, V*0.05, z, (0,0,0), 0.02) #
potential line
sum, w = f[0]+f[n−1], 4
8 for i in range(1, n−1):
sum = sum + w*f[i]
10 w=6−w # alternate between 4, 2
return h*(sum/3. + extra/2.)
12
n = 36 # order
4 p = legendre(n)
x = p.weights [:,0] # abscissa
6 w = p.weights [:,1] # weight
8 for i in range(n):
print ( ’%20.16f %20.16f’ %(x[i], w[i]))
2
Many aspects of quantum mechanics do not seem intuitive to us classical beings,
making computer simulations of quantum systems all the more expedient and interesting.
3 2
For Coulomb potentials, we can set e /4πε0 = 1 in atomic units.
4
This technique is also known as the method of lines.
5
An alternative is to use Numba, or call compiled codes in Fortran or C/C++ using F2Py,
Weave, or Cython (see Section 1.3.2, and Programs 5.7 and S:11.3).
6
“It is weird that quantum mechanics is not weird”, Nevin (a student of mine) thus
exclaimed after seeing quantum mechanics in action and working like classical mechanics.
7
Another example is found in the hydrogen transition frequency which also depends on
the difference of eigenenergies.
Chapter 9
Time-independent quantum
mechanics
We saw in Chapter 8 that time-dependent quantum motion
could be studied in its own right, but some features such as
quantum transitions are connected to the stationary states of
time-independent quantum systems where the potential has no
explicit dependence on time. Transitions between these states
give rise to discrete emission lines which could not be
explained by classical physics when they were discovered
around the turn of the twentieth century. In fact, one of the
most spectacular successes of quantum mechanics was its full
explanation of the hydrogen spectra, helping to establish
quantum physics as the correct theory at the atomic scale.
Program 9.1 steps through the energy range −V0 < E < 0 at
fixed increments. One can show analytically and graphically
that no bound states exist outside this range (Project P9.1). At a
given energy E, the program integrates the Schrödinger
equation from x = −R upward to x = 0, instead of x = +R. The
reason is that as x → ±∞, there are two mathematical solutions,
one exponentially decaying and another exponentially growing.
The former is physically acceptable, but the latter is
numerically dominant. A small error will be exponentially
magnified and overwhelm the correct solution. We saw the
same kind of divergence in the calculation of the golden mean
(Section 1.2.2). This means that if we were to integrate to x = ∞,
the wave function will never be zero at the boundaries, and will
fail the test u(∞) = 0, no matter how exact the energy E is.
The results from Program 9.2 are shown in Figure 9.3. The
parameter values are a = 4, b = 1, and V0 = 6. We again see four
bound states, two even and two odd, the same as the single well
potential. But there are several differences. The wave functions
are very different. For the ground state (−4.907), we see a
double hump structure rather than a single peak. This is caused
by the barrier in the middle. Inside the barrier, the wave
function does not oscillate and must either decay or grow
exponentially. We can understand this from Eq. (9.2), u″ = 2(V
− E)u. Below the potential, V − E is positive, so u″ and u have
the same sign. If u, and hence its second derivative u″, is
positive, the wave function must be concave up, so it will stay
positive (remember no nodes allowed for the ground state).
Similarly for negative u, the opposite is true. Therefore, the
wave function in each well has to bend and passes a maximum
so as to decrease to zero at x = ±∞. In the next even state
(−2.005), a local peak is formed within the barrier for the same
reason, the only way to have two nodes.
The plus and minus signs correspond to the even and odd
states, respectively, i.e., u±(−x) = ±u±(x), assuming φ(−x) =
φ(x). Equation (9.7) represents a linear combination of atomic
orbitals (LCAO). The function φ would describe the ground
state in one of the wells (single-particle state). As the barrier
width becomes large, the two wells are increasingly
independent, so the two states become approximately
degenerate with the same energy.
There are only two states for a single well. For the double
well, there are three states in total. The extra state comes from
the ground state of the single well which splits into two
adjacent levels, one slightly below and the other slightly above
the original level. The two levels come from the near
degeneracy we discussed regarding the double well potential in
Figure 9.3.
The first three bound states agree with the exact results to
four digits, and the fourth to two digits. The accuracy (second
order) is good except for the fourth bound state. The reason is
that the highest bound state is close to the continuum, and
coupling to (i.e., mixing with) the pseudo-continuum makes its
accuracy worse. The FDM results are less accurate than the
shooting method which is of a higher order with either RK45 or
Numerov's method, and does not suffer from pseudo-
continuum coupling. If we need only a few discrete states or
high accuracy, the shooting method is better suited than the
FDM. But the FDM is much simpler to use and can produce
bound states en masse.
From Eq. (6.43) and the discussion following it, the value qj
is zero unless j = 0 or j = N. Because the boundary values u0 =
uN = 0 for bound states are already known, we can remove the
indices j = 0 and j = N from Eq. (9.13). As a result, we can
eliminate qj entirely from Eq. (9.13).
Collecting Aij from (6.54) and Bij above, we can express the
kinetic, potential, and overlap matrices as
All three matrices are tridiagonal with dimensions
(N−1)×(N−1). Except for a multiplication factor, the matrix
in FEM basis is identical to the FDM version, Eq. (9.10).
1 def Vij(i, j): # pot. matrix Vij over [xi, xi+1] by order−4
Gaussian
x=np.array([0.3399810435848564, 0.8611363115940525])
# abscissa
3 w=np.array([0.6521451548625463, 0.3478548451374545])
# weight
phi = lambda i, x: 1.0 − abs(x−xa[i])/h # tent
function
5 vV, hh = np.vectorize(V), h/2.0 #
vectorize V
x1, x2 = xa[i] + hh − hh*x, xa[i] + hh + hh*x
7 return hh*np.sum(w * (vV(x1) * phi(i, x1) * phi(j, x1) +
vV(x2) * phi(i, x2) * phi(j, x2)) )
9
def V_mat(): # fill potential matrix
11 Vm = np.zeros((N−1,N−1))
for i in range(N): # for each element # contribution
to:
13 if (i>0): Vm[i−1,i−1] += Vij(i, i) # left
node
if (i < N−1): Vm[i,i] += Vij(i+1, i+1) # right
node
15 if (i>0 and i< N−1):
Vm[i−1,i] += Vij(i, i+1) # off
diagonals
17 Vm[i,i−1] = Vm[i−1,i] #
symmetry
return Vm
Figure 9.5: The bound state wave function of the Dirac δ atom.
below which the excited state ceases to exist. We can see that
the critical value ac comes from Eq. (9.25) by requiring k− = 0
and noting the special value W(−e−1) = −1 in Eq. (3.22). The
energy E−, ever increasing with decreasing a, has reached zero
at ac and entered the continuum for a < ac. On the other hand,
the energy of the ground state continues to decrease below the
critical distance, finally approaching E+ = −4E0, the united
atom limit at a = 0.
where a and V0 are the width and depth of the square well as
usual. It can be evaluated either numerically or analytically
(Exercise E9.9). We have assumed the box is centered at origin,
−L/2 ≤ x ≤ L/2, so Vmn is zero unless m + n is even.
The advantage of using the box basis set is that the basis
functions are simple, elementary functions. The required
matrices are easy to generate. In fact, Vmn as given by Eq. (9.31)
can be efficiently evaluated using FFT. But convergence can be
slow with increasing N for the upper excited states close to the
continuum, mainly caused by coupling to pseudo-continuum
states discussed earlier.
Figure 9.8: Energy-level diagrams for a rigid box (left), the SHO
(center), and the wedged linear potential (right).
Half-open space
The full SHO basis set spans the whole space. For bound
systems that exist in the half-open space, 0 ≤ x < ∞, the
boundary conditions are u(0) = u(∞) = 0. For example, one
such system is a particle bouncing between a hard wall and a
linear potential similar to quantum free fall in Section 8.3.2.
The potential is V(0) = ∞, and V(x) = βx for x > 0 (Figure 9.9).
Figure 9.9: A hard wall at x = 0 plus a linear potential for x > 0.
We can still use the SHO basis set, but only half of it. The
even-n basis states of Eq. (9.33) are nonzero at the origin, and
must be discarded because they do not satisfy the boundary
conditions. The odd-n basis states, however, do satisfy the
boundary conditions. They are what we need. In fact, these
states are eigenstates of the SHO in the half-open space:
, for x > 0. Therefore, they are a complete
basis set for the half-open space.
The effective potential Veff is the same as Eq. (4.8) for planetary
motion, with the replacement of L2 → l(l + 1)ħ2. The limiting
behavior of u is , and .
Figure 9.12: The radial wave functions of the first six states of
hydrogen. The dotted lines represent the effective potential.
.6 Quantum dot
We have discussed solutions to 1D quantum systems and 3D
central field problems that are effectively one-dimensional in
the radial direction. In this section, we will study 2D quantum
systems.
Perhaps the most interesting among them are quantum
dots [45], systems confined to sizes in the nanometer range.
Some occur in lattice structure, but they are often fabricated in
semiconductors using techniques such as precision
lithography, and are sometimes called designer atoms.9 Their
shapes can be simple or highly irregular. In the latter case,
enforcing boundary conditions can be problematic. One of the
advantages of the FEM is its ability to adapt to flexible
boundaries. We will extend the FEM to solve the Schrödinger
equation in 2D and use it to study quantum dots.
where the sums on the LHS and RHS refer to internal and
boundary nodes, respectively. As before, ui is the solution in
the expansion (7.9), and Aij, qj, and pj are respectively defined
in Eqs. (7.19) and (7.17).
That leaves the second term, pj, as the only nonzero term.
The expression for pj follows from Eq. (7.17) with f identified
above for the Schrödinger equation
Like Eq. (9.14) in 1D FEM, Vij is the potential matrix and Bij the
overlap matrix between the tent functions ϕi and ϕj.
Figure 9.15: The FEM mesh for the right triangular box.
Chapter summary
The focal area of this chapter is the simulation of time-
independent quantum systems. We studied systems such as
simple wells, linear potentials, central field potentials, and
quantum dots. We discussed several methods for solving the
Schrödinger equation to obtain the energy spectrum and the
wave function. Solutions to any given potential including
singular potentials can be found using at least one of the
methods presented, making the study of any quantum system
within our grasp. Furthermore, each of the methods can be
used with minimum modification, at most requiring the user to
supply a custom potential function.
E9.10 Show that the matrix elements for x, x2, p, and p2 in the
SHO basis are
Projects
P9.1 (a) Run Program 9.1 with E starting below the bottom
of the well, say −2V0 < E < −V0. Describe the shape of
the wave function and explain why no bound state
exists.
(b) Modify Program 9.1 to find the odd bound states.
Instead of the derivative being zero at x = 0, the wave
function itself is zero. Modify the conditional statement
in the main loop to detect the sign change in the wave
function. Also add a negative sign to the wave function
for x > 0.
(c) Modify the program so it can find both even and odd
states. Double the width of the well, find the number of
all bound states (both even and odd). Do the same, but
double the depth. Which way is more effective at
increasing the number of bound states? Briefly explain.
x0.
(a) Let and x0 = 0. Use the shooting method
P9.6 (a) Calculate the energy and wave function of the bound
state of the Dirac δ atom. Assume α = 1. Use the FEM
code, Program 9.3, and modify the potential matrix so
that the only nonzero matrix element is at the node
where the δ potential is located. Plot the numerical and
analytic wave functions in the same figure, normalize
both at the center. Compare numerical and exact results
for the energy and wave function.
Note that all states are higher than hydrogen, except the
1s state. Explain why (a figure similar to Figure 9.12
should be helpful).
P9.9 (a) Calculate and plot the wave functions of the unit
circle quantum dot (billiard, Section S:9.2.1) using the
supplied mesh data file. Discuss the symmetry of the
degenerate states.
.A Numerov's method
The Numerov method is useful for a second order ODE of the
following form that does not contain first derivatives
Using the Taylor series for y(x ± h) from Eqs. (2.9) and (2.10)
and adding them up, we have,
or in terms of the y″
Let zn and be the n-th zero of Ai(x) and its derivative Ai′
(x), respectively. The eigenenergies can be found from Eq.
(9.63) as
Table 9.4: The first six zeros of Airy function and its derivative.
If other zeros are needed, they may be generated from the
code below using the SciPy special function library.
15 m, Vm = np.arange(N−2), np.zeros((N,N))
mm = np.sqrt((m+1)*(m+2)) # calc T
matrix
17 Tm = np.diag(np.arange(1, N+N, 2,float)) # diagonal
Tm −= np.diag(mm, 2) + np.diag(mm, −2) # off
diagonal by +/−2
19 for m in range(N): # calc V matrix
for n in range(m, N, 2): # m+n is even every 2
steps
21 Vm[m, n] = 2*itg.gauss(uVu, 0., 10*a0) # use symm.
if (m != n): Vm[n,m] = Vm[m,n]
23 Tm = Tm*omega/4.
E, u = eigsh(Tm + Vm, 6, which= ’SA’) # get lowest 6 states
25
zn, zpn, zbn, zbpn = ai_zeros(3) # find exact values
27 Ex = − beta*x0*np.insert(zpn, range(1, 4), zn) # combine
even/odd
print (E, E/Ex)
21 def shoot(En):
global E # E needed in f(r)
23 E, c, xm = En, (h*h)/6., xL + M*h
wfup, nup = numerov(f, [0,.1], M, xL, h)
25 wfdn, ndn = numerov(f, [0,.1], N−M, xR, −h) # f′ from Eq.
(9.60)
dup = ((1+c*f(xm+h))*wfup[−1] −
(1+c*f(xm−h))*wfup[−3])/(h+h)
27 ddn = ((1+c*f(xm+h))*wfdn[−3] −
(1+c*f(xm−h))*wfdn[−1])/(h+h)
return dup*wfdn[−2] − wfup[−2]*ddn
29
xL, xR, N = 0., 120., 2200 # limits, intervals
31 h, mass = (xR−xL)/N, 1.0 # step size, mass
Lmax, EL, M = 4, [], 100 # M = matching point
33
Estart, dE = −.5/np.arange(1, Lmax+1)**2−.1, 0.001 # ∼
2
−1/2n
35 for L in range(Lmax):
n, E1, Ea = L+1, Estart[L], []
37 while (E1 < −4*dE): # sweep E range for each L
E1 += dE
39 if (shoot(E1)*shoot(E1 + dE) > 0): continue
E = rtf. bisect (shoot, E1, E1 + dE, 1.e−8)
41 Ea.append(E)
wfup, nup = numerov(f, [0,.1], M−1, xL, h) # calc wf
43 wfdn, ndn = numerov(f, [0,.1], N−M−1, xR, −h)
psix = np.concatenate((wfup[:−1], wfdn[::−1]))
45 psix [M:] *= wfup[−1]/wfdn[−1] # match
print ( ’nodes, n,l,E=’, nup+ndn, n, L, E)
47 n += 1
EL.append(Ea)
49
plt.figure () # plot energy levels
51 for L in range(Lmax):
for i in range(len(EL[L])):
53 plt.plot ([L−.3, L+.3], [EL[L][i]]*2, ’k-’)
plt.xlabel(’l’), plt.ylabel(’E’)
55 plt.ylim(−.51, 0), plt.xticks (range(Lmax))
plt.show()
The functions Veff() and f() calculate the effective
potential and the Schrödinger equation (9.8), respectively. The
routine numerov() is a standalone Numerov integrator. It
receives f(x) to be integrated as input, together with initial
values [u0, u1], number of steps n to advance, starting position
x, and step size h. On return, the n new values plus the initial
pair are contained in u = [u0, u1, ···, un+1]. The same module is
included in the ODE library ode.py for convenience.
import numpy as np
2
def abg(p1, p2, p3): # return alpha, beta, gamma, area of
element
4 [x1,y1], [x2,y2], [x3,y3] = p1, p2, p3
alfa = [x2*y3 − x3*y2, x3*y1 − x1*y3, x1*y2 − x2*y1]
6 beta, gama = [y2−y3, y3−y1, y1−y2], [x3−x2, x1−x3,
x2−x1]
area = 0.5*(alfa [0] + alfa [1] + alfa [2]) # area of
triangle
8 return alfa, beta, gama, area
40 plt.show()
If the mesh is such that the system matrices are banded, the
program can be modified to use a banded eigensolver,
eig_banded. The program could then handle very large matrices
# nodes
[0.0, 0.0], [1.0, 0.0], [2.0, 0.0],
[0.0, 0.5], [1.0, 0.5], [2.0, 0.5],
[0.0, 1.0], [1.0, 1.0], [2.0, 1.0],
# elements
[0, 4, 3], [0, 1, 4], [1, 5, 4], [1, 2, 5],
[3, 7, 6], [3, 4, 7], [4, 8, 7], [4, 5, 8],
# boundary nodes
0, 1, 2, 3, 5, 6, 7, 8,
# internal nodes
4,
1
The study concluded: “Students … are weaned on continuous, well-behaved functions
and variables. It is therefore often a shock to them when they study quantum mechanics and
find, suddenly, discrete variables. The purpose of the computer-generated film described in
this paper is to illustrate that these discrete variables are not so peculiar after all – that, in
fact, they arise in a natural way from requiring the solution of the Schrödinger equation to be
continuous, differentiable, and finite”.
2
A mathematically equivalent form to Eq. (9.5) is , but this is
not stable for numerical work, because the wave function or its derivative can become close
to zero, and f(E) could fluctuate wildly.
3
Owing to the boundary conditions, these positive energy states are bound states in the
(numerically finite) box, mimicking the true continuum states of the actual, infinite system.
4
This was discussed in Chapter 7 and illustrated in Figure 7.10 for FEM in 2D. The
reason is still true in 1D.
5
The Dirac δ molecule is a good model for understanding the qualitative features of
diatomic molecules such as , where the terms “gerade” and “ungerade” are used to
describe the symmetric ground and the antisymmetric excited states, respectively.
6
The wave functions un are available from SymPy: sympy.physics.qho_1d.psi_n.
7
Technically, a particle never becomes free in the Coulomb potential, even though it can
escape to infinity if its energy is positive. In this case, the continuum wave function is
distorted compared to the plane wave representing a truly free particle. See Section 12.B and
Exercise S:E12.7.
Because 〈r〉 scales like n , numerical integration must extend to large distances for
8 2
9
Quantum dots are literally shining a new light on quantum mechanics. Since the energy
levels, hence light emission, can be manually controlled via shape and size, they are
beginning to usher in new technologies such as the quantum dot display.
10
For other nontrivial potentials, numerical integration is more conveniently carried out
by mapping the triangles to a simpler shape such as isosceles right triangles through
coordinate transformations.
11
Here we ascribe the term “diagonals” to lines connecting the opposite vertices, and
bisectors to lines connecting the centers of opposite edges.
Chapter 10
Simple random problems
Many systems behave unpredictably and randomly, or at least
seem to. Some are random due to a lack of information such as
a coin toss or the golden autumn leaves fluttering and falling in
the wind. Other systems, though perfectly deterministic and
well defined, are still random because of their intrinsic,
probabilistic nature, such as the radioactive particle decay and
measurement of quantum systems.
deltaN = 0
for i in range(N):
x = rnd.random()
if (x < p):
deltaN = deltaN + 1
N = N − deltaN
Random walk in 1D
In one-dimensional random walks, there are only two possible
directions, left or right. Let the unit step be l, so each step has a
displacement of ±l. If a walker starts from the origin, the
position x, and its square x2, after n steps are
Random walk in 2D
We can generalize 1D random walks to 2D via the displacement
vector . We need to determine x and y in some
random fashion.
Figure 10.4 shows four walkers starting from the origin and
moving with unit step size and uniform angular distribution
(isotropic). The individual walks vary greatly as seen before in
1D random walks. We have to characterize an ensemble of
walkers statistically. For instance, the average position and
position squared are defined accordingly as ensemble averages,
f, N = 0., 1000
for i in range(N):
x = − np.log(rnd.random()) # exponential distribution
f += np.cos(x)
Chapter summary
E10.4
Prove the relations (10.9). For 〈x2(n)〉, group the terms
as
show that
(b) Calculate I(m, n) using Monte Carlo integration.
First choose a fixed m = 3 and n = 10, and vary the
number of sampling points from N = 10 to 106 by
factors of 10. Compare the Monte Carlo and analytic
results. Plot the results on a semilog N scale, and
discuss convergence.
PROJECTS
P10.1 Simulate 1D random walks. Construct a program that
calculates individual path of a single walker, as well as
the averages 〈x(n)〉 and 〈x2(n)〉 for N walkers as a
function of step number n.
10.B). Test your code with sin x dx, and compare the
with .
For large t 1/b, we can drop the second term in the bracket of
Eq. (10.38) all together, so that
REJECTION METHOD
Often, it is not possible to find the inverse function analytically.
For example, one of the most useful distributions, the Gaussian
distribution, cannot be generated by the inverse transform
method (though it is possible using two variables, see Exercise
E10.8). Sometimes the distribution itself cannot be expressed
as a simple, compact function. Rather, it may be in the form of
discrete data like a lookup table. In such cases, we can use the
rejection method which always works.
The idea is similar to the hit-or-miss method (Project
P10.4). Let H be greater or equal to the maximum value of
py(y) in the range y ∈ [a, b]. We put a box stretching from the
lower-left corner [a, 0] to the upper-right corner [b, H]. The
sampling procedure is as follows (as usual, x is uniform in [0,
1)):
1
NumPy also has a random library that is especially useful for generating arrays of
random distributions. For example, see the use of np.random.rand(N) in Program 10.2.
2
This is true to the extent the pseudo-random numbers are uncorrelated, of course.
3
These were the ratios used to approximate π by the fifth century Chinese mathematician
Zu Chongzhi.
Chapter 11
Thermal systems
Up to the last chapter, we had built simulations from first
principles, i.e., calculations were done from Newton's laws or
the Schrödinger equation. Thermal systems, however, require a
different, statistical approach since they are made up of large
numbers of atoms and molecules. Macroscopic thermal
properties are determined by the microscopic interactions
between these particles. Given that the number of particles is at
least on the order of the Avogadro number ∼ 1023, we cannot
hope to simulate thermal systems using first-principle
calculations by tracking all the individual particles.1 Nor would
we want to. Even if their individual properties such as the
energies or velocities were available, we would not be able to
make sense out of that many particles without statistics. It
turns out that we can model much smaller thermal systems and
still simulate the statistical properties of large systems,
provided we sample them correctly and be mindful of the
limitations.
We begin with thermodynamics of equilibrium, exploring
the role of energy sharing, entropy, and temperature as the
driving forces toward equilibrium: the Boltzmann distribution.
We then introduce the Metropolis algorithm and apply it to
study 1D and 2D Ising models, carefully comparing numerical
and analytic solutions where possible, including phase
transitions. After fully assessing the Metropolis method, we
extend it to the study of non-thermal systems such as the
hanging tablecloth via simulated annealing. Finally, we
investigate the thermalization of N-body atomic systems and
kinetic gas theory by molecular dynamics, connecting first-
principle calculations to thermal properties.
11.1.2 ENTROPY
We have seen from above that the thermal system marches
from an ordered initial configuration toward somewhat
disordered equilibrium configuration. The energy distribution
follows a probabilistic course of action given by the exponential
factor. The probability is extremely low that the system would
spontaneously go back to the ordered initial state, even for our
very tiny system of a few thousand oscillators. This all seems
purely mathematical.
11.1.3 TEMPERATURE
We intuitively know that when two systems are in equilibrium,
they have the same temperature. This leads us to expect that
there is a connection between temperature and entropy
reaching maximum in the above example.
Figure 11.5: The changes of entropy per oscillator vs. iterations (left)
and vs. energy exchange (right) between two equal-sized Einstein
solids.
Our small microsystem has very little effect on the
temperature of the reservoir because the amount of energy
exchanged is limited. We can gain more insight into the
equilibrium process by changing the relative sizes of the
interacting systems.
We can see from the slope change in Figure 11.6 that the
difference in temperature measures the tendency to give off
energy. A body at a higher temperature tends to lose heat, and
a body at a lower temperature tends to gain heat. Restated in
temperature, the equilibrium condition (11.6) is TA = TB.
Figure 11.7: The temperatures of two interacting solids. The
parameters are the same as in Figure 11.6.
Figure 11.13: The 2D Ising model. Each spin interacts with four
nearest neighbors.
This is similar to Eq. (11.17) but with two more neighbors. If the
picked spin is on the edge, we use the periodic boundary
conditions (11.16) horizontally (column-wise) and vertically
(row-wise).
Phase transitions
Chapter summary
choose n”.
E11.3 (a) Show that the partition function and the average
energy for an SHO are
Assume , n = 0, 1, 2, …, and ε = ħω is a
unit of energy.
E11.4
(a) For N 1, Stirling's approximation can be used to
compute N! as
E11.8 (a) Derive the energy (11.59) and heat capacity (11.60)
of the 2D Ising model.
PROJECTS
P11.1 Explore the Einstein solid model.
(a) Make a table listing all possible microstates of an
Einstein solid for N = 3 and q = 4. Verify that the total
number agrees with the multiplicity from Eq. (11.45).
Plot ΔSA, ΔSB, and ΔST vs. qA on the linear scale and vs.
the (cumulative) iteration number on the semilog x scale.
entropy at T2 as with .
From Eq. (11.10), it can be shown that the energy per spin is
(Exercise E11.8)
and the heat capacity per spin is, from Eq. (11.11),
In Eqs. (11.59) and (11.60), the functions K(m) and E(m) are
the complete elliptic integrals of the first and second kind (Sec.
11.12 of Ref. [10]), respectively,
Figure 11.27: The complete elliptic integrals of the first and second
kind. The first kind K(m) diverges logarithmically as m → 1.
11 K = 20 # grid dimension
solid = EinsteinSolid(N = K*K, q=10) # 10 units of energy/cell
13 fig = plt. figure ()
img = np.reshape(solid. cell, (K,K)) # shape to KxK image
15 plot = plt.imshow(img, interpolation= ’none’, vmin=0, vmax=50)
plt. colorbar(plot)
17
cell. The histograms are made with the step plotter plt.step()
(see Figure S:9.1), normalized to 1 at the maximum and
centered at the midpoints. To reduce crowdedness, the x tick
labels for the first two rows are omitted.
25 N, passes = 1000, 10
iter, Nmc = passes*N, passes*N
27 T, Eavg, Mavg = [], [], []
for i in range(1,41): # temperature loop
29 kT = 0.1*i # kT = reservoir temperature
spin, E, M = initialize (N)
31 for k in range(iter): # let it equilibrate
E, M = update(N, spin, kT, E, M)
33
E1, M1 = 0., 0.
35 for k in range(Nmc): # take averages
E, M = update(N, spin, kT, E, M)
37 E1, M1 = E1 + E, M1 + M
E1, M1 = E1/Nmc, M1/Nmc
39 T.append(kT), Eavg.append(E1/N), Mavg.append(M1/N)
41 plt. figure ()
plt. plot(T, Eavg, ’o’, T, −np.tanh(1./np.array(T)))
43 plt. xlabel(’kT/ε’), plt.ylabel(r’〈E〉/Nε’)
plt. figure ()
45 plt. plot(T, Mavg, ’o’)
plt. xlabel(’kT/ε’), plt.ylabel(r’〈M〉/N’)
47 plt.show()
19
33 while (1):
vpm.wait(scene), vp.rate(1000)
35 r, v = ode.leapfrog(nbody, r, v, t, h)
r [r > L] −= L # periodic bc
37 r [r < 0.] += L
for i in range(N): atoms[i]. pos = r[i] # move atoms
1
The amount of memory in all the computers in the world would not be nearly enough,
short by a few orders of magnitude, to just store the positions of the particles in a can of air.
2
We cannot prove it, but there are no other more plausible alternatives.
3
A Python list is faster than an ndarray for explicit looping (see Section 2.3.2).
4
Numerically calculating derivatives of a fluctuating function is worse than undesirable
and should be attempted only for educational purposes.
5
A more serious technical barrier is the period of the pseudo-random number generator,
19937
which is 2 as currently implemented in Python. It means that we could simulate a
4
system of no more than 10 spins by brute force.
6
It is as if Richard Feynman was referring to molecular dynamics when he wrote [29]
“what statement would contain the most information in the fewest words? I believe it is the
atomic hypothesis that all things are made of atoms − little particles that move around in
perpetual motion, attracting each other when they are a little distance apart, but repelling
upon being squeezed into one another”. feynmanlectures.caltech.edu/I_01.html
7
Naturally, the Lennard-Jones potential is also given the moniker of “6−12” potential.
Chapter 12
Classical and quantum
scattering
Most problems we have discussed so far, from harmonic
oscillations to planet motion, are bound systems. There are
unbound systems in our physical world, such as light scattering
from water droplets making rainbows, as well as proton-proton
collisions leading to the recent discovery of Higgs boson in the
world's largest atom smasher. These are scattering problems.
To study them, we need a fundamentally new approach to
account for the fact that particles come in from infinity and go
out to infinity.
where the sum is over all values of Θ and b that yield the same
observable scattering angle θ. We shall see an example of this
later on.
The total cross section, σt, can be obtained from Eq. (12.6)
by
Figure 12.6: Scattering from the plum potential at two energies. The
circle represents the size of the plum sphere.
Below we will use the direct method (12.11) for the results
(Program 12.1). Figure 12.7 shows the cross sections for the
plum potential. At the lower energy (Figure 12.7, left), the cross
section behaves like Rutherford scattering from small angles to
just below π/2, where a small plateau develops. The energy is
such that the particle can enter the outer layers of the core, but
is eventually deflected because the energy is still below the
peak of the potential. We can see a small shoulder in the
deflection function responsible for this effect (a slight change in
curvature, barely visible in Figure 12.5 near ). Beyond
the plateau, large scattering angles are predominantly due to
scattering at the core.
Figure 12.7: The cross sections for the plum potential at two
energies. The cross section diverges at the rainbow angle (E = 2,
right).
Figure 12.8: The deflection (left) and scattering (right) angles for the
Yukawa potential (Z = 2, a = 1) at E = 0.1. Five impact parameters
contribute to the scattering angle , marked as (•) on the curves.
Figure 12.9: The cross sections for the Yukawa potential with the
same parameters as in Figure 12.8.
We can now interpret the phase shift in real sine waves. Figure
12.11 (bottom) shows two cases, a positive phase shift
corresponding to a sine wave pulled back, and a negative one to
a sine wave pushed forward (see Figure 12.17 for an actual
case). Attractive potentials produce positive phase shifts, and
repulsive ones produce negative phase shifts. Another
explanation for the factor of two is that the wave is shifted once
on the way in and once on the way out.
Figure 12.12: Phase shift from the delta-wall potential (Figure 9.21).
Figure 12.12 shows an example of phase shifts from the
delta-wall potential, a delta potential −αδ(x − a/2) placed to
the right of a hard wall (Figure 9.21). We can find the phase
shift analytically (Exercise E12.6),
i(kr−lπ/2)
Like the 1D case (12.20), we recognize e /r in Eq.
(12.27) as the incoming and outgoing spherical waves,
respectively. This fact readily lends itself to the interpretation
that the incoming wave is scattered into an outgoing wave with
zero phase shifts because V = 0.
2 2
Figure 12.14: The total and scattered waves, |rψ| and |rψsc| , shown
in the top and the bottom rows, respectively, for scattering from a
hard sphere at two energies, ka = 0.01 (left column) and 2 (right
column).
At the lower energy, both the total and the scattered waves
are nearly independent of directions, showing a high degree of
isotropy. Here, the de Broglie wavelength is long compared to
the sphere or any structure of the potential, so the scattering
amplitude f(θ) has little angular dependence.
Figure 12.15: The differential (left) and total cross sections (right) for
scattering from a hard sphere. The dotted line indicates the classical
cross section.
Figure 12.17 shows the first two radial wave functions ul(kr)
at the energy E = 1. They start from zero and show faster
oscillations than free-particle solutions in the inner region.5
For direct comparison, the peak values are normalized to be
equal. The faster oscillations, or shorter wavelengths, cause the
scattered waves to accumulate phase at a faster rate than the
unscattered free waves, giving rise to positive phase shifts.
Conversely, if the potential was repulsive, the scattered waves
would be suppressed (larger wavelengths or decaying waves),
leading to negative phase shifts. Summarizing these
observations, we have for the sign of phase shifts,
Figure 12.17: Radial wave functions ul for l = 0 and 1 for the Yukawa
potential with Z = 2 and a = 1. The energy is E = 1, or .
The dashed lines are the field-free solutions jl(kr).
For potentials with mixed signs, the sign of the phase shift is
indeterminate, depending on the average effects of the
interaction.
Chapter summary
E12.6 (a) Show that the phase shift of the delta-wall potential
(Figure 9.21, Exercise E9.7) is given by Eq. (12.22).
Assuming m = 1 and α = 1, calculate and plot the phase
where and .
E12.7 (a) Show that for the square spherical potential well, V
= −V0 for r ≤ a, and V = 0 for r > a, the β value in Eq.
(12.35) is given by
Prove that for l = 0, with the β value above, Eq. (12.35)
is identical to the 1D result of Exercise E12.6.
PROJECTS
P12.1 (a) Explore Rutherford scattering numerically. Plot the
trajectories (12.50) for different impact parameters as in
Figure 12.2. Assume atomic units. Consider low energy
plt.subplot(111, polar=True)
plt.plot(theta, r)
or convert (r, θ) to (x, y) plots. In either case, note that
the angle −α < θ < α in Eq. (12.50) is relative to the
radial bisector (Figure 12.1).
(a) Plot (or sketch to scale) these potentials for the same
parameters Z = 2 and a = 1. Compare the shapes of the
potential. Predict which potential will have the greatest
effect on scattering relative to the Yukawa potential.
45 plt.show()
for L in range(Lmax+1):
25 u, g = wf(M, a) # g= u’/u
x = np.arctan(((g*a−1)*jl[L] − k*a*dj[L])/ # phase shift Eq. (12.37)
27 ((g*a−1)*nl[L] − k*a*dn[L]))
while (x < 0.0): x += np.pi # handle jumps by pi
29 ps[L] = x
plt.figure ()
43 plt.plot(theta*180/np.pi, sigma) # plot cross sections
xtck = [0, 30, 60, 90, 120, 150, 180]
45 plt.xticks (xtck, [repr(i) for i in xtck]) # custom ticks
plt.xlabel(r’ $\theta$ (deg)’)
47 plt.ylabel(r’ $\sigma(\theta)$ (a.u.)’), plt.semilogy()
49 plt.show()
The remaining code plots the phase shifts and the cross
sections. We use customized tick marks (line 45) for the latter.
1
This fact is an exception rather than the rule. It is related to the special behavior
(symmetry) of the Coulomb potential which is also responsible for the Runge-Lenz vector
(4.20) being a constant of motion in 1/r fields. In general, the scattering angle depends on
the sign of noncoulombic potentials.
2
A rainbow in the sky looks slightly different to observers at different locations, so
everyone sees their own rainbow. You can easily make your own rainbow by holding a mist-
emitting hose facing away from the afternoon sun.
3
Like the rainbow, the glory has its origin in sunlight back-scattered by water droplets.
Basically, light rays entering the sides of a droplet are first refracted critically, then reflected
from the back to the other side, and refracted again, finally emerging from the droplet in the
opposite direction to the incident light [13]. The net effect is a colored ring around the
shadow of an observer's head on the cloud. It is rarer to observe the glory than the rainbow.
4 −1
Potentials decaying at or slower than x such as the Coulomb potential are long-
ranged. Particles are never free in long-ranged potentials, suffering distortions even at
infinity (see Exercise S:E12.7). As a result, scattering in these potentials does not have well-
defined phase shifts. The same effect causes an infinite number of bound states in the
Coulomb potential (Chapter 9, Section 9.5).
5
For l ≥ 1, true oscillations begin only after entering the classically allowed region
beyond the turning point (Figure S:12.1).
6
The recurrence relation (12.57) is stable in the downward direction for jl and in the
upward direction for nl (see Exercise S:E12.6).
List of programs
We have built many programs in this book. The table below
summarizes these programs and dependencies. Standard
libraries such as Matplotlib (2D), NumPy, and SciPy are
omitted. Library abbreviations are: fft – fast Fourier transform
( fft.py, Chapter 5); fem – finite element method ( fem.py,
Chapter 9); fileio – file input/output ( fileio.py, Chapter 9); itg
– numerical integration ( integral.py, Chapter 8); ode –
ordinary differential equation ( ode.py, Chapter 2); rtf – root
finders ( rootfinder.py, Chapter 3); and vpm – VPython
Modules ( vpm.py, Chapter 6). In addition, we also note the use
of 3D and animation libraries: Axes3D – Matplotlib 3D
plotting; am – Matplotlib animation; and vp – VPython.
Page numbers with the “S:” prefix are entries from the
Digital Online Companion.
linear, 91
quadratic, 103
animation
bouncing ball, 40
falling tablecloth
mechanical, 316
thermal, 596
planetary motion
Earth, 136
Mercury, 144
projectile motion, 84
quantum wavepacket
in SHO, 408
soccer, 117
three-body motion
choreography, 168
collinear, 167
elastic, S:220
representation, 416
baseball, 107
animation, 110
curveball, 110
drag coefficient, 89
binomial
coefficient, 610
distribution, 537
simulator, 560
catenary, S:47
centrifugal
chaos, 227
circle
approximation of π, 554
animation, S:228
comet, S:15–S:18
Halley's, S:15
ISON, S:15
commutator, S:76
debugging, 20
δ comb, S:129
cusp, 477
coefficient, 88
empirical formula, 90
quadratic, 88
viscosity, 87
temperature, 577
electromagnetic waves
electrostatic equilibrium
on a sphere, S:65
Euler method, 42
approximate, S:77
exoplanets, 158–164
HD 139357, 159
mechanical, 315
thermal, 596
aliasing, S:40
two-dimensional, 432
error, 359
accuracy, 359
error, 499
fitting, 163
fixed-point number, 23
floating point, 24
bit shifting, 26
byte string, 25
machine accuracy, 5, 26
mantissa, 4, 24
phantom bit, 25
round-off error, 26
football, 128
fractals, 251
free fall, 42
animation, 40
Euler's method, 44
momentum profile, 423
Runge-Kutta methods, 51
recursion, 8
golf, 112
1+∈
modified potential, 1/r , 487, 511
installation, 26–28
IVisual, 19
Matplotlib inline, 17
1D, 578
3D, S:179
computation, 616
ferromagnetism, 578
IVisual, 19, 26
Kansa's method for PDEs, 363, see also radial basis function
planets, 143
evaluation, 100
laminar flow, 88
Laplace operator
area-preserving, 64
bifurcation, 225
renormalization, S:28
Matlab, 17
Matplotlib, 17, 30
3D plots
axis
label, 12
off, 391
width, 30
color, 30
colorbar, 391
configuration records, 31
contour
font size, 30
frame
off, 391
spacing, 30
IPython inline, 17
line
style, 30
marker, 30
color, S:60
pylab, 17
step plot, step, S:117
text label, 30
model building, 89
pressure, 608
units, 600
error, 547
ants, S:145
Newton
second law, 39
numerical differentiation
first order, 43
midpoint method, 48
numerical error, 5
global error, 45
in energy, 68
round-off, 6
truncation, 7
advanced indexing, 34
argmin, 206
array creation, 31
copy, 33
element insertion or deletion, 32, 291, 327, 388, 396, 523, 528
element-wise operations, 33, 37, 205, 306–307, 312–313, 330, 337, 391, 406, 455, 604,
621, 630, S:58, S:60
F2Py, 17
FFT, S:86
in 2D, 432
flatten, 388
meshgrid, 210
shape, 35
slicing, 32, 211, 306–307, 312–313, 330, 337, 384, 388, 417, 518, S:60
sorting, 389
stacking, S:60
transpose, 385
ordinary differential equation, 39, see also Euler, leapfrog, Numerov, and Runge-Kutta
methods
implicit method, 62
oscillation
damping, 273
resonance, 275
partial differential equation, 271, see also Laplace, Schrödinger, and wave equations
properties, 139
simulation, 136
units, 143
oscillations, 153
projectile motion, 83
linear drag, 91
visualizing, 84
Python, 10
conditional, 13
exception, 528
indentation, 12
input, 12
installation, 26
list, 12
append, 12
count, 627
nested, 387
slicing, 33
sorting, 388
profiling, S:109
chaoticity, S:125
histogram, S:124
scars, S:125
degeneracy, 501
hexagon, 499
stadium, S:118
triangle, 508
T-matrix, S:212
elastic, S:245
inelastic, S:211
amplitudes, S:88
in hydrogen, S:105
integer, 566
Lorentzian, 551
seed, 534
in 2D, 538
recursion
units, 173
Reynolds number, 87
root finding, 94
Runge-Kutta methods, 46
characteristic time, 61
non-vectorized, 60
SciPy wrapper, 81
SciPy, 16
Bessel function
spherical, 660
zeros, S:128
combination, 614
Weave, 17
animation, 273
classical, 66
soccer, 116
stability, 405
special function
Airy function, 483, 507, 515, S:130
zeros, 516
recurrence, 677
zeros, S:128
addition, S:251
orthogonality, S:251
error, 419
Stoke's law, 87
first order, 71
factorization, 257
physics
series, 186
temperature
Curie, 592
thermodynamics, 564
choreography, 168
turbulent flow, 88
unitarity, S:76
Verlet, see leapfrog method
vibration, 277
string, 300
viscosity, 86–87
air, 122
VPython, 18
camera angle, 20
curve, 133
faces, 377
helix, 273
in GlowScript, 30
IVisual, 19
box, 396
making movies, 30
rate requirement, 19
retain, 85
ring, 212
sphere, 41
VIDLE, 29
VPython modules (VPM), 14, 139, 307, 328, 330, 377, 452, 455, S:52, S:61–S:64
normalization, 412
conservation, 405
scarring, S:125
scattering, 656
broadening, 418
in 2D, 432
refocusing, 409
waves, 300–309
on a membrane, 311