Another extremely important topic in Scientific Computation is that of differential equations. These arise obviously in mathematics, but also in most other scientific fields including biology, chemistry, engineering, and economics. Also, it is rare that a differential equation has a nice closed form solution, so often numerical methods must be used to get a solution.
We will discuss two often-used methods for solving differential equations, Euler’s method and Runge-Kutta methods and then delve into a very nice robust julia package.
It is important to note that the order of a differential equation is the degree of the highest derivative, so in the example above, it is two. The following procedure can covert non order-1 differential equation to one that is a first-order system.
Let \(y_1 = y\text{,}\) then \(y_2 = y' = y_1'\text{.}\) Lastly \(y'' = y_1'' = y_2'\) and using the differential equation \(y''=-4y\text{,}\) this can be written:
with the understanding that we will solve this at a discrete set of points, so we let \(y_n = y(t_n)\) and \(t_k = t_0 + k\Delta t\text{,}\) where \(\Delta t\) is a small time step. We can then replace \(y'\) with the approximation:
Subsection43.1.1Implementing Euler’s method in Julia
Let’s take a look at Euler’s method in Julia. Of course, we’ll write a function to evaluate this and there are a few things that we need for the function:
function euler(f::Function, t0:: Real, y0::Real, dt::Real, num_steps::Integer)
num_steps > 0 || throw(ArgumentError("The number of steps must be positive."))
dt > 0 || throw(ArgumentError("The step size dt must be positive."))
t = LinRange(t0,t0+num_steps*dt,num_steps+1)
y = zeros(Float64,num_steps+1)
y[1] = y0
for i=1:num_steps
y[i+1] = y[i] + dt*f(t[i],y[i])
end
(t,y)
end
Example43.1.
We’ll solve \(y'=y\text{,}\)\(y(0)=1\) for dt=0.1 and \(10\) steps.
which is a tuple of two arrays. This results the \(t\) and \(y\) values based on Euler’s method. However, perhaps it’s more interesting to see a plot. Also, note that the analytic solution to this is \(y=e^x\text{,}\) so the plot of the approximate solution using Euler’s method as well as the analytic solution is
There is a family of other methods called the Runge Kutta methods that are relatively simple with a high order of accuracy. One version that was often a standard version is what is called the 4th-order Runge-Kutta or RK4 method is
Section43.3Using the DifferentialEquations package
There is a very mature and robust package for solving differential equations aptly called DifferentialEquations. We will show a few examples to get a feeling for how to use the package, but as you can tell from the documentation, that there are a lot of possibilities with the package so we’ll show a couple of examples.
In short, you’ll need to include the equation, an initial condition and a range of values on which you want it solved. Don’t forget to add the package and evaluate
where \(f\) is a function of \(u\text{,}\) the dependent variable, \(p\) the parameter in the problem (if any) and \(t\text{,}\) the independent variable. We will also defined the initial condition and the range of values for which to solve:
This gives information about the datatypes of the function and initial condition because some solvers will use this information differently. to solve this problem,
Note that the solution appears to be an array of time (that isn’t equally-spaced) and function values at those \(t\) values. If you want to access one of them, you can do:
which returns 1.416261037790314, the third element of the u array. However, this structure is much more than just an array. If you want the function value at 0.75, for example, you can access it like a function evaluation:
which returns 2.1170003461681204 and this is interpolated from the generated points. The result guarantees accuracy to within a default tolerance of 1e-3 or you can set a different tolerance with the keyword reltol such as reltol=1e-6.
which shows that they appear to the resolution of the plot that the two solutions are identical, however if we plot the error associated with the numerical method by
Reproduce the solution to \(y'=y, ~~ y(0)=1\) with the option abstol = 1e-10. Produce a plot of the error as above to show that the result is within the given tolerance.
which is an example of a harmonic oscillator. We first need to put this in a system form by letting \(y_1=y\) and \(y_2=y'\text{.}\) Then from the differential equation \(y'' = - y\) or \(y_2' = -y_1\text{.}\) We can then write this as
If instead, you want the results plotted like a parametric equation, then we need to do a bit more work. The result of the solution sol2 is a function of t that returns a vector of the two variables \(y_1\) and \(y_2\text{.}\) To generate the desired plot:
and recall that the comma afer aspect = 1, is important to make that a tuple and we desire the aspect ratio to be 1 because the output should be a circle. The plot is
The Lorenz system is relatively famous system of differential equations for many reasons. It is a system of ODEs, it is nonlinear and for many parameters the solution exhibits sensitivity on initial conditions, an important property for differential equation that exhibit chaotic behavior. The Lorenz system is
and it is difficult to see the difference between u[1] and u[2]. The classic plot of this solution is as a 3D parametric plot, which can be generated with
This is not clear what is going on because of the angle that we are viewing it. We can change that with the azimuth option of the Axis3 object. With a little bit of playing, if we do
For these examples, we have used the CairoMakie package for plotting. This is very nice for 2D plots (or projections of 3D plots into 2 dimensions), if we use the GLMakie package, we can get an interactive plot. First, we need to load and activate the package with
Subsection43.4.2Other Aspects of the DifferentialEquations
If you take a look at the the documentation of the package, we have only touched the surface of this package and it can do a lot with many different differential equations including initial value problems (that all three examples fit into), boundary value problems, stiff equations (aka they are hard to solve numerically) and stocastic differential equations.
Also, the actual solvers are not discussed here, however if you want to know the details, the documentation explains them. I have found that the default solvers are generally good enough and unless there is an issue, probably work for most problems.