1

I am trying to use odeint but I have a parameter that changes values with every time step. My function is:

def f(y, t, k1, k2, Pr): return k1*(Pr-k2)*y 

Where Pr is a pandas series that contains float values, of which I have observed values. And t is a list of integer years from 1961 to 2014. I wrote the following code for odeint:

y0 = 120000 k1 = 0.2 k2 = -.4 y = odeint(f, y0, t, args = (k1, k2, Pr, )) 

But it gives the following error:

RuntimeError: The size of the array returned by func (54) does not match the size of y0 (1). 
5
  • just pointing out a potential bug:k1 and k2 are overwritten in the first two lines of your function, so the values you're passing in for them are discarded. Commented Sep 20, 2021 at 20:53
  • @EricCanton you are right, i just edited the question Commented Sep 20, 2021 at 20:56
  • Could you let us know the types of Pr and t? e.g. Pandas DataFrame or Series. Or a simplified example showing their instantiation. It's important for getting the right syntax for working with them. Commented Sep 21, 2021 at 1:38
  • 1
    @EricCanton Pr is a pandas series that contains float values and t is the list that contains year values from 1961 to 2014. The length of both is 54. Commented Sep 21, 2021 at 3:50
  • The error you get simply highlights that y0 is a single int, whereas the return value of f contains 54 elements. These two must have the same shape. If the initial value is the same for all 54 elements, then simply write y0 = 1.2e5 * np.ones(54). Commented Sep 22, 2021 at 8:47

1 Answer 1

2

As indicated by the error message, Pr is being passed in as a vector of length 54, instead of the values one-by-one. Inferring that Pr is a NumPy vector, this would mean the output of f is the result of applying the return value elementwise to Pr.

To fix this, you can instead use a function that produces a Pr value from a time input. Again assuming that Pr[k] corresponds to t[k], the simplest version of this function could be:

def get_Pr(time: float): t_index = sum(t <= time) - 1 return Pr[t_index] 

Then modify f as follows:

def f(y, t, k1, k2): this_pr = get_Pr(t) return k1*(this_pr-k2)*y 

edit: ...and then don't pass Pr in as an arg to scipy.odeint, since f gets the value in a different way.

Sign up to request clarification or add additional context in comments.

5 Comments

When I do these changes and run the odeint, it gives the error- TypeError: cannot do label indexing on <class 'pandas.core.indexes.numeric.Int64Index'> with these indexers [1961.0000197468344] of <class 'float'>
Not sure why this error comes. The t is time series from 1961-2014
It's strange that you're getting that error, if t is a list and not a NumPy array or Pandas series... t <= time should give a different error with a Python list, since <= isn't defined between a list and a float.
But that aside, to use an integer index with a Pandas series, use .iloc on it. As in, return Pr.iloc[t_index]
Pr(t) is available at discrete-time intervals (i.e. every year). Could this be a reason for getting the error that is in 1st comment? Are time values supposed to be continuous for odeint?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.