I wrote an RK4 algorithm and am testing it on $y' = -ty$ which has the solution
$y(t) = e^{-t^2 / 2}$
I decided to also graph the error, which I am now trying to decipher. I plotted the solution and error for several time steps. I halved the time step for each test:
In general, my questions are:
How can the error in my algorithm be analyzed? And, why does that first graph look so funny?
As far as the work I've done:
I am conceptually aware of the following jargon and roughly what it means, however the class I took in numerical methods was run by a genius, not a communicator:
- "truncation error"
- "round-off error"
- RK4 is "fourth order" and so error should drop like $(\Delta t)^4$
My best guess is that error increases with each time step due to round-off. However, I have no idea how to assure myself that this is true.
The only thing I knew to do was to check that error is proportional to $(\Delta t)^4$. It sure seems like the error isn't dropping that fast. I found the maximum error for the first test:
$E_{\Delta t} = c(0.1)^4 = 0.4321$
And found c = 4321, and applied it to
$E_{\Delta t /2} = 0.0930$
but $4321(0.05)^4 = 0.027$, which is roughly a third of the error that I got. I remember my professor mentioning "order of magnitude" a lot. I guess they are within an "order of magnitude", so does that mean everything is good here?
def rk4(dt, t, field, y_n):
k1 = dt * field(t, y_n)
k2 = dt * field(t + 0.5 * dt, y_n + 0.5 * k1)
k3 = dt * field(t + 0.5 * dt, y_n + 0.5 * k2)
k4 = dt * field(t + 0.5 * dt, y_n + k3)
return y_n + (k1 + 2 * k2 + 2 * k3 + k4) / 6
if __name__ == '__main__':
# the ODE y' = -t * y, which has solution y = exp(-t^2 / 2)
def field(t, vect):
return np.array([-t * vect])
# Set the interval over which we want a solution.
t_0 = -10
t_n = 10
dt = .05
# Determine number of steps in accordance with mesh size
steps = int((t_n - t_0) / dt)
time = np.linspace(t_0, t_n, steps, endpoint=False)
# time = np.arange(t_0, t_n, dt)
# Initialize solution vectors and error collection
x = np.zeros(steps)
error = np.zeros(steps)
x[0] = 1.928749848e-22
error[0] = 0
for i in range(1, steps):
x[i] = rk.rk4(dt, time[i-1], field, x[i-1])
error[i] = abs(x[i] - math.pow(math.e, (-time[i] ** 2) / 2)) / math.pow(math.e, (-time[i] ** 2) / 2)
Best Answer
Implementing the RK4 method as
and producing a combined plot of solution graphs and error profiles for the relative error divided by the expected scale $h^4$ by
produces the plot
where the convergence of the error profiles shows clearly that the method has order 4 and that the transition from $e^{-50}$ at $t_0=-10$ to the value $1$ at $t=0$ does produce a relatively benign relative error of about $1500\,h^4$ at $t=0$.
Additionally, with smaller step sizes the error profile more and more reflects the symmetry of the problem, meaning that the errors at $t>0$ have the opposite sign but about the same size as the error at $-t$ so that they compensate. This means that the error coefficient at $t=10$ is zero for $h^4$ and what can be seen is the $h^5$ term, accounting for the halving in the scaled relative error at each step size halving.
Away from that point the errors behave as expected for a fourth order method.
Conclusion: Your observed error curve is not reproducible.