Division by zero ? (In newton iteration method) - python

I'm doing a newton iteration to find T_a. Everything seems fine in the code except in one the very first definitions.
My rho(T_a) returns a division by zero (it assumes that T_a is zero while it's just a variable. If I change the T_a in the equation to something like 100, everything runs smoothly.
Any idea why it's returning a division by zero?
from numpy import *
import numpy as np
import pylab
import scipy
from scipy.optimize import leastsq
from math import *
import matplotlib.pyplot as plt
from scipy import integrate
# THETA NOTATION:
#pi/2: substellar point
#-pi/2: antistellar point
#0: terminators
#define constants used in equations:
alb = 0.2 #constant albedo
F = 866 #J/s*m**2
R = 287.0 #J/K*kg
U = 5.0 #m/s
C_p = 1000 #J/K*kg
C_d = 0.0015
p1 = 10**4
p2 = 10**5.0
p3 = 10**6.0 #Pa
sig = 5.67*10**-8.0 #J/s*m**2*K**4 #Stefan-Boltzmann cst
def rho(T_a):
p1=10000.0
R=287.0 #J/K*kg
return (p1/(T_a*R))
def a(T_a):
U = 5 #m/s
C_p = 1000 #J/K*kg
C_d = 0.0015
return rho(T_a)*C_p*C_d*U
#################################################
##### PART 2 : check integrals equality
#################################################
#define the RHS and LHS of integral equality
def LHS(theta):
return (1-alb)*F*np.sin(theta)*np.cos(theta)
#define the result of each integral
Left = integrate.quad(lambda theta: LHS(theta), 0, pi/2)[0]
#define a function 1-(result LHS/result RHS) >>> We look for the zero of this
x0=130.0 #guess a value for T_a
#T_a = 131.0
#Python way of solving for the zero of the function
#Define T_g in function of T_a, have RHS(T_a) return T_g**4 etc, have result_RHS(T_a) return int.RHS(T_a),
#have func(T_a) return result_LHS/result_RHS
def T_g(T_a,theta):
return np.roots(array([(sig),0,0,(a(T_a)),((-a(T_a)*T_a)-LHS(theta))]))[3]
def RHS(theta,T_a):
return sig*T_g(T_a,theta)**4*np.cos(theta)
def result_RHS(T_a,theta):
return integrate.quad(lambda theta: RHS(T_a,theta), -pi/2, pi/2)[0]
def function(T_a,theta):
return 1-((Left/result_RHS(T_a,theta)))
theta = np.arange(-pi/2, pi/2, pi/20)
T_a_0 = scipy.optimize.newton(function,x0,fprime=None,args=(theta,),tol= (10**-5),maxiter=50000)
Output:
Traceback (most recent call last):
File "/Users/jadecheclair/Documents/PHY479Y/FindT_a.py", line 85, in <module>
T_a_0 = scipy.optimize.newton(function,x0,fprime=None,args=(theta,),tol=(10**-5),maxiter=50000)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/optimize/zeros.py", line 120, in newton
q0 = func(*((p0,) + args))
File "/Users/jadecheclair/Documents/PHY479Y/FindT_a.py", line 81, in function
return 1-((Left/result_RHS(T_a,theta)))
File "/Users/jadecheclair/Documents/PHY479Y/FindT_a.py", line 78, in result_RHS
return integrate.quad(lambda theta: RHS(T_a,theta), -pi/2, pi/2)[0]
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/integrate/quadpack.py", line 247, in quad
retval = _quad(func,a,b,args,full_output,epsabs,epsrel,limit,points)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/integrate/quadpack.py", line 312, in _quad
return _quadpack._qagse(func,a,b,args,full_output,epsabs,epsrel,limit)
File "/Users/jadecheclair/Documents/PHY479Y/FindT_a.py", line 78, in <lambda>
return integrate.quad(lambda theta: RHS(T_a,theta), -pi/2, pi/2)[0]
File "/Users/jadecheclair/Documents/PHY479Y/FindT_a.py", line 75, in RHS
return sig*T_g(T_a,theta)**4*np.cos(theta)
File "/Users/jadecheclair/Documents/PHY479Y/FindT_a.py", line 72, in T_g
return np.roots(array([(sig),0,0,(a(T_a)),((-a(T_a)*T_a)-LHS(theta))]))[3]
File "/Users/jadecheclair/Documents/PHY479Y/FindT_a.py", line 38, in a
return rho(T_a)*C_p*C_d*U
File "/Users/jadecheclair/Documents/PHY479Y/FindT_a.py", line 32, in rho
return (p1/(T_a*R))
ZeroDivisionError: float division by zero

Your RHS function is defined slightly differently to all the others, in that it has theta first and T_a as its second argument:
def RHS(theta,T_a):
return sig*T_g(T_a,theta)**4*np.cos(theta)
I think that's why you passed the arguments in the wrong order here:
lambda theta: RHS(T_a,theta)
Get them in the right order and you should be OK.
As a side-note, some of your imports look like they could cause weird bugs:
from numpy import *
from math import *
Numpy and the math module have at least a few function names in common, like sqrt. It's safer to just do import math and import numpy as np, and access the functions through the module name. Otherwise what happens when you call sqrt could change depending on the order you do your imports in.

You reversed your parameters:
In result_RHS you call: RHS(T_a,theta), but the parameter definition of RHS is def RHS(theta,T_a)
Swap those in in the definition and the error no longer occurs. Your definition should look like this:
def RHS(T_a, theta)

Related

Lyapunov exponents with JiTCODE

I am using JiTCODE to calculate the Lyapunov exponents of the Lorenz oscillator.
Here is the simple script following the documentation:
import numpy as np
import pylab as plt
from jitcode import jitcode_lyap, y
p, r, b = 10.0, 28.0, 8.0/3.0
x0 = np.array([10.0, 10.0, 5.0])
f = [
p * y(1) - p * y(0),
-y(0) * y(2) + r * y(0) - y(1),
y(0) * y(1) - b * y(2)
]
n = len(f)
times = range(10, 1000, 10)
nstep = len(times)
lyaps = np.zeros((nstep, n))
ODE = jitcode_lyap(f, n_lyap=n)
ODE.set_integrator("vode")
ODE.set_initial_value(x0, 0.0)
for time in times:
print(ODE.integrate(time)[1])
And I got the following error.
Generating, compiling, and loading C code.
generated C code for f
generated symbolic Jacobian
generated C code for Jacobian
/usr/local/lib/python3.6/dist-packages/scipy/integrate/_ode.py:1009: UserWarning: vode: Excess work done on this call. (Perhaps wrong MF.)
self.messages.get(istate, unexpected_istate_msg)))
Traceback (most recent call last):
File "main.py", line 29, in <module>
print(ODE.integrate(time)[1])
File "/home/abolfazl/.local/lib/python3.6/site-packages/jitcode/_jitcode.py", line 755, in integrate
super(jitcode_lyap, self).integrate(*args, **kwargs)
File "/home/abolfazl/.local/lib/python3.6/site-packages/jitcode/_jitcode.py", line 656, in integrate
return self.integrator.integrate(*args,**kwargs)
File "/home/abolfazl/.local/lib/python3.6/site-packages/jitcode/integrator_tools.py", line 131, in integrate
raise UnsuccessfulIntegration
jitcode.integrator_tools.UnsuccessfulIntegration
I think the equation is not the problem because I have solved that with jitcode but jitcode_lyap can not solve it.
I got the answer from the developer:
Your problem is that your integration steps are too long. Since the tangent vectors are only re-normalised after every integration step, this causes numerical overflows in them as the Lorenz system has a much smaller time scale than the one used as an example in the documentation.
Using times = range(1, 100, 1) fixes this.

