Implementing the metropolis-hasting algorithm - python

Over the past few weeks I have been trying to understand MCMC and the Metropolis-Hastings, but I have failed every time I tried to implement it.
So I am trying to use the metropolis-Hastings algorithm to get the Boltzmann distribution from the uniform distribution, but it is not working.
Here is a summary of what I am doing:
I draw a random number form the uniform distribution m.
I draw another random number form the uniform distribution n.
I set dU = n-m.
If dU < 0, I accept dU, set m = n , and repeat.
If dU > 0, I calculate w = exp(-b*dU), where b is 1/kT, and draw a random number form the uniform distribution r.
If w > r, I accept dU, set m = n, and repeat.
7 If w < r, I reject dU, set m = m, and repeat.
I am a beginner to this field and to python, so I am not sure if the code wrong or the algorithm is wrong ( probably both.)
My code is attached below. Thank you.
import random
%matplotlib inline
import numpy as np
import scipy
import matplotlib.pyplot as plt
from scipy import stats
k = 1.38064852 * 10**(-23)
t = 298
b = 1/(t*k) U = []
m = np.random.uniform(0, 1)
for j in range(100000):
n = np.random.uniform(0, 1)
du = n-m
if du<0:
U.append(du)
m = n
elif du > 0:
w = np.exp(-b*du)
r = np.random.uniform(0, 1)
if w > r:
U.append(du)
m = n
else:
U.append(du)
m = m

Your problem are twofold. One is you sample new energy ('n=random()') as dimensionless quantity, which contradicts everything else you're doing (your temperature is in Kelvin, kB is in J/K etc). And second, using values like 1023 and inverse are not good in physical simulations - you'd better be somewhere within 0...1 range and rescale later. Below I made code which works in electron-volts, sample new energy in eV as well, and produced something which resembles the truth.
import numpy as np
import matplotlib.pyplot as plt
kB = 1.0/11600. # eV/K
T = 300 # K
b = 1.0/(kB * T) # inverse temperature, eV^-1
np.random.seed(76543217) # for reproducibility
N = 100000
EE = np.empty(N+1) # energy
DE = np.empty(N+1) # delta energy
Ei = 1.0 # initial energy, 1eV
EE[0] = Ei
DE[0] = 0.0
for k in range(N):
E = np.random.random()/b # sample energy, in eV
dE = E - Ei
if dE < 0.0:
Ei = E
EE[k+1] = Ei
DE[k+1] = dE
elif dE > 0.0:
w = np.exp(-b*dE)
r = np.random.random()
if w > r:
Ei = E
EE[k+1] = Ei
DE[k+1] = dE
else:
EE[k+1] = Ei
DE[k+1] = 0.0
x = np.linspace(0, N+1, num=N+1)
print(EE[N-30:])
print(np.mean(EE[N-1000:]))
print(np.mean(EE[N-2000:]))
fig, ax = plt.subplots(1, 1)
ax.plot(x[N-1000:], EE[N-1000:], 'r-', lw=5, alpha=0.6, label='Energy')
ax.plot(x[N-1000:], DE[N-1000:], 'go', lw=5, alpha=0.6, label='Delta Energy')
plt.show()
printed are two last mean values for 1000 and 2000 samples, look thermalized to me
0.010188070423940562
0.010666101150488673
and graph for E/dE

Related

translated matlab code into python, but python is way slower

