Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
287 views
ubuntu2404
1
#!/usr/bin/env python3
2
"""
3
Statistical Mechanics Monte Carlo Simulations
4
==============================================
5
6
This module implements Monte Carlo simulations for statistical mechanics systems:
7
- 2D Ising model with Metropolis algorithm
8
- Exact 1D Ising model solutions
9
- Thermodynamic property calculations
10
- Phase transition analysis
11
12
Keywords: ising model monte carlo, statistical mechanics python, metropolis algorithm,
13
phase transition simulation, partition function calculation, magnetic susceptibility
14
15
Author: CoCalc Scientific Templates
16
License: MIT
17
"""
18
19
import numpy as np
20
import matplotlib.pyplot as plt
21
from numba import jit
22
23
# Set reproducible random seed
24
np.random.seed(42)
25
26
class IsingModel2D:
27
"""
28
2D Ising model Monte Carlo simulation using Metropolis algorithm.
29
30
Hamiltonian: H = -J Σ_{<i,j>} S_i S_j - h Σ_i S_i
31
where S_i = ±1 are spin variables.
32
"""
33
34
def __init__(self, N, J=1.0, h=0.0):
35
"""
36
Parameters:
37
-----------
38
N : int
39
Linear lattice size (N×N total spins)
40
J : float
41
Nearest-neighbor coupling constant
42
h : float
43
External magnetic field
44
"""
45
self.N = N
46
self.J = J
47
self.h = h
48
self.spins = np.random.choice([-1, 1], size=(N, N))
49
50
@staticmethod
51
@jit(nopython=True)
52
def total_energy(spins, J, h):
53
"""Calculate total energy of the configuration."""
54
N = spins.shape[0]
55
energy = 0.0
56
57
# Nearest neighbor interactions with periodic boundary conditions
58
for i in range(N):
59
for j in range(N):
60
right = spins[i, (j+1) % N]
61
down = spins[(i+1) % N, j]
62
energy -= J * spins[i, j] * (right + down)
63
64
# External field term
65
energy -= h * np.sum(spins)
66
return energy
67
68
@staticmethod
69
@jit(nopython=True)
70
def metropolis_step(spins, beta, J, h):
71
"""Perform one Metropolis Monte Carlo sweep."""
72
N = spins.shape[0]
73
74
for _ in range(N * N):
75
# Choose random site
76
i, j = np.random.randint(0, N, 2)
77
78
# Calculate energy change for spin flip
79
neighbors = (spins[i, (j+1) % N] + spins[i, (j-1) % N] +
80
spins[(i+1) % N, j] + spins[(i-1) % N, j])
81
82
delta_E = 2 * J * spins[i, j] * neighbors + 2 * h * spins[i, j]
83
84
# Metropolis acceptance criterion
85
if delta_E < 0 or np.random.random() < np.exp(-beta * delta_E):
86
spins[i, j] *= -1
87
88
@staticmethod
89
@jit(nopython=True)
90
def magnetization(spins):
91
"""Calculate magnetization per site."""
92
return np.mean(spins)
93
94
def simulate(self, temperature, n_steps=5000, n_equilibration=1000, sample_interval=10):
95
"""
96
Run Monte Carlo simulation at given temperature.
97
98
Parameters:
99
-----------
100
temperature : float
101
Temperature T
102
n_steps : int
103
Number of Monte Carlo steps after equilibration
104
n_equilibration : int
105
Number of equilibration steps
106
sample_interval : int
107
Sampling interval for measurements
108
109
Returns:
110
--------
111
observables : dict
112
Dictionary containing measured observables
113
"""
114
beta = 1.0 / temperature
115
116
# Equilibration
117
for step in range(n_equilibration):
118
self.metropolis_step(self.spins, beta, self.J, self.h)
119
120
# Measurement phase
121
magnetizations = []
122
energies = []
123
124
for step in range(n_steps):
125
self.metropolis_step(self.spins, beta, self.J, self.h)
126
127
if step % sample_interval == 0:
128
mag = abs(self.magnetization(self.spins))
129
energy = self.total_energy(self.spins, self.J, self.h) / (self.N**2)
130
131
magnetizations.append(mag)
132
energies.append(energy)
133
134
# Calculate thermodynamic quantities
135
mag_mean = np.mean(magnetizations)
136
mag_var = np.var(magnetizations)
137
energy_mean = np.mean(energies)
138
energy_var = np.var(energies)
139
140
observables = {
141
'magnetization': mag_mean,
142
'susceptibility': beta * mag_var * self.N**2,
143
'energy': energy_mean,
144
'heat_capacity': beta**2 * energy_var * self.N**2,
145
'final_configuration': self.spins.copy()
146
}
147
148
return observables
149
150
class IsingModel1D:
151
"""
152
1D Ising model exact solution using transfer matrix method.
153
154
The transfer matrix approach provides exact thermodynamic properties
155
for comparison with Monte Carlo results and validation.
156
"""
157
158
def __init__(self, J=1.0, h=0.0):
159
"""
160
Parameters:
161
-----------
162
J : float
163
Nearest-neighbor coupling constant
164
h : float
165
External magnetic field
166
"""
167
self.J = J
168
self.h = h
169
170
def transfer_matrix(self, temperature):
171
"""
172
Construct transfer matrix for given temperature.
173
174
Returns:
175
--------
176
T_matrix : ndarray
177
2×2 transfer matrix
178
"""
179
beta = 1.0 / temperature
180
181
# Matrix elements
182
T11 = np.exp(beta * (self.J + self.h)) # ↑↑
183
T12 = np.exp(beta * (-self.J)) # ↑↓
184
T21 = np.exp(beta * (-self.J)) # ↓↑
185
T22 = np.exp(beta * (self.J - self.h)) # ↓↓
186
187
return np.array([[T11, T12], [T21, T22]])
188
189
def exact_properties(self, temperature, N=None):
190
"""
191
Calculate exact thermodynamic properties.
192
193
Parameters:
194
-----------
195
temperature : float
196
Temperature T
197
N : int, optional
198
System size for finite-size calculations
199
200
Returns:
201
--------
202
properties : dict
203
Exact thermodynamic properties
204
"""
205
T_matrix = self.transfer_matrix(temperature)
206
eigenvals = np.linalg.eigvals(T_matrix)
207
lambda_max = np.max(eigenvals)
208
209
# Free energy per site (thermodynamic limit)
210
f_per_site = -temperature * np.log(lambda_max)
211
212
properties = {
213
'free_energy_per_site': f_per_site,
214
'eigenvalues': eigenvals
215
}
216
217
# Finite system properties
218
if N is not None:
219
Z = np.trace(np.linalg.matrix_power(T_matrix, N))
220
F_total = -temperature * np.log(Z)
221
properties['partition_function'] = Z
222
properties['free_energy_total'] = F_total
223
224
return properties
225
226
def critical_temperature_2d():
227
"""
228
Return the exact critical temperature for 2D Ising model.
229
230
T_c = 2J / ln(1 + √2) ≈ 2.269 J
231
"""
232
return 2.0 / np.log(1 + np.sqrt(2))
233
234
def phase_transition_study(lattice_size=64, T_min=1.0, T_max=4.0, n_temps=20):
235
"""
236
Study the magnetic phase transition in 2D Ising model.
237
238
Parameters:
239
-----------
240
lattice_size : int
241
Linear size of the lattice
242
T_min, T_max : float
243
Temperature range
244
n_temps : int
245
Number of temperature points
246
247
Returns:
248
--------
249
temperatures : array
250
Temperature points
251
results : list
252
List of simulation results at each temperature
253
"""
254
print(f"Phase transition study: {lattice_size}×{lattice_size} lattice")
255
256
temperatures = np.linspace(T_min, T_max, n_temps)
257
T_c = critical_temperature_2d()
258
print(f"Theoretical critical temperature: T_c = {T_c:.3f}")
259
260
ising = IsingModel2D(N=lattice_size, J=1.0, h=0.0)
261
results = []
262
263
for i, T in enumerate(temperatures):
264
print(f" Temperature {i+1}/{n_temps}: T = {T:.2f}")
265
observables = ising.simulate(T, n_steps=5000, n_equilibration=1000)
266
results.append(observables)
267
268
return temperatures, results, T_c
269
270
def exact_vs_monte_carlo_comparison():
271
"""
272
Compare 1D Ising model exact solution with Monte Carlo simulation.
273
"""
274
print("=== 1D Ising Model: Exact vs Monte Carlo ===")
275
276
# Parameters
277
J = 1.0
278
h = 0.1 # Small field to break symmetry
279
temperatures = np.linspace(0.5, 5.0, 20)
280
281
# Exact solution
282
exact_model = IsingModel1D(J=J, h=h)
283
exact_results = []
284
285
for T in temperatures:
286
props = exact_model.exact_properties(T, N=100)
287
exact_results.append(props)
288
289
print(f"Exact 1D calculation completed: {len(temperatures)} temperatures")
290
return temperatures, exact_results
291
292
def thermodynamic_integration_demo():
293
"""
294
Demonstrate calculation of thermodynamic properties.
295
"""
296
print("=== Thermodynamic Integration Demo ===")
297
298
# Calculate free energy as function of temperature
299
temperatures = np.linspace(0.5, 5.0, 100)
300
model_1d = IsingModel1D(J=1.0, h=0.1)
301
302
free_energies = []
303
partition_functions = []
304
305
for T in temperatures:
306
props = model_1d.exact_properties(T, N=50)
307
free_energies.append(props['free_energy_per_site'])
308
partition_functions.append(props['partition_function'])
309
310
return temperatures, free_energies, partition_functions
311
312
def extract_critical_exponents(temperatures, magnetizations, T_c):
313
"""
314
Extract critical exponents from Monte Carlo data.
315
316
Near T_c: m ∝ |T - T_c|^β where β ≈ 1/8 for 2D Ising model
317
"""
318
# Focus on temperatures near T_c
319
mask = np.abs(temperatures - T_c) < 0.5
320
T_fit = temperatures[mask]
321
m_fit = np.array(magnetizations)[mask]
322
323
# Only use temperatures below T_c where magnetization is non-zero
324
below_Tc = T_fit < T_c
325
if np.sum(below_Tc) > 3:
326
reduced_temp = (T_c - T_fit[below_Tc]) / T_c
327
log_m = np.log(m_fit[below_Tc] + 1e-10) # Avoid log(0)
328
log_t = np.log(reduced_temp + 1e-10)
329
330
# Linear fit in log-log space
331
coeffs = np.polyfit(log_t, log_m, 1)
332
beta_critical = coeffs[0]
333
334
print(f"Estimated critical exponent β = {beta_critical:.3f}")
335
print(f"Theoretical value β = 0.125")
336
337
return beta_critical
338
else:
339
print("Insufficient data points below T_c for critical exponent extraction")
340
return None
341
342
if __name__ == "__main__":
343
# Run demonstrations
344
temperatures, results, T_c = phase_transition_study(lattice_size=32, n_temps=10)
345
346
# Extract observables
347
magnetizations = [r['magnetization'] for r in results]
348
energies = [r['energy'] for r in results]
349
susceptibilities = [r['susceptibility'] for r in results]
350
351
print(f"\nFinal results:")
352
print(f"Lowest T magnetization: {magnetizations[0]:.4f}")
353
print(f"Highest T magnetization: {magnetizations[-1]:.4f}")
354
355
# Critical exponent analysis
356
extract_critical_exponents(temperatures, magnetizations, T_c)
357
358
# Run other demonstrations
359
exact_vs_monte_carlo_comparison()
360
thermodynamic_integration_demo()
361