How to pass an array of input parameters in scipy.optimize.minimize?

I want to use scipy.optimize.minimize to solve for a set of parameters by minimizing an error function.
The function called "error" returns the squared error for the function that I am trying to find z1,z2,z3(the parameters) for.
I have an array of x(called "b" in the function) and y(called "real" in the function) values.
The code below works fine if I set x and y to some integer, but not if I try to pass in an array of x and y values, to act as the variable "b" and "real" in the equation to be minimized.
Trying to pass in an array of X and Y values results in the error pasted below.
Is there a way to pass in arrays to act as a variable in an equation for the minimize function, instead of just a single integer?
Here is what my code looks like:
import numpy as np
import pandas as pd
from scipy.optimize import minimize
#dataset file, with a column named x,y with 1000 rows
f = pd.read_csv('Test_Data_.txt', sep='\t')
#initial guess
x0 = [1, 2, 3]
#f['x'] and f['y'] are columns with 1000 rows
#x = f['x'].values
#y = f['y'].values
x = 1 #these parameters work fine
y = 4
#a function called inside the function to be minimized
def est(z1, z2, z3, b):
return z1 * b**2 + z2 * b + z3
#function to minimize
def error(x, real, b):
return (real - est(x[0], x[1], x[2], b))**2
print(minimize(error, x0, args = ( x, y), method='BFGS', tol=1e-6))
Feeding in the array of x and y values produces the error:
Traceback (most recent call last):
File "problem1.py", line 24, in <module>
minimize(error, x0, args = ( np.array(list(f['y'].values)), np.array(list(f['x'].values))), method='BFGS', tol=1e-6)
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/_minimize.py", line 595, in minimize
return _minimize_bfgs(fun, x0, args, jac, callback, **options)
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/optimize.py", line 970, in _minimize_bfgs
gfk = myfprime(x0)
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/optimize.py", line 300, in function_wrapper
return function(*(wrapper_args + args))
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/optimize.py", line 730, in approx_fprime
return _approx_fprime_helper(xk, f, epsilon, args=args)
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/optimize.py", line 670, in _approx_fprime_helper
grad[k] = (f(*((xk + d,) + args)) - f0) / d[k]
ValueError: setting an array element with a sequence.