So I've been starting to use python recently, and i am working on a project of calculating wind exposure. I've managed my code in matlab and it runs very fast(can be done in 3 minutes), but after I translated my code into python, i am getting the same result but it takes 3hours to finish it's job. I really need a hand on checking what's causing such a huge difference...
So here's my python code. I can give out my matlab code if anyone need it.
from netCDF4 import Dataset, num2date
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
#import pylab as py
#input data
dem = Dataset('comparearea_fill.nc','r')
lon = np.array(dem.variables['lon'])
lat = np.array(dem.variables['lat'])
DEM = np.array(dem.variables['elevation'])
carea = Dataset('carea.nc','r')
u = np.array(carea.variables['u10'])
v = np.array(carea.variables['v10'])
mu = np.mean(u, axis=0)
mv = np.mean(v, axis=0)
x = np.linspace(1,21,21)
y = np.linspace(1,11,11)
newu = interpolate.interp2d(x, y, mu, kind='cubic')
newv = interpolate.interp2d(x, y, mv, kind='cubic')
spu = newu(lon,lat)
spv = newv(lon,lat)
A = np.zeros((4951,9451))
B = np.zeros((4951,9451))
for i in range(100,4850):
for j in range(100,9350):
for n in range(20):
A[i,j] = (DEM[i,j]-np.max(DEM[np.floor(n*spv[i,j]).astype(int),j-np.floor(n*spu[i,j]).astype(int)]))/DEM[i,j]
if A[i,j] < 0:
A[i,j] = 0
B[i,j] = (DEM[i,j]-np.max(DEM[i-np.ceil(n*spv[i,j]).astype(int),j-np.ceil(n*spu[i,j]).astype(int)]))/DEM[i,j]
if B[i,j] < 0:
B[i,j] = 0
C = A+B
plt.contourf(lon,lat,C); plt.colorbar()
here the mu and mv are the monthly average of the u and v wind, while the spu and spv are the spline interpulated u and v wind to fit the resolution of my dem data set.

Odeint, shooting method and boundary conditions in Python

I have been working with odeint and boundary conditions. Bassically what I am trying to do is to solve the differential equations given in this figure 1
where in my code R=R, ph = Phi, al = alpha, a = a, m = m, l = l and om = omega. The initial conditions that I am trying to implement are R(0)=O(r^l); Phi(0)=O(r^{l-1}) if l/=0 and Phi(0)=O(r) if l=0; a(0) = 1 and a(inf)=1/alpha(inf) (additionally I need that R(inf)=0). I tried to applied the shooting method in order to find initial conditions for alpha that best matches with my boundary conditions. I also need to find the omega that best matches the boundary conditions for R at infinity. The code that I wrote is the following:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import time
start = time.clock()
def system_DE(IC,p,r):
l = p[0]
m = p[1]
om = p[2]
R = IC[0]
ph = IC[1]
a = IC[2]
al = IC[3]
dR_dr = ph
da_dr = a*((2*l+1)*r/2*(om**2*a**2*R**2/al**2+ph**2+l*(l+1)*a**2*R**2/r**2+m**2*a**2*R**2)-(a**2-1)/(2*r))
dal_dr = al*(da_dr/a-l*(l+1)*(2*l+1)*a**2*R**2/r-(2*l+1)*m**2*a**2*r*R**2+(a**2-1)/r)
dph_dr = -2*ph/r-dal_dr*ph/al+da_dr*ph/a-om**2*a**2*R/al**2+l*(l+1)*a**2*R/r**2+m**2*a**2*R
return [dR_dr,da_dr,dal_dr,dph_dr]
def init(u,p,r):
if p==0:
return np.array([1,r,1,u])
else:
return np.array([r**l,l*r**(l-1),1,u])
l = 0
m = 1
ep = 0.3
n_om = 10
omega = np.linspace(m-ep,m+ep,n_om)
r = np.linspace(0.0001, 100, 1000)
niter = 100
u = 0
tol = 0.1
ustep = 0.01
p = np.zeros(3)
p[0] = l
p[1] = m
for j in range(len(omega)):
p[2] = omega[j]
for i in range(niter):
u += ustep
Y = odeint(system_DE(init(u,p[0],r[0]),p,r), init(u,p[0],r[0]), r)
print Y[-1,2]
print Y[-1,3]
if abs(Y[len(Y)-1,2]-1/Y[len(Y)-1,3]) < tol:
print(i,'times iterations')
print("a'(inf)) = ", Y[len(Y)-1,2])
print('y"(0) =',u)
break
if abs(Y[len(Y)-1,0]) < tol:
print(j,'times iterations in omega')
print("R'(inf)) = ", Y[len(Y)-1,0])
break
However, when I run it I am obtaining: error: The function and its Jacobian must be callable functions.
Could some one help me to understand what my mistake is?
Regards,
Luis Padilla.
To start with, the first argument to odeint is your derivative function system_DE. Just pass its name, no parentheses or arguments. Odeint with call it internally and supply arguments.
I fixed my code and now it is giving me some results. However, when I run it I am obtaining some warnings that I don't know how to solve it. Could some one help me to solve it? Basically my code is this:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import time
def system_DE(IC,r,l,m,om):
R = IC[0]
ph = IC[1]
a = IC[2]
al = IC[3]
dR_dr = ph
da_dr = a*((2*l+1)*r/2*(om**2*a**2*R**2/al**2+ph**2+l*(l+1)*a**2*R**2/r**2+m**2*a**2*R**2)-(a**2-1)/(2*r))
dal_dr = al*(da_dr/a-l*(l+1)*(2*l+1)*a**2*R**2/r-(2*l+1)*m**2*a**2*r*R**2+(a**2-1)/r)
dph_dr = -2*ph/r-dal_dr*ph/al+da_dr*ph/a-om**2*a**2*R/al**2+l*(l+1)*a**2*R/r**2+m**2*a**2*R
return [dR_dr,dph_dr,da_dr,dal_dr]
def init(u,p,r):
if p==0:
return np.array([1.,r,1.,u])
else:
return np.array([r**p,l*r**(p-1),1,u])
l = 0.
m = 1.
ep = 0.2
n_om = 30
omega = np.linspace(m-ep,m+ep,n_om)
r = np.linspace(0.001, 100, 1000)
niter = 1000
tol = 0.01
ustep = 0.01
for j in range(len(omega)):
print('trying with $omega =$',omega[j])
p = (l,m,omega[j])
u = 0.001
for i in range(niter):
u += ustep
ini = init(u,p[0],r[0])
Y = odeint(system_DE, ini,r,p,mxstep=500000)
if abs(Y[len(Y)-1,2]-1/Y[len(Y)-1,3]) < tol:
break
if abs(Y[len(Y)-1,0]) < tol and abs(Y[len(Y)-1,2]-1/Y[len(Y)-1,3]) < tol:
print(j,'times iterations in omega')
print(i,'times iterations')
print("R'(inf)) = ", Y[len(Y)-1,0])
print("alpha(0)) = ", Y[0,3])
print("\omega",omega[j])
break
plt.subplot(2,1,1)
plt.plot(r,Y[:,0],'r',label = '$R$')
plt.plot(r,Y[:,1],'b',label = '$d R /dr$')
plt.xlim([0,10])
plt.legend()
plt.subplot(2,1,2)
plt.plot(r,Y[:,2],'r',label = 'a')
plt.plot(r,Y[:,3],'b', label = '$alpha$')
plt.xlim([0,10])
plt.legend()
plt.show()
But when I run it I am obtaining this:
lsoda-- warning..internal t (=r1) and h (=r2) are
such that in the machine, t + h = t on the next step
(h = step size). solver will continue anyway
in above, r1 = 0.1243782486482D+01 r2 = 0.8727680448722D-16
How could I fix the problem?
Regards,
Luis Padilla.

