I'm trying to fit an equation that has an integral. The upper limit of the integral is a variable, and as such I'm having trouble using quad as it only accepts floats as limits. I've tried to get around this using a for loop but I still keep getting the same error of 'ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()'.
The equation I'm trying to fit is:
I know the constants M and c, and have data for m(z) and z. I'm trying to fit ΩM and ΩΛ. This is my code:
import numpy as np
import scipy.integrate as integrate
from scipy.optimize import curve_fit
z=[0.03, 0.05, 0.026, 0.075, 0.026, 0.014, 0.101, 0.02, 0.036, 0.045, 0.043, 0.018, 0.079,
0.088, 0.063, 0.071, 0.052, 0.05]
m=[16.26, 17.63, 16.08, 18.43, 16.28, 14.47, 19.16, 15.18, 16.66, 17.61, 17.19, 15.61,
18.27, 19.28, 18.24, 18.33, 17.54, 17.69]
c=299792.458 #speed of light
M=-18.316469239
def integrand(Z,OM,OV):
return np.power((((1+Z)**2)*(1+OM*Z)-Z*(2+Z)*OV),-0.5)
def curve(z,OM,OV):
for i in z:
I=integrate.quad(integrand,0,i,args=(OM,OV))[0]
return M+5*np.log10(c*(1+z))*I)
popts, pcov=curve_fit(curve,z,m)
Thanks in advance and hope that includes everything!
In addition to what was commented you only take the last result of the integration loop into account. The corrected code should be like this:
from matplotlib import pylab as plt
import numpy as np
import scipy.integrate as integrate
from scipy.optimize import curve_fit
z=np.asarray([0.03, 0.05, 0.026, 0.075, 0.026, 0.014, 0.101, 0.02, 0.036, 0.045, 0.043, 0.018, 0.079,
0.088, 0.063, 0.071, 0.052, 0.05])
m=np.asarray([16.26, 17.63, 16.08, 18.43, 16.28, 14.47, 19.16, 15.18, 16.66, 17.61, 17.19, 15.61,
18.27, 19.28, 18.24, 18.33, 17.54, 17.69])
# sorting of the data is not necessary but nicer when plotting
idx = np.argsort(z)
z = np.take(z, idx)
m = np.take(m, idx)
c=299792458 #speed of light
M=-18.316469239
def integrand(Z,OM,OV):
return np.power((((1+Z)**2)*(1+OM*Z)-Z*(2+Z)*OV),-0.5)
def curve(z,OM,OV):
I = [integrate.quad(integrand,0,i,args=(OM,OV))[0] for i in z]
return M+5*np.log10(c*(1+z)*I)
popts, pcov=curve_fit(curve,z,m, p0=(1,1))
plt.plot(z,m,'o')
plt.plot(z,curve(z,*popts))
plt.show()
And indeed it gives a nice match: