the ising model of a ferromagnet in c++

24

Upload: timgreen

Post on 10-Apr-2015

1.620 views

Category:

Documents


7 download

DESCRIPTION

Cambridge Physics Part II computing project. Ising model of a ferromagnet implemented in C++, with analysis.

TRANSCRIPT

Page 1: The Ising model of a ferromagnet in C++

The Ising Model of a Ferromagnet in C++

Candidate No. 6960S

April 27, 2009

Abstract

The implementation of the Metropolis Monte-Carlo method to solve the Ising model of ferromagnetism is

considered and used to determine the properties of the system. Results include plots of the variation of energy

and magnetisation with temperature, comparisons to the analytic solutions - including a �nding of the criticl

exponent �ts to � = 0:118, and a small run with a non-zero magnetic �eld. Also considered are implementation

details such as stepping methods, initial conditions and various optimisations.

1 The Ising model

The Ising model is a simpli�ed model of ferromag-netism developed by and named after Ernst Ising.It supposes that a ferromagnet can be modelled asa graph of spins Si, each edge Ei$j contributing�SiSjJij to the total system energy (from now on,most references to the mean energy per spin are sim-ply the 'energy')

E = �X

Ei$j

SiSjJij (1)

Usually the interaction energy Jij is considered con-stant for all edges. A uniform magnetic �eld H mightalso be introduced, too.

E = �JX

Ei$j

SiSj � �HX

i

Si (2)

Solving the system is to take this expression for theHamiltonian and determine the partition functionZ =P

e�H=kBT for the system, allowing one to cal-culate various properties such as heat capacity.

Normally solving the system for a regular N -dimensional grid (shown in Figure 1) with n spinsmight be supposed to be O(2n), having to check ev-ery con�guration of spins - however Ising solved themodel for a one dimensional chain in his 1925 PhDthesis. He found that it admitted no phase changes(asymptotic divergences in the heat capcaity for a par-ticular temperature in the limit of an in�nite grid).The model was solved in two dimensions in 1944 byLars Onsager[3]. He discovered a phase change in thesystem at T = Tc, where

Tc =2

ln(1 +p(2))

(3)

C =dE

dT/ ln(jT � Tcj) (4)

For the magnetisation M :

M = (1� sinh(ln(1 +p2)TcT)�4)

1

8 (5)

For T close to T = Tc we can approximate this as

M / (Tc � T )� (6)

Solving higher dimensional systems has beensuggested[1] to be impossible analytically or in apolynomial-time (O(nd)) algorithm, i.e. you mustevaluate every con�guration, which takes exponentialtime - though as the Ising model is a simple planarspecial case of the full general model (di�erent net-work topologies, varying interaction energy) it maystill be tractable in higher dimensions.

2 Implementation

The Ising model is usually implemented numeri-cally as the Metropolis Monte-Carlo algorithm. Thismethod is designed to �nd a thermal equilibrium con-�guration of a system starting from arbitrary condi-tions. The method is to ip a spin if it is energeti-cally favourable (i.e. gives a reduction in E, �E < 0)or if the spin has been deemed to be thermally ex-cited by e��E=kBT > p for p � Uniform(0; 1) (fromnow on, TkB=J is usually just described as T or the

1

Page 2: The Ising model of a ferromagnet in C++

2.1 Algorithm 2

Figure 1: Sample repeat units of the spin network, showing 1D, 2D and 3D grids. The outgoing edges wouldbe connected to another identical unit, and at some point 'wrapped' around to connect one parallel side of thegrid to the other

'temperature'), otherwise leave the spin as it is. Byrepeating this method over all the lattice sites (cov-ering n = ND lattice sites per 'iteration'), the systemshould tend towards the thermal equilibrium. As anin�nite grid is impossible on a computer, a cyclic gridis usually used (analagous to a torus topologically).

There are a number of possible implementations thatmight be �rst investigated, including whether or notthe spins should be ipped in grid order or at random,and whether the system should be started in a ran-dom con�guration with the spins randomly aligned upor down or a fully ordered con�guration with all thespins aligned in a single direction. Another questionis the grid size required to give a satisfactory result,and what optimizations might be applied to the sim-ulation code compared to a na��ve implementation.

The code itself is a templated class called Ising< D >,the D parameter being the integral number of di-mensions for the model. The public methods for theclass allow: setting up the grid; calculating the overallproperties of the system; stepping the system by oneiteration using the linear and random method; andoutputting the grid (best in 2D) to an std :: ostream.

2.1 Algorithm

The basic algorithm is outlined below, neglecting ini-tialization code and some calculations (such as theerror in the energy and magnetisation). Full code list-ings are in the appendix. The main loop is as follows:

for(int i=0; i<max_itr; ++i)

{

energy = ising.calculate_energy(\

magnetisation);

std::cout << i << " " << energy <<\

" " << magnetisation << " " <<\

ising\.T << std::endl;

if(i > 100 &&\

error_energy < sigma_tolerance &&\

error_magnetisation < sigma_tolerance)

{

break;

}

ising.flip_all();

}

So this iterates until the iteration counter hits themaximum number of iterations allowed. It calculatesthe mean energy and magnetisation per site for thesystem, outputs it, and then works out if it can stop

Candidate No. 6960S 2 April 27, 2009

Page 3: The Ising model of a ferromagnet in C++

2.3 Finding equilibrium 3

the simulation yet. If not, it proceeds to another seriesof spin ips by calling flip all - which looks like thisfor the linear ipping method:

void flip_linear_all()

{

// Iterate over grid

for(int i = 0; i < grid.size; ++i)

{

int index[D]; get_coord(i, index);

do_flip(index);

}

}

This calls the method do flip, which tests ipping aparticular spin on the grid.

void do_flip(int index[])

{

double flip_prob =\

prob_change_test_flip(index);

if(flip_prob >= 1.0)

flip(index);

else

{

if(flip_prob > rand->get_sample())

{

flip(index);

}

}

}

This implements the basic core algorithm of theMetropolis Monte-Carlo method, by either ippingthe spin if it's energetically favourable, or ipping itby subjecting it to thermal equilibrium.

From this we may also consider a number of di�erentimplementations of the overall algorithm and severalimprovements.

2.2 Di�erent ipping methods

Starting the spins in a random state might be seen tobe less biased and give more opportunity to explorethe full state space, whereas starting the spins in acompletely ordered state might reduce the number ofiterations needed to �nd ordered states of the system.

In addition, the spins can either be ipped in linearlyin-order (as stored in memory in an array) or ran-domly ipping n = ND spins (doesn't have to be ev-ery spin). Flipping linearly in order might be quicker,as all spins are tested, but it might bias us towardscertain con�gurations which might not admit a proper

thermodynamic equilibrium. Random ipping solvesthis but could be slower.

The overall critereon for assessing the e�ectivenessof each method is how many iterations are requiredto reach equilibrium in magnetisation, the fewer thebetter as we need less computation time to get a goodequilibrium value.

As you can see in Figure 2, random starting condi-tions with random stepping takes a long time to reachequilibrium compared to random starting conditionswith linear stepping. Both of these take even longercompared to ordered starting conditions and linearstepping, while this method still �nds the disorderedrandom start just as rapidly. From this, it seems thebest method is ordered starting conditions with linearstepping.

2.3 Finding equilibrium

One more issue is how long to run the simulationfor, or how should we determine we're at equilibrium?In the code, every iteration the total energy and to-tal magnetisation of the system is calculated and themean energy is reassessed, along with the variance inthe energy. We could de�ne the stopping point ofthe simulation as having minimised the error in themean energy per site �E su�ciently. Although the en-ergy and magnetisation aren't strictly independentlyrandomly distributed variables from iteration to it-eration, as they're correlated with the previous andnext iterations, taking the mean over a su�cientlylarge number of iterations to avoid correlation shouldallow us to make this assumption. That we are ex-amining the system at equilibrium helps this, as weexpect to see the system rapidly returning to equilib-rium within a few iterations when displaced and sodestroy long-term correlation. The error in the meanafter I iterations is:

� �E =�EpI

Figure 3 shows the error in the mean energy versus thenumber of iterations required for a number of temper-atures. Somewhere in the region of 1; 000 to 10; 000iterations is required to bring the error down to lessthan 0:001, which seems su�cient considering that �Eis between �2:0 and 2:0. Using this cuto�, the sim-ulation automatically stops when either the error inthe mean energy and magnetisation drops below orwhen the maximum iterations limit is hit.

It might also be possible for the simulation to reachordered states that aren't connected in a reducing-energy sense to a path that actually leads to theproper equilibrium point. Hopefully there is su�-

Candidate No. 6960S 3 April 27, 2009

Page 4: The Ising model of a ferromagnet in C++

2.3 Finding equilibrium 4

0

0.2

0.4

0.6

0.8

1

0 100 200 300 400 500 600 700 800 900 1000

Abso

lute

Mag

net

isat

ion p

er s

ite

Iteration number

Iterated evolution of magnetisation for random starting conditions and random stepping

Random-random T=2.8Random-random T=1.8

0

0.2

0.4

0.6

0.8

1

0 100 200 300 400 500 600 700 800 900 1000

Abso

lute

Mag

net

isat

ion p

er s

ite

Iteration number

Iterated evolution of magnetisation for random starting conditions and linear stepping

Random-linear T=2.8Random-linear T=1.8

0

0.2

0.4

0.6

0.8

1

0 100 200 300 400 500 600 700 800 900 1000

Abso

lute

Mag

net

isat

ion p

er s

ite

Iteration number

Iterated evolution of magnetisation for ordered starting conditions and linear stepping

Ordered-linear T=2.8Ordered-linear T=1.8

Figure 2: Di�erent iteration methods, also showing time evolution of the system above and below the criticalpoint.

0.0001

0.001

0.01

0.1

1

1 10 100 1000 10000

sig

ma/

sqrt

(n)

Iteration number

Estimated error in estimated mean energy for iterations

T=1.4T=2.2T=2.8

Figure 3: Estimation of the error in the mean energy for increasing iteration number, over a number of di�erenttemperatures.

Candidate No. 6960S 4 April 27, 2009

Page 5: The Ising model of a ferromagnet in C++

2.5 Scaling of grid size 5

Optimization Run time Improvement-O3 52:9� 1:8sExponential function 34:2� 1:0s 35.4%signed char 31:9� 2:3s 6.5%int 32:3� 1:7s -1.3%-funroll-loops 30:0� 1:9s 6.0%Wrapping function 28:5� 1:5s 5.0%

Table 1: Various optimizations applied to the codecumulatively. Time is for 10,000 iterations of a 128�128 grid at T = 2:2, averaged over �ve runs

cient thermal randomisation that this won't happen,but the system reaching a false-equilibrium should bewatched for - probably easiest by considering the con-text of the equilibrium to systems at a similar tem-perature.

2.4 Optimisation

Starting with the initial code in which the spins arestored as an array of doubles and everything imple-mented in the simplest way, we can apply a numberof useful optimizations.

First, as described by Nonnenmacher[2], we canreplace the exponential function which calculatese��E=kBT to decide whether or not to thermally ip aspin. As each spin has only four neighbours, �E canonly be one of nine values for each total neighbouringspinP

Ei$jSj = (�4; ::; 4). If we include a non-zero

magnetic �eld, this is also doubled representing thespin being up or down with respect to the �eld. As ex-ponential is quite an expensive function numerically,we can precompute all these values. Table 1 showsthat this gives an impressive 35:4% decrease in runtime.

A further optimization we can add is to store the spinsas signed char (1 byte, 16kB for 128� 128) insteadof double (8 byte, 128kB for 128�128), although less exible if we want to allow states other than fully upand fully down. By avoiding having to do oatingpoint addition and instead doing integral addition,this might be faster. In addition, this might be fasterdue to reduced memory usage - or slightly slower duememory alignment. This is tested by using int (4byte, 64kB for 128� 128) as well as signed char. Asyou can see in Table 1, using signed char gives a6:5% speedup, while int gives a small speedup, butstill 1:3% slower than signed char.

Another optimization is to apply loop unrolling inthe compiler using�funroll� loops, which expandsfor loops when the loop constant is known at compiletime - particually applicable given the loops that iter-ate over the number of dimensions given. This givesa 6:0% decrease in time.

Finally, we can change the wrapping function. As thisis called about 2�D�ND for a D-dimensional grid Nspins on the side, or for a 128�128 grid about 65,536times per iteration and tens of millions of times perrun, it is worth looking at for possible changes. The�rst implementation is:

int wrap(int a, int b)

{

if(a >= b)

return wrap(a - b, b);

else if(a < 0)

return wrap(a + b, b);

else

return a;

}

However, if we reorder this to have the most com-mon case �rst and remove the recursive calls (we'renever more than a grid width away from the wrappedlocation), we get

int wrap(int a, int b)

{

if (a >= 0 && a < b)

return a;

else if(a >= b)

return a - b;

else

return a + b;

}

As you can see in Table 1, this gives about a 5:0%decrease in run time.

2.5 Scaling of grid size

We can �nally consider how the grid size (N) a�ectsthe simulation, and possibly what the appropriategrid size is.

The larger the grid size, we might expect lower energyvariance as a proportion of energy, as a single displace-ment is a smaller proportion of the total. This meansthat the larger the grid size, the fewer iterations weneed to get the error in the estimated mean systemenergy to our target error:

�2�E =�2EI

Figure 5 shows the number of iterations required toget the target error in the mean (� �E = 0:001). As youcan see, the number of iterations falls o� with roughlythis model:

Candidate No. 6960S 5 April 27, 2009

Page 6: The Ising model of a ferromagnet in C++

2.5 Scaling of grid size 6

0.1

1

10

100

10 100 1000

Tim

e /

s

N (grid size)

Scaling of time taken for 10,000 iterations versus grid size

DataN

2 model

Figure 4: Amount of time needed to run 10,000 iterations for varying grid size N .

0

2000

4000

6000

8000

10000

12000

0 100 200 300 400 500 600 700 800 900 1000 1100

I

N

Iterations needed to reach sigmaE = 0.001 for varying N

T=1.5Model T=1.5

T=2.0Model T=2.0

T=2.2Model T=2.2

T=3.0Model T=3.0

Figure 5: Number of iterations required to give the error in the mean energy and magnetisation of 0:001 forvarying grid size N . The model fails for T = 2:2 but �ts well for others.

Candidate No. 6960S 6 April 27, 2009

Page 7: The Ising model of a ferromagnet in C++

7

0

50

100

150

200

250

300

0 100 200 300 400 500 600 700 800 900 1000 1100

t

N

Time needed to reach sigmaE = 0.001 for varying N

T=1.5Model T=1.5

T=2.0Model T=2.0

T=2.2Model T=2.2

T=3.0Model T=3.0

Figure 6: Total time required to reduce the error in the mean energy and magnetisation to the threshold forvarying grid size N .

I(N) =�

N2+ �

Using this, we can also work out how much time isrequired to get the target accuracy and whether anyparticular grid size can achieve this faster than an-other. Figure 4 shows how the run time is propor-tional to N2 and I, suggesting this model:

t(I;N) / N2I

On the system used to run the code, the constant ofproportionality was around titr = 137ns. Combiningthis with the expression for I(N) we get:

t(N) = (�

N2+ �)N2titr

A plot of this is shown in Figure 6 for the calculatedvalues. As you can see, the time taken scales inde�-nitely - indicating that it's best to have a small a gridas you can get away with, though the increase is quiteslight for lower temperatures.

We will continue calculations using N = 128, N = 32and N = 16 to determine if there are any other dif-ferences in grid size that must be taken into account,since Onsager's expressions are only truly valid for

an in�nite grid - not a �nite coordinate-wrapped gridin which there could be slightly di�erent phenomena,especially since there cannot be a true heat capacitydivergence for the �nite system.

3 Results and Discussion

3.1 Energy and magnetisation

By running the simulation over a large range of tem-peratures we can work out the mean energy and mag-netisation around the region of the phase change, andthus try to assess how well the simulation reproducesthe model. The ranges used to give su�cient resolu-tion around the areas of high slope while not spendingtoo long in low slope areas were.

T = 0:500! 4:000 in steps of 0:500

T = 1:000! 2:900 in steps of 0:100

T = 2:100! 2:500 in steps of 0:025

T = 2:240! 2:350 in steps of 0:005

This gives 54 simulation runs in total.

Candidate No. 6960S 7 April 27, 2009

Page 8: The Ising model of a ferromagnet in C++

3.1 Energy and magnetisation 8

-2

-1.8

-1.6

-1.4

-1.2

-1

-0.8

-0.6

-0.4

0.5 1 1.5 2 2.5 3 3.5 4

En

erg

y p

er s

ite

TkB/J

Mean energy at equilibrium for varying temperature

128x12832x3216x16

Figure 7: The mean system energy per spin (averaged over multiple iterations at each temperature). You cansee evidence of the phase change at the point of in ection around 2.2

0

0.1

0.2

0.3

0.4

0.5

0.6

0.7

0.8

0.9

1

0.5 1 1.5 2 2.5 3 3.5 4

Mag

net

isat

ion

per

sit

e

TkB/J

Magnetisation at equilibrium for varying temperature

128x12832x32

16x316

Figure 8: The mean magnetisation of the system per spin, again averaged over multiple iterations at eachtemperature. The phase change is much more clear here, showing up as a very sharp cut in the magnetisationat the critical temperature.

Candidate No. 6960S 8 April 27, 2009

Page 9: The Ising model of a ferromagnet in C++

3.2 Heat capacity 9

0

0.2

0.4

0.6

0.8

1

1.2

0.5 1 1.5 2 2.5 3 3.5 4

Mag

net

isat

ion

per

sit

e

T / (J/kB)

Fits of models to Magnetisation vs. Temperature

128x128 simulationApproximation

Exact

Figure 9: The two models for the magnetisation in Equations 5 and 6. The �rst gives a value of Tc = 2:273,and the second gives Tc = 2:274 and � = 0:118.

From this a number of scripts were use to calculatethe mean system energy and magnetisation per siteat equilibrium, giving Figures 7 and 8. In both thephase transition at the critical temperature is distinct,though more clearly seen in the magnetisation as thevery sharp drop o� to zero.

We can try to �t the analytic models in Equations 5and 6 in order to estimate Tc and � (= 1

8 analytically).These results are summarized in Table 2, along withother methods for estimating Tc from the data.

Since in Figures 7 and 8 the same results are plot-ted for N = 128; 32; 16 we can also consider how de-creasing grid size a�ects our results. It can be clearlyseen that in the energy versus temperature graph thecurve underestimates the energy around and abovethe critical temperature by signi�cant amount, andapparently more so for a lower grid size. This couldmean that Tc will be more overestimated the smallerN is, though the di�erence between N = 128 andN = 32 suggests it may be rapidly convergent for rela-tively low N . Other than this area around the criticaltemperature, the di�erent grid sizes agree well on themean system energy per spin and its variation withtemperature.

For the magnetisation, the smaller grid sizes appear tohave signi�cant problems in reproducing the smoothcurve up to the critical temperature, only N = 128being able to mimic it accurately.

Model Grid size T �c (T �c � Tc)=TcMagnetisation approx 128 2.2738 0.207%Magnetisation exact 128 2.2734 0.184%dEdT 128 2.272 0.12%dEdT 64 2.271 0.08%dEdT 16 2.272 0.12%�2ET 2 128 2.272 0.12%�2ET 2 64 2.272 0.12%�2ET 2 16 2.299 1.31%

Table 2: Estimates for Tc by various �ts by �tting theanalytic models

All the grid sizes seems to have trouble in reduc-ing noise in the magnetisation just after the phasechange, indicated by the simulation going up to themaximum number of iterations allowed (40,000) forT = 2:27:::2:35 - so not properly reducing the error.Even more computer time might be required.

3.2 Heat capacity

We can estimate the heat capacity of the system bytwo methods. Firstly we can use the basic de�nitionof heat capacity.

Candidate No. 6960S 9 April 27, 2009

Page 10: The Ising model of a ferromagnet in C++

3.2 Heat capacity 10

0

0.5

1

1.5

2

2.5

3

3.5

4

0.5 1 1.5 2 2.5 3 3.5 4

dE

/dT

T / (J/kB)

Heat capacity (dE/dT) of system per site with model vs. Temperature

128x128 simulation128x128 analytic fit

0

0.5

1

1.5

2

2.5

3

3.5

4

0.5 1 1.5 2 2.5 3 3.5 4

dE

/dT

T / (J/kB)

Heat capacity (dE/dT) of system per site with model vs. Temperature

32x32 simulation32x32 analytic fit

0

0.5

1

1.5

2

2.5

3

3.5

4

0.5 1 1.5 2 2.5 3 3.5 4

dE

/dT

T / (J/kB)

Heat capacity (dE/dT) of system per site with model vs. Temperature

16x16 simulation16x16 analytic fit

Figure 10: Heat capacity of the system for varying grid sizes estimated using dEdT . Notice how the peak attens

out and shifts slightly to a higher temperature for smaller grid sizes.

Candidate No. 6960S 10 April 27, 2009

Page 11: The Ising model of a ferromagnet in C++

3.2 Heat capacity 11

0

0.5

1

1.5

2

2.5

3

3.5

4

0.5 1 1.5 2 2.5 3 3.5 4

sigm

a E2/T

2

T / (J/kB)

Heat capacity (sigmaE2/T

2) of system per site with model vs. Temperature

128x128 simulation128x128 analytic fit

0

0.5

1

1.5

2

2.5

3

3.5

4

0.5 1 1.5 2 2.5 3 3.5 4

sigm

a E2/T

2

T / (J/kB)

Heat capacity (sigmaE2/T

2) of system per site with model vs. Temperature

32x32 simulation32x32 analytic fit

0

0.5

1

1.5

2

2.5

3

3.5

4

0.5 1 1.5 2 2.5 3 3.5 4

sigm

a E2/T

2

T / (J/kB)

Heat capacity (sigmaE2/T

2) of system per site with model vs. Temperature

16x16 simulation16x16 analytic fit

Figure 11: Heat capacity of the system for varying grid sizes estimated using�2ET 2 . Once again, and perhaps

more clearly, notice how the peak attens out and shifts slightly to a higher temperature for smaller grid sizes.

Candidate No. 6960S 11 April 27, 2009

Page 12: The Ising model of a ferromagnet in C++

12

C =dE

dT

The result of this is shown in Figure 10. As you cansee, it's fairly noisy even though the energy graphlooked smooth.

Alternatively we can use the uctuation-dissipationtheorem and relate it to the variance in the systemenergy at equilibrium.

C =�2ET 2

The result of this is shown in Figure 11. This gives abetter result than the di�erential as it isn't suscept-able to noise in the gradient. Smoothing could beapplied to relieve this, though it might a�ect somefeatures such as the phase change point.

To both the analytic result in Equation 4 is �tted, andthe resulting estimated Tc are sumarized in Table 2.The Tc is consistently about T = 2:272, which whileprecisely determined doesn't accurately reproduce theanalytic result.

The �ts were quite sensitive to conditions and range,but they indicate that the simulation always overesti-mates the critical temperature. In addition, N = 32appears to give results close to N = 128.

3.3 Con�gurations

In order to illustrate the results, some �nal spin con-�gurations are plotted at a number of temperaturesand grid sizes in Figure 12.

3.4 Magnetic �elds

As the code is capable of handling magnetic �elds,a quick run was performed to get a overall view ofhow a magnetic �eld will a�ect the system. Figure 13shows the energy, magnetisation and heat capacity ofthis system. The broadening and increase in Tc canbe considered an e�ect of the magnetic �eld helpingto retain order. In the limit of larger �H compared tothe interaction energy J , we might expect to simplyend up with a Boltzmann distribution since every spinwill be independent.

This could perhaps be compared to the shift upwardsin Tc for �nite grids, as a �nite grid can allow a non-zero mean bias in the spins to form - once again al-lowing some degree of order to be retained at highertemperatures.

4 Conclusion

The simulation appears to be able to reproduce theresults of Onsager's analytic solutions well and withmodest amounts of computing time.

Although a smaller grid size gives results faster, Tc isconsistantly overestimated and possibly more so thesmaller the grid size due to scale order being retainedat higher temperatures. Increasing the grid size be-yond 128 � 128 might not be worth it, given that itseems to rapidly converge on the correct behaviour inthat area - but further tests are needed, especially re-garding the ability of the larger grid sizes to calculatethe magnetisation accurately, given the problems thateven N = 128 appeared to have.

For calculating the heat-capacity of the system the uctuation-dissipation theorem is the best method,as it is least susceptible to noise.

Regarding the actual implementation of the algo-rithm, it appears that starting the system o� in anordered state and stepping through in a linear fash-ion gives the most rapid convergence to the mean (soreducing computing time) and doesn't adversely af-fect the results. Along with this a number of e�ectiveoptimisations have been described, the most e�ectivebeing the pre-calculation of exponentials.

The code is capable of handling magnetic �elds,though they haven't been considered in depth andcould form further investigation - especially the be-haviour in shifting and broadening the phase changepeak.

Other points for further investigation could be di�er-ent topologies, possibly higher dimensional grids (asallowed for by the general form of the code) or evenrandomly linked topologies, and whether they a�ectthe e�ectiveness of the simulation, and an examina-tion of the order-scale in the con�gurations using thedistance spin-spin correlation function:

�(r) =X

i

X

d(i;j)<r

SiSj

With some appropriate distance metric d(i; j), possi-bly Euclidean, or even Manhattan so as to capture theorder-propagation distance on a discrete grid. Onewould expect this to show a smaller and smaller or-der distance with increasing temperature.

Candidate No. 6960S 12 April 27, 2009

Page 13: The Ising model of a ferromagnet in C++

13

0

20

40

60

80

100

120

0 20 40 60 80 100 120

Final configuration of T=1.500

0

20

40

60

80

100

120

0 20 40 60 80 100 120

Final configuration of T=2.100

0

20

40

60

80

100

120

0 20 40 60 80 100 120

Final configuration of T=2.269

0

20

40

60

80

100

120

0 20 40 60 80 100 120

Final configuration of T=2.270

0

20

40

60

80

100

120

0 20 40 60 80 100 120

Final configuration of T=2.300

0

20

40

60

80

100

120

0 20 40 60 80 100 120

Final configuration of T=4.000

Figure 12: Sample �nal spin con�gurations (i.e. output of the spins once the code either hit the maximumiterations or the error hit the threshold). Black squares represent spin-up and white spin-down. You can see thesort of disorder that is rapidly introduced around the critical point, though there is a degree of order retainedover short ranges

Candidate No. 6960S 13 April 27, 2009

Page 14: The Ising model of a ferromagnet in C++

14

-2.2

-2

-1.8

-1.6

-1.4

-1.2

-1

-0.8

-0.6

-0.4

0.5 1 1.5 2 2.5 3 3.5 4

Mea

n e

ner

gy /

sit

e

T / (J/kB)

Mean energy per site for muH=0.1 and J=1

0.1

0.2

0.3

0.4

0.5

0.6

0.7

0.8

0.9

1

0.5 1 1.5 2 2.5 3 3.5 4

Mea

n m

agnet

isat

ion /

sit

e

T / (J/kB)

Mean magnetisation per site for muH=0.1 and J=1

0

0.0002

0.0004

0.0006

0.0008

0.001

0.0012

0.0014

0.5 1 1.5 2 2.5 3 3.5 4

sigm

a2/T

2

T / (J/kB)

Heat capacity sigma2/T

2 muH=0.1 and J=1

Figure 13: Test run using a magnetic �eld of �H = 0:1 (J �xed at 1), showing broadening of the peak aroundthe phase change, and a shift upwards in the maximum - as one might expect, as the magnetic �eld helps toretain order.

Candidate No. 6960S 14 April 27, 2009

Page 15: The Ising model of a ferromagnet in C++

5.1 Code listings 15

References

[1] Barry A. Cipra. The ising model is np-complete.SIAM News, 33(6), 2000.

[2] Achim Nonnenmacher. Optimization of the isingmodel.

[3] Lars Onsager. A two-dimensional model with anorder-disorder transition. Phys. Rev., 65(3 & 4),1944.

5 Appendix

5.1 Code listings

Candidate No. 6960S 15 April 27, 2009

Page 16: The Ising model of a ferromagnet in C++

5.1 Code listings 16

1u:\compII\project\ising.cpp

#include <iostream>#include <vector>#include <stdlib.h>#include "../common/array.hpp"#include "../common/rand.hpp"#include "ising.hpp"

using namespace tfgg2;

#define GRID_DIMENSIONS 2

// Arguments// 1 - Random seed// 2 - Grid dimension// 3 - Starting temperature// 4 - Starting field// 5 - Number of iterations// 6 - Rate of change of temperature with each iteration// 7 - Tolerence in standard deviation of mean energy and magnetisation. Simulation stops

when they drop below this limitint main(int args, const char *argc[]){ int dimensions[GRID_DIMENSIONS]; int seed = atoi(argc[1]); int itr = atoi(argc[5]); double dT = atof(argc[6]); double sigma_tolerance = atof(argc[7]);

for(int i=0; i<GRID_DIMENSIONS; ++i) dimensions[i] = atoi(argc[2]);

UniformRandom rand_gen(seed);

Ising<GRID_DIMENSIONS> ising(dimensions, &rand_gen); ising.T = atof(argc[3]); ising.H = atof(argc[4]);

ising.pre_calc_exp(); // this has to be disabled if dT != 0.0, as the precalculation is invalid

#ifdef ORDERED ising.set_all(1);#else ising.randomize();#endif

double tot_E = 0.0; double tot_sq_E = 0.0; double tot_M = 0.0; double tot_sq_M = 0.0; int counted = 0;

for(int i=0; i<itr; ++i) { double energy, magnetisation;

energy = ising.calculate_energy(magnetisation);

{ tot_E += energy; tot_sq_E += energy*energy; tot_M += magnetisation; tot_sq_M += magnetisation*magnetisation; counted++;

#ifdef PRINT_ERROR std::cerr << i << " " << tot_E << " " << tot_sq_E << " " << sqrt(tot_sq_E/

counted/counted - tot_E*tot_E/counted/counted/counted) << std::endl;#endif }

std::cout << i << " " << energy << " " << magnetisation << " " << ising.T << std::endl;

Candidate No. 6960S 16 April 27, 2009

Page 17: The Ising model of a ferromagnet in C++

5.1 Code listings 17

2u:\compII\project\ising.cpp

#ifdef FLIP_RANDOM ising.flip_random();#else ising.flip_linear_all();#endif

ising.T += dT;

if(i > 100 && (tot_sq_E - tot_E*tot_E/counted)/counted/counted < sigma_tolerance*sigma_tolerance

&& (tot_sq_M - tot_M*tot_M/counted)/counted/counted < sigma_tolerance*sigma_tolerance)

{ //std::cerr << "Break after " << i << " iterations" << std::endl; break; } }

#ifndef PRINT_ERROR ising.output_grid(std::cerr);#endif

return 0;}

Candidate No. 6960S 17 April 27, 2009

Page 18: The Ising model of a ferromagnet in C++

5.1 Code listings 18

1u:\compII\project\ising.hpp

#ifndef _TFGG2_ISING _#define _TFGG2_ISING _

#include <iostream >#include <cmath >#include <omp. h>#include "../ common/ array . hpp "#include "../ common/ rand . hpp "

using namespace tfgg 2;

#ifdef SCHAR typedef signed char spin ;

typedef int spinsum ;

#elif FLOAT typedef float spin ;

typedef float spinsum ;

#elif INT typedef int spin ;

typedef int spinsum ;

#else typedef double spin ;

typedef double spinsum ;

#endif

/** Ising model . D dimensions .*/template <int D >class Ising{protected : DArray <spin , D> grid ;

spinsum pair _interaction ( int index []) { spinsum c = 0. 0;

for ( int i =0; i <D; ++i ) { int jndex [ D] ; memcpy( jndex , index , sizeof ( int )* D) ;

jndex [ i ] = wrap ( jndex [ i ]+ 1, grid . dimensions [ i ]) ; // Only consider one direction , we wouldn ' t want to double count when iterating over the enti re grid

c += grid [ index ] * grid [ jndex ] ; }

return c ;

} void get _coord ( int i , int * index ) { for ( int j = D- 1; j > - 1; -- j ) { index [ j ] = i / grid . dimensions _prod [ j ] ; i = i % grid . dimensions _prod [ j ] ; } }

double exp _pre _calc [ 18 ] ;public : double J , mu, H, kB, T;

UniformRandom * rand ;

Ising ( const int dimensions [] , UniformRandom * rand _) : grid ( dimensions ) , rand ( rand _) { J = 1. 0; mu = 1. 0; H = 0. 0; kB = 1. 0; T = 1. 0;

Candidate No. 6960S 18 April 27, 2009

Page 19: The Ising model of a ferromagnet in C++

5.1 Code listings 19

2u:\compII\project\ising.hpp

}

void pre _calc _exp () { for ( int c =- 4; c <=4; ++c ) { for ( int i = 0; i < 2; ++i ) { double delta _e = ( J * c + mu* H)* 2. 0*( i * 2- 1) ;

exp _pre _calc [( c +4)* 2+i ] = exp (- delta _e/( kB* T)) ;

// std :: cerr << exp _pre _calc [( c +4)* 2+i ] << std :: endl ; } } }

// c = - 4, .. , 4 // grid _spin = - 1, 1 double look _up_probability ( spinsum c , spin grid _spin ) { return exp _pre _calc [(( int ) c +4)* 2 + (( int ) grid _spin + 1)/ 2] ; }

/** State setting */

/// Randomize all the spins void randomize () { for ( int i =0; i <grid . size ; ++i ) { grid . set ( i , 2*( rand - >get _discrete _sample ())- 1) ; } }

/// Set all spins to a particular value void set _all ( spin v ) { for ( int i =0; i <grid . size ; ++i ) { grid . set ( i , v ) ; } }

/** Energy calculations */ /// Calculate energy of entire system double calculate _energy ( double &magnetisation ) { spinsum pair = 0. 0, background = 0. 0;

// Iterate over grid for ( int i = 0; i < grid . size ; ++i ) { int index [ D] ; get _coord ( i , index ) ; pair += pair _interaction ( index ) ; background += grid [ index ] ; }

magnetisation = (( double ) background ) / grid . size ;

return - J *(( double ) pair ) / grid . size - mu* H* magnetisation ;

}

/// Flip the spin at index void flip ( int index []) { grid [ index ] = grid [ index ] * - 1; }

/// Calculate change in energy for flipping a single sp in /// i . e. calculates delta in energy for the flipped spin and the surrounding adjacent

spins double prob _change _test _flip ( int index [])

Candidate No. 6960S 19 April 27, 2009

Page 20: The Ising model of a ferromagnet in C++

5.1 Code listings 20

3u:\compII\project\ising.hpp

{ spinsum c = 0; spin grid _spin = grid [ index ] ;

for ( int i =0; i <D; ++i ) { int jndex [ D] ; memcpy( jndex , index , sizeof ( int )* D) ; int lndex [ D] ; memcpy( lndex , index , sizeof ( int )* D) ;

jndex [ i ] = wrap ( jndex [ i ]+ 1, grid . dimensions [ i ]) ; // up in coordinate direction lndex [ i ] = wrap ( lndex [ i ]- 1, grid . dimensions [ i ]) ; // down in coordinate

direction

c += grid [ jndex ] ; c += grid [ lndex ] ; }

#ifdef EXP _OPT return look _up_probability ( c , grid _spin ) ;#else return exp (-(( J * c + mu* H)* 2. 0* grid _spin )/( kB* T)) ; // Energy change is - 2*

site _contribution , but energy is also - J and - mu* H times#endif }

/** Ising model routines */

/// Calculate flip energy and perform Ising model for f lipping the spin void do _flip ( int index []) { double flip _prob = prob _change _test _flip ( index ) ;

if ( flip _prob >= 1. 0) // it ' s an advantage to flip this spin , so do it flip ( index ) ; else // it ' s not , so subject it to thermal equilibrium { if ( flip _prob > rand - >get _sample ()) // flip anyway ! { flip ( index ) ; } } }

/// Scheme to go through all the points and flip them i n grid order void flip _linear _all () { // Iterate over grid for ( int i = 0; i < grid . size ; ++i ) { int index [ D] ; get _coord ( i , index ) ; do_flip ( index ) ; } }

/// Scheme to generate N random numbers and test flip e ach one . void flip _random () { // grid . size random points , though not every point in the grid ! // We can parallelize this since it just randomly hops about and only actually

changes the data once it has decided #pragma omp parallel for for ( int i = 0; i < grid . size ; ++i ) { // Could just generate one single random number and th en generate index from

it , but this is probably faster ( test !) int index [ D] ; for ( int j =0; j <D; ++j ) { index [ j ] = rand - >get _discrete _sample ( grid . dimensions [ j ]) ;

}

do_flip ( index ) ; }

Candidate No. 6960S 20 April 27, 2009

Page 21: The Ising model of a ferromagnet in C++

5.1 Code listings 21

4u:\compII\project\ising.hpp

}

void output _grid ( std :: ostream &f ) { int y _coord = 0; for ( int i = 0; i < grid . size ; ++i ) { int index [ D] ; get _coord ( i , index ) ;

if ( y _coord != index [ 1]) { f << std :: endl ; y _coord = index [ 1] ; } f << index [ 0] << " " << index [ 1] << " " << grid [ index ] << std :: endl ; } }};

#endif

Candidate No. 6960S 21 April 27, 2009

Page 22: The Ising model of a ferromagnet in C++

5.1 Code listings 22

1u:\compII\common\array.hpp

#ifndef _TFGG2_ARRAY_#define _TFGG2_ARRAY_

#include <iostream>#include <vector>

namespace tfgg2 {

template<class T, int len>void array_size(const T (&)[len]){ return len;}

template<class T, int len>double array_sum(const T a[]){ double rtn = (T)0.0; for(int i=0; i<len; ++i) rtn += a[i];

return rtn;}

template<class T, int len>T array_dot(T *a, T *b){ T rtn = (T)0.0; for(int i=0; i<len; ++i) rtn += a[i] * b[i];

return rtn;}

template<class T, int len>T array_prod(const T a[]){ T rtn = (T)1.0; for(int i=0; i<len; ++i) rtn *= a[i];

return rtn;}

template <int D, class T>void array_diff(T a[],T b[],T *c[]){ for(int i=0; i<D; ++i) c[i] = a[i] - b[i];}

template<class T, int len>void array_print(const T a[]){ for(int i=0; i<len; ++i) std::cout << a[i] << ", "; std::cout << std::endl;}

#ifdef WRAP_OPTint wrap(int a, int b){ if (a >= 0 && a < b) return a; else if(a >= b) return a - b; else return a + b;}#elif WRAP_OPT_INLINEinline int wrap(int a, int b){ if (a >= 0 && a < b) return a;

Candidate No. 6960S 22 April 27, 2009

Page 23: The Ising model of a ferromagnet in C++

5.1 Code listings 23

2u:\compII\common\array.hpp

else if(a >= b) return a - b; else return a + b;}#elseint wrap(int a, int b){ if(a >= b) return wrap(a - b, b); else if(a < 0) return wrap(a + b, b); else return a;}#endif

template <class T, int D>class DArray{protected: std::vector<T> data;

void init(const int dimensions[]) { size = array_prod<int,D>(dimensions); data.resize(size);

memcpy(this->dimensions, dimensions, sizeof(int)*D);

dimensions_prod[0] = 1; for(int i=0; i<D; ++i) { if(i != 0) dimensions_prod[i] = dimensions[i-1] * dimensions_prod[i-1];

//std::cout << dimensions_prod[i] << std::endl; } }

public: int dimensions[D]; int dimensions_prod[D]; int size;

DArray(const int dimensions[]) { init(dimensions); }

DArray(DArray<T,D> &d) { init(d.dimensions); this->data = d.data; }

T& operator[](int i[]) { return data[array_dot<int, D>(i, (int*)dimensions_prod)]; }

void set(const int i, const T &val) { data[i] = val; }};

}

#endif

Candidate No. 6960S 23 April 27, 2009

Page 24: The Ising model of a ferromagnet in C++

5.1 Code listings 24

1u:\compII\common\rand.hpp

#ifndef _TFGG2_RAND_#define _TFGG2_RAND_

#include <gsl/gsl_rng.h>

namespace tfgg2 {

class UniformRandom{ const gsl_rng_type *type; gsl_rng *rng; int seed;public:

UniformRandom(int _seed, const gsl_rng_type *_type = gsl_rng_taus2) : type(_type) { this->rng = gsl_rng_alloc(_type); this->set_seed(_seed); }

~UniformRandom() { gsl_rng_free(this->rng); }

void set_seed(int _seed) { seed = _seed; gsl_rng_set(this->rng, _seed); }

double get_sample() { return gsl_rng_uniform(this->rng); }

int get_discrete_sample(unsigned long n=2) { return gsl_rng_uniform_int(this->rng, n); }

operator double() { return get_sample(); }};

}

#endif

Candidate No. 6960S 24 April 27, 2009