Python: Numerov's method plotting error

I'm trying to solve the Schrödinger equation with the Numerov's method. Here is my code:
from pylab import *
from scipy.optimize import brentq
import numpy as np
l = float(input("Angular momentum l:"))
L = float(input("Width of the potential:"))
Vo = float(input("Value of the potential:"))
N = int(input("Number of steps (~10000):"))
h = float(3*L/N)
psi = np.zeros(N) #wave function
psi[0] = 0
psi[1] = h
def V(x,E):
"""
Effective potential function.
"""
if x > L:
return -2*E+l*(l+1)/x**2
else:
return -2*(Vo+E)+l*(l+1)/x**2
def Wavefunction(energy):
"""
Calculates wave function psi for the given value
of energy E and returns value at point xmax
"""
global psi
global E
E=energy
for i in range(2,N):
psi[i]=(2*(1+5*(h**2)*V(i*h,E)/12)*psi[i-1]-(1-(h**2)*V((i-1)*h,E)/12)*psi[i-2])/(1-(h**2)*V((i+1)*h,E)/12)
return psi[-1]
def find_energy_levels(x,y):
"""
Gives all zeroes in y = psi_max, x=en
"""
zeroes = []
s = np.sign(y)
for i in range(len(y)-1):
if s[i]+s[i+1] == 0: #sign change
zero = brentq(Wavefunction, x[i], x[i+1])
zeroes.append(zero)
return zeroes
def main():
energies = np.linspace(-Vo,0,int(10*Vo)) # vector of energies where we look for the stable states
psi_max = [] # vector of wave function at x = 3L for all of the energies in energies
for energy in energies:
psi_max.append(Wavefunction(energy)) # for each energy find the the psi_max at xmax
E_levels = find_energy_levels(energies,psi_max) # now find the energies where psi_max = 0
print ("Energies for the bound states are: ")
for E in E_levels:
print ("%.2f" %E)
# Plot the wavefunctions for first 4 eigenstates
x = np.linspace(0, 3*L, N)
figure()
for E in E_levels:
Wavefunction(E)
plot(x, psi, label="E = %.2f"%E)
legend(loc="upper right")
xlabel('r')
ylabel('$u(r)$', fontsize = 10)
grid()
savefig('numerov.pdf', bbox_inches='tight')
if __name__ == "__main__":
main()
Everything was working really well, this is a plot for Vo=35, l=1, but when I try whit a value of Vo=85, l=0 (is the same for Vo>50), the plot is not what I expected (the end of the plot blows up). For l=1, the error vanish. I am a novice in Python, so I do not know what would be the error. Thanks for the help.

