In [1]:
import numpy as np
import scipy.sparse.linalg as sp
import sympy as sym
from scipy.linalg import toeplitz
import ipywidgets as widgets
from ipywidgets import IntSlider
import matplotlib.pyplot as plt
%matplotlib inline
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
plt.style.use('ggplot')
import matplotlib as mpl
mpl.rcParams['font.size'] = 14
mpl.rcParams['axes.labelsize'] = 20
mpl.rcParams['xtick.labelsize'] = 14
mpl.rcParams['ytick.labelsize'] = 14
sym.init_printing()
from scipy.integrate import odeint
from ipywidgets import interact
A differenetial equation, in this case a scalar initial value problem (IVP), can be defined as follows: \begin{align*} \dfrac{\mathrm{d}x}{\mathrm{d}t}(t) &= f(t,x(t)),\\ x(0) &= x_0. \end{align*} For a known function $f(t,x)$ and $x_0$. Particularly one could integrate both sides of the first equation as follows, \begin{align*} \int_0^{h} \dfrac{\mathrm{d}x}{\mathrm{d}t}(t)\mathrm{d}t & = \int_0^{h} f(t,x(t))\,\mathrm{d}t,\\ x(h)-x(0) &= \int_0^{h} f(t,x(t))\,\mathrm{d}t, \end{align*} where the Fundamental Theorem of Calculus was used. Now, we solve for the unknow value $x(h)$: \begin{align*} x(h) &= x_0 + \int_0^{h} f(t,x(t))\,\mathrm{d}t. \end{align*} Up to this point, we have not made any approximation. From this point, one can derive several numerical method, depending how you approximate the integral. For instance, if we consider $h=\Delta t$ and we use a Reimann sum from the left (only one interval from $0$ to $\Delta t$), we obtain the method called Forward Euler. But if we do the same but with the Reimann sum from the right, we obtain backward Euler. Another two options that are easy to see are the midpoint rule and the trapezoidal rule. Notice that in some cases mentioned, you would need a non-linear equation (or a system in higher dimension) for each time step.
Considers the following IVP: \begin{align*} \dfrac{\mathrm{d}x}{\mathrm{d}t}(t) &= -\alpha\,x,\\ x(0) &= x_0, \end{align*} for which we know the solution: \begin{align*} x(t) &= x_0\,\exp(-\alpha\,t) \end{align*}
In [2]:
# Warning: In general, we will use \dot{y}=f(t,y), y(0)=y_0,
# so don't get mixed up with the notation from the textbook.
def f_example_1_interact(alpha_input=1,T_max=5,p=2):
# Example 1, numerically.
def f_example_1(t, y, alpha):
return -alpha*y
# Initial condition
y0=1
# time where we want your solution
t = np.linspace(0, T_max, 100)
sol = odeint(f_example_1, y0, t, args=(alpha_input,), tfirst=True)
plt.figure()
plt.plot(t, sol, 'b', label='y(t)')
for i in np.arange(1,np.ceil(T_max/(np.log(p)/alpha_input))):
plt.axvline(x=i*np.log(p)/alpha_input)
print('t: ',i*np.log(p)/alpha_input,', exp(t): ',np.exp(-alpha_input*i*np.log(p)/alpha_input))
plt.legend(loc='best')
plt.xlabel('t')
plt.ylabel(r'$\exp(-\alpha\,t)$')
plt.title('What are the red lines?')
plt.grid(True)
plt.show()
interact(f_example_1_interact,alpha_input=(0.1,10,0.1),T_max=(0.1,100,0.1),p=(2,10,1))
Out[2]:
Considers the following IVP: \begin{align*} \dfrac{\mathrm{d}x}{\mathrm{d}t}(t) &= \sqrt{x}\\ x(0) &= 0, \end{align*}
Recall that $2^{-1074}$ is the smallest number greater than 0 that ``double precision'' can store. See:
In [3]:
print(2**-1074,', ',2**-1075)
In [5]:
# Example 2, numerically.
def f_example_2(t,y):
return np.sqrt(y)
# Initial condition
y0=0.0
# time where we want your solution
t = np.linspace(0, 1, 100)
sol_a = odeint(f_example_2, y0, t, tfirst=True)
sol_b = odeint(f_example_2, y0+2**-1074, t, tfirst=True)
plt.figure()
plt.plot(t, sol_a, 'b', label='y_a(t)')
plt.plot(t, sol_b, 'r', label='y_b(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid(True)
plt.show()
Considers the following IVP: \begin{align*} \dfrac{\mathrm{d}x}{\mathrm{d}t}(t) &= x^2\\ x(0) &= 1, \end{align*} for which we know the solution: \begin{align*} x(t) &= \dfrac{1}{1-t} \end{align*}
In [6]:
def f_example_3_interact(T_max=0.5):
# Example 3, numerically.
def f_example_3(t,y):
return y*y
# Initial condition
y0=1
# time where we want your solution
t = np.linspace(0, T_max, 100)
sol = odeint(f_example_3, y0, t, tfirst=True)
plt.figure()
plt.plot(t, sol, 'b', label='y(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid(True)
plt.show()
interact(f_example_3_interact,T_max=(0.1,1,0.001))
Out[6]:
In [7]:
def f_example_4(t,y,alpha):
return alpha*(1/2-y/(1+y))
# Initial condition
y0=3
# time where we want your solution
t = np.linspace(0, 10, 100)
plt.figure(figsize=(10,8))
for j in np.arange(1,6):
sol= odeint(f_example_4, y0, t, args=(4/j,), tfirst=True)
plt.plot(t, sol, label=r'$\xi(t)$'+r', $\tau= $'+str(j))
plt.axvline(x=j,color='k')
plt.text(j,0.5,r'$\tau= $'+str(j))
plt.legend(loc='best')
plt.ylabel('Concentration')
plt.xlabel('t')
plt.ylim((0,3))
plt.grid(True)
plt.show()
In [8]:
def f_example_4b(t,y,alpha,phi_in):
return phi_in-alpha*(y/(1+y))
# Initial condition
y0=3
# time where we want your solution
t = np.linspace(0, 1, 100)
plt.figure(figsize=(10,8))
sol= odeint(f_example_4b, y0, t, args=(4,5), tfirst=True)
plt.plot(t, sol, label=r'$\xi(t)$')
plt.legend(loc='best')
plt.ylabel('Concentration')
plt.xlabel('t')
plt.title(r'What happens then if $\phi_{in}\geq\alpha$?')
plt.grid(True)
plt.show()
Plotting: \begin{align*} f(t) &= \dfrac{t^2}{\pi^2+t^2}\,\sin(5\,t),\quad 0 \leq t \leq 4\,\pi \end{align*}
In [9]:
t = np.linspace(0,4*np.pi,100)
f = lambda t: (t**2/(np.pi**2+t**2))*np.sin(t)
plt.figure()
plt.plot(t,f(t),'b-',label='f(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid(True)
plt.show()
Plotting: \begin{align*} f(t,\tau) &= \exp(-t/\tau)\,\sin(2\,\pi\,t),\quad 0 \leq t \leq 2. \end{align*}
In [10]:
t = np.linspace(0,2,100)
f = lambda t,tau: np.exp(-t/tau)*np.sin(2*np.pi*t)
plt.figure()
plt.plot(t,f(t,1),'b-',label=r'$f(t,\tau=1)$')
plt.plot(t,f(t,0.5),'r--',label=r'$f(t,\tau=0.5)$')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid(True)
plt.show()
Plotting: \begin{align*} f(t,u) &= u^2\,\dfrac{t}{1+t},\quad 0 \leq t, u \in \mathbb{R}. \end{align*}
In [11]:
elev_widget = IntSlider(min=0, max=180, step=10, value=40)
azim_widget = IntSlider(min=0, max=360, step=10, value=230)
def example_9_interact(elev=40,azim=230):
f = lambda t,u: (u**2)*(t/(1+t))
nt, nu = (100, 50)
t = np.linspace(0, 5, nt)
u = np.linspace(-1, 1, nu)
tt, uu = np.meshgrid(t, u)
zz = f(tt,uu)
fig = plt.figure(figsize=(10,10))
ax = fig.gca(projection='3d')
surf = ax.plot_surface(tt,uu,zz, cmap=cm.coolwarm, linewidth=0, antialiased=False)
ax.view_init(elev,azim)
ax.set_xlabel('t')
ax.set_ylabel('u')
ax.set_zlabel('f')
plt.grid(True)
plt.show()
interact(example_9_interact,elev=elev_widget,azim=azim_widget)
Out[11]:
In [12]:
t = np.linspace(0,4,100)
def f(t):
if t<=2:
return t*np.sin(t)
else:
return np.sin(np.pi*t)/t
fv=np.vectorize(f, otypes=[np.float64])
plt.figure()
plt.plot(t,fv(t),'b-',label='f(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid(True)
plt.show()
Write a function that return $f(t)=\exp(-\alpha\,t^2)$ and $f'(t)=-2\,\alpha\,t\,\exp(-\alpha\,t^2)$.
In [13]:
def f_and_fprime(t,alpha):
f = lambda t: np.exp(-alpha*t**2)
fp = lambda t: -2*alpha*t*f(t)
return np.array([f(t),fp(t)])
print(f_and_fprime(t=1,alpha=1))
donde $\mu_1=300$ y $\mu_2=200$ son constantes de normalización.
In [ ]: