Search code examples
pythonarraysnumpyscipyrunge-kutta

How do I assign a a value to a 'Nonetype' function?


I have been trying to use the Runge-Kutta45 integration method to update a set of positions and velocities of particles in space to get the new state at some time step.

Initially, I created an array with all these elements and combined them (y):

r_vec_1 = np.array([0, 0])
v_vec_1 = np.array([-np.sqrt(2), -np.sqrt(2)])

r_vec_2 = np.array([-1, 0])
v_vec_2 = np.array([np.sqrt(2) / 2, np.sqrt(2) / 2])

r_vec_3 = np.array([1, 0])
v_vec_3 = np.array([np.sqrt(2) / 2, np.sqrt(2) / 2])

y_0 = np.concatenate((r_vec_1, v_vec_1, r_vec_2, v_vec_2, r_vec_3, v_vec_3))
y = y_0

Now, I used this array as my initial conditions and created a function that gave me a new function called F(y) which is the derivative of my function y represented in a set of 1st order ODEs:

def fun(t,y):
    np.array([y[2], y[3], x1_double_dot(y, mass_vector), y1_double_dot(y, mass_vector),
              y[6], y[7], x2_double_dot(y, mass_vector), y2_double_dot(y, mass_vector),
              y[10], y[11], x3_double_dot(y, mass_vector), y3_double_dot(y, mass_vector)])

Once I had obtained the new function file, I used an initial and final time as well as a times step which is needed in the scipy.integrate.RK45 subroutine, resulting in the following code:

#Time start, step, and finish point
t_0 = 0
t = 0
t_step = 0.01
t_final = 200
nsteps = int((t_final - t)/t_step)

#The loop for running the Runge-Kutta method over some time period.
for step in np.linspace(t, t_final, num = nsteps):
    y_new = sp.integrate.RK45(fun(t,y), t_0, y_0, t_final,vectorized=True)
    history.append(y_new)
    y_new = y
    t += dt
history = np.array(history)

The problem is that once I run the code, I would expect the function y to update to the new state and keep integrating over the time period until elapsed. However, upon running this I receive the following error message:

Traceback (most recent call last):
  File "C:\Users\RSlat\PycharmProjects\pythonProject\Practice\3BP Calculator.py", line 68, in <module>
    y_new = sp.integrate.RK45(fun(t,y), t_0, y_0, t_final,vectorized=True)
  File "C:\Users\RSlat\PycharmProjects\pythonProject\Practice\lib\site-packages\scipy\integrate\_ivp\rk.py", line 94, in __init__
    self.f = self.fun(self.t, self.y)
  File "C:\Users\RSlat\PycharmProjects\pythonProject\Practice\lib\site-packages\scipy\integrate\_ivp\base.py", line 138, in fun
    return self.fun_single(t, y)
  File "C:\Users\RSlat\PycharmProjects\pythonProject\Practice\lib\site-packages\scipy\integrate\_ivp\base.py", line 125, in fun_single
    return self._fun(t, y[:, None]).ravel()
  File "C:\Users\RSlat\PycharmProjects\pythonProject\Practice\lib\site-packages\scipy\integrate\_ivp\base.py", line 20, in fun_wrapped
    return np.asarray(fun(t, y), dtype=dtype)
TypeError: 'NoneType' object is not callable

Any help at all would be greatly appreciated. Thanks and have an awesome day!


Solution

  • Apparently (and according to https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.RK45.html) sp.integrate.RK45() requires a callable at the first position.

    Thus it should work when you write it this way:

    sp.integrate.RK45(fun, t_0, y_0, t_final,vectorized=True)
    

    As you can see, I only give the function (callable) "fun" (without parameters) to RK45.