Validate
function for validating convergence orders for Runge Kutta methods.Butcher_dict
for known explicit Runge Kutta methods.Starting with the ODE (ordinary differential equation) initial value problem: y′(t)=f(y,t) y(t=0)=y0,
Given y0 and a smooth f(y,t), all explicit RK methods provide an estimate for y1=y(Δt), with an error term that is proportional to (Δt)m, where m is an integer typically greater than zero. This error term corresponds to the local truncation error. For RK4, for example, while the total accumulated truncation error (i.e., the accumulated error at a fixed final time tf) is proportional to (Δt)4, the local truncation error (i.e., the error after one arbitrarily chosen timestep Δt) is proportional to (Δt)5.
If the exact solution y(t) is known as a closed-form expression, then y(Δt) can be separately written as a Taylor expansion about y(t=0):
y(Δt)=∞∑n=0y(n)(t=0)n!(Δt)n,where y(n)(t=0) is the nth derivative of y(t) evaluated at t=0.
The above expression will be known exactly. Furthermore, if one chooses a numerical value for y0 and leaves Δt unspecified, any explicit RK method will provide an estimate for y(Δt) of the form
y(Δt)=∞∑n=0an(Δt)n,where an must match the Taylor expansion of the exact solution at least up to and including terms proportional to (Δt)m, where m is the order of the local truncation error. If this is not the case, then the Butcher table was almost certainly not typed correctly.
Therefore, comparing the numerical result with unspecified Δt against the exact Taylor series provides a convenient (though not perfectly robust) means to verify that the Butcher table for a given RK method was typed correctly. Multiple typos in the Butcher tables were found using this approach.
Example from Z. Etienne's MATH 521 (Numerical Analysis) lecture notes:
Consider the ODE y′=y−2te−2t,y(0)=y(t0)=0.
approximate the solution at y(t=Δt) to fifth order in Δt.
Δt to find y(Δt). Confirm that the solution obtained when using Heun's method has an error term that is at worst O((Δt)3). If the dominant error is proportional to a higher power of Δt, explain the discrepancy.
We can solve this equation via the method of integrating factors, which states that ODEs of the form: y′(t)+p(t)y(t)=g(t)
Here, p(t)=−1 and g(t)=−2te−2t. Then
μ(t)=exp(−∫dt)=e−t+c=ke−tand
y(t)=et/k[∫ke−s(−2se−2s)ds+c]=−2et[∫se−3sds+c′]=−2et[e−3t(−t3−19)+c′]=−2e−2t(−t3−19)−2c′et=e−2t(2t3+29)+c″et.If y(0)=0 then we can compute the integration constant c″, and y(t) becomes y(t)=29e−2t(3t+1−e3t).
The Taylor Series expansion of the exact solution about t=0 evaluated at y(Δt) yields y(Δt)=−(Δt)2+(Δt)3−3(Δt)44+23(Δt)560−19(Δt)6120+O((Δt)7).
Next we evaluate y(Δt) using Heun's method. We know y(0)=y0=0 and f(y,t)=y−2te−2t, so k1=Δtf(y(0),0)=Δt×0=0k2=Δtf(y(0)+k1,0+Δt)=Δtf(y(0)+0,0+Δt)=Δt(−2Δte−2Δt)=−2(Δt)2e−2Δty(Δt)=y0+12(k1+k2)+O((Δt)3)=0−(Δt)2e−2Δt=−(Δt)2(1−2Δt+2(Δt)2+...)=−(Δt)2+2(Δt)3+O((Δt)4).
Thus the coefficient on the (Δt)3 term is wrong, but this is completely consistent with the fact that our stepping scheme is only third-order accurate in Δt.
In the below approach, the RK result is subtracted from the exact Taylor series result, as a check to determine whether the RK Butcher table was coded correctly; if it was not, then the odds are good that the RK results will not match to the expected local truncation error order. Multiple f(y,t) are coded below to improve the robustness of this test.
import sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ depends
import numpy as np # NumPy: A numerical methods module for Python
from MoLtimestepping.RK_Butcher_Table_Dictionary import Butcher_dict
Each Butcher table/Runge Kutta method is tested by solving an ODE. Comparing the Taylor series expansions of the exact solution and the numerical solution as discussed in the Introduction above will confirm whether the method converges to the appropriate order.
Consider the form of ODE y′=f(y,t). The following begins to construct a dictionary rhs_dict
of right-hand side functions for us to validate explicit Runge Kutta methods. The most up-to-date catalog of functions stored in rhs_dict
can be found in the RK_Butcher_Table_Validation.py module.
def fypt(y,t): # Yields expected convergence order for all cases
# except DP6 which converge to higher order (7, respectively)
return y+t
def fy(y,t): # Yields expected convergence order for all cases
return y
def feypt(y,t): # Yields expected convergence order for all cases
return sp.exp(1.0*(y+t))
def ftpoly6(y,t): # Yields expected convergence order for all cases, L6 has 0 error
return 2*t**6-389*t**5+15*t**4-22*t**3+81*t**2-t+42
rhs_dict = {'ypt':fypt, 'y':fy, 'eypt':feypt, 'tpoly6':ftpoly6}
To validate each Butcher table we compare the exact solutions to ODEs with the numerical solutions using the Runge Kutta scheme built into each Butcher table. The following is a function that
The Validate()
function inputs a specified Butcher_key
, the starting guess solution and time y_n
, t_n
and the right-hand side of the ODE corresponding to a specified initial value problem, rhs_key
.
from MoLtimestepping.RK_Butcher_Table_Dictionary import Butcher_dict
def Validate(Butcher_key, yn, tn, rhs_key):
# 1. First we solve the ODE exactly
y = sp.Function('y')
sol = sp.dsolve(sp.Eq(y(t).diff(t), rhs_dict[rhs_key](y(t), t)), y(t)).rhs
constants = sp.solve([sol.subs(t,tn)-yn])
exact = sol.subs(constants)
# 2. Now we solve the ODE numerically using specified Butcher table
# Access the requested Butcher table
Butcher = Butcher_dict[Butcher_key][0]
# Determine number of predictor-corrector steps
L = len(Butcher)-1
# Set a temporary array for update values
k = np.zeros(L, dtype=object)
# Initialize intermediate variable
yhat = 0
# Initialize the updated solution
ynp1 = 0
for i in range(L):
#Initialize and approximate update for solution
yhat = yn
for j in range(i):
# Update yhat for solution using a_ij Butcher table coefficients
yhat += Butcher[i][j+1]*k[j]
if Butcher_key == "DP8" or Butcher_key == "L6":
yhat = 1.0*sp.N(yhat,20) # Otherwise the adding of fractions kills performance.
# Determine the next corrector variable k_i using c_i Butcher table coefficients
k[i] = dt*rhs_dict[rhs_key](yhat, tn + Butcher[i][0]*dt)
# Update the solution at the next iteration ynp1 using Butcher table coefficients
ynp1 += Butcher[L][i+1]*k[i]
# Finish determining the solution for the next iteration
ynp1 += yn
# Determine the order of the RK method
order = Butcher_dict[Butcher_key][1]+2
# Produces Taylor series of exact solution at t=tn about t = 0 with the specified order
exact_series = sp.series(exact.subs(t, dt),dt, 0, order)
num_series = sp.series(ynp1, dt, 0, order)
diff = exact_series-num_series
return diff
t, dt = sp.symbols('t dt')
# Set initial conditions
t0 = 0
y0 = 1
# Set RHS of ODE
function = 'ypt'# This can be changed, just be careful that the initial conditions are satisfied
for key,value in Butcher_dict.items():
print("RK method: \""+str(key)+"\".")
y = sp.Function('y')
print(" When solving y'(t) = "+str(rhs_dict[function](y(t),t))+", y("+str(t0)+")="+str(y0)+",")
local_truncation_order = list(value)[1]+1
print(" the first nonzero term should have local truncation error proportional to O(dt^"+str(local_truncation_order)+") or a higher power of dt.")
print("Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of:")
sp.pretty_print(Validate(key, y0, t0, function))
# print("\n")
print(" (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.)\n")
RK method: "Euler". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^2) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 2 ⎛ 3⎞ dt + O⎝dt ⎠ (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "RK2 Heun". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^3) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 3 dt ⎛ 4⎞ ─── + O⎝dt ⎠ 3 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "RK2 MP". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^3) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 3 dt ⎛ 4⎞ ─── + O⎝dt ⎠ 3 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "RK2 Ralston". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^3) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 3 dt ⎛ 4⎞ ─── + O⎝dt ⎠ 3 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "RK3". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^4) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 4 dt ⎛ 5⎞ ─── + O⎝dt ⎠ 12 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "RK3 Heun". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^4) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 4 dt ⎛ 5⎞ ─── + O⎝dt ⎠ 12 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "RK3 Ralston". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^4) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 4 dt ⎛ 5⎞ ─── + O⎝dt ⎠ 12 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "SSPRK3". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^4) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 4 dt ⎛ 5⎞ ─── + O⎝dt ⎠ 12 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "RK4". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^5) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 5 dt ⎛ 6⎞ ─── + O⎝dt ⎠ 60 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "DP5". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^6) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 6 dt ⎛ 7⎞ - ──── + O⎝dt ⎠ 1800 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "DP5alt". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^6) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 6 13⋅dt ⎛ 7⎞ ────── + O⎝dt ⎠ 231000 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "CK5". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^6) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 6 dt ⎛ 7⎞ ──── + O⎝dt ⎠ 3600 (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "DP6". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^7) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: ⎛ 8⎞ O⎝dt ⎠ (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "L6". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^7) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 5 6 - 1.0587911840678754238e-22⋅dt - 2.6469779601696885596e-23⋅dt + 0.0013227513 7 ⎛ 8⎞ 227513227513⋅dt + O⎝dt ⎠ (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.) RK method: "DP8". When solving y'(t) = t + y(t), y(0)=1, the first nonzero term should have local truncation error proportional to O(dt^9) or a higher power of dt. Subtracting the numerical result from the exact Taylor expansion, we find a local truncation error of: 2 3.6854403535034607753e-18⋅dt + 5.8394451383711465375e-18⋅dt + 3.7764963953332 3 4 5 980617e-18⋅dt + 9.542884942003761195e-19⋅dt + 1.2718729098615353529e-19⋅dt 6 7 + 3.9082629581905451582e-20⋅dt + 4.8075737201581968464e-21⋅dt + 5.1688448526 8 9 ⎛ 10⎞ 907316834e-22⋅dt + 7.2078645877627939543e-9⋅dt + O⎝dt ⎠ (Coefficients of order 1e-15 or less may generally be ignored, as these are at roundoff error.)
The following code cell converts this Jupyter notebook into a proper, clickable LATEX-formatted PDF file. After the cell is successfully run, the generated PDF may be found in the root NRPy+ tutorial directory, with filename Tutorial-RK_Butcher_Table_Validation.pdf. (Note that clicking on this link may not work; you may need to open the PDF file through another means.)
import cmdline_helper as cmd # NRPy+: Multi-platform Python command-line interface
cmd.output_Jupyter_notebook_to_LaTeXed_PDF("Tutorial-RK_Butcher_Table_Validation")
Created Tutorial-RK_Butcher_Table_Validation.tex, and compiled LaTeX file to PDF file Tutorial-RK_Butcher_Table_Validation.pdf