Anda di halaman 1dari 18

THE TWO-DIMENSIONAL ISING MODEL OF FERROMAGNETISM

USING THE METROPOLIS ALGORITHM

Abstract:

The properties of a two-dimensional lattice of spins were investigated using the Ising Model. A Monte Carlo
method based on the Metropolis algorithm was implemented. This algorithm generates a sequence of samples
whose statistical distribution approaches the Boltzmann distribution of the magnetic system as more iterations
are executed. Under no applied field, the magnetisation, the internal energy and the heat capacity were found to
vary significantly within the vicinity of a critical temperature, at which a continuous phase transition occurs. In
particular, plotting the magnetisation against temperature allowed to estimate the critical temperature as Tc =
2.272 0.004 and
the critical exponent as = 0.109 0.018. The theoretical values predicted by Onsager,
Tc = 2/(1 + ln 2) and = 1/8, are both found within error range. When a non-zero field was applied, the
system was found to have a non-zero magnetisation above the critical temperature and a single equilibrium
state below it.

INTRODUCTION

low Tc ) according to the following equation:

The magnetic properties of ferromagnets can be investigated using a simplified model of spin-spin interactions known as the Ising model. In particular, the
two-dimensional Ising model consists of a square lattice in which each site has either spin up (+1) or down
(-1). Within such model the energy of a N x N lattice
can be written as:
N2

E = J

<i j>

si s j H si

(1)

i=1

