1

How to pass an array to scipy.integate.solve_ivp function? Now the u=1.0, what I wanted is u=np.random.uniform(-1, 1, 1000).

The scipy version is 1.4.1

The code is:

import numpy as np
from scipy.integrate import solve_ivp

def func(t, x, u):
    dydt = (-x + u) / 5
    return dydt

y0 = 0
t_span = [0, 10]  
t_eval = np.linspace(0, 10, 1000)
u = 1.0

sol = solve_ivp(func, t_span=t, y0=y0, t_eval=t_eval, args=(u, ))

Any help would be appreciated!

Don't forget the comma in arg=(u, ), or you will have an error odepack.error: Extra arguments must be in a tuple. Thanks @Bear Brown for solving this problem.

JM Zhou
  • 125
  • 2
  • 13
  • Does this answer your question? [odepack.error: Extra arguments must be in a tuple](https://stackoverflow.com/questions/45734650/odepack-error-extra-arguments-must-be-in-a-tuple) – Brown Bear May 12 '20 at 07:27
  • Not. @BearBrown – JM Zhou May 12 '20 at 07:33
  • you need add comma to your code `(u,)` because `(u)` is not a tuple – Brown Bear May 12 '20 at 07:36
  • oh, great, it works. Thanks a lot. Another question: I want to pass an array, like```u = np.linspace(0, 10, 1000)```, what should I do? @BearBrown – JM Zhou May 12 '20 at 07:42
  • yes, the error is ```RuntimeError: The size of the array returned by func (1000) does not match the size of y0 (1).``` – JM Zhou May 12 '20 at 07:52
  • When I try ```return [dydt]```, I have a new error ```RuntimeError: The array return by func must be one-dimensional, but got ndim=2.```@BearBrown – JM Zhou May 12 '20 at 08:01
  • try to set `y0` past the `u` next way `y0 = [0] * u.shape[0]` – Brown Bear May 12 '20 at 08:05
  • It doesn't work. The error still is ```RuntimeError: The array return by func must be one-dimensional, but got ndim=2.``` @BearBrown – JM Zhou May 12 '20 at 08:11
  • you should rollback the code in the `return` i suggested before – Brown Bear May 12 '20 at 08:14
  • It works, no error happened. But this will change the output ```sol```, the shape of ```sol``` is ```(1000, )``` before, now is ```(1000, 1000)```. I guess the solution is wrong in this way. @BearBrown – JM Zhou May 12 '20 at 08:33
  • What you probably want is some time dependence of the control `u`. To achieve that, you have to pass `u` as function of time, for instance using `u=scipy.interpolate.interp1d(t,u)` so that you can then set `dydt = (-x + u(t)) / 5` inside `func`. – Lutz Lehmann May 12 '20 at 09:07
  • Your understanding is absolutely right, ```u``` is a function of time ```t```. When using ```u=scipy.interpolate.interp1d(t,u)```, how to define ```t```? By the way, how can I get the ```du/dt```? @LutzLehmann – JM Zhou May 12 '20 at 09:32
  • That are the sample times. With longer names, you would set `u=scipy.interpolate.interp1d(t_data,u_data)` directly after the data import, here after defining them as `np.linspace`. One should work heavily to avoid using `du/dt`, see https://math.stackexchange.com/a/3472307/115115 on how that can work in a general situation, or in an example https://stackoverflow.com/a/61006681/3088138 – Lutz Lehmann May 12 '20 at 09:49

1 Answers1

2

I think this may be worked.

import numpy as np
from scipy.integrate import solve_ivp

def func(t, x, u):
    dydt = (-x + u(t)) / 5
    return dydt

y0 = 0
t_span = [0, 10]  
t_eval = np.linspace(0, 10, 1000)
u = lambda t: np.random.uniform(-1, 1, 1000)

sol = solve_ivp(func, t_span=t, y0=y0, t_eval=t_eval, args=(u, ))

Here is a better solution. Thanks @Lutz Lehmann

import numpy as np
from scipy.integrate import solve_ivp
from scipy.interpolate import interp1d

def func(t, x, u):
    dydt = (-x + u(t)) / 5
    return dydt

y0 = 0
t_span = [0, 10]  
t_eval = np.linspace(0, 10, 1000)
u_value = np.random.uniform(-1, 1, 1000)
u = interp1d(x=t_eval, y=u_value)

sol = solve_ivp(func, t_span=t, y0=y0, t_eval=t_eval, args=(u, ))
JM Zhou
  • 125
  • 2
  • 13