python complex_ode pass matrix-valued parameters

I'm having some trouble with python's complex_ode solver.
I'm trying to solve the following equation:
dy/dt = -iAy - icos(Omegat)By
where A and B are NxN arrays and the unknown y is an Nx1 array, i is the imaginary unit and Omega is a parameter.
Here's my code:
import numpy as np
from scipy.integrate import ode,complex_ode
N = 3 #linear matrix dim
Omega = 1.0 #parameter
# define symmetric matrices A and B
A = np.random.ranf((N,N))
A = (A + A.T)/2.0
B = np.random.ranf((N,N))
B = (B + B.T)/2.0
# define RHS of ODE
def f(t,y,Omega,A,B):
return -1j*A.dot(y)-1j*np.cos(Omega*t)*B.dot(y)
# define list of parameter
params=[Omega,A,B]
# choose solver: need complex_ode for this ODE
#solver = ode(f)
solver = complex_ode(f)
solver.set_f_params(*params)
solver.set_integrator("dop853")
# set initial value
v0 = np.zeros((N,),dtype=np.float64)
v0[0] = 1.0
# check that the function f works properly
print f(0,v0,Omega,A,B)
# solve-check the ODE
solver.set_initial_value(v0)
solver.integrate(10.0)
print solver.successful()
Running this script produces the error
capi_return is NULL
Call-back cb_fcn_in___user__routines failed.
Traceback (most recent call last):
File "ode_test.py", line 37, in <module>
solver.integrate(10.0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 515, in integrate
y = ode.integrate(self, t, step, relax)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 388, in integrate
self.f_params, self.jac_params)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 946, in run
tuple(self.call_args) + (f_params,)))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 472, in _wrap
f = self.cf(*((t, y[::2] + 1j * y[1::2]) + f_args))
TypeError: f() takes exactly 5 arguments (2 given)
If instead I use solver = ode(f), ie. the real-valued solver, it runs fine. Except that it doesn't solve the ODE I want which is complex-valued :(
I then tried to reduce the number of parameters by making the matrices A and B global variables. This way the only parameter the function f accepts is Omega. The error changes to
capi_return is NULL
Call-back cb_fcn_in___user__routines failed.
Traceback (most recent call last):
File "ode_test.py", line 37, in <module>
solver.integrate(10.0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 515, in integrate
y = ode.integrate(self, t, step, relax)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 388, in integrate
self.f_params, self.jac_params)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 946, in run
tuple(self.call_args) + (f_params,)))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 472, in _wrap
f = self.cf(*((t, y[::2] + 1j * y[1::2]) + f_args))
TypeError: 'float' object has no attribute '__getitem__'
where I figured out that float refers to the parameter Omega [by trying an integer]. Again, "ode" alone works in this case as well.
Last, I tried the same complex valued equation, but now A and B are just numbers. I tried to pass them both as parameters, i.e. params = [Omega,A,B], as well as making them global variables in which case params=[Omega]. The error is the
TypeError: 'float' object has no attribute '__getitem__'
error - the full error is the same as above. And once again this problem does not occur for the real-valued "ode".
I know zvode is an alternative, but it appears to become quite slow for large N. In the real problem I have, A is a diagonal matrix but B is a non-sparse full matrix.
Any insights are much appreciated! I'm interested both in (i) alternative ways to solve this complex-valued ODE with array-valued parameters, and (ii) how to get complex_ode to run :)
Thanks!
It seems like the link that Reti43 posted contains the answer, so let me put it here for the benefit of future users:
from scipy.integrate import complex_ode
import numpy as np
N = 3
Omega = 1.0;
class myfuncs(object):
def __init__(self, f, fargs=[]):
self._f = f
self.fargs=fargs
def f(self, t, y):
return self._f(t, y, *self.fargs)
def f(t, y, Omega,A,B):
return -1j*(A+np.cos(Omega*t)*B).dot(y)
A = np.random.ranf((N,N))
A = (A + A.T)/2.0
B = np.random.ranf((N,N))
B = (B + B.T)/2.0
v0 = np.zeros((N,),dtype=np.float64)
v0[0] = 1.0
t0 = 0
case = myfuncs(f, fargs=[Omega, A, B] )
solver = complex_ode(case.f)
solver.set_initial_value(v0, t0)
solver.integrate([10.0])
print solver.successful()
"""
t1 = 10
dt = 1
while solver.successful() and solver.t < t1:
solver.integrate(solver.t+dt)
print(solver.t, solver.y)
"""
Could maybe someone comment on why this trick does the job?

