I'm trying to plot the graphs of the following equation in Python.
Solution of the radial differential equation of a 2d quantum ring
The beta parameter is
This was my attempt
import numpy as np
from scipy.special import gamma, genlaguerre
import matplotlib.pyplot as plt
from scipy import exp, sqrt
m = 0.067*9.1*10E-31
R = 5E-9
r = np.linspace(0, 20E-9)
#Definição do parâmetro beta
def beta(gama):
flux = np.linspace(0,1.0)
beta = sqrt((m-flux)**2+(gama**4)/4)
return beta
def Rn(n,gama):
raiz = sqrt((gamma(n+1)/((2**beta(gama)) * gamma(n+beta(gama)+1))))
eval_g = genlaguerre((n,beta(gama)),((gama * r/R)**2/2))
exp_g = exp(-((gama * r/R)**2)/4)
return (1/R) * raiz * (gama * r/R)**beta(gama) * exp_g * eval_g
sol1 = Rn(0,1.5)
sol2 = Rn(0,2.0)
sol3 = Rn(0,2.5)
sol4 = Rn(0,3.0)
fig, ax = plt.subplots()
ax.plot(r/R, sol1, color = 'red', label = '$\gamma$ = 1.5')
ax.plot(r/R, sol2, color = 'green', label = '$\gamma$ = 2.0')
ax.plot(r/R, sol3, color = 'blue', label = '$\gamma$ = 2.5')
ax.plot(r/R, sol4, color = 'black', label = '$\gamma$ = 3.0')
ax.legend()
ax.set_xlabel('R/r')
ax.set_ylabel('$R_0(r)$')
erro using genlaguerre
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Here the link to the article
I'm not into this topic, but afaics there are at least the following mistakes (I assume setting silently n=0 was on purpose):
In opposite to the posted image of the beta function, you added a division by 4 into your function definition.
Correct version:
def beta(gama):
return np.sqrt((m-flux)**2+(gama**4))
That's no reason for distributed instead of fixed peaks but I tell what I see here.
Product instead of division because of lacking parantheses in definition of amplitude function:
Correct version:
def amplitude(gama):
return np.sqrt(gamma(1)/((2**beta(gama)*gamma(beta(gama)+1))))
In the definition of Rn function there's the introducing 1/R missing.
However, all this unfortunately does not change the peaks to happen at equal x positions...
Sorry! The radial wave function of the article is wrong! I made the calculations and found the correct answer. The following code is correct
import numpy as np
from scipy.special import genlaguerre, gamma
import numpy as np
import matplotlib.pyplot as plt
m = 0 # magnetic number
flux = 0 # Phi in eqn 8
R = 5 # nm
r = np.linspace(0, 6 * R)
rho = r / R
def R0(n, gama):
beta = np.sqrt((m - flux)**2 + gama**4/4)
return (gama/R*
np.sqrt(gamma(n+ 1) / ( 2**beta * gamma(n + beta + 1))) *
(gama * rho)**beta *
np.exp(-gama**2 * rho**2 / 4) *
genlaguerre(n, beta)(gama**2 * rho**2 / 2))
sol1 = R0(0, 1.5)
sol2 = R0(0, 2.0)
sol3 = R0(0, 2.5)
sol4 = R0(0, 3.0)
plt.plot(rho, sol1, rho, sol2, rho, sol3, rho, sol4)
plt.legend(['$\gamma = 1.5$', '$\gamma = 2$', '$\gamma = 2.5$', '$\gamma = 3$'])
plt.ylabel('$R_{0}(r)$')
plt.xlabel('$r/R$')
plt.show()
Related
I have two distributions and I would like to know the properties of the multiplication of these distributions.
For example, if I had the distribution of properties velocity and time, I want the characteristics of the probability distribution of distance.
With reasonable estimates for the inegration bounds, I can calculate the probability density function from the product of two random variables:
from scipy import stats
import numpy as np
import matplotlib.pyplot as plt
T, dt = np.linspace(0,20,201, retstep = True)
T = T[1:] # avoid divide by zero below
V = np.linspace(0,20,201)
D = np.linspace(0,120,201)
P_t = stats.gamma(4,1) # probability distribution for time
P_v = stats.norm(8,2) # probability distribution for speed
# complete integration
P_d = [np.trapz(P_t.pdf(T) * P_v.pdf(d / T) / T, dx = dt) for d in D]
plt.plot(T, P_t.pdf(T), label = 'time')
plt.plot(V, P_v.pdf(V), label = 'velocity')
plt.plot(D, P_d, label = 'distance')
plt.legend()
plt.ylabel('Probability density')
I would like to be able to compute things like P_d.sf(d), P_d.cdf(d), etc., for arbitrary values of d. Can I create a new distribution (perhaps using scipy.stats.rv_continuous) to characterize distance?
The solution took a bit of time to understand the rv_continuous. Cobbling together knowledge from a bunch of examples (I should have documented them--sorry) I think I got a working solution.
The only issue is that the domain needs to be known in advance, but I can work with that. If someone has ideas for how to fix that, please let me know.
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import scipy as sp
interp1d = sp.interpolate.interp1d
trapz = sp.integrate.trapz
# Time domain vector - needed in class
dt = 0.01
t_max = 10
T = np.arange(dt, t_max + dt, dt)
# Distance domain vector - needed in class
dd = 0.01
d_max = 30
D = np.arange(0, d_max + dd, dd)
class MultiplicativeModel(stats.rv_continuous):
def __init__(self, Tmodel, Vmodel, *args, **kwargs):
super().__init__(*args, **kwargs)
self.Tmodel = Tmodel # The time-domain probability function
self.Vmodel = Vmodel # The velocity-domain probability function
# Create vectors for interpolation of distributions
self.pdf_vec = np.array([trapz(self.Tmodel.pdf(T) * \
self.Vmodel.pdf(_ / T) / T, dx = dt) \
for _ in D])
self.cdf_vec = np.cumsum(self.pdf_vec) * dd
self.sf_vec = 1 - self.cdf_vec
# define key functions for rv_continuous class
self._pdf = interp1d(D, self.pdf_vec, assume_sorted=True)
self._sf = interp1d(D, self.sf_vec, assume_sorted=True)
self._cdf = interp1d(D, self.cdf_vec, assume_sorted=True)
# Extraolation option below is necessary because sometimes rvs picks
# a number really really close to 1 or 0 and this spits out an error if it
# is outside of the interpolation range.
self._ppf = interp1d(self.cdf_vec, D, assume_sorted=True,
fill_value = 'extrapolate')
# Moments
self._munp = lambda n, *args: np.trapz(self.pdf_vec * D ** n, dx=dd)
With the above defined, we get results like:
dv = 0.01
v_max = 10
V = np.arange(0, v_max + dv, dv)
model = MultiplicativeModel(stats.norm(3, 1),
stats.uniform(loc=2, scale = 2))
# test moments and stats functions
print(f'median: {model.median()}')
# median: 8.700970199181763
print(f'moments: {model.stats(moments = "mvsk")}')
#moments: (array(9.00872026), array(12.2315612), array(0.44131568), array(0.16819043))
plt.figure(figsize=(6,4))
plt.plot(T, model.Tmodel.pdf(T), label = 'Time PDF')
plt.plot(V, model.Vmodel.pdf(V), label = 'Velocity PDF')
plt.plot(D, model.pdf(D), label = 'Distance PDF')
plt.plot(D, model.cdf(D), label = 'Distance CDF')
plt.plot(D, model.sf(D), label = 'Distance SF')
x = model.rvs(size=10**5)
plt.hist(x, bins = 50, density = True, alpha = 0.5, label = 'Sampled distribution')
plt.legend()
plt.xlim([0,30])
I'm having some computational problems with the following code:
import numpy as np
from numpy import arange
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from scipy.integrate import quad
import matplotlib as mpl
mpl.rcParams['agg.path.chunksize'] = 10000
# parameters
Ms = 100 #GeV Singlet Mass
Me = 0.511e-3 #Gev Electron Mass
Mp = 1.22e19 #GeV Planck Mass
gs = 106.75 # Entropy dof
H0 = 2.133*(0.7)*1e-42 # GeV Hubble parameter (unused)
gx = 2 # WIMP's dof
g = 100 # total dof
sigmav=[1e-25,1e-11,1e-12] # cross section's order of magnitude
xi=1e-2
xe=1e2
npts=int(1e5)
x = np.linspace(xi, xe, npts)
def fMB(p,x,m):
return np.exp(-x*np.sqrt(1+p*p/(m*m)))*p*p
def neq(x,m):
return (gx/(2*np.pi*np.pi))*quad(fMB, 0, np.inf, args=(x,m))[0]
def neq_nr(x,m):
return 2*(m**2/(2*np.pi*x))**(3/2)*np.exp(-x)
def stot(x):
return (2*np.pi*np.pi/45)*gs*Ms*Ms*Ms/(x*x*x)
def Yeq(x,m):
return neq(x,m)/stot(x)
Yeq2=np.vectorize(Yeq)
def Yeq_nr(x):
return 0.145*(gx/gs)*(x)**(3/2)*np.exp(-x)
def Yeq_r(x):
return 0.278*(3*gx/4)/gs
def Ytot(x):
if np.any(x<=1):
return Yeq_r(x)
else:
return Yeq_nr(x)
def eqd(yl,x,Ms,σv):
'''
Ms [GeV] : Singlet Mass
σv: [1/GeV^2] : ⟨σv⟩
'''
H = 1.67*g**(1/2)*Ms**2/Mp
dyl = -neq(x,Ms)*σv*(yl**2-Yeq(x,Ms)**2)/(x**(-2)*H*x*Yeq(x,Ms)) #occorre ancora dividere per Yeq_nr(x) oppure Yeq(x)
return dyl
y0=1e-15
yl0 = odeint( eqd, y0, x,args=(Ms,sigmav[0]), full_output=True)
yl1 = odeint( eqd, y0, x,args=(Ms,sigmav[1]), full_output=True)
yl2 = odeint( eqd, y0, x,args=(Ms,sigmav[2]), full_output=True)
fig = plt.figure(figsize=(11,8))
plt.loglog(x,yl0[0], label = r'$\langle σ v\rangle = %s {\rm GeV}^{-2}$'%(sigmav[0]))
plt.loglog(x,yl1[0], label = r'$\langle σ v\rangle = %s {\rm GeV}^{-2}$'%(sigmav[1]))
plt.loglog(x,yl2[0], label = r'$\langle σ v\rangle = %s {\rm GeV}^{-2}$'%(sigmav[2]))
plt.loglog(x,Yeq_nr(x), '--', label = '$Y_{EQ}^{nr}$')
plt.loglog(x,Yeq2(x,Ms), '--', label = '$Y_{EQ}$')
plt.ylim(ymax=0.1,ymin=y0)
plt.xlim(xmax=xe,xmin=xi)
plt.xlabel('$x = m_χ/T$', size= 15)
plt.ylabel('$Y$', size= 15)
plt.title('$m_χ = %s$ GeV'%(Ms), size= 15)
plt.legend(loc='best',fontsize=12)
plt.grid(True)
plt.savefig('abundance.jpg',bbox_inches='tight', dpi=150)
In particular, as soon as I use little values of sigmav (ranging from 10^-12 to 10^-25) the solution is well displayed, but making use of bigger values (starting from 10^-11) I obtain problems and I guess is a order of magnitudes problem, but I don't know how to handle it!
Thanks to everyone!
Edit 1:
I'm uploading a plot making use of three different values of sigmav and as you may see the bigger one (1e-10) is showing (I guess) precision problems plot_1
I keep getting error messages such as invalid syntax, or something is not defined.
here I defined the dependencies
import math #Basic math library
import numpy as np #Numpy -> tools for working with arrays
import matplotlib.pyplot as plt #Matplotlib -> tools for plotting
here I defined the constants
#CONSTANTS
pi = math.pi
omega_n = 30
xi = 0.05
beta = 0.1
here I defined the functions
O = (1/((1-beta**2)**2 + (2*xi*beta)**2)) #Capital Omega defined above
omega_d = omega_n*np.sqrt(1-xi**2) #Damped natural frequency
A = (2*xi*beta*np.cos(omega_n*t)*math.e**(-xi* omega_n* t)
C = 2*omega_n*(xi**2)*beta*math.e**(-xi*omega_n*t)
D = (1-beta**2)*np.sin(omega_d*t)
E = -2*xi*beta*np.cos(omega_d*t)
tmax = 60 #(sec) The max time
delta_t = 0.001 #(sec) The timestep
nPoints = tmax/delta_t #Number of equally spaced data points
t = np.linspace(0,tmax, int(nPoints)) # Time vector
ut = O* (A + omega_d + C) #Transientresponse
us = O* (D + E) #Steady-state response
rt= ut + us
plotting
#Plotting
fig = plt.figure()
axes = fig.add_axes([0.1,0.1,2,1.5])
axes.plot(t,rt,label='Respond ratio of a damped system')
axes.set_xlim([0,tmax])
axes.set_xlabel('Time (sec)')
axes.set_ylabel('Respond ratio')
axes.set_title('Respond ratio-time history')
axes.grid()
axes.legend()
plt.show()
There are several errors here. First, you're missing a bracket in this line:
A = (2*xi*beta*np.cos(omega_n*t)*math.e**(-xi* omega_n* t))
Then you're using the variable t in the same line but you haven't defined t yet. You're defining t after this line. Similarly, you need to define tmax/delta_t before using them in nPoints
I am trying to solve numerically the following integral using NumPy and quad from scipy.integrate. The code is kinda working, but I get spurious notches in the resulting data:
Anybody has an idea why are they occurring and how to get the correct smooth result?
Here is the original code in Python:
#!/usr/bin/env python
import numpy as np
from scipy.integrate import quad
import matplotlib.pyplot as pl
numpts = 300
t_min = -4
t_max = 100
tt = np.linspace(t_min, t_max, numpts)
mean = 0. # ps
fwhm = .05 # ps
def gaussian(x, mean, fwhm):
return 1. / np.sqrt(np.pi) / fwhm * np.exp(-1. * (x - mean)**2 / fwhm**2)
def integrand(t_, t, mean, fwhm):
denum = np.sqrt(t - t_)
r = gaussian(t_, mean, fwhm) / denum
return r
def integrate(t, mean, fwhm, tmin):
return quad(integrand, tmin, t - 1e-9, args=(t, mean, fwhm))[0]
if __name__ == '__main__':
vec_int = np.vectorize(integrate)
y = vec_int(tt, mean, fwhm, tt.min())
fig = pl.figure()
ax = fig.add_subplot(111)
ax.plot(tt, y, 'bo-', mec='none')
ax.set_xlim(-5, 101)
pl.show()
My suspicion would be that an integrable singularity is messing up the inner workings of quad(pack). I'd then try (in this order): use weights="cauchy" in quad; add and subtract the singularity; look at ways of telling quadpack that the integral has a difficult point.
So I solved my problem by switching to the mpmath library and its own integration quad using the tanh-sinh method. I also had to split the integral so that the data is monotonous. The output looks like this:
I am not 100% sure why this works, but it may have to do with the numeric precision and the behaviour of the integration method.
Here's the working code:
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as pl
import mpmath as mp
numpts = 3000
t_min = -4
t_max = 100
tt = np.linspace(t_min, t_max, numpts)
mean = mp.mpf('0') # ps
fwhm = mp.mpf('.05') # ps
def gaussian(x, mean, fwhm):
return 1. / mp.sqrt(np.pi) / fwhm * mp.exp(-1. * (x - mean)**2 / fwhm**2)
def integrand(t_, t, mean, fwhm):
denum = np.sqrt(t - t_)
g = gaussian(t_, mean, fwhm)
r = g / denum
return r
def integrate(t, mean, fwhm, tmin):
t = mp.mpf(t)
tmin = mp.mpf(tmin)
# split the integral because it can only handle smooth functions
res = mp.quad(lambda t_: integrand(t_, t, mean, fwhm),
[tmin, mean],
method='tanh-sinh') + \
mp.quad(lambda t_: integrand(t_, t, mean, fwhm),
[mean, t],
method='tanh-sinh')
ans = res
return ans
if __name__ == '__main__':
mp.mp.dps = 15
mp.mp.pretty = True
vec_int = np.vectorize(integrate)
y = vec_int(tt, mean, fwhm, tt.min())
fig = pl.figure()
ax = fig.add_subplot(111)
# make sure we plot the real part
ax.plot(tt, map(mp.re, y), 'bo-', mec='none')
ax.set_xlim(-5, 101)
pl.show()
So far I have managed to find the particular solution to this equation for any given mass and drag coefficient. I have not however found a way to plot the solution or even evaluate the solution for a specific point. I really want to find a way to plot the solution.
from sympy import *
m = float(raw_input('Mass:\n> '))
g = 9.8
k = float(raw_input('Drag Coefficient:\n> '))
f = Function('f')
f1 = g * m
t = Symbol('t')
v = Function('v')
equation = dsolve(f1 - k * v(t) - m * Derivative(v(t)), 0)
C1 = Symbol('C1')
C1_ic = solve(equation.rhs.subs({t:0}),C1)[0]
equation = equation.subs({C1:C1_ic})
For completeness, you may also use Sympy's plot, which is probably more convenient if you want a "quick and dirty" plot.
plot(equation.rhs,(t,0,10))
Import these libraries (seaborn just makes the plots pretty).
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
Then tack this onto the end. This will plot time, t, against velocity, v(t).
# make a numpy-ready function from the sympy results
func = lambdify(t, equation.rhs,'numpy')
xvals = np.arange(0,10,.1)
yvals = func(xvals)
# make figure
fig, ax = plt.subplots(1,1,subplot_kw=dict(aspect='equal'))
ax.plot(xvals, yvals)
ax.set_xlabel('t')
ax.set_ylabel('v(t)')
plt.show()
I get a plot like this for a mass of 2 and a drag coefficient of 2.
If I've understood correctly, you want to represent the right hand side of your solution, here's one of the multiple ways to do it:
from sympy import *
import numpy as np
import matplotlib.pyplot as plt
m = float(raw_input('Mass:\n> '))
g = 9.8
k = float(raw_input('Drag Coefficient:\n> '))
f = Function('f')
f1 = g * m
t = Symbol('t')
v = Function('v')
equation = dsolve(f1 - k * v(t) - m * Derivative(v(t)), 0)
C1 = Symbol('C1')
C1_ic = solve(equation.rhs.subs({t: 0}), C1)[0]
equation = equation.subs({C1: C1_ic})
t1 = np.arange(0.0, 50.0, 0.1)
y1 = [equation.subs({t: tt}).rhs for tt in t1]
plt.figure(1)
plt.plot(t1, y1)
plt.show()