In [ ]:
from itertools import product, repeat
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import RadioButtons
from pyodesys import ODESys
from pyodesys.integrators import (RK4_example_integrator, EulerForward_example_integrator,
EulerBackward_example_integrator, Trapezoidal_example_integrator,
Midpoint_example_integrator)
from pyodesys.tests.bateman import bateman_full
%matplotlib inline
In [ ]:
choice = RadioButtons(
options=['decay', 'sine'],
description='Case:',
disabled=False
)
choice
In [ ]:
if choice.value == 'decay':
odesys = ODESys(lambda x, y, p: [
(0 if i == 0 else p[i-1]*y[i-1]) -
(0 if i == len(y) - 1 else p[i]*y[i])
for i in range(len(y))
], lambda x, y, p: [[(-p[ri] if ri == ci and ri < len(y) - 1 else (p[ci] if ri == ci + 1 else 0)) for ci in range(len(y))] for ri in range(len(y))])
x0, xend, y0, p, n0 = 0, 1, [5, 2, .3, .1, 0], [13, 7, 3, 1], 24
def ref(x):
return np.array(bateman_full(y0, p+[0], x, exp=np.exp)).T
elif choice.value == 'sine':
A = 3
k = 14
x0, xend, y0, p, n0 = 0, 1, [0, A*k], [k], 128
odesys = ODESys(lambda x, y, p: [y[1], -p[0]**2*y[0]],
lambda x, y, p: [[0, 1], [-p[0]**2, 0]])
def ref(x):
return np.array([A*np.sin(k*x), A*k*np.cos(k*x)]).T
else:
raise ValueError("Unknown choice")
In [ ]:
xout1 = np.linspace(x0, xend, n0 + 1)
res1 = odesys.integrate(xout1, y0, p, first_step=xend/n0, integrator=EulerForward_example_integrator)
yref1 = ref(res1.xout)
fig, axes = plt.subplots(1, 2, figsize=(14, 4))
res1.plot(ls=('-',), ax=axes[0])
xplt = np.linspace(x0, xend)
res1.plot(x=xplt, y=ref(xplt), ls=(':',), ax=axes[0])
res1.plot(y=res1.yout - yref1, ax=axes[1])
In [ ]:
def plot_order_of_convergence(Integrator, nruns=6):
res, nruns = [], 7
for i in range(nruns):
n = n0 * 2**i
x = np.linspace(0, 1, n)
res.append(odesys.integrate(x, y0, p, integrator=Integrator))
vals = {}
for ix, iy in product(range(n0), range(len(y0))):
vals[ix, iy] = [res[i].yout[ix*(2**i), iy] for i in range(nruns)]
logn = np.log(n0 * 2**np.arange(nruns))
fig, axes = plt.subplots(1, len(y0), figsize=(14, 4))
for iy, ax in enumerate(axes):
for ix in range(1, n0):
lnabserr = np.log(np.abs(np.array(vals[ix, iy]) - yref1[ix, iy]))
ax.plot(logn, lnabserr, '.-', c=(ix/n0, 0, 0))
popt = np.polyfit(logn, lnabserr, 1)
ax.plot(logn[[0,-1]], np.polyval(popt, logn[[0,-1]]), label='y=%.2f x %+.2f' % tuple(popt))
ax.legend()
In [ ]:
plot_order_of_convergence(EulerForward_example_integrator)
In [ ]:
plot_order_of_convergence(EulerBackward_example_integrator)
In [ ]:
plot_order_of_convergence(Midpoint_example_integrator)
In [ ]:
plot_order_of_convergence(Trapezoidal_example_integrator)
In [ ]:
plot_order_of_convergence(RK4_example_integrator)