Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
284 views
ubuntu2404
1
#!/usr/bin/env python3
2
"""
3
Condensed Matter Physics Simulations
4
=====================================
5
6
This module implements fundamental condensed matter physics calculations:
7
- Electronic band structure using tight-binding models
8
- Fermi surface calculations and visualization
9
- Phonon dispersion relations
10
- Many-body systems (Hubbard model)
11
12
Keywords: band structure calculation python, tight binding model, fermi surface calculation,
13
phonon dispersion python, hubbard model simulation, electronic properties condensed matter
14
15
Author: CoCalc Scientific Templates
16
License: MIT
17
"""
18
19
import numpy as np
20
import matplotlib.pyplot as plt
21
from scipy.linalg import eigh
22
23
# Set reproducible random seed
24
np.random.seed(42)
25
26
class TightBindingModel:
27
"""
28
Tight-binding model for electronic band structure calculations.
29
30
Supports various lattice geometries and can calculate:
31
- Energy dispersion relations E(k)
32
- Density of states
33
- Fermi surfaces
34
"""
35
36
def __init__(self, lattice_type='square'):
37
"""
38
Parameters:
39
-----------
40
lattice_type : str
41
Type of lattice ('square', 'triangular', 'honeycomb')
42
"""
43
self.lattice_type = lattice_type
44
45
def dispersion_square_2d(self, kx, ky, t=1.0, epsilon_0=0.0):
46
"""
47
Energy dispersion for 2D square lattice.
48
49
E(k) = ε₀ - 2t(cos(kₓ) + cos(kᵧ))
50
51
Parameters:
52
-----------
53
kx, ky : array
54
k-space coordinates
55
t : float
56
Hopping parameter
57
epsilon_0 : float
58
On-site energy
59
"""
60
return epsilon_0 - 2*t*(np.cos(kx) + np.cos(ky))
61
62
def dispersion_graphene(self, kx, ky, t=1.0):
63
"""
64
Energy dispersion for graphene (honeycomb lattice).
65
66
Returns both conduction and valence bands.
67
68
Parameters:
69
-----------
70
kx, ky : array
71
k-space coordinates
72
t : float
73
Hopping parameter
74
"""
75
# Phase factor for nearest neighbors
76
f = 1 + np.exp(1j * kx) + np.exp(1j * (kx/2 + np.sqrt(3)*ky/2))
77
energy_magnitude = t * np.abs(f)
78
79
return energy_magnitude, -energy_magnitude # Conduction, valence bands
80
81
def density_of_states(self, energies, n_bins=200, broadening=0.01):
82
"""
83
Calculate density of states with optional Gaussian broadening.
84
85
Parameters:
86
-----------
87
energies : array
88
Energy values from band calculation
89
n_bins : int
90
Number of energy bins
91
broadening : float
92
Gaussian broadening width
93
"""
94
E_flat = energies.flatten()
95
E_min, E_max = E_flat.min() - 3*broadening, E_flat.max() + 3*broadening
96
E_grid = np.linspace(E_min, E_max, n_bins)
97
98
if broadening > 0:
99
# Gaussian broadened DOS
100
dos = np.zeros_like(E_grid)
101
for E in E_flat:
102
dos += np.exp(-(E_grid - E)**2 / (2*broadening**2))
103
dos /= (np.sqrt(2*np.pi) * broadening * len(E_flat))
104
else:
105
# Histogram DOS
106
hist, bin_edges = np.histogram(E_flat, bins=E_grid)
107
dos = hist / (E_grid[1] - E_grid[0]) / len(E_flat)
108
E_grid = (bin_edges[:-1] + bin_edges[1:]) / 2
109
110
return E_grid, dos
111
112
def fermi_surface(self, kx, ky, mu, temperature=0.01):
113
"""
114
Calculate Fermi surface and electron occupation.
115
116
Parameters:
117
-----------
118
kx, ky : array
119
k-space grid
120
mu : float
121
Chemical potential
122
temperature : float
123
Temperature for Fermi-Dirac distribution
124
125
Returns:
126
--------
127
energy : array
128
Energy dispersion
129
occupation : array
130
Fermi-Dirac occupation function
131
"""
132
energy = self.dispersion_square_2d(kx, ky)
133
134
# Fermi-Dirac distribution
135
if temperature > 0:
136
occupation = 1.0 / (1.0 + np.exp((energy - mu) / temperature))
137
else:
138
occupation = (energy < mu).astype(float)
139
140
return energy, occupation
141
142
class PhononModel:
143
"""
144
Phonon dispersion calculations for various lattice models.
145
146
Implements:
147
- 1D monoatomic chain
148
- 1D diatomic chain
149
- Density of phonon states
150
"""
151
152
@staticmethod
153
def monoatomic_chain_1d(k, K=1.0, M=1.0):
154
"""
155
Phonon frequency for 1D monoatomic chain.
156
157
ω(k) = √(4K/M) |sin(k/2)|
158
159
Parameters:
160
-----------
161
k : array
162
Wave vector
163
K : float
164
Spring constant
165
M : float
166
Atomic mass
167
"""
168
return np.sqrt(4*K/M) * np.abs(np.sin(k/2))
169
170
@staticmethod
171
def diatomic_chain_1d(k, K=1.0, M1=1.0, M2=2.0):
172
"""
173
Phonon frequencies for 1D diatomic chain.
174
175
Returns both optical and acoustic branches.
176
177
Parameters:
178
-----------
179
k : array
180
Wave vector
181
K : float
182
Spring constant
183
M1, M2 : float
184
Masses of the two atoms
185
"""
186
M_sum = M1 + M2
187
M_prod = M1 * M2
188
189
# Discriminant for eigenvalue equation
190
discriminant = M_sum**2 - 4*M_prod*np.cos(k)**2
191
192
# Optical and acoustic branches
193
omega_optical = np.sqrt(K * (M_sum + np.sqrt(discriminant)) / (2*M_prod))
194
omega_acoustic = np.sqrt(K * (M_sum - np.sqrt(discriminant)) / (2*M_prod))
195
196
return omega_optical, omega_acoustic
197
198
class HubbardModel:
199
"""
200
Mean-field solution of the Hubbard model.
201
202
H = -t Σ⟨i,j⟩σ (c†ᵢσ cⱼσ + h.c.) + U Σᵢ nᵢ↑ nᵢ↓
203
204
Implements self-consistent mean-field approximation to study
205
magnetic instabilities and correlation effects.
206
"""
207
208
def __init__(self, lattice_type='square_2d'):
209
"""
210
Parameters:
211
-----------
212
lattice_type : str
213
Lattice geometry
214
"""
215
self.lattice_type = lattice_type
216
217
def mean_field_bands(self, kx, ky, t, mu, U, m):
218
"""
219
Mean-field energy bands for 2D square lattice.
220
221
Parameters:
222
-----------
223
kx, ky : array
224
k-space coordinates
225
t : float
226
Hopping parameter
227
mu : float
228
Chemical potential
229
U : float
230
On-site interaction
231
m : float
232
Magnetization (order parameter)
233
"""
234
# Non-interacting dispersion
235
epsilon_k = -2*t*(np.cos(kx) + np.cos(ky))
236
237
# Mean-field bands
238
E_up = epsilon_k - mu + U*m/2 # Spin-up band
239
E_down = epsilon_k - mu - U*m/2 # Spin-down band
240
241
return E_up, E_down
242
243
def self_consistent_solution(self, t, U, n_target, T=0.1, max_iter=1000, tol=1e-6):
244
"""
245
Solve mean-field equations self-consistently.
246
247
Parameters:
248
-----------
249
t : float
250
Hopping parameter
251
U : float
252
Interaction strength
253
n_target : float
254
Target electron density
255
T : float
256
Temperature
257
max_iter : int
258
Maximum iterations
259
tol : float
260
Convergence tolerance
261
262
Returns:
263
--------
264
mu : float
265
Converged chemical potential
266
m : float
267
Converged magnetization
268
converged : bool
269
Whether solution converged
270
"""
271
# Initial guess
272
mu = U * n_target / 2
273
m = 0.1 # Small initial magnetization
274
275
# k-space grid
276
k_mesh = 64
277
kx = np.linspace(-np.pi, np.pi, k_mesh)
278
ky = np.linspace(-np.pi, np.pi, k_mesh)
279
KX, KY = np.meshgrid(kx, ky)
280
281
for iteration in range(max_iter):
282
# Calculate mean-field bands
283
E_up, E_down = self.mean_field_bands(KX, KY, t, mu, U, m)
284
285
# Fermi-Dirac distributions
286
f_up = 1.0 / (1.0 + np.exp(E_up / T))
287
f_down = 1.0 / (1.0 + np.exp(E_down / T))
288
289
# New density and magnetization
290
n_new = np.mean(f_up + f_down)
291
m_new = np.mean(f_up - f_down)
292
293
# Check convergence
294
if abs(m_new - m) < tol:
295
return mu, m_new, True
296
297
# Update with mixing for stability
298
m = 0.7 * m + 0.3 * m_new
299
300
# Adjust chemical potential to maintain target density
301
mu = mu + 0.1 * (n_target - n_new)
302
303
return mu, m, False
304
305
def band_structure_comparison():
306
"""
307
Compare band structures of different lattice types.
308
"""
309
print("=== Band Structure Comparison ===")
310
311
tb = TightBindingModel()
312
313
# k-space grid
314
k_points = 100
315
kx = np.linspace(-np.pi, np.pi, k_points)
316
ky = np.linspace(-np.pi, np.pi, k_points)
317
KX, KY = np.meshgrid(kx, ky)
318
319
# Calculate dispersions
320
E_square = tb.dispersion_square_2d(KX, KY, t=1.0)
321
E_graphene_c, E_graphene_v = tb.dispersion_graphene(KX, KY, t=1.0)
322
323
# Calculate density of states
324
E_dos_square, dos_square = tb.density_of_states(E_square, broadening=0.05)
325
E_dos_graphene, dos_graphene = tb.density_of_states(
326
np.concatenate([E_graphene_c.flatten(), E_graphene_v.flatten()]),
327
broadening=0.05
328
)
329
330
print(f"Square lattice bandwidth: {E_square.max() - E_square.min():.3f}")
331
print(f"Graphene bandwidth: {E_graphene_c.max() - E_graphene_v.min():.3f}")
332
333
return {
334
'square': {'energy': E_square, 'dos_E': E_dos_square, 'dos': dos_square},
335
'graphene': {'energy_c': E_graphene_c, 'energy_v': E_graphene_v,
336
'dos_E': E_dos_graphene, 'dos': dos_graphene},
337
'kx': KX, 'ky': KY
338
}
339
340
def fermi_surface_evolution():
341
"""
342
Study evolution of Fermi surface with chemical potential.
343
"""
344
print("=== Fermi Surface Evolution ===")
345
346
tb = TightBindingModel()
347
348
# High-resolution k-space grid
349
k_res = 200
350
kx = np.linspace(-np.pi, np.pi, k_res)
351
ky = np.linspace(-np.pi, np.pi, k_res)
352
KX, KY = np.meshgrid(kx, ky)
353
354
# Different chemical potentials (filling levels)
355
mu_values = [-3.0, -2.0, 0.0, 2.0]
356
fermi_data = []
357
358
for mu in mu_values:
359
energy, occupation = tb.fermi_surface(KX, KY, mu, temperature=0.1)
360
fermi_data.append({'mu': mu, 'energy': energy, 'occupation': occupation})
361
362
print(f"Calculated Fermi surfaces for μ = {mu_values}")
363
return fermi_data, KX, KY
364
365
def phonon_comparison():
366
"""
367
Compare phonon dispersions for different chain types.
368
"""
369
print("=== Phonon Dispersion Comparison ===")
370
371
phonon = PhononModel()
372
373
# k-point path
374
k = np.linspace(-np.pi, np.pi, 500)
375
376
# Calculate dispersions
377
omega_mono = phonon.monoatomic_chain_1d(k, K=1.0, M=1.0)
378
omega_opt, omega_ac = phonon.diatomic_chain_1d(k, K=1.0, M1=1.0, M2=2.0)
379
380
print(f"Monoatomic max frequency: {omega_mono.max():.3f}")
381
print(f"Diatomic optical max: {omega_opt.max():.3f}")
382
print(f"Diatomic acoustic max: {omega_ac.max():.3f}")
383
384
return {
385
'k': k,
386
'monoatomic': omega_mono,
387
'optical': omega_opt,
388
'acoustic': omega_ac
389
}
390
391
def hubbard_magnetic_transition():
392
"""
393
Study magnetic transition in Hubbard model.
394
"""
395
print("=== Hubbard Model Magnetic Transition ===")
396
397
hubbard = HubbardModel()
398
399
# Parameters
400
t = 1.0
401
density = 0.8
402
U_values = [0.0, 2.0, 4.0, 6.0]
403
404
results = []
405
for U in U_values:
406
mu, m, converged = hubbard.self_consistent_solution(t, U, density, T=0.1)
407
408
result = {
409
'U': U,
410
'mu': mu,
411
'magnetization': abs(m), # Take absolute value
412
'converged': converged
413
}
414
results.append(result)
415
416
status = "converged" if converged else "not converged"
417
print(f"U/t = {U/t:.1f}: μ = {mu:.3f}, |m| = {abs(m):.4f} ({status})")
418
419
return results
420
421
def calculate_transport_properties(band_data):
422
"""
423
Calculate basic transport properties from band structure.
424
425
This is a simplified demonstration - real transport calculations
426
require more sophisticated methods.
427
"""
428
print("=== Transport Properties Calculation ===")
429
430
# Extract band data
431
energy = band_data['square']['energy']
432
kx = band_data['kx']
433
ky = band_data['ky']
434
435
# Calculate group velocity (simplified)
436
dk = kx[0, 1] - kx[0, 0] # Grid spacing
437
438
# Numerical derivatives for group velocity
439
vx = -np.gradient(energy, dk, axis=1) # vₓ = -∂E/∂kₓ
440
vy = -np.gradient(energy, dk, axis=0) # vᵧ = -∂E/∂kᵧ
441
442
# Speed
443
speed = np.sqrt(vx**2 + vy**2)
444
445
print(f"Maximum group velocity: {speed.max():.3f}")
446
print(f"Average group velocity: {np.mean(speed):.3f}")
447
448
return {'vx': vx, 'vy': vy, 'speed': speed}
449
450
if __name__ == "__main__":
451
# Run all demonstrations
452
band_data = band_structure_comparison()
453
fermi_data, KX, KY = fermi_surface_evolution()
454
phonon_data = phonon_comparison()
455
hubbard_results = hubbard_magnetic_transition()
456
transport = calculate_transport_properties(band_data)
457
458
print("\n=== Summary ===")
459
print(f"Completed all condensed matter physics calculations")
460
print(f"Band structure: {band_data['square']['energy'].shape} k-points")
461
print(f"Fermi surfaces: {len(fermi_data)} chemical potentials")
462
print(f"Phonon modes: {len(phonon_data['k'])} k-points")
463
print(f"Hubbard model: {len(hubbard_results)} interaction strengths")
464