<?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=Yht17</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=Yht17"/>
	<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/wiki/Special:Contributions/Yht17"/>
	<updated>2026-05-18T20:43:10Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795797</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795797"/>
		<updated>2019-11-18T13:37:46Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Extras */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - A frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb|Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== Extras ==&lt;br /&gt;
The simulation script was modified to allow for any spin direction in 2 dimensions. Animations were made by mapping the angle of the spins onto a hsv colourmap. &lt;br /&gt;
[[File:Yht17 CMP Animlong2ff.png|none|thumb|&#039;&#039;&#039;Figure 17&#039;&#039;&#039; - Final frame of a free angle simulation, showing magnetic domains]]&lt;br /&gt;
In this simulation, t = 0.1 and the lattice size is 32×32. The system has not reached equilibrium, as magnetisation is still increasing, but it is clear this is below the Curie temperature. Eventually, the domains should disappear, all the spins should align and magnetisation per spin should become close to 1, but this would be faster with a higher temperature. &lt;br /&gt;
[[File:Yht17 CMP Animlong2 start.PNG|none|thumb|&#039;&#039;&#039;Figure 18&#039;&#039;&#039; - Starting state of system with random spins, representing a sudden change in temperature from a high temperature]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions form.PNG|none|thumb|&#039;&#039;&#039;Figure 19&#039;&#039;&#039; - Domains begin to form]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions change.PNG|none|thumb|&#039;&#039;&#039;Figure 20&#039;&#039;&#039; - Some domains disappear while others become larger and more well aligned]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 end.PNG|none|thumb|&#039;&#039;&#039;Figure 21&#039;&#039;&#039; - The end state of the simulation, showing a few large domains, but clearly not yet at equilibrium as there are large regions in the process of changing spins]]&lt;br /&gt;
&lt;br /&gt;
Unlike the simulations with only 2 spins states, these are able to sustain domains at low temperatures like a real ferromagnetic material such as iron. However, it still lacks interactions that are present in a real material and also lacks a dimension, so it cannot really be used effectively.&lt;br /&gt;
&lt;br /&gt;
Link to full video:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Animlong2small.mp4|Yht17_CMP_Animlong2small.mp4]]&lt;br /&gt;
&lt;br /&gt;
Modified Monte Carlo simulation:&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLatticeColor:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&lt;br /&gt;
        self.n_rows = n_rows&lt;br /&gt;
        self.n_cols = n_cols&lt;br /&gt;
        self.lattice = 2 * np.pi * np.random.random(size=(n_rows, n_cols))&lt;br /&gt;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        #self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        #if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            #self.cutoff = 160000&lt;br /&gt;
        self.cutoff = 0&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(np.cos(self.lattice - np.roll(self.lattice, 1, 0)) + np.cos(self.lattice - np.roll(self.lattice, 1, 1)))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.absolute(np.sum(np.cos(self.lattice)) + np.sum(np.sin(self.lattice)) * 1j)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        random_a = 2 * np.pi * np.random.random()&lt;br /&gt;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] += random_a&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] -= random_a&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        self.lattice[[random_i,random_j]] = self.lattice[[random_i,random_j]] % (2 * np.pi)&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Modified final frame script that also saves an animation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import matplotlib.animation as animation&lt;br /&gt;
&lt;br /&gt;
n_rows = 32&lt;br /&gt;
n_cols = 32&lt;br /&gt;
temperature = 0.1&lt;br /&gt;
runtime = 500001&lt;br /&gt;
il = IsingLatticeColor(n_rows, n_cols)&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
&lt;br /&gt;
sfig = pl.figure(figsize = [10, 10])&lt;br /&gt;
&lt;br /&gt;
E = []&lt;br /&gt;
M = []&lt;br /&gt;
L = []&lt;br /&gt;
for i in times:&lt;br /&gt;
    if i % 100 == 0:&lt;br /&gt;
        L.append((pl.pcolor(np.arange(0, n_rows + 1), np.arange(0, n_cols + 1), np.concatenate((np.concatenate((np.flipud(il.lattice), np.zeros((n_rows, 1))), axis = 1), np.zeros((1, n_cols + 1))), axis = 0), cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi),))&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(&amp;quot;Step&amp;quot;, i)&lt;br /&gt;
    energy, magnetisation = il.montecarlostep(temperature)&lt;br /&gt;
    E.append(energy)&lt;br /&gt;
    M.append(magnetisation)&lt;br /&gt;
