Computational Physics Lab 2

Exploring ODE Algorithms


Whenever you model a dynamic system numerically, two very important questions invariably come up:
Which ODE algorithm to use?
How to pick the time step?
The purpose of this lab is to develop some intuition and gather experience needed to answer these questions.

Part 1. Implementing an ODE Solver

In this part of the lab you will implement and test an ODE solving algorithm. The 2nd order Runge-Kutta represents a good case to study.

Download the following python modules:

v3.py -- A 3d vector class
cpode.py -- Includes a base class for ODE solvers and a few algorithms (Euler, RK4, etc.)
cpforces.py -- A vector model for physical forces

Note the new implementation of the "EulerSolver" class in the cpode module. The features specific to the Euler method were extracted into a small class which now inherits from a much larger "OdeSolver" class (compare with the old code). Classes which implement other ODE solving algorithms (e.g., Euler-Cromer) also inherit from "OdeSolver" and modify just the part of the system specific to those algorithms. This kind of design conforms to the Don't Repeat Yourself (DRY) principle and allows for very efficient implementation of new ODE solvers.

The following examples illustrate the usage of the above modules. You can download them, make them executable, and run.

golf_ball.py -- Code in this file simulates the motion of the golf ball using the air drug and Magnus force models discussed by Giordano and Nakanishi in section 2.5. The ball trajectories generated by this script should be similar to the "normal drive" curve in Figure 2.13 of the textbook.

oscillations.py -- This example simulates the behavior of a simple harmonic oscillator using several different ODE solvers.

Write a python module which implements the 2nd order Runge-Kutta algorithm. For a dynamic ODE in the standard form

the 2nd order Runge-Kutta stepping scheme looks like this:

where

In your module you should implement a class which inherits from "cpode.OdeSolver", just like the "EulerSolver" and other classes inside "cpode.py". Modify the "oscillations.py" example so that you can see the curve produced by your algorithm when you know exactly what to expect. Modify the "golf_ball.py" example and use your algorithm instead of "EulerSolver" in order to make sure that your code works correctly with both scalar and vector forces.

Part 2. Exploring ODE Algorithm Performance

The purpose of this part of the lab is to study the precision of several ODE solving algorithms. We are going to model frictionless oscillatory motion. For this type of motion, conservation of energy provides an extremely usefull crosscheck of the algorithm performance. Proceed as follows:

1) Write a class which implements a 1-dimensional force model which corresponds to the following potential:

Your class should inherit from "cpforces.BasicForce", just like various classes in the cpforces module. In your calculations, don't forget that the derivative of |x| is sgn(x).

2) Replace the "RestoringForce" in the "oscillations.py" example with your model. Check that you get the same behavior as the original in case p = 2. See what happens for the case p = 8. (Note: the Euler method might behave very poorly or even diverge to infinity with the default time step values. Do you know why? Reduce Δt until it works reasonably well.) Does the oscillation period depend on the amplitude?

3) Simulate the motion for 10 periods for the cases p = 2 and p = 8 (you can determine the period for the p = 8 case by eyeballing the plots). For the last oscillation period, calculate the average relative energy error. For each time step i, the relative energy error is

and you need to average it over all steps in the period. The solver keeps the whole history of x and v values, you just need to use the last 1/10th of it. The energy is conserved, so that Eexact can be calculated from the initial conditions.

You might want to plot ei as a function of time. This will help you visualize the error trend and get a detailed impression about the algorithm performance.

4) Make a function which would perform average relative energy error calculation automatically for an arbitrary ODE solving algorithm and an arbitrary time step. Plot the relative energy precision as the function of the time step for several algorithms: Euler, Euler-Cromer, 2nd order Runge-Kutta, 4th order Runge-Kutta. Use logarithmic scales for both the time step and the precision (you can use the loglog function to do this) -- then the plot will tell you directly the number of significant digits in your results. Useful Δt range is from 1 to 10-5 or so, for smaller time steps Python solver becomes too slow. What is the empirical order of convergence of these algorithms for p = 2 and p = 8? At what Δt value the precision of the 4th order Runge-Kutta algorithm is dominated by the round-off errors?


Please submit your lab report before 2 pm 01/29/08. In your report, include the script which generates the plots from Part 2 item 4) and place a small text file named "lab2_report.txt" with your conclusions about convergence rates in the "doc" directory.