Convert sympy symbolic variable to numpy array - python

I want to perform a convolution that contains a sympy symbolic variable, then convert it to a numpy array.
My MWE is:
from numpy import pi, float64, linspace
from scipy.signal import fftconvolve
import matplotlib.pyplot as plt
from sympy import symbols
from sympy.utilities.lambdify import lambdify
a = 0.657
b = 0.745
c = 0.642
d = 0.343
x = symbols('x')
f = 2*b / ((x-a)**2 + b**2)
g = 2*d / ((x-c)**2 + d**2)
fog = fftconvolve(f,g,mode='same')
fog_fun = lambdify(x,fog,'numpy') # returns a numpy-ready function
xlist = linspace(-20,20,int(1e3))
my_fog = fog_fun(xlist)
dx = xlist[1]-xlist[0]
fog1 = 4*pi*(b+d)/((x-a-c)**2+(b+d)**2) # correct analytic solution
plt.figure()
plt.plot(x,fog1,lw=2,label='analytic')
plt.plot(x,my_fog*dx,lw=2,label='sympy')
plt.grid()
plt.legend(loc='best')
plt.show()
I have tried to use the solution suggested here, but I get the error TypeError: can't convert expression to float. I'm not sure how to fix this.
(Note: this is a MWE. The actual f and g I'm actually using are much more complicated than the Lorentzians defined in this post.)

The error you have is with the sympy line, as you're trying to plot the symbolic terms,
plt.plot(x,fog1,lw=2,label='analytic')
if you use the converted my_fog against xlist
plt.plot(xlist,my_fog*dx,lw=2,label='sympy')
it looks like a Lorentzian distribution,

Related

Python fmin using lambda expression

I have the following function for which I try to solve Vcr for given S,h,g:
Vcr/np.sqrt(g*h)=((2/3)*(1-S+ (Vcr**2)/(2*g*h)))**(3/2)
I do as follows:
from scipy.optimize import fsolve
import numpy as np
S = 0.06
h = 15.14
g = 9.8
def eqn(Vcr,g,h,S):
return (Vcr/np.sqrt(g*h)-((2/3)*(1-S+ (Vcr**2)/(2*g*h)))**(3/2))
ans = fsolve(lambda Vcr,g,h,S: eqn(Vcr,g,h,S), x0=5, args=(S,h,g))
print(eqn(ans,g,h,S))
The answer prints 4.9109. This answer is NOT correct. I checked this in Matlab:
fun = #(Vcr) Vcr./sqrt(g*h)-((2/3)*(1-S+ (Vcr.^2)./(2*g*h))).^(3/2);
sol = fzero(fun, 5); % solution critical speed;
# sol = 8.5970
The solution is then substituted in the Python equation and gives me: print(eqn(8.5970,g,h,S))=0
So indeed it should be 8.5970.
How can I solve this in Python with an expression close to the given matlab expression (with anonymous function)? If it is possible I don't want to define a function as def():
The extra arguments to the function must be passed in the order the function expects, you reversed them (args=(S,h,g) while your function declares them in the opposite order: lambda Vcr,g,h,S:).
Putting them in the right order gives you the expected solution:
from scipy.optimize import fsolve
import numpy as np
S = 0.06
h = 15.14
g = 9.8
def eqn(Vcr,g,h,S):
return (Vcr/np.sqrt(g*h)-((2/3)*(1-S+ (Vcr**2)/(2*g*h)))**(3/2))
ans = fsolve(lambda Vcr,g,h,S: eqn(Vcr,g,h,S), x0=5, args=(g, h, S))
print(ans, eqn(ans,g,h,S))
# [8.5970162] [1.11022302e-16]

Evaluate numerically an equation with sympy

I want to ask something that provably is extremly easy but I didn't find how to do it... The point is that I want to define some function in python in a symbolic way using sympy in order to make its derivative and then use this expresion numerically.
Here an example is showed:
import numpy as np
from sympy import *
z = Symbol('z')
function = z*exp(z**2)
deriv = diff(function, z)
x = np.arange(1, 3, 0.1) #interval of points
#How can I evaluate numerically this array "x" with the function deriv???
Do you know how to do it? Thanks!
You can use lambdify with the numpy backend:
import numpy as np
from sympy import *
z = Symbol('z')
function = z*exp(z**2)
deriv = diff(function, z)
x = np.arange(1, 3, 0.1) #interval of points
d = lambdify(z, deriv, "numpy")
d(x)
# array([ 8.15484549e+00, 1.14689175e+01, 1.63762998e+01,
# 2.37373255e+01, 3.49286892e+01, 5.21825471e+01,
# 7.91672020e+01, 1.21994639e+02, 1.90992239e+02,
# 3.03860954e+02, 4.91383350e+02, 8.07886132e+02,
# 1.35069268e+03, 2.29681687e+03, 3.97320108e+03,
# 6.99317313e+03, 1.25255647e+04, 2.28335915e+04,
# 4.23706166e+04, 8.00431723e+04])

Plotting defined function

I've defined a function which I would now like to plot:
import numpy as np
from math import pi, sqrt
import matplotlib.pyplot as plt
def f(x: float) -> float:
return pi * x * sqrt(x**2 + 400) + pi * x**2 - 1200
plt.plot(f(x))
plt.show()
When running this code, I get "NameError: name 'x' is not defined".
It is often usefull to use numpy in conjunction with matplotlib. When you then define a function, you may write it such that it takes single floats as well as numpy arrays as input.
import numpy as np
import matplotlib.pyplot as plt
def f(x):
return np.pi * x * np.sqrt(x**2 + 400) + np.pi * x**2 - 1200
x = np.array([1,2,3,4])
plt.plot(x, f(x))
plt.show()
Of course you could now also evaluate the function for a single float
print( f(9.2) )
or use it for each element of a list or array
y = [f(i) for i in x]
plt.plot(x,y)
But once you know about the fact that mathematical operations can be applied to numpy arrays easily, you probably don't want to opt for the latter anymore.

Finding the derivative of a plot given two axis - python

I have a list of the x-axis and another list of the y-axis values and currently I am finidng the derivative of the gradient as such:
from pylab import polyfit
x = [0,2,3,4]
y = [23,4,34,67]
(m,__) = polyfit(x,y,1)
print m
If I don't want to rely on the pylab/scipy polyfit, how else could I get the deriative?
matplotlib.pylab includes numpy for you, so just use the function numpy.polyfit directly:
import numpy as np
x = [0,2,3,4]
y = [23,4,34,67]
m, __ = np.polyfit(x, y, 1)
print m

How to define a one variable function from another multivariable function

I am trying to define a one variable g function from a multivariable function G:
def dG(thetaf,psi,gamma) :
return 0.35*(cos(psi))**2*(2*sin(3*thetaf/2+2*gamma)+(1+4*sin(gamma)**2)*sin(thetaf/2)-sin(3*thetaf/2))+sin(psi)**2*sin(thetaf/2)
g = lambda thetaf: dG(thetaf,psi,gamma)
unfortunately this is not working and the error i receive is that :
only length-1 arrays can be converted to Python scalars
You have to define some default values. If you do this by using keyword arguments, you don't even need to define a separate function.
from numpy import sin, cos, arange
def dG(thetaf,psi=0.5,gamma=1) :
return 0.35*(cos(psi))**2*(2*sin(3*thetaf/2+2*gamma)+(1+4*sin(gamma)**2)*sin(thetaf/2)-sin(3*thetaf/2))+sin(psi)**2*sin(thetaf/2)
thetaf = arange(10)
print dG(thetaf)
>>> [ 0.4902 0.1475 0.5077 1.6392 1.757 0.4624 -0.472 -0.2416 -0.2771 -1.3398]
You actually can define a separate function, but using keyword defaults is the cleaner alternative.
g = lambda tf: dG(tf, 0.5, 1)
g(thetaf)
array([ 0.4902, 0.1475, 0.5077, 1.6392, 1.757 , 0.4624, -0.472 ,
-0.2416, -0.2771, -1.3398])
Next time, please include the script in your original question in a nice format. It makes helping go faster.
I think it is just a simple mistake. You get theta and phi out of gamma and psi respectively, but then you never use them. Did you mean to use those as your parameters in g? If so, then it should look something like this
from numpy import sin, cos, arange, linspace, pi, zeros
import scipy.optimize as opt
def dG(thetaf, psi, gamma):
return 0.35*(cos(psi))**2*(2*sin(3*thetaf/2+2*gamma)+(1+4*sin(gamma)**2)*sin(thetaf/2)-sin(3*thetaf/2))+sin(psi)**2*sin(thetaf/2)
nt = 100
np = 100
gamma = linspace(0, pi/2, nt)
psi = linspace(0, pi/2, np)
x = zeros((nt, np))
for i, theta in enumerate(gamma):
for j, phi in enumerate(psi):
print('i = %d, j = %d') %(i, j)
g = lambda thetaf: dG(thetaf,phi,theta)
x[i,j] = opt.brenth(g,-pi/2,pi/2)

Categories