fig = pl.figure()&lt;br /&gt;
matax = fig.add_subplot(3,1,1)&lt;br /&gt;
matax.matshow(il.lattice, cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi)&lt;br /&gt;
enerax = fig.add_subplot(3,1,2)&lt;br /&gt;
enerax.set_ylabel(&amp;quot;Energy per spin&amp;quot;)&lt;br /&gt;
enerax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
enerax.set_ylim([-2.1, 2.1])&lt;br /&gt;
magax = fig.add_subplot(3,1,3)&lt;br /&gt;
magax.set_ylabel(&amp;quot;Magnetisation per spin&amp;quot;)&lt;br /&gt;
magax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
magax.set_ylim([-0.1, 1.1])&lt;br /&gt;
enerax.plot(times, np.array(E)/spins)&lt;br /&gt;
magax.plot(times, np.array(M)/spins)&lt;br /&gt;
fig.savefig(&amp;quot;animlong2ff.png&amp;quot;, dpi = 300)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Writer = animation.writers[&#039;ffmpeg&#039;]&lt;br /&gt;
writer = Writer(fps=30, metadata=dict(artist=&#039;Me&#039;), bitrate=1800)&lt;br /&gt;
anim = animation.ArtistAnimation(sfig, L, repeat = False)&lt;br /&gt;
anim.save(&amp;quot;animlong2.mp4&amp;quot;, writer = writer)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795796</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795796"/>
		<updated>2019-11-18T13:37:15Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Extras */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - A frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb|Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== Extras ==&lt;br /&gt;
The simulation script was modified to allow for any spin direction in 2 dimensions. Animations were made by mapping the angle of the spins onto a hsv colourmap. &lt;br /&gt;
[[File:Yht17 CMP Animlong2ff.png|none|thumb|&#039;&#039;&#039;Figure 17&#039;&#039;&#039; - Final frame of a free angle simulation, showing magnetic domains]]&lt;br /&gt;
In this simulation, t = 0.1 and the lattice size is 32×32. The system has not reached equilibrium, as magnetisation is still increasing, but it is clear this is below the Curie temperature. Eventually, the domains should disappear, all the spins should align and magnetisation per spin should become close to 1, but this would be faster with a higher temperature. &lt;br /&gt;
[[File:Yht17 CMP Animlong2 start.PNG|none|thumb|&#039;&#039;&#039;Figure 18&#039;&#039;&#039; - Starting state of system with random spins, representing a sudden change in temperature from a high temperature]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions form.PNG|none|thumb|&#039;&#039;&#039;Figure 19&#039;&#039;&#039; - Domains begin to form]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions change.PNG|none|thumb|&#039;&#039;&#039;Figure 20&#039;&#039;&#039; - Some domains disappear while others become larger and more well aligned]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 end.PNG|none|thumb|&#039;&#039;&#039;Figure 21&#039;&#039;&#039; - The end state of the simulation, showing a few large domains, but clearly not yet at equilibrium as there are large regions in the process of changing spins]]&lt;br /&gt;
&lt;br /&gt;
Unlike the simulations with only 2 spins states, these are able to sustain domains at low temperatures like a real ferromagnetic material such as iron.However, it still lacks interactions that are present in a real material and also lacks a dimension, so it cannot really be used effectively.&lt;br /&gt;
&lt;br /&gt;
Link to full video:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Animlong2small.mp4|Yht17_CMP_Animlong2small.mp4]]&lt;br /&gt;
&lt;br /&gt;
Modified Monte Carlo simulation:&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLatticeColor:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&lt;br /&gt;
        self.n_rows = n_rows&lt;br /&gt;
        self.n_cols = n_cols&lt;br /&gt;
        self.lattice = 2 * np.pi * np.random.random(size=(n_rows, n_cols))&lt;br /&gt;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        #self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        #if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            #self.cutoff = 160000&lt;br /&gt;
        self.cutoff = 0&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(np.cos(self.lattice - np.roll(self.lattice, 1, 0)) + np.cos(self.lattice - np.roll(self.lattice, 1, 1)))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.absolute(np.sum(np.cos(self.lattice)) + np.sum(np.sin(self.lattice)) * 1j)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        random_a = 2 * np.pi * np.random.random()&lt;br /&gt;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] += random_a&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] -= random_a&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        self.lattice[[random_i,random_j]] = self.lattice[[random_i,random_j]] % (2 * np.pi)&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Modified final frame script that also saves an animation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import matplotlib.animation as animation&lt;br /&gt;
&lt;br /&gt;
n_rows = 32&lt;br /&gt;
n_cols = 32&lt;br /&gt;
temperature = 0.1&lt;br /&gt;
runtime = 500001&lt;br /&gt;
il = IsingLatticeColor(n_rows, n_cols)&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
&lt;br /&gt;
sfig = pl.figure(figsize = [10, 10])&lt;br /&gt;
&lt;br /&gt;
E = []&lt;br /&gt;
M = []&lt;br /&gt;
L = []&lt;br /&gt;
for i in times:&lt;br /&gt;
    if i % 100 == 0:&lt;br /&gt;
        L.append((pl.pcolor(np.arange(0, n_rows + 1), np.arange(0, n_cols + 1), np.concatenate((np.concatenate((np.flipud(il.lattice), np.zeros((n_rows, 1))), axis = 1), np.zeros((1, n_cols + 1))), axis = 0), cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi),))&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(&amp;quot;Step&amp;quot;, i)&lt;br /&gt;
    energy, magnetisation = il.montecarlostep(temperature)&lt;br /&gt;
    E.append(energy)&lt;br /&gt;
    M.append(magnetisation)&lt;br /&gt;
fig = pl.figure()&lt;br /&gt;
matax = fig.add_subplot(3,1,1)&lt;br /&gt;
matax.matshow(il.lattice, cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi)&lt;br /&gt;
enerax = fig.add_subplot(3,1,2)&lt;br /&gt;
enerax.set_ylabel(&amp;quot;Energy per spin&amp;quot;)&lt;br /&gt;
enerax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
enerax.set_ylim([-2.1, 2.1])&lt;br /&gt;
magax = fig.add_subplot(3,1,3)&lt;br /&gt;
magax.set_ylabel(&amp;quot;Magnetisation per spin&amp;quot;)&lt;br /&gt;
magax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
magax.set_ylim([-0.1, 1.1])&lt;br /&gt;
enerax.plot(times, np.array(E)/spins)&lt;br /&gt;
magax.plot(times, np.array(M)/spins)&lt;br /&gt;
fig.savefig(&amp;quot;animlong2ff.png&amp;quot;, dpi = 300)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Writer = animation.writers[&#039;ffmpeg&#039;]&lt;br /&gt;
writer = Writer(fps=30, metadata=dict(artist=&#039;Me&#039;), bitrate=1800)&lt;br /&gt;
anim = animation.ArtistAnimation(sfig, L, repeat = False)&lt;br /&gt;
anim.save(&amp;quot;animlong2.mp4&amp;quot;, writer = writer)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795795</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795795"/>
		<updated>2019-11-18T13:03:41Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Extras */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - A frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb|Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== Extras ==&lt;br /&gt;
The simulation script was modified to allow for any spin direction in 2 dimensions. Animations were made by mapping the angle of the spins onto a hsv colourmap. &lt;br /&gt;
[[File:Yht17 CMP Animlong2ff.png|none|thumb|&#039;&#039;&#039;Figure 17&#039;&#039;&#039; - Final frame of a free angle simulation, showing magnetic domains]]&lt;br /&gt;
In this simulation, t = 0.1 and the lattice size is 32×32. The system has not reached equilibrium, as magnetisation is still increasing, but it is clear this is below the Curie temperature. Eventually, the domains should disappear, all the spins should align and magnetisation per spin should become close to 1, but this would be faster with a higher temperature. &lt;br /&gt;
[[File:Yht17 CMP Animlong2 start.PNG|none|thumb|&#039;&#039;&#039;Figure 18&#039;&#039;&#039; - Starting state of system with random spins, representing a sudden change in temperature from a high temperature]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions form.PNG|none|thumb|&#039;&#039;&#039;Figure 19&#039;&#039;&#039; - Domains begin to form]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions change.PNG|none|thumb|&#039;&#039;&#039;Figure 20&#039;&#039;&#039; - Some domains disappear while others become larger and more well aligned]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 end.PNG|none|thumb|&#039;&#039;&#039;Figure 21&#039;&#039;&#039; - The end state of the simulation, showing a few large domains, but clearly not yet at equilibrium]]&lt;br /&gt;
&lt;br /&gt;
Link to full video:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Animlong2small.mp4|Yht17_CMP_Animlong2small.mp4]]&lt;br /&gt;
&lt;br /&gt;
Modified Monte Carlo simulation:&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLatticeColor:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&lt;br /&gt;
        self.n_rows = n_rows&lt;br /&gt;
        self.n_cols = n_cols&lt;br /&gt;
        self.lattice = 2 * np.pi * np.random.random(size=(n_rows, n_cols))&lt;br /&gt;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        #self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        #if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            #self.cutoff = 160000&lt;br /&gt;
        self.cutoff = 0&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(np.cos(self.lattice - np.roll(self.lattice, 1, 0)) + np.cos(self.lattice - np.roll(self.lattice, 1, 1)))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.absolute(np.sum(np.cos(self.lattice)) + np.sum(np.sin(self.lattice)) * 1j)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        random_a = 2 * np.pi * np.random.random()&lt;br /&gt;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] += random_a&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] -= random_a&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        self.lattice[[random_i,random_j]] = self.lattice[[random_i,random_j]] % (2 * np.pi)&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Modified final frame script that also saves an animation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import matplotlib.animation as animation&lt;br /&gt;
&lt;br /&gt;
n_rows = 32&lt;br /&gt;
n_cols = 32&lt;br /&gt;
temperature = 0.1&lt;br /&gt;
runtime = 500001&lt;br /&gt;
il = IsingLatticeColor(n_rows, n_cols)&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
&lt;br /&gt;
sfig = pl.figure(figsize = [10, 10])&lt;br /&gt;
&lt;br /&gt;
E = []&lt;br /&gt;
M = []&lt;br /&gt;
L = []&lt;br /&gt;
for i in times:&lt;br /&gt;
    if i % 100 == 0:&lt;br /&gt;
        L.append((pl.pcolor(np.arange(0, n_rows + 1), np.arange(0, n_cols + 1), np.concatenate((np.concatenate((np.flipud(il.lattice), np.zeros((n_rows, 1))), axis = 1), np.zeros((1, n_cols + 1))), axis = 0), cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi),))&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(&amp;quot;Step&amp;quot;, i)&lt;br /&gt;
    energy, magnetisation = il.montecarlostep(temperature)&lt;br /&gt;
    E.append(energy)&lt;br /&gt;
    M.append(magnetisation)&lt;br /&gt;
fig = pl.figure()&lt;br /&gt;
matax = fig.add_subplot(3,1,1)&lt;br /&gt;
matax.matshow(il.lattice, cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi)&lt;br /&gt;
enerax = fig.add_subplot(3,1,2)&lt;br /&gt;
enerax.set_ylabel(&amp;quot;Energy per spin&amp;quot;)&lt;br /&gt;
enerax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
enerax.set_ylim([-2.1, 2.1])&lt;br /&gt;
magax = fig.add_subplot(3,1,3)&lt;br /&gt;
magax.set_ylabel(&amp;quot;Magnetisation per spin&amp;quot;)&lt;br /&gt;
magax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
magax.set_ylim([-0.1, 1.1])&lt;br /&gt;
enerax.plot(times, np.array(E)/spins)&lt;br /&gt;
magax.plot(times, np.array(M)/spins)&lt;br /&gt;
fig.savefig(&amp;quot;animlong2ff.png&amp;quot;, dpi = 300)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Writer = animation.writers[&#039;ffmpeg&#039;]&lt;br /&gt;
writer = Writer(fps=30, metadata=dict(artist=&#039;Me&#039;), bitrate=1800)&lt;br /&gt;
anim = animation.ArtistAnimation(sfig, L, repeat = False)&lt;br /&gt;
anim.save(&amp;quot;animlong2.mp4&amp;quot;, writer = writer)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795794</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795794"/>
		<updated>2019-11-18T13:01:26Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Extras */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - A frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb|Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== Extras ==&lt;br /&gt;
The simulation script was modified to allow for any spin direction in 2 dimensions. Animations were made by mapping the angle of the spins onto a hsv colourmap. &lt;br /&gt;
[[File:Yht17 CMP Animlong2ff.png|none|thumb|&#039;&#039;&#039;Figure 17&#039;&#039;&#039; - Final frame of a free angle simulation, showing magnetic domains]]&lt;br /&gt;
In this simulation, t = 0.1 and the lattice size is 32×32. The system has not reached equilibrium, as magnetisation is still increasing, but it is clear this is below the Curie temperature. Eventually, the domains should disappear, all the spins should align and magnetisation per spin should become close to 1, but this would be faster with a higher temperature. &lt;br /&gt;
[[File:Yht17 CMP Animlong2 start.PNG|none|thumb|&#039;&#039;&#039;Figure 18&#039;&#039;&#039; - Starting state of system with random spins, representing a sudden change in temperature from a high temperature]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions form.PNG|none|thumb|&#039;&#039;&#039;Figure 19&#039;&#039;&#039; - Domains begin to form]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions change.PNG|none|thumb|&#039;&#039;&#039;Figure 20&#039;&#039;&#039; - Some domains disappear while others become larger and more well aligned]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 end.PNG|none|thumb|&#039;&#039;&#039;Figure 21&#039;&#039;&#039; - The end state of the simulation, showing a few large domains, but clearly not yet at equilibrium]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2small.mp4|none|thumb]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;Modified Monte Carlo simulation: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLatticeColor:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&lt;br /&gt;
        self.n_rows = n_rows&lt;br /&gt;
        self.n_cols = n_cols&lt;br /&gt;
        self.lattice = 2 * np.pi * np.random.random(size=(n_rows, n_cols))&lt;br /&gt;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        #self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        #if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            #self.cutoff = 160000&lt;br /&gt;
        self.cutoff = 0&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(np.cos(self.lattice - np.roll(self.lattice, 1, 0)) + np.cos(self.lattice - np.roll(self.lattice, 1, 1)))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.absolute(np.sum(np.cos(self.lattice)) + np.sum(np.sin(self.lattice)) * 1j)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        random_a = 2 * np.pi * np.random.random()&lt;br /&gt;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] += random_a&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] -= random_a&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        self.lattice[[random_i,random_j]] = self.lattice[[random_i,random_j]] % (2 * np.pi)&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Modified final frame script that also saves an animation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import matplotlib.animation as animation&lt;br /&gt;
&lt;br /&gt;
n_rows = 32&lt;br /&gt;
n_cols = 32&lt;br /&gt;
temperature = 0.1&lt;br /&gt;
runtime = 500001&lt;br /&gt;
il = IsingLatticeColor(n_rows, n_cols)&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
&lt;br /&gt;
sfig = pl.figure(figsize = [10, 10])&lt;br /&gt;
&lt;br /&gt;
E = []&lt;br /&gt;
M = []&lt;br /&gt;
L = []&lt;br /&gt;
for i in times:&lt;br /&gt;
    if i % 100 == 0:&lt;br /&gt;
        L.append((pl.pcolor(np.arange(0, n_rows + 1), np.arange(0, n_cols + 1), np.concatenate((np.concatenate((np.flipud(il.lattice), np.zeros((n_rows, 1))), axis = 1), np.zeros((1, n_cols + 1))), axis = 0), cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi),))&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(&amp;quot;Step&amp;quot;, i)&lt;br /&gt;
    energy, magnetisation = il.montecarlostep(temperature)&lt;br /&gt;
    E.append(energy)&lt;br /&gt;
    M.append(magnetisation)&lt;br /&gt;
fig = pl.figure()&lt;br /&gt;
matax = fig.add_subplot(3,1,1)&lt;br /&gt;
matax.matshow(il.lattice, cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi)&lt;br /&gt;
enerax = fig.add_subplot(3,1,2)&lt;br /&gt;
enerax.set_ylabel(&amp;quot;Energy per spin&amp;quot;)&lt;br /&gt;
enerax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
enerax.set_ylim([-2.1, 2.1])&lt;br /&gt;
magax = fig.add_subplot(3,1,3)&lt;br /&gt;
magax.set_ylabel(&amp;quot;Magnetisation per spin&amp;quot;)&lt;br /&gt;
magax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
magax.set_ylim([-0.1, 1.1])&lt;br /&gt;
enerax.plot(times, np.array(E)/spins)&lt;br /&gt;
magax.plot(times, np.array(M)/spins)&lt;br /&gt;
fig.savefig(&amp;quot;animlong2ff.png&amp;quot;, dpi = 300)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Writer = animation.writers[&#039;ffmpeg&#039;]&lt;br /&gt;
writer = Writer(fps=30, metadata=dict(artist=&#039;Me&#039;), bitrate=1800)&lt;br /&gt;
anim = animation.ArtistAnimation(sfig, L, repeat = False)&lt;br /&gt;
anim.save(&amp;quot;animlong2.mp4&amp;quot;, writer = writer)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2small.mp4&amp;diff=795793</id>
		<title>File:Yht17 CMP Animlong2small.mp4</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2small.mp4&amp;diff=795793"/>
		<updated>2019-11-18T12:58:18Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795444</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795444"/>
		<updated>2019-11-15T11:51:18Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Extras */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - A frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb|Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== Extras ==&lt;br /&gt;
The simulation script was modified to allow for any spin direction in 2 dimensions. Animations were made by mapping the angle of the spins onto a hsv colourmap. &lt;br /&gt;
[[File:Yht17 CMP Animlong2ff.png|none|thumb|&#039;&#039;&#039;Figure 17&#039;&#039;&#039; - Final frame of a free angle simulation, showing magnetic domains]]&lt;br /&gt;
In this simulation, t = 0.1 and the lattice size is 32×32. The system has not reached equilibrium, as magnetisation is still increasing, but it is clear this is below the Curie temperature. Eventually, the domains should disappear, all the spins should align and magnetisation per spin should become close to 1, but this would be faster with a higher temperature. &lt;br /&gt;
[[File:Yht17 CMP Animlong2 start.PNG|none|thumb|&#039;&#039;&#039;Figure 18&#039;&#039;&#039; - Starting state of system with random spins, representing a sudden change in temperature from a high temperature]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions form.PNG|none|thumb|&#039;&#039;&#039;Figure 19&#039;&#039;&#039; - Domains begin to form]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions change.PNG|none|thumb|&#039;&#039;&#039;Figure 20&#039;&#039;&#039; - Some domains disappear while others become larger and more well aligned]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 end.PNG|none|thumb|&#039;&#039;&#039;Figure 21&#039;&#039;&#039; - The end state of the simulation, showing a few large domains]]&lt;br /&gt;
&lt;br /&gt;
Modified Monte Carlo simulation: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLatticeColor:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&lt;br /&gt;
        self.n_rows = n_rows&lt;br /&gt;
        self.n_cols = n_cols&lt;br /&gt;
        self.lattice = 2 * np.pi * np.random.random(size=(n_rows, n_cols))&lt;br /&gt;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        #self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        #if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            #self.cutoff = 160000&lt;br /&gt;
        self.cutoff = 0&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(np.cos(self.lattice - np.roll(self.lattice, 1, 0)) + np.cos(self.lattice - np.roll(self.lattice, 1, 1)))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.absolute(np.sum(np.cos(self.lattice)) + np.sum(np.sin(self.lattice)) * 1j)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        random_a = 2 * np.pi * np.random.random()&lt;br /&gt;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] += random_a&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] -= random_a&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        self.lattice[[random_i,random_j]] = self.lattice[[random_i,random_j]] % (2 * np.pi)&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Modified final frame script that also saves an animation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import matplotlib.animation as animation&lt;br /&gt;
&lt;br /&gt;
n_rows = 32&lt;br /&gt;
n_cols = 32&lt;br /&gt;
temperature = 0.1&lt;br /&gt;
runtime = 500001&lt;br /&gt;
il = IsingLatticeColor(n_rows, n_cols)&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
&lt;br /&gt;
sfig = pl.figure(figsize = [10, 10])&lt;br /&gt;
&lt;br /&gt;
E = []&lt;br /&gt;
M = []&lt;br /&gt;
L = []&lt;br /&gt;
for i in times:&lt;br /&gt;
    if i % 100 == 0:&lt;br /&gt;
        L.append((pl.pcolor(np.arange(0, n_rows + 1), np.arange(0, n_cols + 1), np.concatenate((np.concatenate((np.flipud(il.lattice), np.zeros((n_rows, 1))), axis = 1), np.zeros((1, n_cols + 1))), axis = 0), cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi),))&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(&amp;quot;Step&amp;quot;, i)&lt;br /&gt;
    energy, magnetisation = il.montecarlostep(temperature)&lt;br /&gt;
    E.append(energy)&lt;br /&gt;
    M.append(magnetisation)&lt;br /&gt;
fig = pl.figure()&lt;br /&gt;
matax = fig.add_subplot(3,1,1)&lt;br /&gt;
matax.matshow(il.lattice, cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi)&lt;br /&gt;
enerax = fig.add_subplot(3,1,2)&lt;br /&gt;
enerax.set_ylabel(&amp;quot;Energy per spin&amp;quot;)&lt;br /&gt;
enerax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
enerax.set_ylim([-2.1, 2.1])&lt;br /&gt;
magax = fig.add_subplot(3,1,3)&lt;br /&gt;
magax.set_ylabel(&amp;quot;Magnetisation per spin&amp;quot;)&lt;br /&gt;
magax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
magax.set_ylim([-0.1, 1.1])&lt;br /&gt;
enerax.plot(times, np.array(E)/spins)&lt;br /&gt;
magax.plot(times, np.array(M)/spins)&lt;br /&gt;
fig.savefig(&amp;quot;animlong2ff.png&amp;quot;, dpi = 300)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Writer = animation.writers[&#039;ffmpeg&#039;]&lt;br /&gt;
writer = Writer(fps=30, metadata=dict(artist=&#039;Me&#039;), bitrate=1800)&lt;br /&gt;
anim = animation.ArtistAnimation(sfig, L, repeat = False)&lt;br /&gt;
anim.save(&amp;quot;animlong2.mp4&amp;quot;, writer = writer)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Monte_Carlo_Ising.ipynb&amp;diff=795443</id>
		<title>File:Yht17 CMP Monte Carlo Ising.ipynb</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Monte_Carlo_Ising.ipynb&amp;diff=795443"/>
		<updated>2019-11-15T11:47:51Z</updated>

		<summary type="html">&lt;p&gt;Yht17: Yht17 uploaded a new version of File:Yht17 CMP Monte Carlo Ising.ipynb&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795442</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795442"/>
		<updated>2019-11-15T11:46:24Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Extras */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - A frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb|Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== Extras ==&lt;br /&gt;
The simulation script was modified to allow for any spin direction in 2 dimensions. Animations were made by mapping the angle of the spins onto a hsv colourmap. &lt;br /&gt;
[[File:Yht17 CMP Animlong2ff.png|none|thumb|&#039;&#039;&#039;Figure 17&#039;&#039;&#039; - Final frame of a free angle simulation, showing magnetic domains]]&lt;br /&gt;
In this simulation, t = 0.1 and the lattice size is 32×32. The system has not reached equilibrium, as magnetisation is still increasing, but it is clear this is below the Curie temperature. Eventually, the domains should disappear, all the spins should align and magnetisation per spin should become close to 1, but this would be faster with a higher temperature. &lt;br /&gt;
[[File:Yht17 CMP Animlong2 start.PNG|none|thumb|&#039;&#039;&#039;Figure 18&#039;&#039;&#039; - Starting state of system with random spins, representing a sudden change in temperature from a high temperature]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions form.PNG|none|thumb|&#039;&#039;&#039;Figure 19&#039;&#039;&#039; - Domains begin to form]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 regions change.PNG|none|thumb|&#039;&#039;&#039;Figure 20&#039;&#039;&#039; - Some domains disappear while others become larger and more well aligned]]&lt;br /&gt;
[[File:Yht17 CMP Animlong2 end.PNG|none|thumb|&#039;&#039;&#039;Figure 21&#039;&#039;&#039; - The end state of the simulation, showing a few large domains]]&lt;br /&gt;
&lt;br /&gt;
Modified Monte Carlo simulation: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLatticeColor:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&lt;br /&gt;
        self.n_rows = n_rows&lt;br /&gt;
        self.n_cols = n_cols&lt;br /&gt;
        self.lattice = 2 * np.pi * np.random.random(size=(n_rows, n_cols))&lt;br /&gt;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        #self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        #if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            #self.cutoff = 160000&lt;br /&gt;
        self.cutoff = 0&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(np.cos(self.lattice - np.roll(self.lattice, 1, 0)) + np.cos(self.lattice - np.roll(self.lattice, 1, 1)))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.absolute(np.sum(np.cos(self.lattice)) + np.sum(np.sin(self.lattice)) * 1j)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        random_a = 2 * np.pi * np.random.random()&lt;br /&gt;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] += random_a&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] -= random_a&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        self.lattice[[random_i,random_j]] = self.lattice[[random_i,random_j]] % (2 * np.pi)&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Modified final frame script that also saves an animation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import matplotlib.animation as animation&lt;br /&gt;
n_rows = 32&lt;br /&gt;
n_cols = 32&lt;br /&gt;
temperature = 0.1&lt;br /&gt;
runtime = 500001&lt;br /&gt;
il = IsingLatticeColor(n_rows, n_cols)&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
&lt;br /&gt;
sfig = pl.figure(figsize = [10, 10])&lt;br /&gt;
&lt;br /&gt;
E = []&lt;br /&gt;
M = []&lt;br /&gt;
L = []&lt;br /&gt;
for i in times:&lt;br /&gt;
    if i % 100 == 0:&lt;br /&gt;
        L.append((pl.pcolor(np.arange(0, n_rows + 1), np.arange(0, n_cols + 1), np.concatenate((np.concatenate((np.flipud(il.lattice), np.zeros((n_rows, 1))), axis = 1), np.zeros((1, n_cols + 1))), axis = 0), cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi),))&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(&amp;quot;Step&amp;quot;, i)&lt;br /&gt;
    energy, magnetisation = il.montecarlostep(temperature)&lt;br /&gt;
    E.append(energy)&lt;br /&gt;
    M.append(magnetisation)&lt;br /&gt;
fig = pl.figure()&lt;br /&gt;
matax = fig.add_subplot(3,1,1)&lt;br /&gt;
matax.matshow(il.lattice, cmap = &amp;quot;hsv&amp;quot;, vmin = 0, vmax = 2 * np.pi)&lt;br /&gt;
enerax = fig.add_subplot(3,1,2)&lt;br /&gt;
enerax.set_ylabel(&amp;quot;Energy per spin&amp;quot;)&lt;br /&gt;
enerax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
enerax.set_ylim([-2.1, 2.1])&lt;br /&gt;
magax = fig.add_subplot(3,1,3)&lt;br /&gt;
magax.set_ylabel(&amp;quot;Magnetisation per spin&amp;quot;)&lt;br /&gt;
magax.set_xlabel(&amp;quot;Monte Carlo Steps&amp;quot;)&lt;br /&gt;
magax.set_ylim([-0.1, 1.1])&lt;br /&gt;
enerax.plot(times, np.array(E)/spins)&lt;br /&gt;
magax.plot(times, np.array(M)/spins)&lt;br /&gt;
fig.savefig(&amp;quot;animlong2ff.png&amp;quot;, dpi = 300)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Writer = animation.writers[&#039;ffmpeg&#039;]&lt;br /&gt;
writer = Writer(fps=30, metadata=dict(artist=&#039;Me&#039;), bitrate=1800)&lt;br /&gt;
anim = animation.ArtistAnimation(sfig, L, repeat = False)&lt;br /&gt;
anim.save(&amp;quot;animlong2.mp4&amp;quot;, writer = writer)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2_end.PNG&amp;diff=795441</id>
		<title>File:Yht17 CMP Animlong2 end.PNG</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2_end.PNG&amp;diff=795441"/>
		<updated>2019-11-15T11:33:43Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2_regions_change.PNG&amp;diff=795440</id>
		<title>File:Yht17 CMP Animlong2 regions change.PNG</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2_regions_change.PNG&amp;diff=795440"/>
		<updated>2019-11-15T11:33:17Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2_regions_form.PNG&amp;diff=795439</id>
		<title>File:Yht17 CMP Animlong2 regions form.PNG</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2_regions_form.PNG&amp;diff=795439"/>
		<updated>2019-11-15T11:33:02Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2_start.PNG&amp;diff=795438</id>
		<title>File:Yht17 CMP Animlong2 start.PNG</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2_start.PNG&amp;diff=795438"/>
		<updated>2019-11-15T11:32:47Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2ff.png&amp;diff=795433</id>
		<title>File:Yht17 CMP Animlong2ff.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Animlong2ff.png&amp;diff=795433"/>
		<updated>2019-11-15T11:23:19Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795420</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795420"/>
		<updated>2019-11-15T10:56:25Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* References */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - A frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb|Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== Extras ==&lt;br /&gt;
The simulation script was modified to allow for any spin direction. Animations were made using a hsv colourmap &lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795107</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795107"/>
		<updated>2019-11-14T13:33:32Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 6 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - A frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb|Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795007</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795007"/>
		<updated>2019-11-14T11:18:13Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb|Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795005</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795005"/>
		<updated>2019-11-14T11:16:41Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation) including various small tests:&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795003</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=795003"/>
		<updated>2019-11-14T11:15:12Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
Monte Carlo simulation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
class IsingLattice:&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    #n_cycles = 0&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, n_rows, n_cols):&lt;br /&gt;
        #all initialisations placed in this method to always initialise properly&lt;br /&gt;
        #energy and magnetisation in lists to allow easier extraction of data&lt;br /&gt;
        self.E = []&lt;br /&gt;
        self.M = []&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;
        #energy and magnetisation always kept track of so that the montecarlostep method only needs to call the energy and magnetisation methods once&lt;br /&gt;
        self.c_energy = self.energy()&lt;br /&gt;
        self.c_magnetisation = self.magnetisation()&lt;br /&gt;
        #this cutoff works well for lattices that aren&#039;t very big&lt;br /&gt;
        self.cutoff = round(0.5 * (n_rows * n_cols) ** 2)&lt;br /&gt;
        if n_rows * n_cols &amp;gt; 400:&lt;br /&gt;
            self.cutoff = 160000&lt;br /&gt;
&lt;br /&gt;
    def energy(self):&lt;br /&gt;
        &amp;quot;Return the total energy of the current lattice configuration.&amp;quot;&lt;br /&gt;
        energy = -np.sum(self.lattice * np.roll(self.lattice, 1, 0) + self.lattice * np.roll(self.lattice, 1, 1))&lt;br /&gt;
        #energy = -sum([(self.lattice[ii, ij] * self.lattice[ii - 1, ij] + self.lattice[ii, ij] * self.lattice[ii, ij - 1]) for ii in range(self.n_rows) for ij in range(self.n_cols)])&lt;br /&gt;
        return energy&lt;br /&gt;
&lt;br /&gt;
    def magnetisation(self):&lt;br /&gt;
        &amp;quot;Return the total magnetisation of the current lattice configuration.&amp;quot;&lt;br /&gt;
        magnetisation = np.sum(self.lattice)&lt;br /&gt;
        #magnetisation = np.sum(c for r in self.lattice for c in r)&lt;br /&gt;
        return magnetisation&lt;br /&gt;
&lt;br /&gt;
    def montecarlostep(self, T):&lt;br /&gt;
        &amp;quot;Performs a single Monte Carlo step&amp;quot;&lt;br /&gt;
        #the following two lines will select the coordinates of the random spin for you&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;
        #the following line will choose a random number in the range [0,1) for you&lt;br /&gt;
        random_number = np.random.random()&lt;br /&gt;
        #changes the lattice then checks its energy&lt;br /&gt;
        self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        new_energy = self.energy()&lt;br /&gt;
        new_magnetisation = self.magnetisation()&lt;br /&gt;
        #two if statements condensed into one to save time&lt;br /&gt;
        if random_number &amp;gt; np.exp((self.c_energy - new_energy) / T):&lt;br /&gt;
            #if the new lattice is rejected, it is reverted&lt;br /&gt;
            self.lattice[random_i,random_j] *= -1&lt;br /&gt;
        else:&lt;br /&gt;
            #if the new lattice is accepted, the values of energy and magnetisation are updated&lt;br /&gt;
            self.c_energy = new_energy&lt;br /&gt;
            self.c_magnetisation = new_magnetisation&lt;br /&gt;
        #add values of energy and magnetisation to lists&lt;br /&gt;
        self.E.append(self.c_energy)&lt;br /&gt;
        self.M.append(self.c_magnetisation)&lt;br /&gt;
        return [self.c_energy, self.c_magnetisation]&lt;br /&gt;
&lt;br /&gt;
    def statistics(self):&lt;br /&gt;
        #complete this function so that it calculates the correct values for the averages of E, E*E (E2), M, M*M (M2), and returns them&lt;br /&gt;
        #the cutoff is applied only at this point&lt;br /&gt;
        return [np.mean(np.array(self.E)[self.cutoff:]), np.mean((np.array(self.E)[self.cutoff:]) ** 2), np.mean(np.array(self.M)[self.cutoff:]), np.mean((np.array(self.M)[self.cutoff:]) ** 2), len(self.E)]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Runs Monte Carlo simulation over a temperature range:&lt;br /&gt;
&amp;lt;pre&amp;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;
#updates the lattice without updating the energy&lt;br /&gt;
#this will cause the beginning of the simulation to produce erroneous but will be covered up by the cutoff point&lt;br /&gt;
il.lattice = np.ones((n_rows, n_cols))&lt;br /&gt;
spins = n_rows*n_cols&lt;br /&gt;
runtime = 300000&lt;br /&gt;
times = range(runtime)&lt;br /&gt;
temps = np.arange(0.05, 5.05, 0.05)&lt;br /&gt;
energies = []&lt;br /&gt;
magnetisations = []&lt;br /&gt;
energysq = []&lt;br /&gt;
magnetisationsq = []&lt;br /&gt;
#lists are created to keep track of the standard deviations to use for error bars&lt;br /&gt;
energystds = []&lt;br /&gt;
magnetisationstds = []&lt;br /&gt;
for t in temps:&lt;br /&gt;
    for i in times:&lt;br /&gt;
        if i % 10000 == 0:&lt;br /&gt;
            print(t, i)&lt;br /&gt;
        energy, magnetisation = il.montecarlostep(t)&lt;br /&gt;
    aveE, aveE2, aveM, aveM2, n_cycles = il.statistics()&lt;br /&gt;
    stdE = np.std(il.E[il.cutoff:])&lt;br /&gt;
    stdM = np.std(il.M[il.cutoff:])&lt;br /&gt;
    energies.append(aveE)&lt;br /&gt;
    energysq.append(aveE2)&lt;br /&gt;
    energystds.append(stdE)&lt;br /&gt;
    magnetisations.append(aveM)&lt;br /&gt;
    magnetisationsq.append(aveM2)&lt;br /&gt;
    magnetisationstds.append(stdM)&lt;br /&gt;
    #reset the IL object for the next cycle&lt;br /&gt;
    il.E = []&lt;br /&gt;
    il.M = []&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
#plots including error bars&lt;br /&gt;
enerax.errorbar(temps, np.array(energies)/spins, yerr = np.array(energystds)/spins)&lt;br /&gt;
magax.errorbar(temps, np.array(magnetisations)/spins, yerr = np.array(magnetisationstds)/spins)&lt;br /&gt;
pl.show()&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.svg&amp;quot;)&lt;br /&gt;
pl.savefig(&amp;quot;32x32_2.png&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#final data saved with extra columns for standard deviations&lt;br /&gt;
final_data = np.column_stack((temps, energies, energysq, energystds, magnetisations, magnetisationsq, magnetisationstds))&lt;br /&gt;
np.savetxt(&amp;quot;32x32_2.dat&amp;quot;, final_data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Plots energy and magnetisation against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#files loaded in&lt;br /&gt;
d2x2 = np.loadtxt(&amp;quot;2x2_2.dat&amp;quot;)&lt;br /&gt;
d4x4 = np.loadtxt(&amp;quot;4x4_2.dat&amp;quot;)&lt;br /&gt;
d8x8 = np.loadtxt(&amp;quot;8x8_2.dat&amp;quot;)&lt;br /&gt;
d16x16 = np.loadtxt(&amp;quot;16x16_2.dat&amp;quot;)&lt;br /&gt;
d32x32 = np.loadtxt(&amp;quot;32x32_2.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates plot areas&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.2, 0.2])&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.2, 1.2])&lt;br /&gt;
&lt;br /&gt;
#plots energies&lt;br /&gt;
enerax.plot(d2x2[:,0], d2x2[:,1] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
enerax.plot(d4x4[:,0], d4x4[:,1] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
enerax.plot(d8x8[:,0], d8x8[:,1] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
enerax.plot(d16x16[:,0], d16x16[:,1] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
enerax.plot(d32x32[:,0], d32x32[:,1] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#plots magnetisations&lt;br /&gt;
magax.plot(d2x2[:,0], d2x2[:,4] / 4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
magax.plot(d4x4[:,0], d4x4[:,4] / 16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
magax.plot(d8x8[:,0], d8x8[:,4] / 64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
magax.plot(d16x16[:,0], d16x16[:,4] / 256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
magax.plot(d32x32[:,0], d32x32[:,4] / 1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
enerax.legend()&lt;br /&gt;
magax.legend()&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific heat capacity against temperature for all lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#function defined to make plotting easier&lt;br /&gt;
def var_by_T2(E, E2, T):&lt;br /&gt;
    return (E2 - E ** 2) / (T ** 2)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d2x2[:,0], var_by_T2(d2x2[:,1], d2x2[:,2], d2x2[:,0])/4, label = &amp;quot;2x2&amp;quot;)&lt;br /&gt;
pl.plot(d4x4[:,0], var_by_T2(d4x4[:,1], d4x4[:,2], d4x4[:,0])/16, label = &amp;quot;4x4&amp;quot;)&lt;br /&gt;
pl.plot(d8x8[:,0], var_by_T2(d8x8[:,1], d8x8[:,2], d8x8[:,0])/64, label = &amp;quot;8x8&amp;quot;)&lt;br /&gt;
pl.plot(d16x16[:,0], var_by_T2(d16x16[:,1], d16x16[:,2], d16x16[:,0])/256, label = &amp;quot;16x16&amp;quot;)&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;C against T.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Loads in the provided data files:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#provided files loaded in&lt;br /&gt;
c2x2 = np.loadtxt(&amp;quot;C++_data/2x2.dat&amp;quot;)&lt;br /&gt;
c4x4 = np.loadtxt(&amp;quot;C++_data/4x4.dat&amp;quot;)&lt;br /&gt;
c8x8 = np.loadtxt(&amp;quot;C++_data/8x8.dat&amp;quot;)&lt;br /&gt;
c16x16 = np.loadtxt(&amp;quot;C++_data/16x16.dat&amp;quot;)&lt;br /&gt;
c32x32 = np.loadtxt(&amp;quot;C++_data/32x32.dat&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots specific head capacity against temperature for provided and simulated data:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(d32x32[:,0], var_by_T2(d32x32[:,1], d32x32[:,2], d32x32[:,0])/1024, label = &amp;quot;Simulated 32x32&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], label = &amp;quot;Provided 32x32&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Comparison 32.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over entire temperature range:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit2 = np.polyfit(c32x32[:,0],c32x32[:,5],2)&lt;br /&gt;
fit3 = np.polyfit(c32x32[:,0],c32x32[:,5],3)&lt;br /&gt;
fit4 = np.polyfit(c32x32[:,0],c32x32[:,5],4)&lt;br /&gt;
fit5 = np.polyfit(c32x32[:,0],c32x32[:,5],5)&lt;br /&gt;
fit6 = np.polyfit(c32x32[:,0],c32x32[:,5],6)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(c32x32[:,0], c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit2, c32x32[:,0]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit3, c32x32[:,0]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit4, c32x32[:,0]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit5, c32x32[:,0]), lw = 1, label = &amp;quot;Order 5 fit&amp;quot;)&lt;br /&gt;
pl.plot(c32x32[:,0], np.polyval(fit6, c32x32[:,0]), lw = 1, label = &amp;quot;Order 6 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Whole fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fits polynomials for the specific heat capacity over a small temperature range near the peak:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
T = c32x32[:,0]&lt;br /&gt;
#selects values of temperature only near the peak (manually chosen)&lt;br /&gt;
selection = np.logical_and(T &amp;gt; 2.2, T &amp;lt; 2.4)&lt;br /&gt;
&lt;br /&gt;
#creates all the polynomial fits&lt;br /&gt;
fit232 = np.polyfit(T[selection], c32x32[:,5][selection], 2)&lt;br /&gt;
fit3 = np.polyfit(T[selection], c32x32[:,5][selection], 3)&lt;br /&gt;
fit4 = np.polyfit(T[selection], c32x32[:,5][selection], 4)&lt;br /&gt;
&lt;br /&gt;
#all polynomial fits plotted at once&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(T, c32x32[:,5], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 1, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit232, T[selection]), lw = 1, label = &amp;quot;Order 2 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit3, T[selection]), lw = 1, label = &amp;quot;Order 3 fit&amp;quot;)&lt;br /&gt;
pl.plot(T[selection], np.polyval(fit4, T[selection]), lw = 1, label = &amp;quot;Order 4 fit&amp;quot;)&lt;br /&gt;
pl.xlabel(&amp;quot;Temperature&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Specific Heat Capacity&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Cut fit.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Repeated for other lattice sizes (see notebook file).&lt;br /&gt;
&lt;br /&gt;
Creates a file containing curie temperatures:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#creates a file containing the curie temperatures for the five lattice sizes&lt;br /&gt;
np.savetxt(&amp;quot;Curie.dat&amp;quot;, np.column_stack(np.array([[2, 4, 8, 16, 32], [-fit22[1] / (2 * fit22[0]), -fit24[1] / (2 * fit24[0]), -fit28[1] / (2 * fit28[0]), -fit216[1] / (2 * fit216[0]), -fit232[1] / (2 * fit232[0])]])))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Plots and fits curie temperatures for different lattice sizes:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#loads curie temperatures&lt;br /&gt;
curiedata = np.loadtxt(&amp;quot;Curie.dat&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#creates the straight line fit&lt;br /&gt;
fitcurie = np.polyfit(1 / curiedata[:,0], curiedata[:,1], 1, cov = True)&lt;br /&gt;
&lt;br /&gt;
pl.figure()&lt;br /&gt;
pl.plot(1 / curiedata[:,0], curiedata[:,1], ls = &amp;quot;&amp;quot;, marker = &amp;quot;x&amp;quot;, ms = 4, mew = 0.5, label = &amp;quot;Data&amp;quot;)&lt;br /&gt;
pl.plot([-0.2,0.7], np.polyval(fitcurie[0], [-0.2,0.7]), lw = 1, label = &amp;quot;Linear fit&amp;quot;)&lt;br /&gt;
#plots the y axis&lt;br /&gt;
pl.plot([0,0],[2,3], ls = &amp;quot;--&amp;quot;)&lt;br /&gt;
#plots a horizontal line at the y-intercept&lt;br /&gt;
pl.plot([-1,1],2 * [fitcurie[0][1]], ls = &amp;quot;--&amp;quot; , label = &amp;quot;T = 2.29&amp;quot;)&lt;br /&gt;
pl.xlim([-0.1,0.6])&lt;br /&gt;
pl.ylim([2.25,2.6])&lt;br /&gt;
pl.xlabel(&amp;quot;1 / Lattice Length&amp;quot;)&lt;br /&gt;
pl.ylabel(&amp;quot;Curie temperature&amp;quot;)&lt;br /&gt;
pl.legend()&lt;br /&gt;
pl.savefig(&amp;quot;Curie.png&amp;quot;, dpi = 300)&lt;br /&gt;
pl.show()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jupyter notebook containing all written code (except for simulation):&lt;br /&gt;
&lt;br /&gt;
[[Media:Yht17_CMP_Monte_Carlo_Ising.ipynb]]&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Monte_Carlo_Ising.ipynb&amp;diff=795000</id>
		<title>File:Yht17 CMP Monte Carlo Ising.ipynb</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Monte_Carlo_Ising.ipynb&amp;diff=795000"/>
		<updated>2019-11-14T11:13:35Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794946</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794946"/>
		<updated>2019-11-14T10:24:14Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
&amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794945</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794945"/>
		<updated>2019-11-14T10:23:11Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &amp;lt;math&amp;gt;T_{C,\infty}&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794944</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794944"/>
		<updated>2019-11-14T10:22:35Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;. The value of the y-intercept would be &lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794942</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794942"/>
		<updated>2019-11-14T10:21:36Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;T_{C,L}&amp;lt;/math&amp;gt; was plotted against &amp;lt;math&amp;gt;\frac{1}{L}&amp;lt;/math&amp;gt;&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794913</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794913"/>
		<updated>2019-11-13T17:35:39Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 6 - T&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; with different lattice sizes&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794912</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794912"/>
		<updated>2019-11-13T17:34:07Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2J}{k_{b}\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794911</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794911"/>
		<updated>2019-11-13T17:26:20Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2}{\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794910</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794910"/>
		<updated>2019-11-13T17:25:52Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -6000J and S = 9.57 × 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;
If one of the spins were to flip, E = -5988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2}{\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794909</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794909"/>
		<updated>2019-11-13T17:01:40Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2}{\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The agreement is quite good, only 1% off. The main sources of error are probably the large amount of fluctuations in the simulation near the Curie temperature and how a polynomial fit was used to fit a curve that should theoretically diverge.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794908</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794908"/>
		<updated>2019-11-13T16:58:51Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2}{\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
asdf&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794907</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794907"/>
		<updated>2019-11-13T16:57:38Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2}{\ln(1 + \sqrt{2})} = 2.27&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references \&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794906</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794906"/>
		<updated>2019-11-13T16:56:49Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2}{\ln(1 + \sqrt{2})}&amp;lt;/math&amp;gt;&amp;lt;ref&amp;gt;&amp;lt;nowiki&amp;gt;http://www.teori.atom.fysik.su.se/~lindroth/comp08/ising.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794905</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794905"/>
		<updated>2019-11-13T16:54:38Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2}{\ln(1 + \sqrt{2})}&amp;lt;/math&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794904</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794904"/>
		<updated>2019-11-13T16:54:11Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt;]]&lt;br /&gt;
T&amp;lt;sub&amp;gt;C,∞&amp;lt;/sub&amp;gt; was found to be 2.29. According to literature, &amp;lt;math&amp;gt;T_{C,\infty} = \frac{2}{\ln(1 + \sqrt{2})}&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794903</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794903"/>
		<updated>2019-11-13T16:46:24Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;, a graph was produced.&lt;br /&gt;
[[File:Yht17 CMP Curie.png|none|thumb|&#039;&#039;&#039;Figure 16&#039;&#039;&#039; - Linear fit to find T&amp;lt;sub&amp;gt;C,&amp;lt;/sub&amp;gt;]]&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Curie.png&amp;diff=794902</id>
		<title>File:Yht17 CMP Curie.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Curie.png&amp;diff=794902"/>
		<updated>2019-11-13T16:45:09Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794901</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794901"/>
		<updated>2019-11-13T16:28:07Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations. The fit was repeated for all lattice sizes.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Lattice side length&lt;br /&gt;
!Curie temperature&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2.54&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|2.45&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|2.35&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|2.32&lt;br /&gt;
|-&lt;br /&gt;
|32&lt;br /&gt;
|2.30&lt;br /&gt;
|}&lt;br /&gt;
Using the relation &amp;lt;math&amp;gt;T_{C,L} = \frac{A}{L} + T_{C,\infty}&amp;lt;/math&amp;gt;,&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794900</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794900"/>
		<updated>2019-11-13T16:06:38Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range for a 32×32 lattice]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;br /&gt;
[[File:Yht17 CMP Cut fit.png|none|thumb|&#039;&#039;&#039;Figure 15&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over temperatures near the peak for a 32×32 lattice]]&lt;br /&gt;
If the fit is only for data points near the peak, any polynomial above order 1 fits well. Quadratic fits will be used for following calculations.&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Cut_fit.png&amp;diff=794899</id>
		<title>File:Yht17 CMP Cut fit.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Cut_fit.png&amp;diff=794899"/>
		<updated>2019-11-13T16:03:31Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794898</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794898"/>
		<updated>2019-11-13T15:50:34Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;br /&gt;
[[File:Yht17 CMP Whole fit.png|none|thumb|&#039;&#039;&#039;Figure 14&#039;&#039;&#039; - Various polynomial fits for specific heat capacity over the whole temperature range]]&lt;br /&gt;
It can be seen from &#039;&#039;&#039;Figure 14&#039;&#039;&#039; that polynomial fits over the whole temperature range do not fit very well.&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Whole_fit.png&amp;diff=794897</id>
		<title>File:Yht17 CMP Whole fit.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Whole_fit.png&amp;diff=794897"/>
		<updated>2019-11-13T15:45:12Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794896</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794896"/>
		<updated>2019-11-13T15:28:55Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
Data was provided of simulations which have been run for much longer. These should be more accurate.&lt;br /&gt;
[[File:Yht17 CMP Comparison 32.png|none|thumb|&#039;&#039;&#039;Figure 13&#039;&#039;&#039; - Specific heat capacity against temperature for simulated and provided data]]&lt;br /&gt;
The simulated and provided data mostly fit well but the provided data has a smoother line and a sharper peak.&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Comparison_32.png&amp;diff=794895</id>
		<title>File:Yht17 CMP Comparison 32.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_Comparison_32.png&amp;diff=794895"/>
		<updated>2019-11-13T15:25:50Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794894</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794894"/>
		<updated>2019-11-13T15:06:27Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 7 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]It can be seen that larger lattices produce a sharper peak.&lt;br /&gt;
&lt;br /&gt;
== Section 8 ==&lt;br /&gt;
asdf&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794893</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794893"/>
		<updated>2019-11-13T14:58:58Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 7 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;br /&gt;
[[File:Yht17 CMP C against T.png|none|thumb|&#039;&#039;&#039;Figure 12&#039;&#039;&#039; - Specific heat capacity against T for different lattice sizes]]&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_C_against_T.png&amp;diff=794892</id>
		<title>File:Yht17 CMP C against T.png</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_C_against_T.png&amp;diff=794892"/>
		<updated>2019-11-13T14:57:30Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794891</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794891"/>
		<updated>2019-11-13T14:50:17Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 6 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In &#039;&#039;&#039;figure 10&#039;&#039;&#039; it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794890</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794890"/>
		<updated>2019-11-13T14:30:25Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In figure 10 it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
From the graphs above, it is difficult to determine T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;. T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; could be much more easily found by plotting heat capacity against temperature. There would be a peak at T = T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By definition, the heat capacity &amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle}{\partial T}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By differentiating this, a better representation can be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\langle E\rangle_{T}=\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b}T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;U=\frac{1}{Z}=\frac{1}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;V=\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial U}{\partial T}=-\frac{\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}}{k_{b} T^{2}\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\partial V}{\partial T}=\frac{1}{k_{b} T^{2}} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{\partial\langle E\rangle_{T}}{\partial T}=U \frac{\partial V}{\partial T}+V \frac{\partial U}{\partial T}=\frac{1}{k_{b} T^{2}} \frac{\sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}}{\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}}-\frac{1}{k_{b} T^{2}} \frac{\left(\sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}{\left(\sum_{\alpha} e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C=\frac{1}{k_{b} T^{2}}\left(\frac{1}{Z} \sum_{\alpha} E(\alpha)^{2} e^{-\frac{E(\alpha)}{k_{b} T}}-\left(\frac{1}{Z} \sum_{\alpha} E(\alpha) e^{-\frac{E(\alpha)}{k_{b} T}}\right)^{2}\right)=\frac{\left\langle E^{2}\right\rangle_{T}-\langle E\rangle_{T}^{2}}{k_{b} T^{2}}=\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means by plotting &amp;lt;math&amp;gt;\frac{\operatorname{Var}[E]}{k_{b} T^{2}}&amp;lt;/math&amp;gt; against T, T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt; can be found.&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794889</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794889"/>
		<updated>2019-11-13T12:06:06Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 6 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]In figure 10 it can be seen that the results for a 16×16 lattice and a 32×32 lattice are similar.&lt;br /&gt;
[[File:Yht17 CMP 16 Long range fluctuations.PNG|none|thumb|&#039;&#039;&#039;Figure 11&#039;&#039;&#039; - Frame from a 16×16 simulation with t = 2 showing long range fluctuations]]&lt;br /&gt;
With smaller lattices like a 8×8 lattice, there is not enough space to model long range fluctuations. A larger lattice like the 16×16 lattice in figure 11 can demonstrate long range fluctuations.&lt;br /&gt;
&lt;br /&gt;
== Section 7 ==&lt;br /&gt;
asdf&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_16_Long_range_fluctuations.PNG&amp;diff=794888</id>
		<title>File:Yht17 CMP 16 Long range fluctuations.PNG</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=File:Yht17_CMP_16_Long_range_fluctuations.PNG&amp;diff=794888"/>
		<updated>2019-11-13T12:02:48Z</updated>

		<summary type="html">&lt;p&gt;Yht17: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
	<entry>
		<id>https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794887</id>
		<title>Rep:CMP:yht17</title>
		<link rel="alternate" type="text/html" href="https://chemwiki.ch.ic.ac.uk/index.php?title=Rep:CMP:yht17&amp;diff=794887"/>
		<updated>2019-11-13T11:45:10Z</updated>

		<summary type="html">&lt;p&gt;Yht17: /* Section 6 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Section 1 ==&lt;br /&gt;
In the Ising model, the total interaction energy &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j}&amp;lt;/math&amp;gt;, where N is the number of spins, s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; is the spin of lattice point i and J is a constant for the strength of the interaction.&lt;br /&gt;
&lt;br /&gt;
The lowest energy state is when all the spins are in the same direction. This means that &amp;lt;math&amp;gt;s_{i} s_{j} = 1&amp;lt;/math&amp;gt; for all i and j.&lt;br /&gt;
&lt;br /&gt;
Each lattice point has 2D neighbours, where D is the number of dimensions. The lowest possible energy using this model is thus &amp;lt;math&amp;gt;E = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} s_{i} s_{j} = -\frac{1}{2} J \sum_{i}^{N} \sum_{j \in neighbours(i)} 1 = -\frac{1}{2} J \sum_{i}^{N} 2D = -\frac{1}{2} J (2DN) = -DNJ&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The multiplicity of this state is 2, since the spins can be all up or all down.&lt;br /&gt;
&lt;br /&gt;
The entropy &amp;lt;math&amp;gt;S = k_{b} \ln(\Omega) = k_{b} \ln(2) = 9.57 \times 10^{-24}&amp;lt;/math&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In a system where D = 3 and N = 1000 and in its lowest energy state, E = -3000J and S = 9.57 × 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;
If one of the spins were to flip, E = -2988J and S = 1.05 × 10&amp;lt;sup&amp;gt;-22&amp;lt;/sup&amp;gt; J K&amp;lt;sup&amp;gt;-1&amp;lt;/sup&amp;gt;. ΔE = 12J and ΔS = 9.54 × 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;
[[File:ThirdYearCMPExpt-IsingSketch.png|none|thumb|&#039;&#039;&#039;Figure 1&#039;&#039;&#039; - Taken from [https://wiki.ch.ic.ac.uk/wiki/index.php?title=Third_year_CMP_compulsory_experiment/Introduction_to_the_Ising_model]]]&lt;br /&gt;
The total magnetisation of a system &amp;lt;math&amp;gt;M = \sum_{i} s_{i}&amp;lt;/math&amp;gt;. In &amp;lt;b&amp;gt;figure 1&amp;lt;/b&amp;gt;, the total magnetisation of the 1D and 2D lattices are both 1.&lt;br /&gt;
&lt;br /&gt;
In a lattice with D = 3 and N = 1000 at absolute zero, there is no entropic contribution to the free energy, so all the lattice points should have the same spin and the total magnetisation should be ±1000.&lt;br /&gt;
&lt;br /&gt;
== Section 2 ==&lt;br /&gt;
[[File:Yht17 CMP ILcheck.PNG|none|thumb|&#039;&#039;&#039;Figure 2&#039;&#039;&#039; - Test of energy and magnetisation methods]]&lt;br /&gt;
&lt;br /&gt;
== Section 3 ==&lt;br /&gt;
In a system with 100 spins, there are 2&amp;lt;sup&amp;gt;100&amp;lt;/sup&amp;gt;, or about 1.27 × 10&amp;lt;sup&amp;gt;30&amp;lt;/sup&amp;gt; possible configurations. If a computer could analyse and find the energy and magnetisation for 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; of these configurations per second, it would take over 40 trillion years to find a single value of &amp;lt;math&amp;gt;\langle M \rangle _{T}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To accelerate the process, a Monte Carlo algorithm was employed.&lt;br /&gt;
&lt;br /&gt;
At a temperature below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, the spins of the entire lattice should align, resulting in magnetisation.&lt;br /&gt;
[[File:Yht17 CMP Anim.png|none|thumb|&#039;&#039;&#039;Figure 3&#039;&#039;&#039; - Final frame of animation of 8×8 lattice at t = 0.5]]&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&#039;&#039;&#039;Table 1 - Statistics&#039;&#039;&#039;&lt;br /&gt;
!E&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2.0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!E&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|4.0&lt;br /&gt;
|-&lt;br /&gt;
!M&lt;br /&gt;
|1.0&lt;br /&gt;
|-&lt;br /&gt;
!M&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&lt;br /&gt;
|1.0&lt;br /&gt;
|}&lt;br /&gt;
The temperature of the simulation in &#039;&#039;&#039;figure 3&#039;&#039;&#039; is below T&amp;lt;sub&amp;gt;C&amp;lt;/sub&amp;gt;, and indeed the spins do align. The statistics in &#039;&#039;&#039;table 1&#039;&#039;&#039; also show that the spins are aligned.&lt;br /&gt;
&lt;br /&gt;
Due to issues with the animation script, this part was completed after the statistics function was fixed to account for the time taken to equilibriate.&lt;br /&gt;
&lt;br /&gt;
== Section 4 ==&lt;br /&gt;
The script to run the Monte Carlo algorithm may not be very fast.&lt;br /&gt;
&lt;br /&gt;
A test function was used to time how long it takes for the script to run a 25 by 25 grid of spins for 2000 steps at T = 1. This was done on a campus computer.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 2 - Time trial of unoptimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|2.2466&lt;br /&gt;
|2.2551&lt;br /&gt;
|2.2456&lt;br /&gt;
|2.2509&lt;br /&gt;
|2.2414&lt;br /&gt;
|2.2479&lt;br /&gt;
|0.0021&lt;br /&gt;
|}&lt;br /&gt;
The script was optimised using some built-in functions from the numpy module and the test was repeated.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 3 - Time trial of optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.2151&lt;br /&gt;
|0.2159&lt;br /&gt;
|0.2220&lt;br /&gt;
|0.2194&lt;br /&gt;
|0.2155&lt;br /&gt;
|0.2176&lt;br /&gt;
|0.0012&lt;br /&gt;
|}&lt;br /&gt;
The optimisation results in a script that is over 10 times faster than the unoptimised script.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 4 - Time trial of further optimised script&lt;br /&gt;
!Trial 1 (s)&lt;br /&gt;
!Trial 2 (s)&lt;br /&gt;
!Trial 3 (s)&lt;br /&gt;
!Trial 4 (s)&lt;br /&gt;
!Trial 5 (s)&lt;br /&gt;
!Average (s)&lt;br /&gt;
!Standard deviation (s)&lt;br /&gt;
|-&lt;br /&gt;
|0.1343&lt;br /&gt;
|0.1349&lt;br /&gt;
|0.1355&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.1356&lt;br /&gt;
|0.1351&lt;br /&gt;
|0.0002&lt;br /&gt;
|}&lt;br /&gt;
With some further optimisations to the algorithm step method, the script is now over 15 times faster than the original unoptimised script.&lt;br /&gt;
&lt;br /&gt;
== Section 5 ==&lt;br /&gt;
After the beginning of the simulation, there is a period of time before the system reaches equilibrium. This time varies as the temperature and size of lattice changes, but it increases as the lattice size increases and also generally as the temperature decreases. For the average energies and magnetisations to be accurate, they should not take into account any states before the system reaches equilibrium. This can be achieved by manually setting a cutoff point before which no states are considered. For a 8×8 lattice, 2000 cycles is sufficient for the system to reach equilibrium.&lt;br /&gt;
[[File:Yht17 CMP 8 8 0.5.PNG|none|thumb|&#039;&#039;&#039;Figure 4&#039;&#039;&#039; - Final state of 8×8 lattice at t = 0.5]]&lt;br /&gt;
With this fix in place, the script can be used to find properties of the system. By starting with an aligned lattice at a low temperature then repeatedly raising the temperature by a small interval and letting the system equilibriate, the point at which entropy starts to dominate can be found.&lt;br /&gt;
&lt;br /&gt;
== Section 6 ==&lt;br /&gt;
The simulation was run over the temperature range t = 0.05 to t = 5.0 for the lattice sizes 2×2, 4×4, 8×8, 16×16 and 32×32.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table 5 - simulation details&lt;br /&gt;
!Lattice size&lt;br /&gt;
!Cycles&lt;br /&gt;
!Cutoff point&lt;br /&gt;
|-&lt;br /&gt;
|2×2&lt;br /&gt;
|100000&lt;br /&gt;
|8&lt;br /&gt;
|-&lt;br /&gt;
|4×4&lt;br /&gt;
|100000&lt;br /&gt;
|128&lt;br /&gt;
|-&lt;br /&gt;
|8×8&lt;br /&gt;
|100000&lt;br /&gt;
|2048&lt;br /&gt;
|-&lt;br /&gt;
|16×16&lt;br /&gt;
|200000&lt;br /&gt;
|32768&lt;br /&gt;
|-&lt;br /&gt;
|32×32&lt;br /&gt;
|300000&lt;br /&gt;
|160000&lt;br /&gt;
|}&lt;br /&gt;
[[File:Yht17 CMP 2x2 2.png|none|thumb|&#039;&#039;&#039;Figure 5&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 2×2 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 4x4 2.png|none|thumb|&#039;&#039;&#039;Figure 6&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 4×4 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 8x8 2.png|none|thumb|&#039;&#039;&#039;Figure 7&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 8×8 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 16x16 2.png|none|thumb|&#039;&#039;&#039;Figure 8&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 16×16 lattice]]&lt;br /&gt;
[[File:Yht17 CMP 32x32 2.png|none|thumb|&#039;&#039;&#039;Figure 9&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for a 32×32 lattice]]The error bars were plotted using the standard deviation.&lt;br /&gt;
[[File:Yht17 CMP 2481632.PNG|none|thumb|&#039;&#039;&#039;Figure 10&#039;&#039;&#039; - Average energy and magnetisation per spin at increasing temperatures for all lattices]]&lt;/div&gt;</summary>
		<author><name>Yht17</name></author>
	</entry>
</feed>