PythonでODEを数値的に解決するにはどうすればよいですか?
検討する
\ddot{u}(\phi) = -u + \sqrt{u}
次の条件で
u(0) = 1.49907
そして
\dot{u}(0) = 0
制約あり
0 <= \phi <= 7\pi.
最後に、x座標とy座標がuの関数として生成されるパラメトリックプロットを作成します。
問題は、2次微分方程式であるため、odeintを2回実行する必要があることです。初回実行後にもう一度実行してみましたが、ヤコビアンエラーが返されました。一度に2回実行する方法が必要です。
ここにエラーがあります:
odepack.error:関数とそのヤコビ行列は呼び出し可能な関数でなければなりません
以下のコードが生成します。問題の行は、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()
編集
9ページでプロットを作成しようとしています
これが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()
他の question のコードは、あなたが望むものに本当に近いです。 2つの変更が必要です。
deriv
内の2つの記号を変更したため)y
コンポーネントは、解の1次導関数の値からではなく、解の値から取得されるため、u[:,0]
(関数値)をu[:, 1]
に置き換える必要があります。 (誘導体)。これが最終結果です:
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()
ただし、それは自己文書化(u, udot = z
)であり、np.linspace
ではなくnp.arange
を使用するため、unutbuの回答のコードを使用することをお勧めします。次に、これを実行して目的の数値を取得します。
x = 1 / u * np.cos(phi)
y = 1 / u * np.sin(phi)
plt.plot(x, y)
plt.show()
Scipy.integrate.odeを使用できます。初期条件y(t0)= y0でdy/dt = f(t、y)を解くには、4次のRunge-Kuttaでtime = t1で、次のようにします。
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
編集:数値積分を使用するには、導関数を1次にする必要があります。これは、たとえば、 z1 = uおよびz2 = du/dt。その後、dz1/dt = z2およびdz2/dt = d ^ 2u/dt ^ 2になります。これらを元の方程式に代入し、単純にベクトルdZ/dtを反復します。これは1次です。
編集2:これは全体のサンプルコードです:
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() ODE統合を行います。それはあなたが探しているものですか?