<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://chemwiki.ch.ic.ac.uk/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ds3012</id>
	<title>ChemWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://chemwiki.ch.ic.ac.uk/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ds3012"/>
	<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/wiki/Special:Contributions/Ds3012"/>
	<updated>2026-05-15T20:13:49Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=490504</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=490504"/>
		<updated>2015-02-27T14:40:59Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Finding the Peak in Heat Capacity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these configurations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Curie Temperature&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27 (J/k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;),&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Chem. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value. Alongside this, some error may also have been derived from the decision of the number of Monte Carlo cycles at which to begin averaging. In order to prevent any issues arriving here, a large number of cycles should be used - this was not implemented here due to the computation time that would be required.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=490484</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=490484"/>
		<updated>2015-02-27T13:12:12Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Introduction to the Monte Carlo simulation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these configurations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Curie Temperature&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27 (J/k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;),&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Chem. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=490206</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=490206"/>
		<updated>2015-02-26T21:53:23Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Finding the Peak in Heat Capacity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Curie Temperature&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27 (J/k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;),&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Chem. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489883</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489883"/>
		<updated>2015-02-26T10:31:45Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Finding the Peak in Heat Capacity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Curie Temperature&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27 (J/k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;),&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489881</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489881"/>
		<updated>2015-02-26T10:24:11Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* The effect of system size */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489879</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489879"/>
		<updated>2015-02-26T10:23:35Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Simulating the Monte Carlo Cycles */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489878</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489878"/>
		<updated>2015-02-26T10:21:35Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Simulating the Monte Carlo Cycles */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489877</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489877"/>
		<updated>2015-02-26T10:21:20Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Modifying IsingLattice.py to Implement a Monte Carlo Cycle */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489876</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489876"/>
		<updated>2015-02-26T10:21:09Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Simulating the Monte Carlo Cycles */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489875</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489875"/>
		<updated>2015-02-26T10:20:52Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Simulating the Monte Carlo Cycles */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489874</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489874"/>
		<updated>2015-02-26T10:20:40Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Average Energy and Magnetisation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489873</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489873"/>
		<updated>2015-02-26T10:20:21Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Introduction to the Monte Carlo simulation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489872</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489872"/>
		<updated>2015-02-26T10:19:36Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Spin &amp;#039;flipping&amp;#039; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489871</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489871"/>
		<updated>2015-02-26T10:18:27Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Magnetisation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system with 1000 spins at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489870</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489870"/>
		<updated>2015-02-26T10:16:48Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Magnetisation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatleft&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489869</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489869"/>
		<updated>2015-02-26T10:16:09Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* The effect of system size */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, whilst minimising the computational time required, an 8x8 lattice is likely to be the optimum choice. This is because the graph for this system size is comparable to that for a 32x32 lattice, whilst being faster to compute.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489866</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489866"/>
		<updated>2015-02-26T10:04:39Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Finding the Peak in Heat Capacity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Phys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489723</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489723"/>
		<updated>2015-02-25T16:13:20Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Finding the Peak in Heat Capacity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27,&amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Whys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt; which indicates a good agreement between the value calculated in this investigation and the theoretical exact value. This is surprising given that it would be expected that the polynomial fitting of the data to locate the maximum would contribute a considerable degree of error to the final value.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489719</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489719"/>
		<updated>2015-02-25T16:10:25Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27 &amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Whys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489717</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489717"/>
		<updated>2015-02-25T16:09:40Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Finding the Peak in Heat Capacity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared to the theoretical exact value of 2.27 &amp;lt;ref&amp;gt;D. K. Khudier, N. I. Fawaz, &#039;&#039;Int. Lett. Them. Whys. Astron.&#039;&#039;, 2013, &#039;&#039;&#039;10&#039;&#039;&#039;, 201-212. Available from: http://www.ilcpa.pl/wp-content/uploads/2012/11/ILCPA-102-2013-201-2121.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489715</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489715"/>
		<updated>2015-02-25T16:03:19Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Finding the Peak in Heat Capacity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
