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]
Related
I would like to make an iteration in order to get a function verifying an integral equation. The integral operator is hidden in the function lambdaop. However, I just cannot iterate on the process getting an error
File "blablabla/.spyder-py3/temp.py", line 11, in integrand
return -0.5*f(x)*scipy.special.expi(-abs(x-tau))
TypeError: can't multiply sequence by non-int of type 'float'
that I do not understand. I have done here for only two functions by my ultimate goal would be to make n iteration. I guess the error comes from the way of defining the function that is not suitable (maybe not use "lambda definitions" ... ) but I do not want to create a vector of size n in place of the function since I want to integrate it after. Anyone has an idea how to fix this problem ?
import numpy as np
import matplotlib.pyplot as plt
import math
import scipy.integrate
import scipy.special
def initial(x):
return x + 2/3
def integrand(f,x,tau):
return -0.5*f(x)*scipy.special.expi(-abs(x-tau))
def lambdaop(f,x,tau):
def step(x,tau):
return integrand(f,x,tau)
g = lambda tau: scipy.integrate.quad(step,0,np.inf,args=(tau,))
return g
g = lambdaop(initial,1,2)
h = lambdaop(g,1,2)
print(h(5))
x = np.linspace(0,3,101)
y = np.linspace(0,3,101)
for i in np.arange(101):
y[i] = h(x[i])[0]
plt.plot(x,y)
plt.show()
I have not seen any other topic like mine but in case it is a duplicate, please excuse me.
Add some print statements in your integrand function.
For example,
def integrand(f,x,tau):
print('-------')
print('args:', f, x, tau)
v = f(x)
print(f'f({x})={v}')
s = scipy.special.expi(-abs(x-tau))
print(f's={s}')
result = -0.5*v*s
print('=====')
return result
and you'll see that:
f(1.0)=(inf, inf)
s=-0.0037793524098489063
The (inf, inf) is where the error message is coming from.
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,
I want to solve an optimization problem as proposed in this thread. Now, I not only want to solve for the x[1]...x[n], but also for the variable y. It looks like something is wrong with the indexing.
from sympy import Sum, symbols, Indexed, lambdify
from scipy.optimize import minimize
import numpy as np
def _eqn(y, variables, periods, sign=-1.0):
x, i = symbols("x i")
n = periods-1
s = Sum(Indexed('x', i)/(1+0.06)**i, (i, 1, n))
f = lambdify(x, s, modules=['sympy'])
return float(sign*(y + f(variables)))
z = 3
results = minimize(lambda xy: _eqn(xy[0], xy[1:z], z),np.zeros(z))
print(results.x)
From the error message it seems there is an issue in your indexing. The summation runs from 1 to n but by default indexing of list type objects in Python goes from 0 to n-1. If I change this in your code it seems to work. Check it out.
import sympy as sp
from scipy.optimize import minimize
import numpy as np
sp.init_printing()
def _eqn(y, variables, periods, sign=-1.0):
x, i = sp.symbols("x i")
n = periods-1
s = sp.Sum(sp.Indexed('x', i)/(1+0.06)**(i+1), (i, 0, n-1)).doit()
f = sp.lambdify(x, s, modules=['sympy'])
return float(sign*(y + f(variables)))
z = 3
results = minimize(lambda xy: _eqn(xy[0], xy[1:z], z),np.zeros(z))
print(results.x)
If all you need is variable number of arguments for minimization then does the following code work for you?
from sympy import var
from scipy.optimize import minimize
import numpy as np
def _eqn(y, variables, periods, sign=-1.0):
f = 0
for i,x in enumerate(variables):
f += x/(1+0.06)**(i+1)
return float(sign*(y + f))
z = 3
results = minimize(lambda xy: _eqn(xy[0], xy[1:z], z),np.zeros(z))
print(results.x)
I've got a problem with my code. I want to get a referential solution for a model that shall describe the populations of bears and trouts and their interconnection.
I can't find what I did wrong, but python calls three lines with problems and end with the error 'numpy.ndarray' object is not callable'. What am I doing wrong?
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import interp1d
def referenz_loesung(f, ref_loeser, x0, t0, T):
print "Berechne Referenzloesung..."
h_ref = 0.0001
#it mentions the following line as problematic
t_punkte, x_punkte = ref_loeser(f, x0, t0, T, h_ref) #it mentions this line as problematic
print "Erstelle Funktionen aus Referenzloesungen mit Hilfe von Splines."
a = interp1d(t_punkte, x_punkte[: , 0])
b = interp1d(t_punkte, x_punkte[: , 1])
return a, b
if __name__ == "__main__":
def f(x, t): # Funktion aus vorherigen Uebungen der DGL: x'(t) = f(x(t), t)
y = np.zeros(2)
y[0] = -2*x[0] + 10 * x[1]
y[1] = -x[0]
return y
x0 = np.array([1., 0.])
t0 = 0
T = 10
h = 0.5
from unsersolver import integriere
#it mentions the following line as problematic
t_punkte, x_werte = integriere (f, x0, t0, T, h)
from implEuler import integriere as ref_loeser
#it mentions the following line as problematic
x1_ref, x2_ref = referenz_loesung(f,ref_loeser, x0, t0, T)
ref_punkte = np.linspace(t0, T, 1000)
from woche1_1_m import auswerten_nx1
ref_werte1 = auswerten_nx1(x1_ref, ref_punkte)
ref_werte2 = auswerten_nx1(x2_ref, ref_punkte)
The things I import are from other files from earlier weeks that all work actually work properly.
Any idea what I could do? I'm at the very start of learning python, so I don't really have a clue.
Thanks!
It would be more helpful if you could post the code for integriere() or ref_loeser().
With the information I have let me ask you to try back-tracing to the root of the problem:
Start of the problem is t_punkte, x_werte = integriere(f, x0, t0, T, h) which you say gives a numpy error, and since the only numpy parameter you're passing to this is x0, i'd suggest checking the usage of x0 in your integriere() code.
Next, I'd suggest not passing a function as a parameter, I don't think that is a standard convention. You could define a def ref_loeser(parameters..) outside the refrenz_loesung() function call, and then call it like you did.
And since referenz_loesung() calls ref_loeser() which is the same as integriere() I highly recommend you to check the code in this function.
Good luck!
x_lsg = berechne_nullstelle(x_werte(n-1)) <--- error
x_lsg = berechne_nullstelle(x_werte[n-1]) works?
x_werte is an ND-array, you need to access the n-1 element, use x_werte[n-1] instead.
The ( ) is for function calls, so python interpreter assumed you were calling an numpy.ndarry and hence threw that error
You would get this error if e.g. you put x0() in your code. It's impossible for us to tell what the real error is without the source of the other modules.
My best guess: is it possible that you got the parameters to integriere in the wrong order? If so, perhaps that function tries to call the parameter, expecting it to be a function, but because you've put a numpy array in that parameter it gets "called" instead?
So, this is the code for the implEuler file. The 'unsersolver' should be correct as it was given to me by the teacher...
import matplotlib.pyplot as plt
import numpy as np
from newton import berechne_nullstelle
def integriere(f, x0, t0, T, h):
d = len(x0)
t_punkte = np.arange(t0, T, h)
N = len(t_punkte)
x_werte = np.zeros ((N, d))
x_werte[0] = x0
for n in range(1, N):
def f_implEuler(x):
x_werte^(n-1) + h * f(x_werte, t_punkte^(n)) - x_werte
x_lsg = berechne_nullstelle(x_werte(n-1))
x_werte[n] = x_lsg
print integriere
Does that help in any way?
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)