如何使用蒙特卡罗模拟获得 3d Ising Spin 系统的自由能面?

计算科学 Python 计算物理学 模拟 3d
2021-12-22 05:37:09

我正在对 3D Ising Spin 系统的属性进行蒙特卡罗模拟。我想从模拟中得到自旋系统的自由能面。它是磁化强度与自由能曲线。自由能定义为 F(m)=-kT ln(P(m)) 其中 m 是磁化强度,P 是占据相应磁化强度的概率。假设没有施加外部磁场。由于 m=0 附近的能量势垒非常高,我采用了伞形采样。但结果似乎并不像预期的那样。我没有得到偏置强度为 500 的稳定平衡位置(-1 和 1 处的最小值)。对于 T

预期结果如下所示,

在此处输入图像描述

我得到的是,

在此处输入图像描述

为了找到 P(m),我们使用来自 mcmove 操作的频率直方图数据。(见下面的代码)

# -*- coding: utf-8 -*-
"""
Created on Sun Mar 22 19:28:53 2020

@author: Endeavour
"""

from numpy.random import rand
import numpy as np     
import matplotlib.pyplot as plt    
import seaborn as sns 



Q       = 10        #The bias strength


def initialise(N):   
    ''' generates a random spin spin_statesuration for initial condition'''
    spin_states = np.random.choice([1, -1], size=(N, N,N))
    #spin_states=np.ones([N,N,N])
    return spin_states



def calcMag(spin_states):
    '''Magnetization of a given spin_statesuration'''
    mag = (np.sum(spin_states))
    return (mag/(N*N*N))

def calcEnergy(spin_states):
    '''Energy of a given spin_statesuration'''
    energy = 0
    for i in range(len(spin_states)):
        for j in range(len(spin_states)):
            for k in range(len(spin_states)) :
                s = spin_states[i,j,k]
                energy += -s*find_neighbours(spin_states,N,i,j,k)
    energy+=Q*(calcMag(spin_states))**2
    return energy/6.

def find_neighbours(spin_states,N,x,y,z):
    left   =spin_states[x,(y-1)%N,z]
    right  =spin_states[x,(y+1)%N,z]
    top    =spin_states[(x-1)%N,y,z]
    bottom =spin_states[(x+1)%N,y,z]
    front  =spin_states[x,y,(z+1)%N]
    back   =spin_states[x,y,(z-1)%N]

    tot_spin=left+right+top+bottom+front+back 

    return (tot_spin)

def mcmove(spin_states, beta):
    '''Monte Carlo move using Metropolis algorithm '''
    cost=calcEnergy(spin_states) #Store initial energy
    for x in range(len(spin_states)):
        for y in range(len(spin_states)):
            for z in range(len(spin_states)):
                x = np.random.randint(len(spin_states))
                y = np.random.randint(len(spin_states))
                z = np.random.randint(len(spin_states))
                s = spin_states[x,y,z]
                s*=-1
                cost = calcEnergy(spin_states)-cost
                print(cost)
                if rand() < np.exp(-cost*beta):  #if cost<0 exp(-cost*beta) should be >1
                    s *= -1
                spin_states[x, y,z] = s
    return spin_states

#-------------------------Simulation Parameters----------       
nt      = 70        #  nt>20 20 points will be between 4 &5 number of temperature points
N       = 16        #  size of the lattice, size x size
eqSteps = 10       #  number of MC sweeps for equilibration
mcSteps = 100       #  number of MC sweeps for calculation
Temp     =4.6       #Temperature
#-------------------------------------------------------------

dat_M=[]            #Magnetisation data for mc trials
mag=[]              #Abscissa for plotting calculated from bin values 


spin_states = initialise(N)
iT=1.0/Temp#Inverse Temperature for beta

for i in range(eqSteps):         # equilibrate
    mcmove(spin_states, iT)      # Monte Carlo moves
    if(i%5==0): print ('ok trial')

for i in range(mcSteps):
    mcmove(spin_states, iT)
    Mag = calcMag(spin_states)/(N*N*N)        # calculate the magnetisation
    dat_M.append(Mag)
print(dat_M)


divs=np.arange(-1,1,0.005)       #Find out bin values      
sns.distplot(dat_M,kde=0,bins=divs) #Plot the histogram

hist_counts,bin_edges=np.histogram(dat_M,bins=divs) #Take the count(freq) 
for i in range(len(divs)-1):
        mean=(divs[i]+divs[i+1])/2  #Aerage magnetisation for each bin
        mag.append(mean)

W=Q*np.square(mag)                      #Bias potential 
free_energy=[]


for y in (hist_counts):
    if (y!=0) :
        free_energy.append(-(1/iT)*np.log(y/mcSteps)  )    #-kTlog(P(m))
    else:
        free_energy.append(np.nan)

free_energy=np.subtract(free_energy,W)  #Correction for bias potetial

#Plotting        
plt.figure(num=2,figsize=(10,6),dpi=80, facecolor='w', edgecolor='b')
plt.xlabel('x')
plt.ylabel('$-kTlogP_i$')
plt.title('Free Energy surface Q=%d,Temperature=%f'%(Q,Temp))
#plt.plot(mag,free_energy,'-',label='Potential Strength(Q): %d \n Biasing strength($x^m$):%d'%(Q,m))
plt.plot(mag,free_energy,'+',label='Test')
plt.legend()

我找不到该方法的任何问题。也许代码有问题。请您指出任何错误吗?任何提示或解决方案都会有很大帮助。我根本无法得到两个最小值。我尝试过不同的偏置强度,但没有成功。

先感谢您。

进行一些更正后,当前代码似乎处于无限循环中。我已经打印了成本,但它只给出了 2 个值 -2.66664719581604 和 0.0。

1个回答

据我所知,您没有对模拟施加任何偏见。Q偏见发挥作用的唯一地方是calcEnergy方法中,您的代码永远不会调用该方法。

通常,当您计算移动的接受概率时,需要在实际的 MC 代码中使用偏差。