Ising Model [Python]

I am trying to simulate the Ising phase transition in the Barabashi-Albert network and try to reproduce the results of some observable quantities, such as magnetization and energy, as one would observe in a simulation of the Ising grid. However, I am having problems interpreting my results: I’m not sure if the physics is wrong or if there is an error in the implementation. Here is a minimal working example:

import numpy as np 
import networkx as nx
import random
import math

## sim params

# coupling constant
J = 1.0 # ferromagnetic

# temperature range, in units of J/kT
t0 = 1.0
tn = 10.0
nt = 10.
T = np.linspace(t0, tn, nt)

# mc steps
steps = 1000

# generate BA network, 200 nodes with preferential attachment to 3rd node
G = nx.barabasi_albert_graph(200, 3)

# convert csr matrix to adjacency matrix, a_{ij}
adj_matrix = nx.adjacency_matrix(G)
top = adj_matrix.todense()
N = len(top)

# initialize spins in the network, ferromagnetic
def init(N):
    return np.ones(N)

# calculate net magnetization
def netmag(state):
    return np.sum(state)

# calculate net energy, E = \sum J *a_{ij} *s_i *s_j
def netenergy(N, state):
    en = 0.
    for i in range(N):
        for j in range(N):
            en += (-J)* top[i,j]*state[i]*state[j] 
    return en

# random sampling, metropolis local update
def montecarlo(state, N, beta, top):

    # initialize difference in energy between E_{old} and E_{new}
    delE = []

    # pick a random source node
    rsnode = np.random.randint(0,N)

    # get the spin of this node
    s2 = state[rsnode]

    # calculate energy by summing up its interaction and append to delE
    for tnode in range(N):
        s1 = state[tnode]
        delE.append(J * top[tnode, rsnode] *state[tnode]* state[rsnode])

    # calculate probability of a flip
    prob = math.exp(-np.sum(delE)*beta)

    # if this probability is greater than rand[0,1] drawn from an uniform distribution, accept it
    # else retain current state
    if prob> random.random():
        s2 *= -1
    state[rsnode] = s2

    return state

def simulate(N, top):

    # initialize arrays for observables
    magnetization = []
    energy = []
    specificheat = []
    susceptibility = []

    for count, t in enumerate(T):


        # some temporary variables
        e0 = m0 = e1 = m1 = 0.

        print 't=', t

        # initialize spin vector
        state = init(N)

        for i in range(steps):

            montecarlo(state, N, 1/t, top)

            mag = netmag(state)
            ene = netenergy(N, state)

            e0 = e0 + ene
            m0 = m0 + mag
            e1 = e0 + ene * ene
            m1 = m0 + mag * mag

        # calculate thermodynamic variables and append to initialized arrays
        energy.append(e0/( steps * N))
        magnetization.append( m0 / ( steps * N)) 
        specificheat.append( e1/steps - e0*e0/(steps*steps) /(N* t * t))
        susceptibility.append( m1/steps - m0*m0/(steps*steps) /(N* t *t))

        print energy, magnetization, specificheat, susceptibility

        plt.figure(1)
        plt.plot(T, np.abs(magnetization), '-ko' )
        plt.xlabel('Temperature (kT)')
        plt.ylabel('Average Magnetization per spin')

        plt.figure(2)
        plt.plot(T, energy, '-ko' )
        plt.xlabel('Temperature (kT)')
        plt.ylabel('Average energy')

        plt.figure(3)
        plt.plot(T, specificheat, '-ko' )
        plt.xlabel('Temperature (kT)')
        plt.ylabel('Specific Heat')

        plt.figure(4)
        plt.plot(T, susceptibility, '-ko' )
        plt.xlabel('Temperature (kT)')
        plt.ylabel('Susceptibility')

simulate(N, top)

Observed results :

I tried to comment on the code to a large extent, in case I missed something, please ask.

Questions

  • Is the magnetization trend correct? The magnetization decreases with increasing temperature, but cannot determine the critical temperature of the phase transition.
  • , , -, , . ?
  • monte carlo? , ?

EDIT: 02.06: simulation is broken into antiferromagnetic configuration:

+4
1

, , . , . - 200x200 (40000) 3% . montecarlo netenergy. 5 , :

# keep the topology as a sparse matrix
top = nx.adjacency_matrix(G)

def netenergy(N, state):
    en = 0.
    for i in range(N):
        ss = np.sum(state[top[i].nonzero()[1]])
        en += state[i] * ss
    return -0.5 * J * en

0,5 - , !

def montecarlo(state, N, beta, top):
    # pick a random source node
    rsnode = np.random.randint(0, N)
    # get the spin of this node
    s = state[rsnode]
    # sum of all neighbouring spins
    ss = np.sum(state[top[rsnode].nonzero()[1]])
    # transition energy
    delE = 2.0 * J * ss * s
    # calculate transition probability
    prob = math.exp(-delE * beta)
    # conditionally accept the transition
    if prob > random.random():
        s = -s
    state[rsnode] = s

    return state

2.0 - !

numpy. top[i] - node top[i].nonzero()[1] - (top[i].nonzero()[0] - , 0, - ). state[top[i].nonzero()[1]] , , node i.

. , :

e1 = e0 + ene * ene
m1 = m0 + mag * mag

:

e1 = e1 + ene * ene
m1 = m1 + mag * mag

specificheat.append( e1/steps - e0*e0/(steps*steps) /(N* t * t))
susceptibility.append( m1/steps - m0*m0/(steps*steps) /(N* t *t))

:

specificheat.append((e1/steps/N - e0*e0/(steps*steps*N*N)) / (t * t))
susceptibility.append((m1/steps/N - m0*m0/(steps*steps*N*N)) / t)

( )

. t .

, () , . , . , , , , . , . - . ? - , () .

-, , , , , . 200 , 1000 .

.

+2

Source: https://habr.com/ru/post/1674192/


All Articles