ODE Solvers - AM Exercises
ODE Solvers - AM Exercises
Solving Ordinary Differential Equations (ODEs)
You can download the slides for this lecture
here
The intentions behind this exercise are:
- To give you a clear goal to meet
- To give you a chance to revise or learn a few things. Specifically:
- The abstract base class pattern;
- Unit testing with
unittest
; - Ordinary differential equation solver implementations.
A nice feature of this assignment is that you are provided with a testing infrastructure
which gives an
implicit specification of the code you are required to write. This means that when
you've written code
such that all the tests pass then you will know that you have completed the exercise.
Getting the code for these exercises
Download the file ODEsAM.zip. You have been
provided with one source class (
AbstractOdeSolver
) and with two test files.
You will not need to edit any of these 3 source files. If you do make edits to
them during the course of the exercise then make sure that your final version
works with the original versions of these files.Forward Euler
Running first test:
Check to see what running the simplest test-suite
TestOdeSolvers.py
does at this
stage. It should stop with ModuleNotFoundError: No module named 'ForwardEulerOdeSolver'
. In order for the test to run, you need to create the
ForwardEulerOdeSolver
class in ForwardEulerOdeSolver.py
. This class should
inherit from AbstractOdeSolver
, and should provide the one method:
Solve()
. (This method's implementation does not yet have to contain any code
other than pass
.) Now check that the TestOdeSolvers.py
test-suite runs. It
is expected to throw exceptions at this stage.Writing a forward Euler solver:
The good news is that 1 out of 3 of the tests in the
TestOdeSolvers
test-suite
pass immediately. The first test test_abstract_class_methods
verifies that
all the functionality I have written in the abstract base class works and
consequently the test passes. The other two tests which check
ForwardEulerOdeSolver.Solve()
works correctly are the tests which are failing.
If you need a revision tutorial about the Forward Euler method then please ask
now.Your task is to implement the
Solve()
method so that it solves from the
initial values over a time-interval with a fixed time step using forward Euler.
On exit from the method you should have populated solutionTrace
with a list of
values (as pairs/tuples) and timeTrace
with the list of corresponding
times. The test-suite uses two simple model ordinary differential 2-d systems
of equations. These are plugged into the solver as right-hand side functions.
They are defined at the top of the test-suite file and both have straightforward
analytic solutions.As you develop your
Solve()
method you should reduce the number of failing
lines. One or two of the test lines are harder to satisfy than others. Attempt
to have no failures but the fewer the better. Please make sure that you have
comments in your code.A Higher-Order Solver
Now run
TestHigherOrderOdeSolverRunner
. This new test-suite
requires you make another class HigherOrderOdeSolver.py
which should
again provide only a Solve()
method. It tests the convergence behaviour of
your two solvers and checks that the higher-order one is better. My model answer
(which passes the test) uses a standard second order Runge-Kutta method. Again
work on your solution until there are few lines (ideally no lines) of failing
tests.Using a library function
Write a solver implementation which uses
You should be able to do this with very few lines of code, including just a single call to
scipy.integrate.odeint
at its core.You should be able to do this with very few lines of code, including just a single call to
odeint
. Test it in a similar way to the
HigherOrderOdeSolver
, using progressively smaller time-steps.- What do you notice about the reported error?
- What control do you have over the error?
Convergence Behaviour
[Extension] Use the test output in
TestHigherOrderOdeSolver
as the
model for plotting convergence behaviour for these two solvers and at
least one other solver that you should write. Use matplotlib
or some other
plotting program to make a log-log plot with time-step on the x-axis and error
on the y-axis.C++
[Extension] If you love
C++
then you are welcome to investigate coding ODE
solvers in C++ by investigating the assignment which formed the basis of this exercise:
https://www.cs.ox.ac.uk/people/joe.pitt-francis/oxfordonly/FridayAssignment.pdf