[[File:DMSCurieTemperature.png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 11&#039;&#039;&#039;: Curie temperature vs. 1/(lattice length), with extrapolated linear fit&#039;&#039;]]&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. This value can be compared &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMSCurieTemperature.png&amp;diff=489713</id>
		<title>File:DMSCurieTemperature.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMSCurieTemperature.png&amp;diff=489713"/>
		<updated>2015-02-25T15:57:05Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-11&amp;diff=489712</id>
		<title>Rep:Mod:DMS3053-11</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-11&amp;diff=489712"/>
		<updated>2015-02-25T15:55:29Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: Created page with &amp;quot;    from matplotlib import pylab as pl     import numpy as np     from scipy.interpolate import InterpolatedUnivariateSpline      def extract_data(file):         data_array =...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;    from matplotlib import pylab as pl&lt;br /&gt;
    import numpy as np&lt;br /&gt;
    from scipy.interpolate import InterpolatedUnivariateSpline&lt;br /&gt;
&lt;br /&gt;
    def extract_data(file):&lt;br /&gt;
        data_array = np.loadtxt(file)&lt;br /&gt;
        lattice_lengths = data_array[:,0]&lt;br /&gt;
        inverse_lengths = 1 / lattice_lengths&lt;br /&gt;
        curie_temps = data_array[:,1]&lt;br /&gt;
        return inverse_lengths, curie_temps&lt;br /&gt;
    &lt;br /&gt;
    def plotdata(file):&lt;br /&gt;
        file_data = extract_data(file)&lt;br /&gt;
        L_min = np.min(file_data[0])&lt;br /&gt;
        L_max = np.max(file_data[0])&lt;br /&gt;
        L_range = np.linspace(L_min, L_max, 1000) # Generates 1000 evenly spaced points between T_min and T_max&lt;br /&gt;
        L_range1 = np.linspace(0, L_max, 1000) # Range for extrapolation to y-axis&lt;br /&gt;
        fit = np.polyfit(file_data[0], file_data[1], 1)&lt;br /&gt;
        fitted_T_values = np.polyval(fit, L_range)&lt;br /&gt;
        extrapolation = InterpolatedUnivariateSpline(L_range, fitted_T_values, k=1) # Allows for extrapolation of the fit to find intercept accurately&lt;br /&gt;
        T_values = extrapolation(L_range1) # Calculates the extrapolated temperatures&lt;br /&gt;
        pl.ylabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
        pl.xlabel(&amp;quot;1/(Lattice Length)&amp;quot;)&lt;br /&gt;
        pl.ylim([2.2, 2.6])&lt;br /&gt;
        pl.plot(file_data[0], file_data[1], L_range1, T_values)&lt;br /&gt;
        pl.legend([&#039;Data&#039;, &#039;Extrapolated linear fit&#039;], loc=&#039;upper center&#039;, bbox_to_anchor=(0.5, 1.10),&lt;br /&gt;
              ncol=2)&lt;br /&gt;
        pl.show()&lt;br /&gt;
        print(T_values[L_range1 == 0]) # Prints the y-intercept of the graph&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489711</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489711"/>
		<updated>2015-02-25T15:54:18Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Finding the Peak in Heat Capacity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 8: Lattice sizes and their corresponding Curie temperatures&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 2.53503504&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 2.43843844 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 2.33433433 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 2.30455455 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 2.27752753 &lt;br /&gt;
|}&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489710</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489710"/>
		<updated>2015-02-25T15:52:39Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Finding the Peak in Heat Capacity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. 10)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489708</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489708"/>
		<updated>2015-02-25T15:51:46Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Locating the Curie temperature */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&lt;br /&gt;
===Finding the Peak in Heat Capacity===&lt;br /&gt;
In order to find the Curie temperature for an infinite Ising Lattice, the Curie temperature for each system size considered was first found (using the script shown in the previous exercise). These temperatures were then saved to a .dat file (whose contents are also showed in &#039;&#039;Table 8&#039;&#039;, along with their corresponding lattice sizes. Finally, using the script presented [[Mod:DMS3053-11|here]], a graph of Curie temperature versus the inverse of the lattice length was plotted, according to the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;T_{C, L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &#039;&#039;(eq. X)&lt;br /&gt;
where &amp;lt;math&amp;gt;T_{C, L}&amp;lt;/math&amp;gt; is the Curie temperature for a lattice with length L and &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; is the Curie temperature for an infinite Ising lattice. Hence, it is clear that the desired Curie temperature must be the y-intercept of the graph shown in &#039;&#039;Figure 11&#039;&#039; (hence the use of extrapolation in the python script). Taking this extrapolated value gives a Curie temperature of 2.271. &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-10&amp;diff=489702</id>
		<title>Rep:Mod:DMS3053-10</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-10&amp;diff=489702"/>
		<updated>2015-02-25T15:38:42Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: Created page with &amp;quot;    from matplotlib import pylab as pl     import numpy as np      def extract_data_c(file):         data_array = np.loadtxt(file)         temps = data_array[:,0]         heat...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;    from matplotlib import pylab as pl&lt;br /&gt;
    import numpy as np&lt;br /&gt;
&lt;br /&gt;
    def extract_data_c(file):&lt;br /&gt;
        data_array = np.loadtxt(file)&lt;br /&gt;
        temps = data_array[:,0]&lt;br /&gt;
        heat_cap_per_spin = data_array[:,5]&lt;br /&gt;
        return temps, heat_cap_per_spin&lt;br /&gt;
    &lt;br /&gt;
    def plotdata(file):&lt;br /&gt;
        file_data = extract_data_c(file)&lt;br /&gt;
        T_min = 2.15&lt;br /&gt;
        T_max = 2.55 # Min and Max altered to get good peak fit&lt;br /&gt;
        T_range = np.linspace(T_min, T_max, 1000) #g= Generates 1000 evenly spaced points between T_min and T_max&lt;br /&gt;
        selection = np.logical_and(file_data[0] &amp;gt; T_min, file_data[0] &amp;lt; T_max) # Selects rows of data for which both conditions are met&lt;br /&gt;
        peak_T_values = file_data[0][selection] # Selects the appropriate temperature values&lt;br /&gt;
        peak_C_values = file_data[1][selection] # Selects the appropriate heat capacity values&lt;br /&gt;
        fit = np.polyfit(peak_T_values, peak_C_values, 3) # Fits a third order polynomial&lt;br /&gt;
        fitted_C_values = np.polyval(fit, T_range) # Uses the fit object to generate the corresponding values of C&lt;br /&gt;
        Cmax = np.max(fitted_C_values) # Locates the maximum in heat capacity&lt;br /&gt;
        Tmax = T_range[fitted_C_values == Cmax] # Locates the corresponding value of temperature&lt;br /&gt;
        pl.ylabel(&amp;quot;Heat Capacity&amp;quot;)&lt;br /&gt;
        pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
        pl.ylim([0.0, 2.0])&lt;br /&gt;
        pl.plot(file_data[0], file_data[1], T_range, fitted_C_values)&lt;br /&gt;
        pl.legend([&#039;Data&#039;, &#039;Polynomial fit&#039;], loc=&#039;upper center&#039;, bbox_to_anchor=(0.5, 1.10),&lt;br /&gt;
              ncol=5)&lt;br /&gt;
        pl.show()&lt;br /&gt;
        print(Cmax)&lt;br /&gt;
        print(Tmax)&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489698</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489698"/>
		<updated>2015-02-25T15:35:21Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Polynomial Fitting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|left|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489696</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489696"/>
		<updated>2015-02-25T15:34:47Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Locating the Curie temperature */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
===Fitting in a Particular Temperature Range===&lt;br /&gt;
[[File:DMS8x8peak(3).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 10&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with peak polynomial fit&#039;&#039;]]&lt;br /&gt;
As was observed in the previous exercise, large polynomial orders are required to fit the C++ data well across the whole temperature range. The python script was modified to that presented [[Mod:DMS3053-10|here]] (this script also contains the python code to compute the maximum heat capacity and temperature at which this occurs for the following exercise), which fits a polynomial only in the region of the maximum heat capacity for the system. An example of such fit is shown in &#039;&#039;Figure 10&#039;&#039; for the 8x8 system. Here, it should be noted that for all of the system sizes studied, a polynomial order of 3 was used - this is a clear improvement compared to the 13th order polynomials used previously.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS8x8peak(3).png&amp;diff=489695</id>
		<title>File:DMS8x8peak(3).png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS8x8peak(3).png&amp;diff=489695"/>
		<updated>2015-02-25T15:34:17Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-8&amp;diff=489653</id>
		<title>Rep:Mod:DMS3053-8</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-8&amp;diff=489653"/>
		<updated>2015-02-25T13:42:55Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: Created page with &amp;quot;    from matplotlib import pylab as pl     import numpy as np      def extract_data_c(file):         data_array = np.loadtxt(file)         temps = data_array[:,0]         heat...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;    from matplotlib import pylab as pl&lt;br /&gt;
    import numpy as np&lt;br /&gt;
&lt;br /&gt;
    def extract_data_c(file):&lt;br /&gt;
        data_array = np.loadtxt(file)&lt;br /&gt;
        temps = data_array[:,0]&lt;br /&gt;
        heat_cap_per_spin = data_array[:,5]&lt;br /&gt;
        return temps, heat_cap_per_spin&lt;br /&gt;
&lt;br /&gt;
    def extract_data(file):&lt;br /&gt;
        data_array = np.loadtxt(file)&lt;br /&gt;
        list = file.split(&amp;quot;x&amp;quot;) # Splits the file name to find the lattice size&lt;br /&gt;
        spin = int(list[0])&lt;br /&gt;
        spins = spin*spin # Provided that the lattice in use is square&lt;br /&gt;
        temps = data_array[:,0]&lt;br /&gt;
        energies = data_array[:,1]&lt;br /&gt;
        squared_energies = data_array[:,2]&lt;br /&gt;
        variance = squared_energies - (energies*energies)&lt;br /&gt;
        heat_capacity = variance / (temps*temps)&lt;br /&gt;
        heat_cap_per_spin = heat_capacity / spins&lt;br /&gt;
        return temps, heat_cap_per_spin&lt;br /&gt;
    &lt;br /&gt;
    def plotdata(fileC, filePY):&lt;br /&gt;
        fileC_data = extract_data_c(fileC)&lt;br /&gt;
        filePY_data = extract_data(filePY)&lt;br /&gt;
        pl.ylabel(&amp;quot;Heat Capacity&amp;quot;)&lt;br /&gt;
        pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
        pl.ylim([0.0, 2.0])&lt;br /&gt;
        pl.plot(fileC_data[0], fileC_data[1], filePY_data[0], filePY_data[1])&lt;br /&gt;
        pl.legend([&#039;C++&#039;, &#039;Python&#039;], loc=&#039;upper center&#039;, bbox_to_anchor=(0.5, 1.10),&lt;br /&gt;
              ncol=5)&lt;br /&gt;
        pl.show()&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489651</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489651"/>
		<updated>2015-02-25T13:40:52Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Comparison with C++ Data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 4x4 || 8x8&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 32x32&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489499</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489499"/>
		<updated>2015-02-24T16:06:50Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Polynomial Fitting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
[[File:Py8x8(13fit).png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 9&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for Python data for 8x8 system with a 13th order polynomial fit&#039;&#039;]]&lt;br /&gt;
For comparison, a 13th order polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;. Here, it is evident that for this data, a higher order polynomial is required to obtain a fit comparable to that for the C++ data above.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Py8x8(13fit).png&amp;diff=489497</id>
		<title>File:Py8x8(13fit).png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Py8x8(13fit).png&amp;diff=489497"/>
		<updated>2015-02-24T16:05:56Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489494</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489494"/>
		<updated>2015-02-24T16:03:10Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Polynomial Fitting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
[[File:DMS8x8513.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 8&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for 8x8 system with two polynomial fits&#039;&#039;]]&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure 8&#039;&#039;, where the polynomial fit is shown for orders 5 and 13. A consideration of this graph reveals that whilst a polynomial of order 5 may be appropriate for a 2x2 system, it is inadequate for the larger system of 8x8. Whilst an order of 13 substantially improves the polynomial fit, one must, in general, take care with &#039;overfitting&#039; data.&lt;br /&gt;
&lt;br /&gt;
For comparison, a polynomial was fitted to the 8x8 Python data previously computed - this is shown in &#039;&#039;Figure 9&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS8x8513.png&amp;diff=489492</id>
		<title>File:DMS8x8513.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS8x8513.png&amp;diff=489492"/>
		<updated>2015-02-24T16:00:28Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489490</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489490"/>
		<updated>2015-02-24T15:59:38Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Polynomial Fitting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]]. For this fitting, it was found that a polynomial order of 5 was required to provide a good fit for the 2x2 data - this increased significantly as the lattice size increased. An example fit is shown for the 8x8 system in &#039;&#039;Figure X&#039;&#039;, where the polynomial fit is shown for orders 5 and 13.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-9&amp;diff=489480</id>
		<title>Rep:Mod:DMS3053-9</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-9&amp;diff=489480"/>
		<updated>2015-02-24T15:48:59Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: Created page with &amp;quot;    from matplotlib import pylab as pl     import numpy as np      def extract_data(file):         data_array = np.loadtxt(file)         temps = data_array[:,0]         heat_c...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;    from matplotlib import pylab as pl&lt;br /&gt;
    import numpy as np&lt;br /&gt;
&lt;br /&gt;
    def extract_data(file):&lt;br /&gt;
        data_array = np.loadtxt(file)&lt;br /&gt;
        temps = data_array[:,0]&lt;br /&gt;
        heat_cap_per_spin = data_array[:,5]&lt;br /&gt;
        return temps, heat_cap_per_spin&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    def plotdata(file):&lt;br /&gt;
        file_data = extract_data(file)&lt;br /&gt;
        fit = np.polyfit(file_data[0], file_data[1], 11) # fit a third order polynomial&lt;br /&gt;
        T_min = np.min(file_data[0])&lt;br /&gt;
        T_max = np.max(file_data[0])&lt;br /&gt;
        T_range = np.linspace(T_min, T_max, 1000) #generate 1000 evenly spaced points between T_min and T_max&lt;br /&gt;
        fitted_C_values = np.polyval(fit, T_range) # use the fit object to generate the corresponding values of C&lt;br /&gt;
        pl.ylabel(&amp;quot;Heat Capacity&amp;quot;)&lt;br /&gt;
        pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
        pl.ylim([0.0, 1.5])&lt;br /&gt;
        pl.plot(file_data[0], file_data[1], T_range, fitted_C_values)&lt;br /&gt;
        pl.legend([&#039;Data&#039;, &#039;Polynomial fit&#039;], loc=&#039;upper center&#039;, bbox_to_anchor=(0.5, 1.10),&lt;br /&gt;
              ncol=5)&lt;br /&gt;
        pl.show()&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489479</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489479"/>
		<updated>2015-02-24T15:48:11Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Polynomial Fitting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
In order to make use of the C++ data in finding the Curie temperature for the Ising Lattices under consideration, polynomials were fit to the data - the script written for this purpose is shown [[Mod:DMS3053-9|here]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-temprange&amp;diff=489477</id>
		<title>Rep:Mod:DMS3053-temprange</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-temprange&amp;diff=489477"/>
		<updated>2015-02-24T15:39:09Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: Created page with &amp;quot;    from IsingLattice import *     from matplotlib import pylab as pl     import numpy as np      n_rows = 32     n_cols = 32     il = IsingLattice(n_rows, n_cols)     il.latt...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;    from IsingLattice import *&lt;br /&gt;
    from matplotlib import pylab as pl&lt;br /&gt;
    import numpy as np&lt;br /&gt;
&lt;br /&gt;
    n_rows = 32&lt;br /&gt;
    n_cols = 32&lt;br /&gt;
    il = IsingLattice(n_rows, n_cols)&lt;br /&gt;
    il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
    spins = n_rows*n_cols&lt;br /&gt;
    runtime = 1000&lt;br /&gt;
    times = range(runtime)&lt;br /&gt;
    temps = np.arange(0.25, 5.25, 0.25)&lt;br /&gt;
    energies = []&lt;br /&gt;
    magnetisations = []&lt;br /&gt;
    energysq = []&lt;br /&gt;
    magnetisationsq = []&lt;br /&gt;
    E_errors = []&lt;br /&gt;
    M_errors = []&lt;br /&gt;
    for t in temps:&lt;br /&gt;
        for i in times:&lt;br /&gt;
            if i % 100 == 0:&lt;br /&gt;
                print(t, i)&lt;br /&gt;
            energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
        aveE, aveE2, aveM, aveM2, n_cycles, std_errorE, std_errorM = il.statistics()&lt;br /&gt;
        energies.append(aveE)&lt;br /&gt;
        energysq.append(aveE2)&lt;br /&gt;
        magnetisations.append(aveM)&lt;br /&gt;
        magnetisationsq.append(aveM2)&lt;br /&gt;
        E_errors.append(std_errorE)&lt;br /&gt;
        M_errors.append(std_errorM)&lt;br /&gt;
        #reset the IL object for the next cycle&lt;br /&gt;
        il.E = 0.0&lt;br /&gt;
        il.E2 = 0.0&lt;br /&gt;
        il.M = 0.0&lt;br /&gt;
        il.M2 = 0.0&lt;br /&gt;
        il.n_cycles = 0&lt;br /&gt;
    fig = pl.figure()&lt;br /&gt;
    enerax = fig.add_subplot(2,1,1)&lt;br /&gt;
    enerax.set_ylabel(&amp;quot;Energy per spin&amp;quot;)&lt;br /&gt;
    enerax.set_xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
    enerax.set_ylim([-2.1, 2.1])&lt;br /&gt;
    magax = fig.add_subplot(2,1,2)&lt;br /&gt;
    magax.set_ylabel(&amp;quot;Magnetisation per spin&amp;quot;)&lt;br /&gt;
    magax.set_xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
    magax.set_ylim([-1.1, 1.1])&lt;br /&gt;
    enerax.plot(temps, np.array(energies)/spins)&lt;br /&gt;
    enerax.errorbar(temps, np.array(energies)/spins, xerr = 0, yerr = np.array(E_errors)/spins)&lt;br /&gt;
    magax.plot(temps, np.array(magnetisations)/spins)&lt;br /&gt;
    magax.errorbar(temps, np.array(magnetisations)/spins, xerr = 0, yerr = np.array(M_errors)/spins)&lt;br /&gt;
    pl.show()&lt;br /&gt;
&lt;br /&gt;
    final_data = np.column_stack((temps, energies, energysq, magnetisations, magnetisationsq))&lt;br /&gt;
    np.savetxt(&amp;quot;32x32.dat&amp;quot;, final_data)&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489476</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489476"/>
		<updated>2015-02-24T15:37:07Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Running over a range of temperatures */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file (shown [[Mod:DMS3053-temprange|here]]). Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-5&amp;diff=489475</id>
		<title>Rep:Mod:DMS3053-5</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053-5&amp;diff=489475"/>
		<updated>2015-02-24T15:36:07Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;    import numpy as np&lt;br /&gt;
    from math import exp, sqrt&lt;br /&gt;
&lt;br /&gt;
    class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
        E = 0.0&lt;br /&gt;
        E2 = 0.0&lt;br /&gt;
        M = 0.0&lt;br /&gt;
        M2 = 0.0&lt;br /&gt;
        E_list = []&lt;br /&gt;
        M_list = []&lt;br /&gt;
&lt;br /&gt;
        n_cycles = 0&lt;br /&gt;
        skip_region = 0 # Defines the number of initial cycles not to be averaged for above quantities&lt;br /&gt;
&lt;br /&gt;
        def __init__(self, n_rows, n_cols):&lt;br /&gt;
            self.n_rows = n_rows&lt;br /&gt;
            self.n_cols = n_cols&lt;br /&gt;
            self.lattice = np.random.choice([-1,1], size=(n_rows, n_cols))&lt;br /&gt;
&lt;br /&gt;
        def energy(self):&lt;br /&gt;
            # Returns the total energy of the current lattice configuration.&lt;br /&gt;
            J = 1.0 # Including this factor allows for later modifications&lt;br /&gt;
            summed_spins = np.sum(np.multiply(self.lattice, np.roll(self.lattice, 1, axis = 0)))&lt;br /&gt;
            # Multiplies a spin with its vertical neighbour, via rolling the array, then sums these results&lt;br /&gt;
            summed_spins += np.sum(np.multiply(self.lattice, np.roll(self.lattice, 1, axis = 1)))&lt;br /&gt;
            # Multiplies a spin with its horizontal neighbour, then sums these results&lt;br /&gt;
            energy = - 1.0 * J * summed_spins&lt;br /&gt;
            return energy &lt;br /&gt;
&lt;br /&gt;
        def magnetisation(self):&lt;br /&gt;
            # Returns the total magnetisation of the current lattice configuration.&lt;br /&gt;
            magnetisation = np.sum(self.lattice) # Sums all of the elements of the generated lattice&lt;br /&gt;
            return magnetisation&lt;br /&gt;
        &lt;br /&gt;
        def montecarlostep(self, T):&lt;br /&gt;
            # This function performs a single Monte Carlo step&lt;br /&gt;
            energy = self.energy() # Energies calculated using this function are in units of the Boltzmann constant&lt;br /&gt;
            magnetisation = self.magnetisation()&lt;br /&gt;
            # This section randomly selects the coordinate of the spin to be flipped, then flips it &lt;br /&gt;
            #- generates new configuration&lt;br /&gt;
            random_i = np.random.choice(range(0, self.n_rows))&lt;br /&gt;
            random_j = np.random.choice(range(0, self.n_cols))&lt;br /&gt;
            self.lattice[random_i, random_j] = - self.lattice[random_i, random_j]&lt;br /&gt;
            energy1 = self.energy() # Calculates the energy of the new configuration&lt;br /&gt;
            magnetisation1 = self.magnetisation() # Calculates the magnetisation of the new configuration&lt;br /&gt;
            # The following line selects a random number in the range [0,1) for step 4 below&lt;br /&gt;
            random_number = np.random.random()&lt;br /&gt;
            # This section performs step 4 of the Monte Carlo cycle&lt;br /&gt;
            deltaE = energy1 - energy # Calculates energy difference between &lt;br /&gt;
            #new and original spin arrays&lt;br /&gt;
            if deltaE &amp;lt; 0:# Accepts the new configuration and sets energy and magnetisation equal to the properties for the new arrangement&lt;br /&gt;
                energy = energy1 &lt;br /&gt;
                magnetisation = magnetisation1 &lt;br /&gt;
            elif random_number &amp;lt;= exp(- deltaE / T): # Allows for statistical inclusion of arrangements with deltaE &amp;gt; 0, with a &#039;large&#039; Boltzmann factor&lt;br /&gt;
                energy = energy1&lt;br /&gt;
                magnetisation = magnetisation1&lt;br /&gt;
            else: # Rejects the new arrangement - flips the spin back to that in the original self.lattice&lt;br /&gt;
                self.lattice[random_i, random_j] = - self.lattice[random_i, random_j]&lt;br /&gt;
            if self.n_cycles &amp;gt;= self.skip_region: # Begins adding values to running sums after self.skip_region cycles&lt;br /&gt;
                self.E += energy&lt;br /&gt;
                self.E2 += energy**2&lt;br /&gt;
                self.M += magnetisation&lt;br /&gt;
                self.M2 += magnetisation**2 # self.X updates the running total for property X&lt;br /&gt;
                self.E_list.append(energy)&lt;br /&gt;
                self.M_list.append(magnetisation) # Appends values to list for standard error calculation&lt;br /&gt;
            else:&lt;br /&gt;
                pass&lt;br /&gt;
            self.n_cycles += 1 # Updates the running total for number of Monte Carlo cycles&lt;br /&gt;
            return energy, magnetisation&lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
        def statistics(self):&lt;br /&gt;
            # This function calculates the values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
            averaging_cycles = self.n_cycles - self.skip_region&lt;br /&gt;
            avgE = self.E / averaging_cycles&lt;br /&gt;
            avgE2 = self.E2 / averaging_cycles&lt;br /&gt;
            avgM = self.M / averaging_cycles&lt;br /&gt;
            avgM2 = self.M2 / averaging_cycles&lt;br /&gt;
            std_errorE = np.std(self.E_list) / sqrt(averaging_cycles)&lt;br /&gt;
            std_errorM = np.std(self.M_list) / sqrt(averaging_cycles)&lt;br /&gt;
            return avgE, avgE2, avgM, avgM2, self.n_cycles, std_errorE, std_errorM&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489469</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489469"/>
		<updated>2015-02-24T14:59:29Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Locating the Curie temperature */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file. Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes. The Python code used to produce these graphs is shown [[Mod:DMS3053-8|here]].&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489468</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489468"/>
		<updated>2015-02-24T14:52:19Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Locating the Curie temperature */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file. Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
===Comparison with C++ Data===&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes.&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Polynomial Fitting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489467</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489467"/>
		<updated>2015-02-24T14:49:10Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Locating the Curie temperature */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file. Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes.&lt;br /&gt;
&lt;br /&gt;
Considering these graphs, it is clear that, in general, there is a reasonable correlation between the Python and C++ data; however, some of the data, particularly that for high lattice sizes, shows that the Python computations have not always found the maximum of heat capacity. This correlation would be improved by making computations at the same range of temperatures, but with a smaller gap between the temperatures taken; however, this would substantially increase computation time.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489464</id>
		<title>Rep:Mod:DMS3053</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:Mod:DMS3053&amp;diff=489464"/>
		<updated>2015-02-24T14:46:12Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: /* Locating the Curie temperature */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;CMP Programming Experiment - Daniel Spencer, 00736964&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify&amp;quot;&amp;gt;&lt;br /&gt;
==Introduction to the Ising Model==&lt;br /&gt;
===Minimum energy of the Ising Model===&lt;br /&gt;
Using the equation&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E= - \frac{1}{2} J \sum_i^N \sum_{j\  \in\  \mathrm{neighbours}\left(i\right)} s_i s_j&amp;lt;/math&amp;gt; (&#039;&#039;eq. 1&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
the minimum energy of an Ising lattice of &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; dimensions, with &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; spins (where each &lt;br /&gt;
spin had a value of +1 or -1) and an interaction strength of &amp;lt;math&amp;gt;J&amp;lt;/math&amp;gt; was considered. This was achieved first through a consideration of a one-dimensional system with five parallel spins (where the spins are parallel as this corresponds to the minimum energy arrangement of the system). Hence, the energy of this linear system was found to be&amp;lt;br&amp;gt;&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,1D} = -5J &amp;lt;/math&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
For a linear, one-dimensional system, the number of neigbouring spins is two. The number of neighbours can be determined for two- and three- dimensional systems through a geometric consideration of their structure - the values are presented in &#039;&#039;Table 1&#039;&#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 1: Dimension numbers and number of neighbours&#039;&#039;&lt;br /&gt;
! Number of Dimensions, D !! Number of Neighbours&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1 || 2&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2 || 4&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3 || 6&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| D || 2D&lt;br /&gt;
|}&lt;br /&gt;
These data indicate that the number of neighbours is twice the number of dimensions, for the dimensions considered here. This can be extrapolated to give the general number of neighbours as &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For the minimum energy of the system, where all spins are parallel, every combination &amp;lt;math&amp;gt;s_i s_j&amp;lt;/math&amp;gt; has a value of 1. Notably, for each value of &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, there will be &amp;lt;math&amp;gt;2D&amp;lt;/math&amp;gt; neighbour interactions. Ergo, using &#039;&#039;eq. 1&#039;&#039;, the general minimum energy can be found to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,D} = -DNJ &amp;lt;/math&amp;gt; (&#039;&#039;eq. 2&#039;&#039;).&amp;lt;br&amp;gt;&lt;br /&gt;
To check this equation, it can be applied to the two-dimensional Ising lattice with 25 spins - this gives a value of&lt;br /&gt;
::&amp;lt;math&amp;gt;E_\text{min,2D} = -50J &amp;lt;/math&amp;gt;,&amp;lt;br&amp;gt;&lt;br /&gt;
which matches with the value predicted from first-principles.&lt;br /&gt;
&lt;br /&gt;
For this D-dimensional system, the multiplicity (i.e. the number of ways of achieving the specified configuration of spins) must be equal to two, as either all of the spins could be aligned &#039;up&#039; (+1) or &#039;down&#039; (-1). Using this multiplicity, the entropy of the system can be calculated using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;S = k_B \ln\Omega&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 3&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
where Ω is the number of microstates (equal to the multiplicity in this case), which gives a value of &amp;lt;math&amp;gt;k_B \ln2 &amp;lt;/math&amp;gt;, or 9.57 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Spin &#039;flipping&#039;===&lt;br /&gt;
&lt;br /&gt;
Using the Ising model, it is also possible to consider a change in state, reflected by a &#039;flipping&#039; of the direction of one of the lattice spins. For this case, the energy (using &#039;&#039;eq. 1&#039;&#039;) can be determined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;E&#039;= - \frac{1}{2} J (2DN - 4D - 4D) = 4DJ - DNJ&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 4&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where the additional &amp;lt;math&amp;gt;4D&amp;lt;/math&amp;gt; terms arise from the loss of 4D stabilising spin-aligned interactions and the gain of 4D destabilising spins anti-aligned interactions following spin &#039;flipping&#039;. Using &#039;&#039;eq. 2&#039;&#039; and &#039;&#039;eq. 4&#039;&#039;, the change in energy derived from this spin &#039;flip&#039; can be calculated to be&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta E= 4DJ - DNJ + DNJ = 4DJ&amp;lt;/math&amp;gt;. (&#039;&#039;eq. 5&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For a system with three dimensions (D = 3) and 1000 spins (N = 1000), the system, using &#039;&#039;eq. 5&#039;&#039;, was determined to increase in energy by &amp;lt;math&amp;gt;12 J&amp;lt;/math&amp;gt;. Notably, this change in energy is independent of the number of spins in the system - it depends only on the number of dimensions and J.&lt;br /&gt;
[[File:ThirdYearCMPExpt-IsingSketch.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 1&#039;&#039;&#039;: Representation of Ising lattices in one (N=5), two (N=25), and three (N=125) dimensions. +1 and -1 spins are denoted by the red and blue cells respectively. Diagram taken from the lab script.&#039;&#039;]]&lt;br /&gt;
A significant consideration with regards to the spin &#039;flipping&#039; described here is the accompanying increase in entropy - the driving force for this process. For the scenario describing the change in direction of a single spin, the multiplicity of the system will be &amp;lt;math&amp;gt;2N&amp;lt;/math&amp;gt; - this is a consequence of the system prior to &#039;flipping&#039; having a multiplicity of two (all spins aligned &#039;up&#039; or &#039;down&#039;), where now, any one of the spins could flip, adding the factor of N to the multiplicity. Hence, the new entropy can be defined to be&lt;br /&gt;
::&amp;lt;math&amp;gt;S&#039; = k_B \ln 2N&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 6&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
which allows the change in entropy to be calculated according to &#039;&#039;eq. 7&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;\Delta S = k_B \ln 2N - k_B \ln2 = k_B \ln N&amp;lt;/math&amp;gt; (&#039;&#039;eq. 7&#039;&#039;)&amp;lt;br&amp;gt;&lt;br /&gt;
For the system described above (D = 3, N = 1000), the change in entropy associated with the spin &#039;flip&#039; process is therefore &amp;lt;math&amp;gt;k_B ln 1000&amp;lt;/math&amp;gt;, which is equal to 9.53 x 10&amp;lt;sup&amp;gt;-23&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Magnetisation===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 2: Ising lattices and magnetisations&#039;&#039;&lt;br /&gt;
! Ising Lattice !! Magnetisation&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2D - spins as in &#039;&#039;Figure 1&#039;&#039; || 1&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 3D at 0 K || 1000 or -1000&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;Figure 1&#039;&#039; shows three examples of Ising lattices, with one, two and three dimensions respectively. Using the equation for magnetisation (&#039;&#039;eq. 8&#039;&#039;), the magnetisations of these systems can be calculated to be those presented in &#039;&#039;Table 2&#039;&#039;.&lt;br /&gt;
::&amp;lt;math&amp;gt;M= \sum_i s_i&amp;lt;/math&amp;gt; (&#039;&#039;eq. 8&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
For the three-dimensional system at a temperature of 0 K, all of the spins must be aligned either &#039;up&#039; or &#039;down&#039;, as the entropic increase associated with &#039;flipped&#039; spins does not provide a driving force at absolute zero - the only factor to consider is that of the energy, which is a minimum when all of the spins are aligned. For this case, the magnetisation could be either 1000 or -1000, depending upon the direction of the spin alignment. From a consideration of the magnetisation values calculated here, it is evident that with all of the spins aligned, the (magnitude of the) magnetisation of the system is at a maximum.&lt;br /&gt;
&lt;br /&gt;
==Calculating the energy and magnetisation==&lt;br /&gt;
===Modifying the files===&lt;br /&gt;
[[File:DMStest_output2.png|300px|thumb|right|&#039;&#039; &#039;&#039;&#039;Figure 2&#039;&#039;&#039;: Output image from testing IsingLattice.py using Ilcheck.py&#039;&#039;]]&lt;br /&gt;
In order to use Python to compute the energy and magnetisation for a given two-dimensional Ising lattice, the class IsingLattice was used, where energy() and magnetisation() functions were written to calculate their corresponding properties for a random numpy array of spins (generated using np.random.choice). For this aspect of the experiment, the value of J was assumed to be 1.0, working in reduced units. The Python script developed can be viewed [[Mod:DMS3053-1|here]], including annotations.&lt;br /&gt;
&lt;br /&gt;
===Testing the files===&lt;br /&gt;
In order to test the script prepared thus far, the Ilcheck.py script was run, generating the image presented in &#039;&#039;Figure 2&#039;&#039;. An examination of this output clearly indicates that the script provides accurate energies and magnetisations for the minimum and maximum energy configurations, along with for an intermediate, random arrangement. Hence, it can be concluded that at the current level, the Python script is functioning as required.&lt;br /&gt;
&lt;br /&gt;
==Introduction to the Monte Carlo simulation==&lt;br /&gt;
===Average Energy and Magnetisation===&lt;br /&gt;
[[File:DMSILanim3.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 3&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in the minimum energy state&#039;&#039;]]&lt;br /&gt;
[[File:DMSILanim_meta.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 4&#039;&#039;&#039;: Animation result from ILanim.py, showing the resting of the system in a meta-stable state&#039;&#039;]]&lt;br /&gt;
&lt;br /&gt;
In order to consider the generalisability of the prepared script, it is important to analyse how the script will function for large systems, such as those with 100 spins in the spin array. As each of these spins can be either &#039;up&#039; or &#039;down&#039;, each spin has two choices. Hence, the number of possible configurations for the system can be written as &amp;lt;math&amp;gt;2^{100}&amp;lt;/math&amp;gt;, which has a value of 1.2677 x 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If one considers the sampling of a single configuration to take 1 x 10&amp;lt;sup&amp;gt;-9&amp;lt;/sup&amp;gt; s, then it is clear that sampling all of these considerations would take a total of 1.2677 x 10&amp;lt;sup&amp;gt;21&amp;lt;/sup&amp;gt; s (also expressed as 4.017 x 10&amp;lt;sup&amp;gt;13&amp;lt;/sup&amp;gt; years). From this analysis, it is evident that the sampling of configurations was a significant consideration in the writing of a python script for this task.&lt;br /&gt;
&lt;br /&gt;
In order to account for this, the technique of importance sampling was implemented, using the statistical Boltzmann distribution, &amp;lt;math&amp;gt;\exp(- \Delta E / k_B T)&amp;lt;/math&amp;gt;. Note that as the energy computed using the energy() function is in units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;, this factor is not included in the script.&lt;br /&gt;
&lt;br /&gt;
===Modifying IsingLattice.py to Implement a Monte Carlo Cycle===&lt;br /&gt;
The python script developed at this stage is presented [[Mod:DMS3053-2|here]], accompanied by annotations to explain how the script functions.&lt;br /&gt;
&lt;br /&gt;
===Simulating the Monte Carlo Cycles===&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 3: statistics() output for animated system at global minimum configuration (Figure 3)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.70542501728&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 3.13520970111&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.829971492744&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.770986982766&lt;br /&gt;
|}&lt;br /&gt;
For cases where T &amp;lt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, it would be expected that the system would have a spontaneous magnetisation. When T &amp;gt; T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;, the entropy will be the dominating factor, potentially resulting in the system having a magnetisation of zero.&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 4: statistics() output for animated system at meta-stable configuration (Figure 4)&#039;&#039;&lt;br /&gt;
! Property !! Value&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;gt; || -1.35076450189&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 1.89025801939&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;gt; || -0.344104665826&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;gt; || 0.138855365306&lt;br /&gt;
|}&lt;br /&gt;
Using the presented script and the ILanim.py script, the Monte Carlo cycles can be simulated to view the results on the spin array as the process progresses. Here, the system under consideration was an 8 x 8 spin array, at a temperature of 0.5. &#039;&#039;Figure 3&#039;&#039; shows the typical outcome of the animation, with the system having reached the most stable, minimum energy arrangement. For the result presented here, the output of the statistics() function was that shown in &#039;&#039;Table 3&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
It was also observed that the system could locate a meta-stable state, with large regions of spin &#039;up&#039; and &#039;down&#039; spins. An example of such a result is presented in &#039;&#039;Figure 4&#039;&#039; (for which the output data from statistics() is presented in &#039;&#039;Table 4&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Accelerating the code==&lt;br /&gt;
&lt;br /&gt;
In order to examine the efficiency of the python script developed thus far, the Iltimetrial.py script was utilised to investigate the time taken to perform 2000 Monte Carlo cycles. This script was modified to the version presented [[Mod:DMS3053-3|here]],  which repeats the time measurement a defined number of times, then calculates the average time and the standard error in this average. For the Monte Carlo script prepared previously, the average time for 2000 Monte Carlo cycles was measured to be 5.475804 s and a standard error was calculated to be 0.008325 s, with 100 measurements made using the script.&lt;br /&gt;
&lt;br /&gt;
Evidently, the current script is slow at conducting large numbers of Monte Carlo cycles and hence, a more efficient script was developed using the np.roll, np.multiply and np.sum functions - this is presented [[Mod:DMS3053-4|here]].&lt;br /&gt;
&lt;br /&gt;
After this optimisation of the python script, the Iltimetrial.py script was re-run, giving an average time of 0.291467 s, with a standard error of 0.000156 s. Clearly, this optimised script is substantially faster than that developed previously (approximately 19 times faster).&lt;br /&gt;
&lt;br /&gt;
==The effect of temperature==&lt;br /&gt;
===Correcting the averaging code===&lt;br /&gt;
As the equilibrium state of the system requires a number of Monte Carlo cycles to be reached, it is evident that the average energies and magnetisations are accounting for values for non-equilibrium arrangements - this was accounted for through a consideration of the number of cycles required to reach equilibrium. For this, the ILfinalframe.py script was used, giving the graphs shown in &#039;&#039;Table 5&#039;&#039;. Here, each system was run for 150000 Monte Carlo cycles.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 5: Graphs of energy and magnetisation versus number of Monte Carlo cycles for different temperatures and system sizes&#039;&#039;&lt;br /&gt;
! Temperature !! System Size !! Resulting Graphs !! Cycles for Equilibrium&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 4x4 || [[File:DMS0544.png|300px]] || 24&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 8x8 || [[File:DMS0588.png|300px]] || 392&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 0.5 || 16x16 || [[File:DMS051616.png|300px]] || 5549&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 2x2 || [[File:DMS1022.png|300px]] || (0)&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 4x4 || [[File:DMS1044.png|300px]] || 49&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 8x8 || [[File:DMS10882.png|300px]] || 590&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 16x16 || [[File:DMS101616.png|300px]] || ~6300&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 1.0 || 32x32 || [[File:DMS103232.png|300px]] || ~110000&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 4x4 || [[File:DMS2044.png|300px]] || -&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2.0 || 8x8 || [[File:DMS2088.png|300px]] || -&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable floatright&amp;quot; width=42%&lt;br /&gt;
|+ &#039;&#039;Table 6: Number of cycles to be ignored for each system size&#039;&#039;&lt;br /&gt;
! System Size !! Number of cycles before averaging &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 2x2 || 0 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 4x4 || 100 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 8x8 || 1000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 16x16 || 8000 &lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| 32x32 || 120000 &lt;br /&gt;
|}&lt;br /&gt;
Analysis of these graphs indicates that at higher temperatures, such as 2.0 (also observed at 1.5), large fluctuations in the energy and magnetisation are observed - these fluctuations are the reason that the average values of the properties must be taken. As the temperature is increased for systems of size 4x4, 8x8 and 16x16, it is clear that the number of cycles required in order to reach equilibrium increases. Hence, for the temperature range to be considered later (0.25 to 5.00), the required number of cycles was overestimated in order to ensure that all measurements were taken whilst the system was in equilibrium. The proposed numbers of cycles to be ignored for each system size are presented in &#039;&#039;Table 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The python script developed up to this point was modified to account for these values by inclusion of a skip_region variable, which defines the number of cycles performed before energies and magnetisations contribute to the self.X values (before averaging occurs). The modified script is presented [[Mod:DMS3053-5|here]].&lt;br /&gt;
&lt;br /&gt;
===Running over a range of temperatures===&lt;br /&gt;
[[File:DMS88dat.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 5&#039;&#039;&#039;: Average energy and average magnetisation vs. temperature for 8x8 lattice, with error bars&#039;&#039;]]&lt;br /&gt;
Using the python script modified in the previous exercise, the code can now be used to simulate the 8x8 system at a range of temperatures, using the ILtemperaturerange.py file. Here, the temperature range of 0.25 to 5.00 was used, with a separation of 0.25 between points, whilst the runtime was set to 10000 (neglecting the property values for the first 1000 cycles). Running this simulation produced the graphs in &#039;&#039;Figure 5&#039;&#039;, where error bars computed using standard errors have also been included (these are small as a consequence of small standard errors). From the graph of average energy versus temperature, the phase transition can be observed - this occurs in the region with a gradient that is not close to zero. The data used here (temperature, average energies, average squared-energies, average magnetisations and average squared-magnetisations) was then saved as a numpy array in a new file, 8x8.dat.&lt;br /&gt;
&lt;br /&gt;
==The effect of system size==&lt;br /&gt;
[[File:DMSLatticeSizeCombinedPlot.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 6&#039;&#039;&#039;: Average energy and average magnetisation (per spins) vs. temperature for multiple lattice sizes&#039;&#039;]]&lt;br /&gt;
The process conducted for the 8x8 lattice in the previous exercise was then repeated for lattices of sizes 2x2, 4x4, 16x16 and 32x32, with the data saved in .dat files. These files were then accessed, and the average energy and magnetisation data were plotted on one graph for all of the lattices sizes - this was achieved using the script presented [[Mod:DMS3053-6|here]]. The graphs produced in this manner are shown in &#039;&#039;Figure 6&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A consideration of this graph suggests that in order to capture the long range fluctuations, a 16x16 lattice is necessary.&lt;br /&gt;
&lt;br /&gt;
==Determining the heat capacity==&lt;br /&gt;
[[File:DMSheatcapacity2.png|300px|thumb|right|&#039;&#039;&#039;&#039;&#039;Figure 7&#039;&#039;&#039;: Heat capacity (per spin) versus temperature for different lattice sizes&#039;&#039;]]&lt;br /&gt;
Using the .dat files previously produced, the heat capacity was calculated for each lattice size using the equation&lt;br /&gt;
::&amp;lt;math&amp;gt;C = \frac{\partial E}{\partial T} = \frac{\mathrm{Var}[E]}{k_B T^2}&amp;lt;/math&amp;gt;, (&#039;&#039;eq. 9&#039;&#039;) &amp;lt;br&amp;gt;&lt;br /&gt;
where &amp;lt;math&amp;gt;\mathrm{Var}[E] = &amp;lt;E^2&amp;gt; - &amp;lt;E&amp;gt;^2 &amp;lt;/math&amp;gt;. When implementing this, the k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt; term was neglected due to the energy values having units of k&amp;lt;sub&amp;gt;B&amp;lt;/sub&amp;gt;. The script used for this purpose is provided [[DMS3053-7|here]]. The plot of heat capacity per spin versus temperature for all of the lattice sizes considered is presented in &#039;&#039;Figure 7&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Locating the Curie temperature==&lt;br /&gt;
The data for the heat capacity generated using the python script prepared in this experiment was compared to that from longer C++ computations - graphs showing this comparison are presented in &#039;&#039;Table 7&#039;&#039; for a range of lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable center&amp;quot; width=70%&lt;br /&gt;
|+ &#039;&#039;Table 7: Graphs of heat capacity (per spin) versus temperature for C++ and Python data&#039;&#039;&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS2x2c.png|300px]] || [[File:DMS4x4c.png|300px]] || [[File:DMS8x8c.png|300px]]&lt;br /&gt;
|- style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| [[File:DMS16x16c.png|300px]] || [[File:DMS32x32c.png|300px]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS32x32c.png&amp;diff=489463</id>
		<title>File:DMS32x32c.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS32x32c.png&amp;diff=489463"/>
		<updated>2015-02-24T14:46:06Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS16x16c.png&amp;diff=489462</id>
		<title>File:DMS16x16c.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS16x16c.png&amp;diff=489462"/>
		<updated>2015-02-24T14:45:06Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS8x8c.png&amp;diff=489461</id>
		<title>File:DMS8x8c.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS8x8c.png&amp;diff=489461"/>
		<updated>2015-02-24T14:43:58Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS4x4c.png&amp;diff=489460</id>
		<title>File:DMS4x4c.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:DMS4x4c.png&amp;diff=489460"/>
		<updated>2015-02-24T14:43:38Z</updated>

		<summary type="html">&lt;p&gt;Ds3012: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ds3012</name></author>
	</entry>
</feed>