Solving Laplace's equation

i'm trying to solve Laplace's equation with a particular geometry (two circular conductors), here's what i've done in python :
from __future__ import division
from pylab import *
from scipy import *
from numpy import *
from matplotlib import *
N1=50 # number of points along x and y
N=2*N1+1 # number of points in total
# in cm.
xc1=4
xc2=9
yc1=0
yc2=0
R1=1.75
R2=9
ecart = 1
a, b = linspace(-1, 19, N), linspace(-10, 10, N)
xa, ya = meshgrid(a, b)
V = zeros_like(xa)
for i in range(N):
for j in range(N):
x, y = xa[i,j], ya[i,j]
if (((x-xc1)**2/(R1**2))+((y-yc1)**2/(R1**2)))<=1 : # potential in the central conductor
V[i,j] = 30
if (((x-xc2)**2/(R2**2))+((y-yc2)**2/(R2**2)))>=1 : # potential in the outer conductor
V[i,j] =0
#draws the potential along X along the axis of symmetry.
Vnew = V.copy()
while ecart > 5*10**-2:
for i in range(1,N-1):
for j in range(1,N-1):
Vnew[i,j] = 0.25*(V[i-1,j] + V[i+1,j] + V [i,j-1] + V[i,j+1])
# convergence criterion
ecart = np.max(np.abs(V - (Vnew))/np.max(V))
print(ecart)
# save in the grid V of the calculated grid
for i in range(N):
for j in range(N):
x, y = xa[i,j], ya[i,j]
if (((x-xc1)**2/(R1**2))+((y-yc1)**2/(R1**2))) > 1 and (((x-xc2)**2/(R2**2))+((y-yc2)**2/(R2**2))) < 1 :
V[i,j] = Vnew[i,j]
it actually works with ecart>5*10**-2, but I would like to do it with ecart>10**-3 and here is the problem, it takes too much time ,actually it never ends...
Does someone have any idea in order to improve the program ?
Thank you in advance !

3D plot of a generated 2D matrix

I've written a code for my school project. The u and v matrices are generated already. I've made a 2D contour, but I wish to plot u and v in 3D.
import numpy as np
#import matplotlib.pyplot as plt
#inputs
m = 40
n = 20
Uinf = 2
delX = 0.05
delY = 0.05
nu = 0.8e-2
u= np.zeros((m+1,n))
v= np.zeros((m+1,n))
#intializing boundry conditions
u[:,0] = v[:,0] = v[:,n-1] = v[0,:] = 0
u[:,n-1] = u[0,:] = Uinf
#main program
for i in range(0,m):
for j in range(1,n-1):
a = (nu*delX) / (u[i,j]*delY**2)
b = (v[i,j]*delX) / (2*u[i,j]*delY)
u[i+1,j] = (a-b)*u[i,j+1]+(1-2*a)*u[i,j]+(a+b)*u[i,j-1]
v[i+1,j] = v[i+1,j-1]-(delY/(2*delX))*(u[i+1,j]-u[i,j]+u[i+1,j-1]-u[i,j-1])
I have to mention that I don't wanna generate an arbitrary function; u[i,j] and v[i,j] are present.
Thanks!

Categories