#imports
import numpy as np
from numpy import random
import matplotlib as mpl
import matplotlib.pyplot as plt
def probabilities_spin_flipping(T, h):
"""Funktion, die die Wahrscheinlichkeiten eines Spin-flippings herausgibt. Argumente sind Temperatur T
und Magnetfeldstärke h. combination_spins gibt die möglichen spinkonfigurationen von Anfangsposition
und summe der Nachbarspins aus"""
J = 1
combination_spins = [(-1, 4), (1, 4), (-1, 2), (1, 2), (-1, 0), (1, 0), (-1, -2), (1, -2), (-1, -4), (1, -4)]
def probabilities(spin, total_spin):
"""Ermittlung der Wahrscheinlichkeiten über die Energiedifferenz Delta_E"""
Delta_E = 2 * ( J * spin * total_spin + h * spin)
probability = np.exp(- Delta_E / T)
if Delta_E < 0:
return 1
if Delta_E >= 0:
return probability
return {(spin, total_spin): probabilities(spin, total_spin) for (spin, total_spin) in combination_spins}
# Kontrolle
probabilities_spin_flipping(5, 0)
def next_neighbors(x, y, lattice):
""" Eine Funktion, um von einer Gegebenen Position im Gitter -gegeben durch die Parameter x und y.
Wir betrachten periodische Randbedingungen, dafür ist das Argument lattice in der Funktion vorhanden.
"""
bottom = (x, (y - 1) % lattice)
top = (x, (y + 1) % lattice)
right = ((x + 1) % lattice, y)
left = ((x - 1) % lattice, y)
return [left, right, top, bottom]
# Kontrolle
print(next_neighbors(2,2,3))
# Um eine Sweep zu starten, benötigen wir eine zufällig gewählte Spinverteilung auf dem Gitter.
def init_lattice_spin(lattice):
spin_values = [-1, 1]
return random.choice(spin_values, size=(lattice, lattice))
# Kontrolle
init_lattice_spin(3)
def single_sweep(init, lattice, T, h):
"""Funktion zur durchführung einer einzelnen Metropolis-Sweep. In der Schleife wird der Metropolis Algorythmus durchgeführt.
Ausgegeben wird von der Funktion direkt nichts, allerdings wird das Anfangsgitter überschrieben.
Dies wird in der nächsten Code-Zeile vorgeführt"""
probabilities = probabilities_spin_flipping(T, h)
for m in range(lattice ** 2):
i = random.randint(0, lattice)
j = random.randint(0, lattice)
sigma_i = init[i, j]
sigma_j = next_neighbors(i, j, lattice)
sigma_j_total = 0
for n in range(4):
sigma_j_total += init[sigma_j[n]]
if random.random() < probabilities[(sigma_i, sigma_j_total)]:
init[i, j] *= -1
# Kontrolle
grid = init_lattice_spin(4)
print(grid)
single_sweep(grid,4, 1.2, 8)
print(grid)
#16x16 Gitter erzeugen mit positiven Spins
init_4 = np.ones((16,16))
# Abspeichern des Resultates mit den vorgegebenen Werten
Spins = single_sweep(init_4, 16, 1.5, -8)
print(init_4)
#Plotten der Konfiuration nach einem Single-Sweep
fig, ax = plt.subplots(figsize=(8, 8))
X, Y = np.meshgrid(range(17), range(17))
plt.pcolormesh(X, Y, init_4, cmap=plt.cm.coolwarm)
plt.colorbar()
plt.title('Spinkonfiguration nach einem Sweep')
plt.show()
def magn_per_spin(init, lattice):
"""Ausrechnen der Magnetisierung pro Spin mit der gitterkonfiguration und der Gitterkonstante als Parameter.
Ausgegeben wird der Betrag."""
return np.abs(np.sum(init) / (lattice ** 2))
#Kontrolle
print(magn_per_spin(init_4, 16))
fig = plt.figure(figsize=(9, 4), dpi=90)
#Plotten der Magnetisierung über die Anzahl der sweeps
init_5 = init_lattice_spin(16)
t_1 = 300
magnetization = [magn_per_spin(init_5, 16)]
#Schleife, um nach jedem Sweep die Magnetisierung zu messen
for i in range(t_1):
single_sweep(init_5, 16, 1, 0)
m = magn_per_spin(init_5, 16)
magnetization.append(m)
plt.plot(magnetization, color='blue')
print(init_5) # hier ist das Endgitter zu sehen
plt.title('Entwicklung der Magnetisierung per Spin')
plt.xlabel('Anzahl der sweeps')
plt.ylabel('Magnetisierung pro Spin')
plt.xlim(0, t_1)
plt.grid(True)
plt.show()
fig, ax = plt.subplots(figsize=(10, 7))
plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.5)
#zufällige Spin Konfiguration
ax1 = plt.subplot(211)
init_6 = init_lattice_spin(16)
t_2 = 100
magnetization_6_1 = [magn_per_spin(init_6, 16)]
for i in range(t_2):
Spins = single_sweep(init_6, 16, 5, 0)
m_6_1 = magn_per_spin(init_6, 16)
magnetization_6_1.append(m_6_1)
plt.plot(magnetization_6_1, color='blue')
plt.title('Entwicklung der Magnetisierung pro Spin für ein zufälliges Anfangsgitter')
plt.xlabel('Anzahl der sweeps')
plt.ylabel('Magnetisierung per Spin')
plt.xlim(0, t_2)
plt.grid(True)
#Positive Spin Konfiguration
ax2 = plt.subplot(212)
init_pos = np.ones((16, 16))
magnetization_6_2 = [magn_per_spin(init_pos, 16)]
for i in range(t_2):
Spins = single_sweep(init_pos, 16, 5, 0)
m_6_2 = magn_per_spin(init_pos, 16)
magnetization_6_2.append(m_6_2)
plt.plot(magnetization_6_2, color='blue')
plt.title('Entwicklung der Magnetisierung pro Spin für ein positives Anfangsgitter')
plt.xlabel('Anzahl der sweeps')
plt.ylabel('Magnetisierung per Spin')
plt.xlim(0, t_2)
plt.grid(True)
plt.show()
def converge_magn_time(lattice, T, h):
"""Funktion um die Zeit zur Zusammenführung der Magnetisierungen beider Systeme zu berechnen.
Wir betrachten ein gordnetes und ein ungeordnetes Gitter. Der oben beschriebene Prozess ist implementiert,
und die Schleife bricht ab, wenn die Magnetisierungen beider Systeme in einem Bereich von 0,05 voneinander liegen.
Ausgegeben wird die Anzahl der Zeitschritte, bis die Schleife abbricht, bzw. die Anzahl an sweeps."""
init_pos = np.ones((16, 16)) #positive Spinverteilung
init_random = init_lattice_spin(16) #random Spinverteilung
magn_pos = np.zeros(shape=10)
magn_random = np.zeros(shape=10)
timestep = 0
while True:
single_sweep(init_pos, lattice, T, h)
single_sweep(init_random, lattice, T, h)
magn_pos[i%10] = magn_per_spin(init_pos, lattice)
magn_random[i%10] = magn_per_spin(init_random, lattice)
timestep += 1
if np.abs((np.sum(magn_pos) - np.sum(magn_random)) / 10 ) < 0.05 and timestep >= 10:
break
return timestep
#Kontrolle
converge_magn_time(16, 1, 0)
def estimated_time(lattice, runs, T, h):
"""Funktion, um die durchschnittliche Zeit über mehrere Runs zu ermitteln. gleichzeitig wird der Standartfehler berechnet
und ausgegeben."""
time = np.zeros(shape=(runs))
for i in range(runs):
time[i] = converge_magn_time(lattice, T, h)
mean_time = np.mean(time)
error_bars = np.std(time) / (np.sqrt(runs))
return [mean_time, error_bars]
# Definieren des Temperatur-Arrays
Temp = np.linspace(1, 4, 61)
print(Temp)
"""Ermitteln der Zeiten bis zur Annäherung über Schleifen. Es wird ein Index der Zeit und gelichzeitig die Temperaturen
druchlaufen. Die ermittelten Durchscnittswerte werden verwendet."""
converge_times = np.zeros(shape=len(Temp))
error_times = np.zeros(shape=len(Temp))
for i, temps in enumerate(Temp):
converge_times[i] = estimated_time(16, 30, temps, 0)[0]
error_times[i] = estimated_time(16, 30, temps, 0)[1]
print(converge_times)
#Plotten der Zeiten in Abhängigkeit der Temperatur
fig = plt.figure(figsize=(9, 6), dpi=90)
plt.errorbar(Temp, converge_times, yerr=error_times, fmt='.', color='black', ecolor='lightgray', elinewidth=1.5)
plt.plot(Temp, converge_times, linewidth=1)
plt.title('Annäherungszeit in Abhängigkeit der Temperatur')
plt.xlabel('Temperatur')
plt.xlim(1, 4)
plt.grid(True)
plt.show()
def estimated_magn(T, t_eq):
"""Funktion, um die druchschnittliche Magnetisierung über 100 Messungen und 2 * t_eq zu berechnen."""
magn = np.zeros(100,)
init_pos = np.ones((16, 16))
for k in range(100):
single_sweep(init_pos, 16, T, 0)
for k in range(2 * t_eq):
single_sweep(init_pos, 16, T, 0)
magn[k] = magn_per_spin(init_pos, 16)
mean_time = np.mean(magn)
return mean_time
print(estimated_magn(2, converge_times[0]))
converge_magn = np.zeros(shape=len(Temp))
for i, temps in enumerate(Temp):
converge_magn[i] = estimated_magn(T, converge_times[i])
print(converge_magn)
#Plotten der Magnetisierung in Abhängigkeit der Temperatur
fig = plt.figure(figsize=(9, 6), dpi=90)
plt.scatter(Temp, converge_magn)
plt.plot(Temp, converge_magn, linewidth=1)
plt.title('Annäherungszeit in Abhängigkeit der Temperatur')
plt.xlabel('Temperatur')
plt.xlim(1, 4)
plt.grid(True)
plt.show()