How to define a one variable function from another multivariable function - python

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)

Related

Solving function containing gamma in Python

I'm quite new to programming with python.
I was wondering, if there is a smart way to solve a function, which includes a gamma function with a certain shape and scale.
I already created a function G(x), which is the cdf of a gamma function up to a variable x. Now I want to solve another function including G(x). It should look like: 0=x+2*G(x)-b. Where b is a constant.
My code looks like that:
b= 10
def G(x):
return gamma.cdf(x,a=4,scale=25)
f = solve(x+2*G(x)-b,x,dict=True)
How is it possible to get a real value for G(x) in my solve function?
Thanks in advance!
To get roots from a function there are several tools in the scipy module.
Here is a solution with the method fsolve()
from scipy.stats import gamma
from scipy.optimize import fsolve
def G(x):
return gamma.cdf(x,a=4,scale=25)
# we define the function to solve
def f(x,b):
return x+2*G(x)-b
b = 10
init = 0. # The starting estimate for the roots of f(x) = 0.
roots = fsolve(f,init,args=(b))
print roots
Gives output :
[9.99844838]
Given that G(10) is close to zero this solution seems likely
Sorry, I didn't take into account your dict=True option but I guess you are able to put the result in whatever structure you want without my help.
rom sympy import *
# from scipy.stats import gamma
# from sympy.stats import Arcsin, density, cdf
x, y, z, t, gamma, cdf = symbols('x y z t gamma cdf')
#sol = solve([x - 3, y - 1], dict=True)
from sympy.stats import Cauchy, density
from sympy import Symbol
x0 = Symbol("x0")
gamma = Symbol("gamma", positive=True)
z = Symbol("z")
X = Cauchy("x", x0, gamma)
density(X)(z)
print(density(X)(z))
sol = solve([x+2*density(X)(z)-10, y ], dict=True)
print(sol)
Or:
from scipy.stats import gamma
from sympy import solve, Poly, Eq, Function, exp
from sympy.abc import x, y, z, a, b
def G(x):
return gamma.cdf(x,a=4,scale=25)
b= 10
f = solve(x+2*G(x)-b,x,dict=True)
stats cdf gamma solve sympy

Python - Using a Kronecker Delta with ODEINT

I'm trying to plot the output from an ODE using a Kronecker delta function which should only become 'active' at a specific time = t1.
This should give a sawtooth like response where the initial value decays down exponentially until t=t1 where it rises again instantly before decaying down once again.
However, when I plot this it looks like the solver is seeing the Kronecker delta function as zero for all time t. Is there anyway to do this in Python?
from scipy import KroneckerDelta
import scipy.integrate as sp
import matplotlib.pyplot as plt
import numpy as np
def dy_dt(y,t):
dy_dt = 500*KroneckerDelta(t,t1) - 2y
return dy_dt
t1 = 4
y0 = 500
t = np.arrange(0,10,0.1)
y = sp.odeint(dy_dt,y0,t)
plt.plot(t,y)
In the case of a simple Kronecker delta using time, you can run the ode in pieces like so:
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import numpy as np
def dy_dt(y,t):
return -2*y
t_delta = 4
tend = 10
y0 = [500]
t1 = np.linspace(0,t_delta,50)
y1 = odeint(dy_dt,y0,t1)
y0 = y1[-1] + 500 # execute Kronecker delta
t2 = np.linspace(t_delta,tend,50)
y2 = odeint(dy_dt,y0,t2)
t = np.append(t1, t2)
y = np.append(y1, y2)
plt.plot(t,y)
Another option for complicated situations is to the events functionality of solve_ivp.
I think the problem could be internal rounding errors, because 0.1 cannot be represented exactly as a python float. I would try
import math
def dy_dt(y,t):
if math.isclose(t, t1):
return 500 - 2*y
else:
return -2y
Also the documentation of odeint suggests using the args parameter instead of global variables to give your derivative function access to additional arguments and replacing np.arange by np.linspace:
import scipy.integrate as sp
import matplotlib.pyplot as plt
import numpy as np
import math
def dy_dt(y, t, t1):
if math.isclose(t, t1):
return 500 - 2*y
else:
return -2*y
t1 = 4
y0 = 500
t = np.linspace(0, 10, num=101)
y = sp.odeint(dy_dt, y0, t, args=(t1,))
plt.plot(t, y)
I did not test the code so tell me if there is anything wrong with it.
EDIT:
When testing my code I took a look at the t values for which dy_dt is evaluated. I noticed that odeint does not only use the t values that where specified, but alters them slightly:
...
3.6636447422787928
3.743098503914526
3.822552265550259
3.902006027185992
3.991829287543431
4.08165254790087
4.171475808258308
...
Now using my method, we get
math.isclose(3.991829287543431, 4) # False
because the default tolerance is set to a relative error of at most 10^(-9), so the odeint function "misses" the bump of the derivative at 4. Luckily, we can fix that by specifying a higher error threshold:
def dy_dt(y, t, t1):
if math.isclose(t, t1, abs_tol=0.01):
return 500 - 2*y
else:
return -2*y
Now dy_dt is very high for all values between 3.99 and 4.01. It is possible to make this range smaller if the num argument of linspace is increased.
TL;DR
Your problem is not a problem of python but a problem of numerically solving an differential equation: You need to alter your derivative for an interval of sufficient length, otherwise the solver will likely miss the interesting spot. A kronecker delta does not work with numeric approaches to solving ODEs.

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])

