Numerical ODE solving in Python

前端 未结 4 483
失恋的感觉
失恋的感觉 2020-12-30 06:06

How do I numerically solve an ODE in Python?

Consider

\"equation

\\ddot{u}(         


        
相关标签:
4条回答
  • 2020-12-30 06:19

    The code from your other question is really close to what you want. Two changes are needed:

    • You were solving a different ODE (because you changed two signs inside function deriv)
    • The y component of your desired plot comes from the solution values, not from the values of the first derivative of the solution, so you need to replace u[:,0] (function values) for u[:, 1] (derivatives).

    This is the end result:

    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()
    

    However, I suggest that you use the code from unutbu's answer because it's self documenting (u, udot = z) and uses np.linspace instead of np.arange. Then, run this to get your desired figure:

    x = 1 / u * np.cos(phi)
    y = 1 / u * np.sin(phi)
    plt.plot(x, y)
    plt.show()
    
    0 讨论(0)
  • 2020-12-30 06:21

    scipy.integrate() does ODE integration. Is that what you are looking for?

    0 讨论(0)
  • 2020-12-30 06:30

    You can use scipy.integrate.ode. To solve dy/dt = f(t,y), with initial condition y(t0)=y0, at time=t1 with 4th order Runge-Kutta you could do something like this:

    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: You have to get your derivative to first order to use numerical integration. This you can achieve by setting e.g. z1=u and z2=du/dt, after which you have dz1/dt = z2 and dz2/dt = d^2u/dt^2. Substitute these into your original equation, and simply iterate over the vector dZ/dt, which is first order.

    Edit 2: Here's an example code for the whole thing:

    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()
    
    0 讨论(0)
  • 2020-12-30 06:38
    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()
    

    enter image description here

    0 讨论(0)
提交回复
热议问题