This book explains the foundations of modern solvers for ordinary differential equations (ODEs). Formulating and solving ODEs is an essential part of mathematical modeling and computational science, and numerous solvers are available in commercial and open source software. However, no single ODE solver is the best choice for every single problem, and choosing the right solver requires fundamental insight into how the solvers work. This book will provide exactly that insight, to enable students and researchers to select the right solver for any ODE problem of interest, or implement their own solvers if needed. The presentation is compact and accessible, and focuses on the large and widely used class of solvers known as Runge-Kutta methods. Explicit and implicit methods are motivated and explained, as well as methods for error control and automatic time step selection, and all the solvers are implemented as a class hierarchy in Python.
The main purpose of the notes is to serve as a concise and gentle introduction to solving differential equations in Python, specifically for the course Introduction to programming for scientific applications (IN1900, 10 ETCS credits) at the University of Oslo. These notes will be most useful for readers with a basic knowledge of Python and NumPy, and it is also useful to have a fundamental understanding of ODEs.
One may question the usefulness of learning how to write your own ODE solvers in Python when there are already multiple solvers available, such as those in the SciPy library. However, no single ODE solver is universally optimal and efficient for all ODE problems, and the choice of solver should always be based on the specific characteristics of the problem at hand. To make the right choice, it is extremely beneficial to understand the strengths and weaknesses of different solvers, and the best way to gain this knowledge is by programming your own collection of ODE solvers. Different ODE solvers are conveniently grouped into families and hierarchies, offering an excellent example of how object-oriented programming (OOP) can maximize code reuse and minimize duplication.
The book’s presentation style is compact and pragmatic, incorporating numerous code examples to illustrate how various ODE solvers can be implemented and applied in practice. The complete source code for all examples, as well as Jupyter notebooks for each chapter, are provided in the accompanying online resources. The programs and code examples are written in a simple and compact Python style, avoiding the use of advanced tools and features. Experienced Python programmers may find more elegant and modern solutions to many of the examples, utilizing abstract base classes, type hints, data classes, and other advanced features. However, the book’s main goal is to introduce the fundamentals of ODE solvers and OOP as part of an introductory programming course, and we believe this purpose is best served by focusing on the basics.
Readers familiar with scientific computing or numerical software may also miss a discussion of computational performance. While performance is certainly relevant when solving ODEs, optimizing the performance of a Python-based solver easily becomes quite technical, and requires features like just-in-time compilers (e.g., Numba) or mixed-language programming. The solvers in this book use fairly basic features of Python and NumPy, sacrificing some performance in favor of enhancing understanding of solver properties and implementation.
Author(s): Joakim Sundnes
Series: Simula SpringerBriefs on Computing
Publisher: Springer
Year: 2023
Language: English
Pages: 124
Series Foreword
Preface
Contents
Chapter 1 Programming a Simple ODE Solver
1.1 Creating a General-Purpose ODE Solver
1.2 The ODE Solver Implemented as a Class
1.3 Systems of ODEs
1.4 A ForwardEuler Class for Systems of ODEs
1.5 Checking the Error in the Numerical Solution
1.6 Using ODE Solvers from SciPy
Chapter 2 Improving the Accuracy
2.1 Explicit Runge-Kutta Methods
2.2 A Class Hierarchy of Runge-Kutta Methods
2.3 Testing the Solvers
Chapter 3 Stable Solvers for Stiff ODE Systems
3.1 Stiff ODE Systems and Stability
3.2 Implicit methods for stability
3.3 Implementing Implicit Runge-Kutta Methods
3.4 Implicit Methods of Higher Order
3.4.1 Fully Implicit RK Methods
3.4.2 Diagonally Implicit RK Methods
3.5 Implementing Higher Order IRK Methods
3.5.1 A Base Class for Fully Implicit Methods
3.5.2 Base Classes for SDIRK and ESDIRK Methods
Chapter 4 Adaptive Time Step Methods
4.1 A Motivating Example
4.2 Choosing the Time Step Based on the Local Error
4.3 Estimating the Local Error
4.3.1 Error Estimates from Embedded Methods
4.4 Implementing an Adaptive Solver
4.5 More Advanced Embedded RK Methods
Chapter 5 Modeling Infectious Diseases
5.1 Derivation of the SIR model
5.2 Extending the SIR Model
5.3 A Model of the Covid-19 Pandemic
Appendix A Programming of Difference Equations
A.1 Sequences and Difference Equations
A.2 More Examples of Difference Equations
A.3 Systems of Difference Equations
A.4 Taylor Series and Approximations
References
Index