I'm trying to compute the following integral
using scipy, with the following program:
def E(z):
result = 1/np.sqrt(Om*(1 + z)**3 + Ode + Ox*(1 + z)**2)
return result
def r(z, E):
result, error = quad(E, 0, z) # integrate E(z) from 0 to z
return result
z being the independent variable, while Om Ode and Ox are simply constants (previously assigned).
When I then try to call the function:
z = np.linspace(1e-3, 4, 300)
plt.plot(z, r(z))
I get the error
flip, a, b = b < a, min(a, b), max(a, b)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any()
or a.all()
What is the problem? Is scipy.quad unable to integrate up to a variable?
Thank you so much for your help
You could use a combination of Python's map(function, iterable, ...) function,
Return an iterator that applies function to every item of iterable, yielding the results.
and functools partial(func[,*args][, **keywords]) method:
Return a new partial object which when called will behave like func called with the positional arguments args and keyword arguments keywords.
import numpy as np
from scipy.integrate import quad
import matplotlib.pyplot as plt
from functools import partial
def E(z):
Om = 0.32
Ode = 0.68
Ox = 0
result = 1/np.sqrt(Om*(1 + z)**3 + Ode + Ox*(1 + z)**2)
return result
def r(z):
result = np.array(
list(map(partial(quad, E, 0), z))
)[:, 0] # integrate E(z) from 0 to z
return result
z = np.linspace(1e-3, 4, 300)
fig, ax = plt.subplots()
ax.plot(z, r(z))
fig.show()
Related
I want to convert the piecewise-function output of a calculation in Mathematica into Python. Taking inspiration from this page for the Mathematica->Python conversion and this page for writing piecewise functions, I have
from numpy import linspace, vectorize, array
from numpy import arctan, log
import matplotlib.pyplot as plt
from sympy.parsing.mathematica import parse
def fun(x,a,b,c):
# string inside parse('') is my mathematica output
if a == 0:
out = parse('a (-I b + x) ArcTan[(b - a)/c]')
else:
out = parse('4 c a^2 Log[c^2 + (x - a)^2]')
return out
a = 0.17
b = 0.44
c = 0.29
x = linspace(0,50,int(1e3))
vfun = vectorize(fun)
y = vfun(x,a,b,c)
yp = 4*c*a**2*log(c**2 + (x - a)**2)
plt.figure()
plt.plot(x,y,'.-')
plt.title('mathematica -> python conversion')
plt.figure()
plt.plot(x,yp,'.-')
plt.title('expected')
plt.show()
The plot looks like:
whereas it should be:
Have I done something wrong when converting Mathematica to Python? Or is there a problem when assigning numerical values to a, b, and c? (Note that this is a MWE, and the Mathematica code that I want to convert is much longer and complicated than what is shown above.)
A much easier solution is using eval. Now I know eval is very dangerous but most of the time when it takes input from user, but here the input is already defined for us.Now onto the answer.
You are not getting the expected output because your vectorized array does not contain any floats but only contains output from mathematica's parser which return unevaluated string, so we can use .evalf() as answer given by #David, lambdify() which uses eval() internally or we can directly use eval().
Here is the documentation of the methods used : https://docs.sympy.org/latest/tutorial/basic_operations.html
from numpy import linspace, vectorize, array
from numpy import arctan, log
import matplotlib.pyplot as plt
from sympy.parsing.mathematica import MathematicaParser
def fun(x,a,b,c):
obj = MathematicaParser()
if a == 0:
out = obj.parse('a (-I b + x) ArcTan[(b - a)/c]')
else:
out = obj.parse('4 c a^2 Log[c^2 + (x - a)^2]')
return out
a = 0.17
b = 0.44
c = 0.29
x = linspace(0,50,int(1e3))
yp = 4*c*a**2*log(c**2 + (x - a)**2)
vfun = vectorize(fun)
y = vfun(x,a,b,c)
#Here y is a type <class 'numpy.ndarray'> containing 1000 <class 'numpy.str_'>
#['4*c*a**2*log(c**2+(x-a)**2)' '4*c*a**2*log(c**2+(x-a)**2)'
#'4*c*a**2*log(c**2+(x-a)**2)' '4*c*a**2*log(c**2+(x-a)**2)'
#'4*c*a**2*log(c**2+(x-a)**2)' '4*c*a**2*log(c**2+(x-a)**2)'
#'4*c*a**2*log(c**2+(x-a)**2)' '4*c*a**2*log(c**2+(x-a)**2)'
#....
y = eval(y[0]) #y[0] is '4*c*a**2*log(c**2+(x-a)**2)'
#When we evaluate y[0] we again get y as <class 'numpy.ndarray'> conatining 1000 <class 'numpy.float64'>
#Because x is <class 'numpy.ndarray'> it evaluates the first string over
#all the points in x.
#[-0.07309464 -0.07770262 -0.08110382 -0.0828403 -0.08263539 -0.08052339
#-0.07683235 -0.07203573 -0.06659307 -0.06086366 -0.05509179 -0.04942739
#-0.04395413 -0.03871304 -0.03371924 -0.0289728 -0.02446552 -0.02018495
#.....
plt.figure()
plt.plot(x, y,'.-')
plt.title('mathematica -> python conversion')
plt.figure()
plt.plot(x,yp,'.-')
plt.title('expected')
plt.show()
Output :
This is a dirty solution:
import numpy as np
import matplotlib.pyplot as plt
from sympy.parsing.mathematica import mathematica
from sympy import symbols
def fun(x, a, b, c):
# string inside parse('') is my mathematica output
if a == 0:
out = mathematica('a (-I b + x) ArcTan[(b - a)/c]')
else:
out = mathematica('4 c a^2 Log[c^2 + (x - a)^2]')
return out
aa = 0.17
bb = 0.44
cc = 0.29
II = 1
xx = np.linspace(0, 50, int(1e3))
x, a, b, c, I = symbols('x, a, b, c, I')
fun1 = fun(x, a, b, c)
fun2 = fun1.subs({a: aa, c: cc})
print(fun2.evalf())
y_list = []
for item in xx:
y_list.append(fun2.subs({x:item}).evalf())
print(y_list[:10])
plt.figure()
plt.plot(xx, y_list,'.-')
plt.title('mathematica -> python conversion')
plt.show()
I will explain it later how all of this works.
Update
As you may see, when a == 0, the function is 0, you need to check that.
When you use mathematica, the type of fun1 is a sympy function (sympy.core.mul.Mul), that's why you have to use symbols and fun1.subs() and fun2.evalf(), in other words, you need to know who to use the basic functions of sympy.
The way you evaluate a function in order to plot it, well, you use a list:
y_list = []
for item in xx:
y_list.append(fun2.subs({x:item}).evalf())
By the way, I am using sympy version 1.4.
I was trying to plot (the modulus of) sum of quadratic roots and it returns me an error illustrated as follow:
import numpy as np
import matplotlib.pyplot as plt
def rooting(a, b, c):
y = [a, b, c]
z = np.roots(y)
return np.absolute(z[0]+z[1])
x = np.linspace(1, 10, 10)
plt.plot(x, rooting(x, 2, 3))
and the error was:
File "C:\Users\user\Anaconda3\lib\site-packages\numpy\core\fromnumeric.py", line 1570, in nonzero
res = nonzero()
SystemError: <built-in method nonzero of numpy.ndarray object at 0x000001422B9BFD00> returned a result with an error set
Can someone tell me what's going on?
The problem arises because you are passing the variable to a vector and then concatenate with b and c are numbers, you must pass to the variable to a scalar, I show my next solution based on the above.
def rooting(a, b, c):
y = [a, b, c]
z = np.roots(y)
return np.absolute(z[0]+z[1])
x = np.linspace(1, 10, 10)
y = [rooting(xi, 2, 3) for xi in x]
plt.plot(x, y)
plt.show()
Using the quadratic formula, we know the roots are (-b ± √(b**2-4ac))/2a.
So the modulus of the sum of the roots is |b/a|.
With this simplification, we can compute the result in a vectorized way (no list comprehesion, looping, or multiple calls of rooting necessary):
import numpy as np
import matplotlib.pyplot as plt
def rooting(a, b, c):
# The roots are (-b ± √(b**2-4ac))/2a
# So the modulus of the sum of the roots is |b/a|
return np.abs(b/a)
x = np.linspace(0, 10, 11)
plt.plot(x, rooting(x, 2, 3))
plt.show()
I have 3 arrays of data to integrate over and need to return a 3d array. This is my code
import numpy as np
from scipy import integrate
def f(x, y, z):
return x + y + 2*z
a = np.arange(64)
b = np.arange(100)
c = np.arange(100)
result = []
for x in a:
for y in b:
for z in c:
result.append(integrate.quad(f, 0, x, (y, z))[0])
result_1 = np.array(result).reshape(len(a), len(b), len(c))
print(result_1)
It works, but this code is so slow and I need to handle problems bigger than this. Is there any other method, something like broadcasting? And the following is the function I need to handle:
import numpy as np
from scipy import integrate, special
def f(v,r):
alpha = 0.5
chi = 1/2*special.erf((r+1.2)/0.3)-1/2*special.erf((r-1.2)/0.3)
return 4/(np.sqrt(2*np.pi*alpha))*chi*np.exp(-v**2/(2*alpha))
def E_1(r):
def f_1(v,r):
return r*f(v,r)
a = 0
b = r
g = lambda x: -np.inf
h = lambda x: np.inf
return integrate.dblquad(f_1, a, b, g, h)
def E_f(tau, xi_1, xi_2):
return E_1(xi_1*np.cos(tau) + xi_2*np.sin(tau))[0]*(-np.sin(tau))
I need to input tau, xi_1, xi_2 as three arrays, and return to a 3D array. And its arrange like coordinate, every coordinate point corresponds to a result. Just like the first example.
I'm trying to find all the intersection points of two graphs and display them on the final plot. I've looked around and tried multiple things, but I haven't been able to obtain what l'm looking for.
Currently, I attempting to generate a list wherein the intersection points would be listed, though I keep getting the following error:
The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all().
import numpy as np
from scipy.optimize import fsolve
import matplotlib.pyplot as plt
x = np.arange(-7.0, 7.0, 0.05)
def y(x):
return np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)
def g(x):
return -10 * np.arctan(x)
def intersection(x):
if (y(x) - g(x)) == 0:
print y.all(x)
plt.plot(x, y(x), '-')
plt.plot(x, g(x), '-')
plt.show()
It's similar to:
Intersection of two graphs in Python, find the x value:
import numpy as np
from scipy.optimize import fsolve
import matplotlib.pyplot as plt
x = np.arange(-7.0, 7.0, 0.05)
y = np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)
g = -10 * np.arctan(x)
def intersection():
idx = np.argwhere(np.isclose(y, g, atol=10)).reshape(-1)
print idx
plt.plot(x, y, '-')
plt.plot(x, g, '-')
plt.show()
intersection()
edit: you don't use a function, but a list of values
For single solutions, this is answered in http://glowingpython.blogspot.de/2011/05/hot-to-find-intersection-of-two.html:
from scipy.optimize import fsolve
def findIntersection(fun1,fun2,x0):
return fsolve(lambda x : fun1(x) - fun2(x),x0)
result = findIntersection(y,g,0.0)
Now, you just need to iterate through your range to get all the roots. This gives some duplicates, which you might be able to remove by using mpmath, setting the precision low enough, and using a set.
from scipy.optimize import fsolve
import numpy as np
rng = np.arange(-7.0, 7.0, 0.05)
def y(x):
return np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)
def g(x):
return -10 * np.arctan(x)
def findIntersection(fun1,fun2,x0):
return fsolve(lambda x : fun1(x) - fun2(x),x0)
result = []
for x in rng:
result.append(float(findIntersection(y,g,x)))
I am a python beginner, currently using scipy's odeint to compute a coupled ODE system, however, when I run, python shell always tell me that
>>>
Excess work done on this call (perhaps wrong Dfun type).
Run with full_output = 1 to get quantitative information.
>>>
So, I have to change my time step and final time, in order to make it integratable. To do this, I need to try a different combinations, which is quite a pain. Could anyone tell me how can I ask odeint to automatically vary the time step and final time to successfully integrate this ode system?
and here is part of the code which has called odeint:
def main(t, init_pop_a, init_pop_b, *args, **kwargs):
"""
solve the obe for a given set of parameters
"""
# construct initial condition
# initially, rho_ee = 0
rho_init = zeros((16,16))*1j ########
rho_init[1,1] = init_pop_a
rho_init[2,2] = init_pop_b
rho_init[0,0] = 1 - (init_pop_a + init_pop_b)########
rho_init_ravel, params = to_1d(rho_init)
# perform the integration
result = odeint(wrapped_bloch3, rho_init_ravel, t, args=args)
# BUG: need to pass kwargs
# rewrap the result
return from_1d(result, params, prepend=(len(t),))
things = [2*pi, 20*pi, 0,0, 0,0, 0.1,100]
Omega_a, Omega_b, Delta_a, Delta_b, \
init_pop_a, init_pop_b, tstep, tfinal = things
args = ( Delta_a, Delta_b, Omega_a, Omega_b )
t = arange(0, tfinal + tstep, tstep)
data = main(t, init_pop_a, init_pop_b, *args)
plt.plot(t,abs(data[:,4,4]))
where wrapped_bloch3 is the function compute dy/dt.
EDIT: I note you already got an answer here: complex ODE systems in scipy
odeint does not work with complex-valued equations. I get
from scipy.integrate import odeint
import numpy as np
def func(t, y):
return 1 + 1j
t = np.linspace(0, 1, 200)
y = odeint(func, 0, t)
# -> This outputs:
#
# TypeError: can't convert complex to float
# odepack.error: Result from function call is not a proper array of floats.
You can solve your equation by the other ode solver:
from scipy.integrate import ode
import numpy as np
def myodeint(func, y0, t):
y0 = np.array(y0, complex)
func2 = lambda t, y: func(y, t) # odeint has these the other way :/
sol = ode(func2).set_integrator('zvode').set_initial_value(y0, t=t[0])
y = [sol.integrate(tp) for tp in t[1:]]
y.insert(0, y0)
return np.array(y)
def func(y, t, alpha):
return 1j*alpha*y
alpha = 3.3
t = np.linspace(0, 1, 200)
y = myodeint(lambda y, t: func(y, t, alpha), [1, 0, 0], t)