from numpy import *
from numpy import random
from numba import jit
@jit(nopython=True)
def CEnergy(latt):
"Energy of configuration for the 2D Ising model"
N = shape(latt)[0]
Ene = 0
for i in range(len(latt)):
for j in range(len(latt)):
S = latt[i,j] # Spin, can be either +1 or -1
WF = latt[(i+1)%N,j]+latt[i,(j+1)%N]+latt[(i-1)%N,j]+latt[i,(j-1)%N]
Ene += -S * WF
return Ene/2.
def RandomL(N):
"Random lattice corresponding to infinite temperature"
return array(sign(2*random.random((N,N))-1),dtype=int)
@jit(nopython=True)
def RunWangLandau(Nitt,Energies,latt,indE):
N = len(latt)
Ene = int(CEnergy(latt))
#min,maximum energy
Emin, Emax = Energies[0],Energies[-1]
# Logarithm of the density of states
lngE = zeros(len(Energies))
# Histogram
Hist = zeros(len(Energies))
# modification factor
lnf = 1.0 # f = exp(lnf)=e
N2 = N*N
for itt in range(Nitt):
t = int(random.rand()*N2)
(i, j) = (int(t/N), t%N)
S = latt[i,j]
WF = latt[(i+1)%N,j]+latt[i,(j+1)%N]+latt[(i-1)%N,j]+latt[i,(j-1)%N]
Enew = Ene + int(2*S*WF) # the energy change if we flip the spin
# P = g(E)/g(Enew) = exp(log(g(E))-log(g(Enew)))
# P = exp(lngE(E)-lngE(Enew))
lgnew = lngE[indE[Enew-Emin]]
lgold = lngE[indE[Ene-Emin]]
P = 1.0
if lgold-lgnew < 0 : P=exp(lgold-lgnew)
if P > random.rand():
# accept the step
latt[i,j] = -S
Ene = Enew
Hist[indE[Ene-Emin]] += 1
lngE[indE[Ene-Emin]] += lnf
if (itt+1) % 1000 == 0: # checking for flatness of the histogram
aH = sum(Hist)/N2 # average
mH = min(Hist)
if mH > aH*flatness: # histogram is flat
Hist = zeros(len(Hist))
lnf /= 2.
print(itt, 'histogram is flat', mH, aH, 'f=', exp(lnf))
return (lngE, Hist, Energies)
from numpy import random
def WangLandau(Nitt, N, flatness):
"Wang Landau in Python"
Energies = (array(4*arange(-int(N*N/2),int(N*N/2)+1),dtype=int)).tolist()
Energies.pop(1)
Energies.pop(-2)
Energies = array(Energies)
Emin, Emax = Energies[0],Energies[-1]
#index array
indE = -ones(Emax+1-Emin, dtype=int)
for i,E in enumerate(Energies):
indE[E-Emin]=i
# Ising lattice at infinite T
latt = RandomL(N)
return RunWangLandau(Nitt,Energies,latt,indE)
flatness = 0.9
#N = 20
#Nitt = 100000000
N=10
Nitt = 10000000
(lngE, Hist, Energies) = WangLandau(Nitt, N, flatness)
# Proper normalization of the Density of states
# g *= 4/(g[0]+g[-1])
# log(g) += log(4)-log(g[-1])-log(1+exp(log(g[0])-log(g[-1])))
#
if lngE[-1]>lngE[0]:
lgC = log(4)-lngE[-1]-log(1+exp(lngE[0]-lngE[-1]))
else:
lgC = log(4)-lngE[0]-log(1+exp(lngE[-1]-lngE[0]))
lngE += lgC
exp(lngE[0])+exp(lngE[-1])
from pylab import *
%matplotlib inline
plot(lngE)
Energies[0]
def Thermod(T, lngE, Energies, N):
Z = 0.
Ev = 0. # <E>
E2v = 0. # <E^2>
for i,E in enumerate(Energies):
w = exp(lngE[i]-lngE[0]-(E-Energies[0])/T)
Z += w
Ev += w*E
E2v += w*E**2
Ev *= 1./Z
E2v *= 1./Z
cv = (E2v-Ev**2)/T**2
return (Ev/(N**2), cv/(N**2))
Te = linspace(0.5,4.,300)
Thm=[]
for T in Te:
Thm.append(Thermod(T, lngE, Energies, N))
Thm = array(Thm)
from pylab import *
%matplotlib inline
plot(Te, Thm[:,0], label='E(T)')
plot(Te, Thm[:,1], label='cv(T)')
xlabel('T')
legend(loc='best')
show()