How to put an integral in a function in python/matplotlib

So pretty much, I am aiming to achieve a function f(x)
My problem is that my function has an integral in it, and I only know how to construct definite integrals, so my question is how does one create an indefinite integral in a function (or there may be some other method I am currently unaware of)
My function is defined as :
(G is gravitational constant, although you can leave G out of your answer for simplicity, I'll add it in my code)
Here is the starting point, but I don't know how to do the integral portion
import numpy as np
def f(x):
rho = 5*(1/(1+((x**2)/(3**2))))
function_result = rho * 4 * np.pi * x**2
return function_result
Please let me know if I need to elaborate on something.
EDIT-----------------------------------------------------
I made some major progress, but I still have one little error.
Pretty much, I did this:
from sympy import *
x = Symbol('x')
rho = p0()*(1/(1+((x**2)/(rc()**2))))* 4 * np.pi * x**2
fooply = integrate(rho,x)
def f(rx):
function_result = fooply.subs({x:rx})
return function_result
Which works fine when I plug in one number for f; however, when I plug in an array (as I need to later), I get the error:
raise SympifyError(a)
sympy.core.sympify.SympifyError: SympifyError: [3, 3, 3, 3, 3]
(Here, I did print(f([3,3,3,3,3]))). Usually, the function returns an array of values. So if I did f([3,2]) it should return [f(3),f(2)]. Yet, for some reason, it doesn't for my function....
Thanks in advance
how about:
from sympy import *
x, p0, rc = symbols('x p0 rc', real=True, positive=True)
rho = p0*(1/(1+((x**2)/(rc))))* 4 * pi * x**2
fooply = integrate(rho,x)/x
rho, fooply
(4*pi*p0*x**2/(1 + x**2/rc),
4*pi*p0*rc*(-sqrt(rc)*atan(x/sqrt(rc)) + x)/x)
fooply = fooply.subs({p0: 2.0, rc: 3.0})
np_fooply = lambdify(x, fooply, 'numpy')
print(np_fooply(np.array([3,3,3,3,3])))
[ 29.81247362 29.81247362 29.81247362 29.81247362 29.81247362]
To plug in an array to a SymPy expression, you need to use lambdify to convert it to a NumPy function (f = lambdify(x, fooply)). Just using def and subs as you have done will not work.
Also, in general, when using symbolic computations, it's better to use sympy.pi instead of np.pi, as the former is symbolic and can simplify. It will automatically be converted to the numeric pi by lambdify.

"'numpy.ndarray' object is not callable"

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?

Categories