1

There are two (possible) problems to this code I could use help with.

I have written the following code to calculate the average energy, magnetisation and specific heat of a material with lattice sizes 10x10, 50x50 and 100x100.

Graphs

The graphs shown have significant fluctuations, which I feel is for two reasons.

  • Firstly, I can only seem to run the program with around 100 'relax' steps before performing the actual calculation. Answers to similar questions on here suggest doing around 1000 steps, but my program takes extremely long to do this.
  • Secondly, there was a hint given to us by our professor which is the following:

    "If you start the loop over the temperature with the lowest temperature, use as initial state the configuration with all spins up. When you change the temperature, use the last spin configuration as the first configuration for the next Nwait MMC steps. – This will reduce the fluctuations on the data"

I've been trying to implement this by for example, putting

  if m == 1:
        s = np.ones(10,10)
    else:
        config = initialstate(N)

in the for loop with N = 10x10.

But that only partially solves it, as I'm not using the last spin configuration as the first configuration for the next relax steps.

The code:

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

#----------------------------------------------------------------------
##  BLOCK OF FUNCTIONS USED IN THE MAIN CODE
#----------------------------------------------------------------------
def initialstate(N):   
    ''' generates a random spin configuration for initial condition'''
    state = 2*np.random.randint(2, size=(N,N),dtype='int64')-1
    return state

def mcmove(config, beta):
    '''Monte Carlo move using Metropolis algorithm '''
    for i in range(N):
        for j in range(N):
                a = np.random.randint(0, N,dtype='int64')
                b = np.random.randint(0, N,dtype='int64')
                s =  config[a, b]
                nb = config[(a+1)%N,b] + config[a,(b+1)%N] + config[(a-1)%N,b] + config[a,(b-1)%N]
                energy = 2*s*nb
                if energy < 0:
                    s *= -1
                elif rand() < np.exp(-energy*beta):
                    s *= -1
                config[a, b] = s
    return config

def calcEnergy(config):
    '''Energy of a given configuration'''
    energy = 0
    for i in range(len(config)):
        for j in range(len(config)):
            S = config[i,j]
            nb = config[(i+1)%N, j] + config[i,(j+1)%N] + config[(i-1)%N, j] + config[i,(j-1)%N]
            energy += -nb*S
    return energy/4.


def calcMag(config):
    '''Magnetization of a given configuration'''
    mag = np.sum(config)
    return mag

#----------------------------------------------------------------------
##  MAIN PART OF THE CODE
#----------------------------------------------------------------------




nt      = 20        # number of temperature points
eqSteps = 100      # number of MC sweeps for equilibration
mcSteps = 100     # number of MC sweeps for calculation

T              = np.linspace(1, 4, nt)        #temperature

Energy_10         = np.zeros(nt,dtype='int64')
Magnetization_10    = np.zeros(nt,dtype='int64')
SpecificHeat_10     = np.zeros(nt,dtype='int64')

Energy_20         = np.zeros(nt,dtype='int64')
Magnetization_20    = np.zeros(nt,dtype='int64')
SpecificHeat_20     = np.zeros(nt,dtype='int64')

Energy_30         = np.zeros(nt,dtype='int64')
Magnetization_30    = np.zeros(nt,dtype='int64')
SpecificHeat_30     = np.zeros(nt,dtype='int64')



for m in range(len(T)):  #for loop for 10x10 lattice
    E1 = M1 = 0
    N = 10 # size of the lattice, N x N
    config = initialstate(N)

    for i in range(eqSteps):
        mcmove(config, 1.0/T[m])

    for i in range(mcSteps):
        mcmove(config, 1.0/T[m])        # monte carlo moves
        Ene = calcEnergy(config)        # calculate the energy
        Mag = calcMag(config)           # calculate the magnetisation

        E1 = E1 + Ene
        M1 = M1 + Mag

        Energy_10[m]         = E1/(N**2)
        Magnetization_10[m]  = M1/(N**2)
        SpecificHeat_10[m]   = (((T[m]**2)*(E1/(N**2))*(E1)-(E1/(N**2))**2))/(N**2)