Spins on adjacent sites, called nearest neighbours, interact in a pairwise manner with strength J, known
as the exchange energy coefficient. In addition, the
externally applied magnetic field H couples linearly
with the magnetisation. is the magnetic moment of
each spin.
In 1944, Onsager published the analytic solution
to the two-dimensional Ising model [1]. The critical temperature in the thermodynamic limit (i.e. an
infinitely largelattice, N ) is predicted to be
Tc = 2/(1 + ln 2). Below this temperature, the material behaves like a ferromagnet, as the spins tend
to align in the most stable configuration even in the
absence of a field. Above it, the spins tend to be
randomly oriented unless the field is non-zero, as expected for a paramagnet. Predicted by Onsager and
rigourously proved by Yang in 1952 [2], the magnetisation is expected to depend on the temperature (be-

M=


 !1/8
Tc 4
1 sinh(ln(1 + 2) )
T

(2)

Within the vicinity of the critical temperature, this


expression can be Taylor expanded, in which case
the magnetization is found to vary as M (Tc T ) ,
where = 1/8.
An analysis of the computational aspects of the
problem is disclosed in the next section. Section 3
includes a description of the implementation of the
necessary algorithm to solve the problem. In subsection 3.1, the performance of the program is discussed,
including steps taken to improve its efficiency. Section 4 presents the quantitative and qualitative results
of the problem and a discussion of their physical significance. The overall conclusions are presented in
section 5.

ANALYSIS

The statistical mechanics of complex physical systems usually poses problems that are very difficult
to solve by analytical methods. Numerical simulation techniques are therefore indispensable tools to
the study of such problems, which range from phase
transitions in binary alloys to neural networks.
The Ising model of ferromagnetism exhibits this
feature clearly. For example, if we considered a small
10 x 10 lattice of spins, the total number of microstates would be of 2100 ' 1.2 x 1030 . Summing

over such a large number of microstates to perform


the ensemble averages involved in the calculations of
the thermodynamic variables of the system would be
very inefficient.
Instead of choosing configurations randomly and
then weighting them with the appropriate Boltzmann
distribution, a more efficient approach to this problem
involves choosing the spin configurations with a probability eE/kB T (where E is the energy of the configuration and T is the temperature set by the reservoir)
and then weighting them evenly. This is the underlying idea behind the Metropolis algorithm [3]. The
Metropolis algorithm consists of the following steps:

IMPLEMENTATION

The program listing can be found in the Appendix.


A class, Matrix, which can be found in file
Matrix.h, was created to represent two-dimensional
arrays in a simple way. There is only one function defined within the class, which allows to call a matrix as
lattice(row, col).
random_generator generates a random number
between 0 and 1 based on gsl_rng_uniform. This
function is called by initialize_lattice_random
to generate a random set of spins. Alternatively, the
lattice may be initialised with all spins up using the
function initialize_lattice_uniform.
The function energy returns the energy of the spin
configuration using equation 1. This function computes the sum over the nearest neighbours of all lattice
sites by calling the function nearest_neighbours,
which implements periodic boundary conditions. J
and are defined in this function and are both set to
unity for convenience. The Boltzmann constant, kB ,
is also defined as a constant and set to unity.
The function magnetisation returns the magnetization per unit spin. Given that is set to 1, this
function simply sums all spins and divides by N 2 .
Metropolis executes steps 3-4 described in section 2. The row and column of the lattice site considered are passed as parameters. This function creates
a new lattice that differs from the previous one by a
flipped spin. The flipping is performed by the function flip_spin. The previous lattice configuration is
saved so that the energy difference between the two
can be calculated. To perform steps 4.(b) and 4.(c)
the Boltzmann factor is compared to a random number generated by random_generator.
Step 5 can be performed in two distinct ways:
all lattice sites may be visited systematically line after line (single_Monte_Carlo_step_regular) or
N 2 lattice sites may be picked randomly (single_
Monte_Carlo_step_random). In the latter case, the
row and column of the site considered correspond to
the integral part of N times the output of random_
generator.
In the main, the size of the lattice, the initial temperature and the applied magnetic field are initialized.
The program has two modes: mode_1 simply takes
M single time steps, saves the magnetization per spin
at each instant and prints the final lattice configuration using Gnuplot. mode_2 covers a range of temperatures and saves the following physical variables at
equilibrium for each temperature: magnetization per
site, energy per site, their standard deviations and heat
capacity. The former mode is useful to understand
what the equilibrium states at different temperatures

1. Create a N x N lattice
2. Select a lattice site
3. Determine the energy change E involved in flipping the spin
4. Decide whether to flip the spin or leave it unchanged as follows:
(a) If E < 0 flip the spin
(b) If E > 0 and exp(E/kB T ) > r, where r is a
random number generated in the interval [0,1],
flip the spin
(c) Otherwise, leave the spin unchanged
5. Repeat steps 2-4 for N 2 lattice sites
The N 2 operations described above may be thought
of as a single time step. In order to reach a quasiequilibrium state, the simulation must be run for several time steps. At this point the thermodynamic and
magnetic properties of the system may be measured
by repeating several time steps and then averaging
over the relevant quantities stored at each time instant.
This time average is equivalent to an ensemble average.
In order to ensure that each lattice site had four
nearest neighbours, periodic boundary conditions
were used. Hence, when the selected site was along
the border of the lattice, its neighbours were taken
from the opposite side of the lattice. This effectively
reduced the geometry to a torus, thus avoiding undesirable effects at the edges.
Even though the two-dimensional Ising model of
ferromagnetism was solved analytically by Onsager,
this numerical simulation technique is in fact of great
value, as it may be generalized to higher dimensions,
for which no analytical solution has been found,
and to more complex interactions (e.g. next-nearestneighbour interactions). Nevertheless, the quantitative results obtained through this method were compared to the analytical results derived by Onsager.

val allowed to significantly reduce the run time, especially for large N.
M was also the number of time steps taken to compute the ensemble average of the relevant quantities.
This also justifies the need to have a greater M closer
to the critical temperature, as the fluctuations become
significant in this region.
The CPU time required to perform 1000 single
time steps (STS) at a fixed temperature for a 20 x
20 lattice was 30 s, whereas for a 30 x 30 lattice the
same procedure took
S 2 min 40 s. Performing 100 STS
for T [1.5, 2.0] [3.0, 3.5], with T = 0.1, and 1000
STS for T [2.0, 3.0], with T = 0.05, for a 10 x 10
lattice took 1 min 30 s. The same result for N = 20
and N = 30 required 24 min and 1h 58 min of CPU
time, respectively.

are, whereas the latter is useful to plot the relevant


physical quantities against temperature.
The heat capacity is estimated using two methods:
calculating the discrete derivative C = dE/dT and using the Fluctuation-Dissipation Theorem, according
to which:
2
C = E2
(3)
kB T
where E is the standard deviation of energy. In the
former case, the energy and the temperature of the
previous iteration must be saved in order to calculate
the appropriate ratio of differences.
Close to the critical temperature, the fluctuations
are so large and the energy gap required to move from
one equilibrium state (all spins down) to another (all
spins up) is so low that the average magnetization
per site tends to switch from 1 to -1 and vice-versa.
This effect tends to artificially decrease the value of
the magnetization just below the critical temperature.
To avoid this, the absolute value of the magnetization
was printed in mode 2.

4
4.1

3.1

RESULTS AND DISCUSSION


No Applied Field (H = 0)

Performance
By visualizing the lattice configuration and the magnetisation against time, a continuous phase transition
was observed to occur near T = 2.30 [J/kB ]. Above
this critical temperature Tc , the equilibrium state was
a randomly aligned lattice (figure 1) with average
magnetization zero (figure 2). Below this temperature, two different equilibrium states were observed:
one with all spins down and another with all spins up.
The system would attain one of the two states depending on the initial configuration (figure 3).

The two initial lattice configurations were used at different temperatures. The uniform lattice configuration reached quasi-equilibrium more rapidly than the
random one below the critical temperature, whereas
above it the random configuration was only slightly
faster to reach near-equilibrium. Given that the initial
temperature in mode 2 was always set below the critical temperature, the lattice was always initialized with
all spins up. For the following temperatures the initial configuration was the equilibrium configuration
of the previous temperature, therefore the initialization of the lattice was only relevant for the starting
temperature.
In addition, there were two alternative ways
of picking the spin to flip. The two functions,
single_Monte_Carlo_step_regular and single_
Monte_Carlo_step_random, were tested for different temperatures, but no significant differences in efficiency were noted. As a result, the spins were
flipped sequentially using single_Monte_Carlo_
step_regular.
Moreover, since the plots against temperature have
their most distinctive features within the vicinity of
the critical temperature, the temperature increment
was set to 0.05 for the interval T [2.0, 3.0] and 0.1
elsewhere. The system also requires more time to attain near-equilibrium close to the critical temperature,
so the number of single time steps M taken to reach
equilibrium was of 1000 for T [2.0, 3.0] and 100
elsewhere. Having 1000 time steps only in this inter-

Figure 1: Spin configuration of a 20 x 20 lattice at temperature T = 4.0 [J/kB ] after 100 single time steps. Black
squares represent spin down whereas white squares correspond to spin up. As expected, the spins are randomly
aligned above Tc .

0.5

Magnetization vs. Temperature (N = 30)

Data
Onsager Analytic Solution

0.9

Magnetization per site []

Magnetization per site []

sation vs. temperature graph approaches zero magnetization more smoothly than the theoretical prediction
(figure 4), so the critical temperature could only be
estimated as Tc = 2.3 0.1[J/kB ]. Onsagers critical
temperature is within this interval.

Magnetization vs. Time (N = 20, T = 4.0)

-0.5

-1

10

20

30

40

50

60

Number of Time Steps

70

80

90

100

Figure 2: Magnetization versus time for a 20 x 20 lattice at


temperature T = 4.0 [J/kB ]. Since the temperature is above
Tc , the average magnetization near equilibrium is zero.

0.6
0.5
0.4
0.3
0.2

0
1.4

1.6

1.8

2.2

2.4

2.6

2.8

Temperature [J/kB]

3.2

3.4

3.6

Figure 4: Magnetisation versus temperature for a 30 x 30


lattice (red) and Onsagers analytic solution (green, equation 2). As expected, the magnetisation decreases abruptly
close to Tc . However, the numerical estimate diverges from
the theoretical prediction just above the critical temperature,
as the magnetisation goes more smoothly to zero. This is
due to the finite size of the system.

Uniform
Random

Magnetization per site []

0.7

0.1

Magnetization vs. Time (N = 20, T = 1.5)

1.5

0.8

0.5
0
-0.5

Energy vs. Temperature (N = 30)

-0.6

-1

-0.8
0

10

20

30

40

50

60

Number of Time Steps

70

80

90

100

Energy per site [J]

-1.5

Figure 3: Magnetization versus time for a 20 x 20 lattice at


temperature T = 1.5 [J/kB ] for two different initial configurations. The two initial configurations gave rise to two different equilibrium states, one with all spins up and another
with all spins down. Due to the absence of an externally applied field, the system is invariant under the flip of all spins,
and therefore these two equilibrium states are energetically
equivalent and equally likely to be observed.

-1
-1.2
-1.4
-1.6
-1.8
-2
1.4

By plotting the magnetisation and the energy


against temperature a phase transition could be identified, as the magnetisation decreases sharply to zero
close to the critical temperature and the energy per
site increases in the same region. The same features
were observed for different values of N. However,
none of the two graphs allowed to accurately estimate
the critical temperature by visual inspection. Since
the lattices considered were of finite size, the magneti-

1.6

1.8

2.2

2.4

2.6

2.8

Temperature [J/kB]

3.2

3.4

3.6

Figure 5: Energy per site versus temperature for a 30 x 30


lattice. As expected, the energy increases across the phase
transition. The variation of the energy is not as steep as for
the magnetisation, therefore a better estimate of the critical
temperature is found from the M vs. T graph.

The heat capacity C was measured via two different methods. The graph C vs. T obtained by calculating the discrete derivative dE/dT was far less

clear than the one obtained from the FluctuationDissipation Theorem due to the random errors in the
simulation (figure 6). Nevertheless, the best graph
does allow to make a better estimate of Tc , since the
heat capacity peaks at this temperature: for N = 30,
Tc = 2.3 0.05 (figure 7). The heat capacity is expected to diverge according to Onsagers model, but
such divergence is not observed in lattices of finite
size.

Onsagers prediction that the magnetisation varies


as M (Tc T ) was used to make an accurate estimate of both the critical temperature Tc and the universal exponent for different values of N (10, 15,
20, 25, 30). The function f (T ) = C1 (Tc T ) was fit
to the data points from the numerical simulation using
the Gnuplot command fit. However, given that this
expression is only valid for temperatures just below
the critical temperature, only some data points were
selected. Figure 8 clearly shows that the data points
at the top section of the graph with negative curvature
do follow the analytic solution very closely. Those
data points were the ones considered when fitting to
the model. In addition, the uncertainties in each of the
measurements were taken to be the standard deviation
of fluctuations in the magnetisation.

Heat Capacity vs. Temperature (N = 30)

2500

Heat Capacity [kB]

2000

1500

1000
1.2

Magnetization vs. Temperature with Fitting (N = 30)


Complete Data
Fitting Data
f(x)

0
1.4

1.6

1.8

2.2

2.4

2.6

2.8

Temperature [J/kB]

3.2

3.4

Magnetization per site []

500

3.6

Figure 6: Heat Capacity versus Temperature for a 30 x 30


lattice using the Discrete Deriviative dE/dT. Although the
general shape of the curve is noticeable, the noise due to the
random errors in the simulation is significant.

1
0.8
0.6
0.4
0.2
0
1.4

1.8

2.2

2.4

2.6

2.8

Temperature [J/kB]

3.2

3.4

3.6

Heat Capacity vs. Temperature (N = 30)

2200

Figure 8: Magnetisation versus temperature for a 30 x 30


lattice. The complete set of data points, the selected data
(and respective error bars) and the fitting model are presented in red, blue and magenta, respectively. For N = 30,
Tc = 2.277 0.018[J/kB ] and = 0.09 0.02.

2000
1800
1600

Heat Capacity [kB]

1.6

1400
1200

Table 1 summarizes the estimates of Tc and for


the different values of N considered:

1000
800
600

Table 1: Summary of the estimated values of the critical


temperature Tc and universal coefficient as parameters of
the model

400
200
0
1.4

1.6

1.8

2.2

2.4

2.6

2.8

Temperature [J/kB]

3.2

3.4

3.6

N
10
15
20
25
30

Figure 7: Heat Capacity versus Temperature (red) for a 30


x 30 lattice using the Fluctuation-Dissipation Theorem. An
spline (blue) was added to visualize the peaked curve more
clearly and hence to estimate the critical temperature more
accurately. In addition, a vertical line (green) was plotted
to identify the data point of maximum heat capacity. From
this graph, Tc = 2.3 0.05, which is more accurate than the
previous estimate made from the M vs. T graph.

Tc [J/kB ]
2.35 0.03
2.30 0.02
2.299 0.019
2.286 0.004
2.277 0.018

0.7 0.3
0.40 0.15
0.17 0.06
0.11 0.06
0.09 0.02

Onsagers prediction
of the critical temperature,

Tc = 2/(1 + ln 2), only applies in the limit N .

To extrapolate the numerical predictions to N ,


ln(Tc ) was plotted against ln(N): the slope of the linear regression was found to be close to -2. Hence,
plotting Tc against 1/N 2 should have an intersect with
the vertical axis corresponding to Tc as derived by Onsager (figure 9). The critical temperature was estimated as Tc = 2.272 0.004 [J/kB ].

ity class. A universality class is characterized by the


dimensionality of space (in this case, d = 2, since the
lattice is two-dimensional) and the number of components of the order parameter (in this case, n = 1,
since the spin is a scalar). Regardless of the size N,
all spin lattices belong to this d = 2, n = 1 universality
class, and therefore the predicted value of from the
numerical simulation should correspond to the theoretical value of 1/8 for all N.

Critical Temperature versus 1/N2

2.38

However, the two estimates of for N = 10, 15 are


clearly far from the expected value. Figure 10 shows
M vs. T (with the fitting model) for N = 10. Clearly,
selecting the data points that should be used to fit the
model is not as clear as for N = 30, for example. Since
that selection was greatly influenced by the previous
knowledge about the critical temperature (namely, for
example, from C vs. T) and given the large correlation
of 0.445 between Tc and , the two estimates of for
N = 10, 15 were neglected. The average of the three
values for N = 20, 25, 30 gives a final estimate of
= 0.109 0.018. The theoretical value is within
error range.

2.36
2.34

Tc

2.32
2.3
2.28
2.26
2.24

0.002

0.004

0.006

0.008

1/N2

0.01

Figure 9: Tc versus 1/N 2 and respective linear regression.


The intersect was estimated as Tc = 2.272 0.004 [J/kB ]

4.2

Non-Zero Applied Field (H 6= 0)

Magnetization versus Temperature with Fitting (N = 10)


Complete Data
Model
Fitting Data

Magnetization per site []

0.5

When a non-zero magnetic field was applied, a nonzero magnetisation was found above the critical temperature. The magnetisation has the same sign as the
applied field, that is, if the sign of the field is switched,
the sign of the magnetisation changes as well. In addition, the magnetisation tends to increase with the
applied field. Figure 11 illustrates these observations.

-0.5

-1
1.4

1.6

1.8

2.2

2.4

2.6

2.8

Temperature [J/kB]

3.2

3.4

3.6

Below the critical temperature, there is now a single stable equilibrium state. By considering the same
initial configurations as in figure 4, for an applied field
H = 1.0 [J/] both lattices reach the same equilibrium state, contrary to previous observations. The application of the magnetic field explicitly breaks the
symmetry of the system under the switch of all spins.
Hence, there is now a preferred direction, so one of
the uniform states is raised in energy while the other
is lowered.

Figure 10: Magnetisation versus temperature for a 10 x 10


lattice. The complete set of data points, the selected data
and respective error bars and the fitting model are presented
in red, blue and magenta, respectively. Clearly the graph
is not as clear as for N = 30 (figure 8), for example, which
justifies the difficulty in selecting the appropriate points to
fit the model.

As the name suggests, the universal exponent


should be the same for all states of the same universal-

Magnetization versus Time: Varying Field

1.5

H = 1.0
H = 0.5
H = 0.1
H = 0.5

Magnetization per site []

REFERENCES
[1] L. Onsager, Crystal statistics. i. a twodimensional model with an order-disorder transition, Phys. Rev., vol. 65, pp. 117149, Feb 1944.

0.5
0

[2] C. N. Yang, The spontaneous magnetization


of a two-dimensional ising model, Phys. Rev.,
vol. 85, pp. 808816, Mar 1952.

-0.5
-1
-1.5

100

200

300

400

500

600

700

800

900

1000

Number of Single Time Steps

Figure 11: Magnetisation versus time for varying fields at


temperature T = 3.0 [J/kB ]. Red, green, blue and magenta
data points correspond to H = 1.0, 0.5, 0.1, -0.5 [J/], respectively. It is possible to conclude that increasing the applied field increases the magnetisation, that is, spins become
more aligned. Moreover, switching the sign of the applied
field also switches the magentisation at equilibrium.

CONCLUSIONS

A Monte Carlo method using the Metropolis algorithm was developed to study the properties of a
two-dimensional lattice of spins. A continuous phase
transition was identified at a critical temperature.
Magnetisation, energy and heat capacity were observed to have the same temperature dependence for
different values of N. Below this temperature, spins
tend to align, whereas above it spins are randomly
oriented at equilibrium. The critical temperature
was found to decrease with 1/N 2 and was estimated
as Tc = 2.272 0.004 in the thermodynamic limit
N . The universal exponent was determined
as = 0.109 0.018. When a magnetic field
was applied, only one stable equilibrium state was
found below the critical temperature. Above this
temperature, the magnetisation was determined to be
non-zero and dependent on the magnitude and sign
of the field.

[3] N. Metropolis, A. Rosenbluth, M. Rosenbluth,


A. Teller, and E. Teller, Equation of State Calculations by Fast Computing Machines, Journal of
Chemical Physics, vol. 21, pp. 10871092, June
1953.

Appendix: Program Script

6.1 Matrix.h
// Class of matrices
class Matrix
{
private:
std::vector<double> m_data;
int
m_rows;
int
m_cols;
public:
Matrix( int n_rows, int n_cols, double init = 0.0 )
: m_data( n_rows * n_cols, init ),
m_rows( n_rows ), m_cols( n_cols ) { }
Matrix(){}
double& operator() ( int i, int j )
{
return m_data[i * m_cols + j];
}
};

6.2 ising_bm442.cc
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//

Computing Project, Part II Physics


CRSID bm442
Project A: The Ising Model of a Ferromagnet
The program asks to insert the mode: 1 / 2.
1

Takes M single time steps, saves magnetization


at each time instant in file "M_vs_t.txt" and
automatically shows lattice after the M steps
by calling Gnuplot.

Covers a range of temperatures and saves the


magnetisation per spin, the energy per spin,
their standard deviations and the heat capacity
in file "output.txt"

The initial temperature and field, the size of the


lattice and the number of single steps for mode 1
are set in the main function.

#include <iostream>

#include
#include
#include
#include
#include
#include
#include
#include
#include

<iomanip>
<cmath>
<ctime>
<cstdlib>
<cstdio>
<fstream>
"gsl/gsl_rng.h"
<vector>
"Matrix.h"

#define k_B 1.0

// Boltzmann Constant

// Function that calculates the product of spins for nearest neighbours of one site
double nearest_neighbours( Matrix& lattice, int row, int col, int N)
{
double nn_sum = 0.0;
int a, b, c, d;
// Periodic Boundary Conditions
if ( col - 1 < 0)
{
a = N - 1;
}
else
{
a = col - 1;
}
if ( col + 1 > N - 1)
{
b = 0;
}
else
{
b = col + 1;
}
if ( row - 1 < 0)
{
c = N - 1;
}
else
{
c = row - 1;
}
if ( row + 1 > N - 1)
{
d = 0;
}
else

{
d = row + 1;
}
// 4 nearest neighbours
nn_sum
nn_sum
nn_sum
nn_sum

=
=
=
=

nn_sum
nn_sum
nn_sum
nn_sum

+
+
+
+

((double)lattice(
((double)lattice(
((double)lattice(
((double)lattice(

row,
row,
row,
row,

col
col
col
col

))
))
))
))

*
*
*
*

((double)lattice(
((double)lattice(
((double)lattice(
((double)lattice(

row, a
row, b
c, col
d, col

));
));
));
));

return nn_sum;
}

// Function that calculates the magnetization per site


double magnetisation( Matrix& lattice, int N)
{
double M = 0.0;
for ( int row = 0; row < N; row++ )
{
for ( int col = 0; col < N; col++ )
{
M = M + ((double)lattice( row, col ));
}
}
// Dividing by N2 to get energy per lattice site
return M / (double)pow( N, 2 );
}

// Function that calculates the energy of a spin configuration


double energy( Matrix& lattice, int N, double H )
{
double
J = 1.0;
// Nearest Neighbours Coupling Constant
double
miu = 1.0;
// Magnetic Moment of Electron
double
nn_sum = 0.0;
// Sum over nearest neighbours (initialization)
double
spin_sum = 0.0;
// Sum of spins (initialization)
for ( int row = 0; row < N; row++ )
{
for ( int col = 0; col < N; col++ )
{
nn_sum = nn_sum + nearest_neighbours( lattice, row, col, N );
spin_sum = spin_sum + ((double)lattice( row, col ));
}
}

10

// Avoiding double counting of nearest neighbours interactions


nn_sum = nn_sum / 2.0;
return (-J * nn_sum - H * miu * spin_sum);
}

// Function that returns a random number between 0 and 1 using the GSL function gsl_rng.
double random_generator( unsigned long int seed = 0)
{
static gsl_rng* rng = 0;
if ( rng == 0 ) rng = gsl_rng_alloc( gsl_rng_default );
if ( seed != 0 ) gsl_rng_set( rng, seed );
return gsl_rng_uniform( rng );
}

// Function that flips spin


void flip_spin( Matrix&
{
if (lattice( row, col
{
lattice( row, col )
}
else
{
lattice( row, col )
}
}

lattice, int row, int col )


) == 1.0)
= -1.0;

= 1.0;

// Metropolis Algorithm
void Metropolis( Matrix& lattice, int row, int col, int N, double T, double H )
{
// Creating new microstate with one spin flipped at ( row, col )
Matrix new_microstate( N, N );
for (int i = 0; i < N; i++ )
{
for (int j = 0; j < N; j++ )
{
new_microstate( i, j ) = lattice( i, j );
}
}

11

// All spins equal to previous configuration so far. Flip one spin:


flip_spin( new_microstate, row, col );

// Change in energy for transition


double delta_E = energy( new_microstate, N, H ) - energy( lattice, N, H );
// Random number between 0 and 1
double p = random_generator( );
if ( delta_E < 0.0 )
{
flip_spin( lattice, row, col );
}
else if ( exp(-delta_E/(k_B * T)) > p )
{
flip_spin( lattice, row, col );
}
}

// Function that executes Single Time Step in a regular sequence


void single_Monte_Carlo_step_regular( Matrix& lattice, int N, double T, double H )
{
// Going through all lattice sites to decide whether or not to flip spin
for ( int row = 0; row < N; row++ )
{
for ( int col = 0; col < N; col++ )
{
Metropolis( lattice, row, col, N, T, H );
}
}
}

// Function that executes Single Time Step in a random sequence


void single_Monte_Carlo_step_random( Matrix& lattice, int N, double T, double H )
{
// Going through N2 lattice sites to decide whether or not to flip spin
for ( int i = 0; i < N * N; i++ )
{
int row = (int) (random_generator( ) * (double) N);
int col = (int) (random_generator( ) * (double) N);
Metropolis( lattice, row, col, N, T, H );

12

}
}

// Function that sets initial random set of spins


void initialize_lattice_random( Matrix& lattice, int N )
{
for ( int row = 0; row < N; row++ )
{
for ( int col = 0; col < N; col++ )
{
double q = random_generator( );
if ( q < 0.5 )
{
lattice( row, col ) = 1.0;
}
else
{
lattice( row, col ) = -1.0;
}
}
}
}

// Function that sets initial uniform set of spins


void initialize_lattice_uniform( Matrix& lattice, int N )
{
for ( int row = 0; row < N; row++ )
{
for ( int col = 0; col < N; col++ )
{
lattice( row, col ) = 1.0;
}
}
}
void mode_1( Matrix& lattice, int N, int M, double T_0, double H_0 )
{
double T = T_0;
double H = H_0;
std::ofstream f("init");
f
f
f
f
f
f

<<
<<
<<
<<
<<
<<

"t = 1 \n";
"show grid\n";
"set term x11 persist \n";
"set palette defined (-1 \"black\", 1 \"white\")" << "\n";
"set xrange [1:" << N << "] \n";
"set yrange [1:" << N << "] \n";

13

f << "set xtics 0,1," << N << "\n";


f << "set ytics 0,1," << N << "\n";
f << "plot lattice_data.txt matrix every ::1::(" << N << "+1) with image" << "\n";
f.close();
std::ofstream g("lattice_data.txt");
std::ofstream h("M_vs_t.txt");
for ( int i = 0; i < M; i++ )
{
single_Monte_Carlo_step_regular( lattice, N, T, H );
h << i << " " << magnetisation( lattice, N ) << "\n";
if( i == M - 1 )
{
// To ensure that we start counting spins from row 1 rather than 0
// I add these values, which will not be seen because the range
// goes from 1 to N, thereby neglecting this 0th row
for( int j = 0; j < N + 1; j++ )
{
g << "1 ";
}
g << "\n";
for ( int row = 0; row < N; row++ )
{
// To ensure that we start counting spins from column 1, as above
g << "1 ";
for ( int col = 0; col < N; col++ )
{
g << lattice( row, col ) << " ";
}
g << "\n";
}
}
}
g.close();
h.close();
system("gnuplot init");
}
void mode_2( Matrix& lattice, int N, int M, double T_0, double H_0 )
{
// Initialization of Dummy Variables for calculations

14

double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double

magnetisation_sum
energy_sum
squared_magnetisation_sum
squared_energy_sum
mean_magnetisation
mean_energy
mean_energy_per_site
mean_squared_magnetisation
mean_squared_energy
squared_std_magnetisation
std_magnetisation
squared_std_energy
std_energy
heat_capacity_1
heat_capacity_2
mean_energy_previous
T_previous

=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=

0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;
0.0;

// Initialization of Temperature and Magnetic Field


double T = T_0;
double H = H_0;

std::ofstream j("output");
while ( T < 3.5 )
{
// More Monte Carlo Steps required to attain equilibrium close to transition
if ( T == T_0 )
{
M = 100;
}
else
{
M = 1000;
}
// Reaching equilibrium
for ( int i = 0; i < M; i++ )
{
single_Monte_Carlo_step_regular( lattice, N, T, H );
}
// Performing calculations of properties of ensemble
for ( int j = 0; j < M; j++ )
{
single_Monte_Carlo_step_regular( lattice, N, T, H );
magnetisation_sum = magnetisation_sum + magnetisation( lattice, N );

15

squared_magnetisation_sum = squared_magnetisation_sum + pow( magnetisation( lattice, N ), 2 );


energy_sum = energy_sum + energy( lattice, N, H );
squared_energy_sum = squared_energy_sum + pow( energy( lattice, N, H ), 2 );
}
// Dividing by number of iterations M to get mean quantities
mean_magnetisation = magnetisation_sum / (double) M;
mean_energy = energy_sum / (double) M;
mean_squared_magnetisation = squared_magnetisation_sum / (double) M;
mean_squared_energy = squared_energy_sum / (double) M;

mean_energy_per_site = mean_energy / (double) (N * N);

squared_std_magnetisation = fabs(mean_squared_magnetisation - pow( mean_magnetisation, 2 ));


std_magnetisation = sqrt(squared_std_magnetisation);
squared_std_energy = fabs(mean_squared_energy - pow( mean_energy, 2 ));
std_energy = sqrt(squared_std_energy);

// Heat Capacity = dE/dT, but we require two values of T, so it has to wait for 2nd loop
if( T > T_0 )
{
heat_capacity_1 = (mean_energy - mean_energy_previous) / (T - T_previous);
}
// Heat Capacity from Fluctuation-Dissipation Theorem
heat_capacity_2 = squared_std_energy / pow( T, 2 );

// Printing to file
j << T << " " << fabs(mean_magnetisation) << " " << mean_energy_per_site << " ";
j << std_magnetisation << " " << std_energy << " ";
j << heat_capacity_1 << " " << heat_capacity_2 << "\n";

// Previous Values of T and <E> are required to compute Heat Capacity = dE/dT
mean_energy_previous = mean_energy;

16

T_previous = T;
// Reinitialization of Summing Variables
energy_sum = 0.0;
magnetisation_sum = 0.0;
squared_energy_sum = 0.0;
squared_magnetisation_sum = 0.0;

// Plots have most of their distinctive features close to critical temperature


// so more data points are required in its vicinity
if ( T < 2.0 || T > 3.0 )
{
T = T + 0.1;
}
else
{
T = T + 0.05;
}
}
}
int main()
{
int
int
Matrix
double
double
int

N = 10;
M = 1000;
lattice( N, N );
T_0 = 1.5;
H_0 = 0.0;
mode;

std::cout << "Insert mode: ";


std::cin >> mode;
// Initializing lattice
initialize_lattice_uniform( lattice, N );
switch (mode)
{
case 1:
mode_1( lattice, N, M, T_0, H_0 );
break;
case 2:
mode_2( lattice, N, M, T_0, H_0 );
break;
default:

17

//
//
//
//
//
//

Size of Spin Lattice


Number of Single Monte Carlo Steps
Square Lattice
Initial Temperature
Initial External Magnetic Field
Selects mode of program

std::cout << "No valid mode selected\n";


break;
}
return 0;
}

18

Anda mungkin juga menyukai