I have one equation defined in the function
def fun(x, y, z, v, b):
Y = (z*(np.sign(x) * (np.abs(x))**(y-1))) - (v*np.sign(b) * (np.abs(b))**(v-1))/(1-b**v)
return Y.flatten()
that I want to solve for the value of x, given the values of Z0, SS (year 1: Z0=1.2, SS=2, ...) and different combinations of alpha
and kappa
, for which I am creating a grid.
Z0 = [1.2, 5, 3, 2.5, 4.2]
SS = [2, 3, 2.2, 3.5, 5]
ngrid = 10
kv = np.linspace(0.05, 2, ngrid)
av = np.linspace(1.5, 4, ngrid)
q0 = []
for z in range(len(Z0)):
zz = Z0[z]
ss = SS[z]
for i in range(ngrid):
for j in range(ngrid):
kappa = kv[i]
alpha = av[j]
res0 = root(lambda x: fun(x, alpha, zz, kappa, ss), x0=np.ones(range(ngrid)))
q0 = res0.x
print(q0)
where y = alpha; v=kappa, z = Z0; b = S.
I am getting all [], [], ....
Not sure what is going on. Thanks for your help
Before you attempt to use res0.x
, check res0.success
. In this case, you'll find that it is False
in each case. When res0.success
is False, take a look at res0.message
for information about why root
failed.
During development and debugging, you might also consider getting the solver working for just one set of parameter values before you embed root
in three nested loops. For example, here are a few lines from an ipython session (variables were defined in previous lines, not shown):
In [37]: res0 = root(lambda x: fun(x, av[0], Z0[0], kv[0], SS[0]), x0=np.ones(range(ngrid)))
In [38]: res0.success
Out[38]: False
In [39]: res0.message
Out[39]: 'Improper input parameters were entered.'
The message suggests that something is wrong with the input parameters. You call root
like this:
res0 = root(lambda x: fun(x, alpha, zz, kappa, ss), x0=np.ones(range(ngrid)))
A close look at that line shows the problem: the initial guess is np.ones(range(ngrid))
:
In [41]: np.ones(range(ngrid))
Out[41]: array([], shape=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), dtype=float64)
That's not what you want! The use of range
looks like a simple typo (or "thinko"). The initial guess should be
x0=np.ones(ngrid)
In ipython, we get:
In [50]: res0 = root(lambda x: fun(x, av[0], Z0[0], kv[0], SS[0]), x0=np.ones(ngrid))
In [51]: res0.success
Out[51]: True
In [52]: res0.x
Out[52]:
array([-0.37405428, -0.37405428, -0.37405428, -0.37405428, -0.37405428,
-0.37405428, -0.37405428, -0.37405428, -0.37405428, -0.37405428])
All the return values are the same (and this happens for other parameters values), which suggests that you are solving a scalar equation. A closer look at fun
shows that you only use x
in element-wise operations, so you are in fact solving just a scalar equation. In that case, you can use x0=1
:
In [65]: res0 = root(lambda x: fun(x, av[0], Z0[0], kv[0], SS[0]), x0=1)
In [66]: res0.success
Out[66]: True
In [67]: res0.x
Out[67]: array([-0.37405428])
You could also consider using root_scalar
instead of root
.