Comment résoudre numériquement un ODE en Python?
Considérer
\ddot{u}(\phi) = -u + \sqrt{u}
avec les conditions suivantes
u(0) = 1.49907
et
\dot{u}(0) = 0
avec la contrainte
0 <= \phi <= 7\pi.
Enfin, je veux produire un tracé paramétrique où les coordonnées x et y sont générées en fonction de u.
Le problème est que j'ai besoin d'exécuter odeint deux fois car il s'agit d'une équation différentielle de second ordre. J'ai essayé de le relancer après la première fois mais il revient avec une erreur jacobienne. Il doit y avoir un moyen de l'exécuter deux fois en même temps.
Voici l'erreur:
odepack.error: La fonction et son jacobien doivent être des fonctions appelables
que le code ci-dessous génère. La ligne en question est le sol = odeint.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from numpy import linspace
def f(u, t):
return -u + np.sqrt(u)
times = linspace(0.0001, 7 * np.pi, 1000)
y0 = 1.49907
yprime0 = 0
yvals = odeint(f, yprime0, times)
sol = odeint(yvals, y0, times)
x = 1 / sol * np.cos(times)
y = 1 / sol * np.sin(times)
plot(x,y)
plt.show()
Modifier
J'essaie de construire l'intrigue à la page 9
Voici l'intrigue avec Mathematica
In[27]:= sol =
NDSolve[{y''[t] == -y[t] + Sqrt[y[t]], y[0] == 1/.66707928,
y'[0] == 0}, y, {t, 0, 10*\[Pi]}];
In[28]:= ysol = y[t] /. sol[[1]];
In[30]:= ParametricPlot[{1/ysol*Cos[t], 1/ysol*Sin[t]}, {t, 0,
7 \[Pi]}, PlotRange -> {{-2, 2}, {-2.5, 2.5}}]
import scipy.integrate as integrate
import matplotlib.pyplot as plt
import numpy as np
pi = np.pi
sqrt = np.sqrt
cos = np.cos
sin = np.sin
def deriv_z(z, phi):
u, udot = z
return [udot, -u + sqrt(u)]
phi = np.linspace(0, 7.0*pi, 2000)
zinit = [1.49907, 0]
z = integrate.odeint(deriv_z, zinit, phi)
u, udot = z.T
# plt.plot(phi, u)
fig, ax = plt.subplots()
ax.plot(1/u*cos(phi), 1/u*sin(phi))
ax.set_aspect('equal')
plt.grid(True)
plt.show()
Le code de votre autre question est vraiment proche de ce que vous voulez. Deux changements sont nécessaires:
deriv
)y
de votre tracé souhaité provient des valeurs de la solution, pas des valeurs de la dérivée première de la solution, vous devez donc remplacer u[:,0]
(valeurs de fonction) pour u[:, 1]
(dérivés).Voici le résultat final:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
def deriv(u, t):
return np.array([u[1], -u[0] + np.sqrt(u[0])])
time = np.arange(0.01, 7 * np.pi, 0.0001)
uinit = np.array([1.49907, 0])
u = odeint(deriv, uinit, time)
x = 1 / u[:, 0] * np.cos(time)
y = 1 / u[:, 0] * np.sin(time)
plt.plot(x, y)
plt.show()
Cependant, je vous suggère d'utiliser le code de la réponse d'unutbu car il est auto-documenté (u, udot = z
) et utilise np.linspace
au lieu de np.arange
. Ensuite, exécutez ceci pour obtenir le chiffre souhaité:
x = 1 / u * np.cos(phi)
y = 1 / u * np.sin(phi)
plt.plot(x, y)
plt.show()
Vous pouvez utiliser scipy.integrate.ode. Pour résoudre dy/dt = f (t, y), avec la condition initiale y (t0) = y0, à l'instant = t1 avec Runge-Kutta de 4e ordre, vous pouvez faire quelque chose comme ceci:
from scipy.integrate import ode
solver = ode(f).set_integrator('dopri5')
solver.set_initial_value(y0, t0)
dt = 0.1
while t < t1:
y = solver.integrate(t+dt)
t += dt
Edit: Vous devez obtenir votre dérivé au premier ordre pour utiliser l'intégration numérique. Vous pouvez y parvenir en définissant par exemple z1 = u et z2 = du/dt, après quoi vous avez dz1/dt = z2 et dz2/dt = d ^ 2u/dt ^ 2. Remplacez-les dans votre équation d'origine et parcourez simplement le vecteur dZ/dt, qui est de premier ordre.
Edit 2: Voici un exemple de code pour le tout:
import numpy as np
import matplotlib.pyplot as plt
from numpy import sqrt, pi, sin, cos
from scipy.integrate import ode
# use z = [z1, z2] = [u, u']
# and then f = z' = [u', u''] = [z2, -z1+sqrt(z1)]
def f(phi, z):
return [z[1], -z[0]+sqrt(z[0])]
# initialize the 4th order Runge-Kutta solver
solver = ode(f).set_integrator('dopri5')
# initial value
z0 = [1.49907, 0.]
solver.set_initial_value(z0)
values = 1000
phi = np.linspace(0.0001, 7.*pi, values)
u = np.zeros(values)
for ii in range(values):
u[ii] = solver.integrate(phi[ii])[0] #z[0]=u
x = 1. / u * cos(phi)
y = 1. / u * sin(phi)
plt.figure()
plt.plot(x,y)
plt.grid()
plt.show()
scipy.integrate () fait l'intégration ODE. C'est bien ce que vous cherchez?