for m in range(len(T)):  #for loop for 50x50 lattice
    E1 = M1 = 0
    N = 50
    config = initialstate(N)

    for i in range(eqSteps):
        mcmove(config, 1.0/T[m])

    for i in range(mcSteps):
        mcmove(config, 1.0/T[m])        # monte carlo moves
        Ene = calcEnergy(config)        # calculate the energy
        Mag = calcMag(config)           # calculate the magnetisation

        E1 = E1 + Ene
        M1 = M1 + Mag

        Energy_20[m]         = E1/(N**2)
        Magnetization_20[m]  = M1/(N**2)
        SpecificHeat_20[m]   = ((T[m]**2)*(E1/(N**2))*(E1)-(E1/(N**2))**2)/(N**2)


for m in range(len(T)): #for loop for 100x100 lattice
    E1 = M1 = 0
    N = 100
    config = initialstate(N)

    for i in range(eqSteps):
        mcmove(config, 1.0/T[m])

    for i in range(mcSteps):
        mcmove(config, 1.0/T[m])        # monte carlo moves
        Ene = calcEnergy(config)        # calculate the energy
        Mag = calcMag(config)           # calculate the magnetisation

        E1 = E1 + Ene
        M1 = M1 + Mag

        Energy_30[m]         = E1/(N**2)
        Magnetization_30[m]  = M1/(N**2)
        SpecificHeat_30[m]   = ((T[m]**2)*(E1/(N**2))*(E1)-(E1/(N**2))**2)/(N**2)


        #----------------------------------------------------------------------     
# Plot the Energy, Magnetization and Specific Heat
#----------------------------------------------------------------------
f = plt.figure(figsize=(18, 10), dpi=80, facecolor='w', edgecolor='k');    

sp =  f.add_subplot(2, 2, 1 );
plt.plot(T, Energy_10, 'g',label = 'N=10')
plt.plot(T, Energy_20, 'r',label = 'N=50')
plt.plot(T, Energy_30, 'b',label = 'N=100')
plt.legend()
plt.xlabel("Temperature (T)", fontsize=20);
plt.ylabel("Energy ", fontsize=20);
plt.show()


sp =  f.add_subplot(2, 2, 2 );
plt.plot(T, abs(Magnetization_10), 'g',label = 'N=10')
plt.plot(T, abs(Magnetization_20), 'r',label = 'N=50')
plt.plot(T, abs(Magnetization_30), 'b',label = 'N=100')
plt.legend()
plt.xlabel("Temperature (T)", fontsize=20);
plt.ylabel("Magnetization ", fontsize=20);
plt.show()

sp =  f.add_subplot(2, 2, 3 );
plt.plot(T, SpecificHeat_10, 'g',label = 'N=10')
plt.plot(T, SpecificHeat_20, 'r',label = 'N=50')
plt.plot(T, SpecificHeat_30, 'b',label = 'N=100')
plt.legend()
plt.xlabel("Temperature (T)", fontsize=20);
plt.ylabel("Specific Heat ", fontsize=20);
plt.show()


#----------------------------------------------------------------------
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
P.Blah
  • 31
  • 1
  • 4
  • Sorry, I can't help you with this topic. There seems to be a fair bit of [duplication](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) in that code. It would make it easier for people to help you if you could use functions (or something) to reduce that duplication. Ideally, code on SO should be a [mcve] that focuses on a single issue. – PM 2Ring Oct 04 '17 at 14:56
  • No problem at all, thank you for clarifying! – P.Blah Oct 04 '17 at 15:01
  • Maybe this https://stackoverflow.com/a/45403017/4045774 will help a bit to improve the performance. – max9111 Oct 08 '17 at 20:30

0 Answers0