ValueError shape <= 0 for distribution function

I need to complete a distribution function which looks like this into python:
−∞< x <∞,
P(x)dx= ((1+x^2/n)^-(n+1)/2) * Γ(n+1/2)/Γ(n/2)*(nπ)**1/2 dx, n=1.
So i tried it like this:
from numpy import *
from scipy import stats
from scipy.special import gammaln
from pylab import *
def studentstPDF(x,n=1):
"""
Call:
d = studentstPDF(x,n)
Input argument:
x: float (array)
n: float, default = 1.0
Output argument:
p: float
Examples:
In [1]: studentstPDF(1,1)
Out[1]: 0.1591549
"""
p = (1+((x**2)/n))**((-n+1)/2) * gamma((n+1)/2) / gamma(n/2) * (n*math.pi)**1/2
p[x<inf] = 0.0
p[x>-inf] = 0.0
return(p)
but now I get the error 'ValueError: shape <= 0'
What does that mean? And where am I wrong with my function?
In [16]:
studentstPDF(1,1)
Traceback (most recent call last):
File "<ipython-input-16-ddd6d9df823d>", line 1, in <module>
studentstPDF(1,1)
File "/Users/Veysel/Downloads/Exercise4-2/exercise4.py", line 122, in studentstPDF
p = (1+((x**2)/n))**((-n+1)/2) * gamma((n+1)/2) / gamma(n/2) * (n*math.pi)**1/2
File "mtrand.pyx", line 1871, in mtrand.RandomState.gamma (numpy/random/mtrand/mtrand.c:13491)
ValueError: shape <= 0
Your gamma function from scipy.special is most likely being overwritten by another gamma function of another nature, perhaps a random variable function from your mass imports. Import like this instead:
from scipy.special import gamma as Gamma
and write out your expression like this:
p = (1+((x**2)/n))**((-n+1)/2) * Gamma((n+1)/2) / Gamma(n/2) * (n*math.pi)**1/2
If you absolutely have to import the same way, use scipy.special.gamma in place of your current gamma calls and import scipy.
Your error itself is a result of attempting to use the multiplicative operator * on operands that do not have the same shape.

scipy curve_fit fails on exponential fit

When I try to do an exponential fit using curve_fit, scipy returns an error. Am I doing something wrong? Removing the negative sign from np.exp(-b * t) allows curve_fit to work, but the values it returns are way off.
#!/usr/bin/python
import numpy as np
import scipy as sp
from scipy.optimize import curve_fit
import scipy.optimize as opt
import matplotlib.pyplot as plt
x = [40,45,50,55,60]
y = [0.99358851674641158, 0.79779904306220106, 0.60200956937799055, 0.49521531100478472, 0.38842105263157894]
def model_func(t, a, b, c):
return a * np.exp(-b * t) + c
opt_parms, parm_cov = sp.optimize.curve_fit(model_func, x, y, maxfev=1000)
a,b,c = opt_parms
print a,b,c
print x
print y
print model_func(x, a,b,c)
Fails with error:
Traceback (most recent call last):
File "asdf.py", line 18, in <module>
opt_parms, parm_cov = sp.optimize.curve_fit(model_func, x, y, maxfev=1000)
File "/usr/lib/python2.7/dist-packages/scipy/optimize/minpack.py", line 426, in curve_fit
res = leastsq(func, p0, args=args, full_output=1, **kw)
File "/usr/lib/python2.7/dist-packages/scipy/optimize/minpack.py", line 276, in leastsq
m = _check_func('leastsq', 'func', func, x0, args, n)[0]
File "/usr/lib/python2.7/dist-packages/scipy/optimize/minpack.py", line 13, in _check_func
res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
File "/usr/lib/python2.7/dist-packages/scipy/optimize/minpack.py", line 346, in _general_function
return function(xdata, *params) - ydata
ValueError: operands could not be broadcast together with shapes (0) (5)
change x and y to numpy arrays
x = np.array([40,45,50,55,60])
y = np.array([0.99358851674641158, 0.79779904306220106, 0.60200956937799055, 0.49521531100478472, 0.38842105263157894])
then I think you are good, because the function requires vectorized computation, whereas lists are not adequate.

Categories