Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
287 views
ubuntu2404
1
# -*- coding: UTF-8 -*-
2
3
4
5
import os
6
import sys
7
import codecs
8
9
if '--interactive' not in sys.argv[1:]:
10
if sys.version_info[0] == 2:
11
sys.stdout = codecs.getwriter('UTF-8')(sys.stdout, 'strict')
12
sys.stderr = codecs.getwriter('UTF-8')(sys.stderr, 'strict')
13
else:
14
sys.stdout = codecs.getwriter('UTF-8')(sys.stdout.buffer, 'strict')
15
sys.stderr = codecs.getwriter('UTF-8')(sys.stderr.buffer, 'strict')
16
17
if '/usr/share/texlive/texmf-dist/scripts/pythontex' and '/usr/share/texlive/texmf-dist/scripts/pythontex' not in sys.path:
18
sys.path.append('/usr/share/texlive/texmf-dist/scripts/pythontex')
19
from pythontex_utils import PythonTeXUtils
20
pytex = PythonTeXUtils()
21
22
pytex.docdir = os.getcwd()
23
if os.path.isdir('.'):
24
os.chdir('.')
25
if os.getcwd() not in sys.path:
26
sys.path.append(os.getcwd())
27
else:
28
if len(sys.argv) < 2 or sys.argv[1] != '--manual':
29
sys.exit('Cannot find directory .')
30
if pytex.docdir not in sys.path:
31
sys.path.append(pytex.docdir)
32
33
34
35
pytex.id = 'py_default_default'
36
pytex.family = 'py'
37
pytex.session = 'default'
38
pytex.restart = 'default'
39
40
pytex.command = 'code'
41
pytex.set_context('')
42
pytex.args = ''
43
pytex.instance = '0'
44
pytex.line = '96'
45
46
print('=>PYTHONTEX:STDOUT#0#code#')
47
sys.stderr.write('=>PYTHONTEX:STDERR#0#code#\n')
48
pytex.before()
49
50
import numpy as np
51
import matplotlib.pyplot as plt
52
from scipy.sparse import diags
53
from scipy.linalg import expm
54
import matplotlib
55
matplotlib.use('Agg') # Use non-interactive backend
56
57
# Set random seed for reproducibility
58
np.random.seed(42)
59
60
# Parameters for quantum simulation
61
hbar = 1.0 # Reduced Planck constant (natural units)
62
m = 1.0 # Particle mass (natural units)
63
L = 10.0 # Box length
64
N = 1000 # Number of grid points
65
dx = L / N # Grid spacing
66
dt = 0.001 # Time step
67
68
# Create spatial grid
69
x = np.linspace(0, L, N)
70
71
# Define potential: harmonic oscillator + barrier
72
omega = 1.0 # Oscillator frequency
73
V = 0.5 * m * omega**2 * (x - L/2)**2 # Harmonic potential
74
V += 2.0 * np.exp(-((x - L/3)/(L/20))**2) # Gaussian barrier for tunneling
75
76
# Create kinetic energy operator (finite difference)
77
kinetic_diag = -2 * np.ones(N)
78
kinetic_off = np.ones(N-1)
79
T_matrix = -(hbar**2 / (2*m*dx**2)) * (
80
diags([kinetic_off, kinetic_diag, kinetic_off], [-1, 0, 1], shape=(N, N))
81
)
82
83
# Hamiltonian matrix
84
H = T_matrix + diags(V, 0)
85
86
# Initial wavefunction: Gaussian wave packet
87
x0 = L/4 # Initial position
88
sigma = L/20 # Wave packet width
89
k0 = 5.0 # Initial momentum
90
psi_initial = np.exp(-(x - x0)**2 / (2*sigma**2)) * np.exp(1j * k0 * x)
91
psi_initial = psi_initial / np.sqrt(np.trapezoid(np.abs(psi_initial)**2, x))
92
93
# Time evolution operator
94
U = expm(-1j * H.toarray() * dt / hbar)
95
96
# Evolve the wavefunction
97
times = np.arange(0, 5.0, dt)
98
psi = psi_initial.copy()
99
100
# Store some snapshots
101
snapshot_times = [0, 1.0, 2.0, 3.0, 4.0]
102
snapshots = []
103
snapshot_indices = []
104
105
for i, t in enumerate(times):
106
if any(abs(t - st) < dt/2 for st in snapshot_times):
107
snapshots.append(psi.copy())
108
snapshot_indices.append(i)
109
psi = U @ psi
110
111
print(f"Quantum simulation completed: {len(times)} time steps")
112
print(f"Stored {len(snapshots)} wavefunction snapshots")
113
print(f"Conservation check - final norm: {np.trapezoid(np.abs(psi)**2, x):.6f}")
114
115
116
pytex.after()
117
pytex.command = 'code'
118
pytex.set_context('')
119
pytex.args = ''
120
pytex.instance = '1'
121
pytex.line = '165'
122
123
print('=>PYTHONTEX:STDOUT#1#code#')
124
sys.stderr.write('=>PYTHONTEX:STDERR#1#code#\n')
125
pytex.before()
126
127
# Create quantum mechanics visualization
128
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))
129
130
# Plot potential
131
ax1.plot(x, V, 'k-', linewidth=2, label='Potential V(x)')
132
ax1.set_ylabel('Energy (natural units)', fontsize=12)
133
ax1.set_title('Quantum Tunneling Through Potential Barrier', fontsize=14, fontweight='bold')
134
ax1.legend()
135
ax1.grid(True, alpha=0.3)
136
137
# Plot wavefunction snapshots
138
colors = plt.cm.viridis(np.linspace(0, 1, len(snapshots)))
139
for i, (psi_snap, color) in enumerate(zip(snapshots, colors)):
140
probability = np.abs(psi_snap)**2
141
ax2.fill_between(x, 0, probability, alpha=0.6, color=color,
142
label=f't = {snapshot_times[i]:.1f}')
143
144
ax2.set_xlabel('Position x (natural units)', fontsize=12)
145
ax2.set_ylabel('Probability Density |ψ(x,t)|²', fontsize=12)
146
ax2.set_title('Wavefunction Evolution: Quantum Tunneling Dynamics', fontsize=14, fontweight='bold')
147
ax2.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
148
ax2.grid(True, alpha=0.3)
149
150
plt.tight_layout()
151
plt.savefig('assets/quantum_tunneling.pdf', dpi=300, bbox_inches='tight')
152
plt.close()
153
154
print("Quantum tunneling visualization saved to assets/quantum_tunneling.pdf")
155
156
157
pytex.after()
158
pytex.command = 'code'
159
pytex.set_context('')
160
pytex.args = ''
161
pytex.instance = '2'
162
pytex.line = '215'
163
164
print('=>PYTHONTEX:STDOUT#2#code#')
165
sys.stderr.write('=>PYTHONTEX:STDERR#2#code#\n')
166
pytex.before()
167
168
from scipy.special import hermite
169
from scipy.special import factorial
170
171
# Quantum harmonic oscillator parameters
172
omega = 1.0 # Angular frequency
173
m = 1.0 # Mass
174
hbar = 1.0 # Reduced Planck constant
175
176
# Length scale
177
x0 = np.sqrt(hbar / (m * omega))
178
179
# Create position grid
180
x_osc = np.linspace(-4*x0, 4*x0, 1000)
181
182
# Calculate first 6 energy eigenstates
183
n_states = 6
184
wavefunctions = []
185
energies = []
186
187
for n in range(n_states):
188
# Energy eigenvalue
189
E_n = hbar * omega * (n + 0.5)
190
energies.append(E_n)
191
192
# Normalization factor
193
norm = 1.0 / np.sqrt(2**n * factorial(n)) * (m*omega/(np.pi*hbar))**(1/4)
194
195
# Hermite polynomial
196
H_n = hermite(n)
197
198
# Wavefunction
199
xi = x_osc / x0 # Dimensionless coordinate
200
psi_n = norm * np.exp(-xi**2 / 2) * H_n(xi)
201
wavefunctions.append(psi_n)
202
203
print(f"Calculated {n_states} harmonic oscillator eigenstates")
204
print(f"Energy levels: {[f'{E:.2f}' for E in energies[:4]]}")
205
206
207
pytex.after()
208
pytex.command = 'code'
209
pytex.set_context('')
210
pytex.args = ''
211
pytex.instance = '3'
212
pytex.line = '255'
213
214
print('=>PYTHONTEX:STDOUT#3#code#')
215
sys.stderr.write('=>PYTHONTEX:STDERR#3#code#\n')
216
pytex.before()
217
218
# Visualize harmonic oscillator eigenstates
219
fig, ax = plt.subplots(figsize=(12, 10))
220
221
# Plot potential
222
V_osc = 0.5 * m * omega**2 * x_osc**2
223
ax.plot(x_osc/x0, V_osc/(hbar*omega), 'k-', linewidth=3, label='Potential V(x)')
224
225
# Plot energy levels and wavefunctions
226
colors = plt.cm.Set1(np.linspace(0, 1, n_states))
227
for n, (psi, E, color) in enumerate(zip(wavefunctions, energies, colors)):
228
# Energy level
229
ax.axhline(E/(hbar*omega), color=color, linestyle='--', alpha=0.7)
230
231
# Wavefunction (scaled and shifted)
232
psi_scaled = psi * 2 + E/(hbar*omega) # Scale and shift
233
ax.plot(x_osc/x0, psi_scaled, color=color, linewidth=2,
234
label=f'n={n}, E={E/(hbar*omega):.1f}ℏω')
235
236
ax.set_xlabel('Position x/x₀', fontsize=14)
237
ax.set_ylabel('Energy / ℏω', fontsize=14)
238
ax.set_title('Quantum Harmonic Oscillator: Energy Eigenstates and Wavefunctions',
239
fontsize=16, fontweight='bold')
240
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
241
ax.grid(True, alpha=0.3)
242
ax.set_xlim(-4, 4)
243
ax.set_ylim(0, 6)
244
245
plt.tight_layout()
246
plt.savefig('assets/harmonic_oscillator.pdf', dpi=300, bbox_inches='tight')
247
plt.close()
248
249
print("Harmonic oscillator visualization saved to assets/harmonic_oscillator.pdf")
250
251
252
pytex.after()
253
pytex.command = 'code'
254
pytex.set_context('')
255
pytex.args = ''
256
pytex.instance = '4'
257
pytex.line = '307'
258
259
print('=>PYTHONTEX:STDOUT#4#code#')
260
sys.stderr.write('=>PYTHONTEX:STDERR#4#code#\n')
261
pytex.before()
262
263
# Particle in a box simulation
264
L_box = 1.0 # Box length
265
m_box = 1.0 # Particle mass
266
hbar = 1.0 # Reduced Planck constant
267
268
# Position grid
269
x_box = np.linspace(0, L_box, 1000)
270
271
# Calculate first 5 energy levels and wavefunctions
272
n_levels = 5
273
box_energies = []
274
box_wavefunctions = []
275
276
for n in range(1, n_levels + 1):
277
# Energy eigenvalue
278
E_n = (n**2 * np.pi**2 * hbar**2) / (2 * m_box * L_box**2)
279
box_energies.append(E_n)
280
281
# Wavefunction
282
psi_n = np.sqrt(2/L_box) * np.sin(n * np.pi * x_box / L_box)
283
box_wavefunctions.append(psi_n)
284
285
# Calculate probability current for superposition state
286
# Create superposition of n=1 and n=2 states
287
c1, c2 = 1/np.sqrt(2), 1/np.sqrt(2) # Equal superposition
288
psi_superposition = c1 * box_wavefunctions[0] + c2 * box_wavefunctions[1]
289
290
print(f"Particle in box: calculated {n_levels} energy levels")
291
print(f"Energy ratios E_n/E_1: {[E/box_energies[0] for E in box_energies]}")
292
293
294
pytex.after()
295
pytex.command = 'code'
296
pytex.set_context('')
297
pytex.args = ''
298
pytex.instance = '5'
299
pytex.line = '339'
300
301
print('=>PYTHONTEX:STDOUT#5#code#')
302
sys.stderr.write('=>PYTHONTEX:STDERR#5#code#\n')
303
pytex.before()
304
305
# Visualize particle in a box
306
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8))
307
308
# Left panel: Energy levels and wavefunctions
309
colors = plt.cm.viridis(np.linspace(0, 1, n_levels))
310
for n, (psi, E, color) in enumerate(zip(box_wavefunctions, box_energies, colors)):
311
# Energy level
312
ax1.axhline(E, color=color, linestyle='--', alpha=0.7, linewidth=1)
313
314
# Wavefunction (scaled and shifted)
315
psi_scaled = psi * 0.3 + E # Scale and shift
316
ax1.plot(x_box, psi_scaled, color=color, linewidth=2,
317
label=f'n={n+1}, E={E:.2f}')
318
319
# Draw box walls
320
ax1.axvline(0, color='black', linewidth=4)
321
ax1.axvline(L_box, color='black', linewidth=4)
322
ax1.axhline(0, color='black', linewidth=2)
323
324
ax1.set_xlabel('Position x', fontsize=12)
325
ax1.set_ylabel('Energy', fontsize=12)
326
ax1.set_title('Particle in a Box: Quantum Energy Levels', fontsize=14, fontweight='bold')
327
ax1.legend()
328
ax1.grid(True, alpha=0.3)
329
330
# Right panel: Superposition state and probability density
331
ax2.plot(x_box, psi_superposition, 'b-', linewidth=2, label='ψ(x) = (ψ₁ + ψ₂)/√2')
332
ax2.fill_between(x_box, 0, np.abs(psi_superposition)**2, alpha=0.5, color='red',
333
label='|ψ(x)|²')
334
335
ax2.axvline(0, color='black', linewidth=4)
336
ax2.axvline(L_box, color='black', linewidth=4)
337
ax2.set_xlabel('Position x', fontsize=12)
338
ax2.set_ylabel('Amplitude / Probability Density', fontsize=12)
339
ax2.set_title('Quantum Superposition: Interference Pattern', fontsize=14, fontweight='bold')
340
ax2.legend()
341
ax2.grid(True, alpha=0.3)
342
343
plt.tight_layout()
344
plt.savefig('assets/particle_in_box.pdf', dpi=300, bbox_inches='tight')
345
plt.close()
346
347
print("Particle in box visualization saved to assets/particle_in_box.pdf")
348
349
350
pytex.after()
351
pytex.command = 'code'
352
pytex.set_context('')
353
pytex.args = ''
354
pytex.instance = '6'
355
pytex.line = '407'
356
357
print('=>PYTHONTEX:STDOUT#6#code#')
358
sys.stderr.write('=>PYTHONTEX:STDERR#6#code#\n')
359
pytex.before()
360
361
import numpy as np
362
import matplotlib.pyplot as plt
363
from numba import jit
364
365
# Set random seed for reproducibility
366
np.random.seed(42)
367
368
@jit(nopython=True)
369
def ising_energy(spins, J, h):
370
"""Calculate total energy of Ising model configuration"""
371
N = spins.shape[0]
372
energy = 0.0
373
374
# Nearest neighbor interactions
375
for i in range(N):
376
for j in range(N):
377
# Periodic boundary conditions
378
right = spins[i, (j+1) % N]
379
down = spins[(i+1) % N, j]
380
energy -= J * spins[i, j] * (right + down)
381
382
# External field
383
energy -= h * np.sum(spins)
384
return energy
385
386
@jit(nopython=True)
387
def metropolis_step(spins, beta, J, h):
388
"""Single Metropolis Monte Carlo step"""
389
N = spins.shape[0]
390
391
for _ in range(N * N):
392
# Random site
393
i, j = np.random.randint(0, N, 2)
394
395
# Calculate energy change for spin flip
396
neighbors = (spins[i, (j+1) % N] + spins[i, (j-1) % N] +
397
spins[(i+1) % N, j] + spins[(i-1) % N, j])
398
399
delta_E = 2 * J * spins[i, j] * neighbors + 2 * h * spins[i, j]
400
401
# Metropolis acceptance
402
if delta_E < 0 or np.random.random() < np.exp(-beta * delta_E):
403
spins[i, j] *= -1
404
405
@jit(nopython=True)
406
def magnetization(spins):
407
"""Calculate magnetization per site"""
408
return np.mean(spins)
409
410
# Ising model parameters
411
N = 64 # Lattice size
412
J = 1.0 # Ferromagnetic coupling
413
h = 0.0 # No external field
414
415
# Temperature range for phase transition study
416
T_min, T_max = 1.0, 4.0
417
n_temps = 20
418
temperatures = np.linspace(T_min, T_max, n_temps)
419
420
# Critical temperature (analytical result for 2D Ising)
421
T_c = 2 * J / np.log(1 + np.sqrt(2)) # ≈ 2.269
422
423
print(f"2D Ising model simulation: {N}×{N} lattice")
424
print(f"Theoretical critical temperature: T_c = {T_c:.3f}")
425
426
# Monte Carlo simulation
427
n_steps = 5000
428
n_equilibration = 1000
429
430
magnetizations = []
431
susceptibilities = []
432
energies = []
433
heat_capacities = []
434
435
for T in temperatures:
436
beta = 1.0 / T
437
438
# Initialize random configuration
439
spins = np.random.choice([-1, 1], size=(N, N))
440
441
# Equilibration
442
for step in range(n_equilibration):
443
metropolis_step(spins, beta, J, h)
444
445
# Measurement phase
446
mag_samples = []
447
energy_samples = []
448
449
for step in range(n_steps):
450
metropolis_step(spins, beta, J, h)
451
452
if step % 10 == 0: # Sample every 10 steps
453
mag_samples.append(abs(magnetization(spins)))
454
energy_samples.append(ising_energy(spins, J, h) / (N*N))
455
456
# Calculate thermodynamic quantities
457
mag_mean = np.mean(mag_samples)
458
mag_var = np.var(mag_samples)
459
energy_mean = np.mean(energy_samples)
460
energy_var = np.var(energy_samples)
461
462
magnetizations.append(mag_mean)
463
susceptibilities.append(beta * mag_var * N * N)
464
energies.append(energy_mean)
465
heat_capacities.append(beta**2 * energy_var * N * N)
466
467
# Store final configuration for visualization
468
final_spins = spins.copy()
469
470
print(f"Monte Carlo simulation completed: {len(temperatures)} temperatures")
471
print(f"Final magnetization at T={T:.2f}: {magnetizations[-1]:.4f}")
472
473
474
pytex.after()
475
pytex.command = 'code'
476
pytex.set_context('')
477
pytex.args = ''
478
pytex.instance = '7'
479
pytex.line = '521'
480
481
print('=>PYTHONTEX:STDOUT#7#code#')
482
sys.stderr.write('=>PYTHONTEX:STDERR#7#code#\n')
483
pytex.before()
484
485
# Visualize Ising model results
486
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
487
488
# Magnetization vs temperature
489
ax1.plot(temperatures, magnetizations, 'bo-', linewidth=2, markersize=6)
490
ax1.axvline(T_c, color='red', linestyle='--', linewidth=2, label=f'T_c = {T_c:.3f}')
491
ax1.set_xlabel('Temperature T', fontsize=12)
492
ax1.set_ylabel('Magnetization |⟨m⟩|', fontsize=12)
493
ax1.set_title('Ising Model: Magnetic Phase Transition', fontsize=14, fontweight='bold')
494
ax1.legend()
495
ax1.grid(True, alpha=0.3)
496
497
# Magnetic susceptibility
498
ax2.plot(temperatures, susceptibilities, 'ro-', linewidth=2, markersize=6)
499
ax2.axvline(T_c, color='red', linestyle='--', linewidth=2, label=f'T_c = {T_c:.3f}')
500
ax2.set_xlabel('Temperature T', fontsize=12)
501
ax2.set_ylabel('Susceptibility χ', fontsize=12)
502
ax2.set_title('Magnetic Susceptibility: Critical Behavior', fontsize=14, fontweight='bold')
503
ax2.legend()
504
ax2.grid(True, alpha=0.3)
505
506
# Energy vs temperature
507
ax3.plot(temperatures, energies, 'go-', linewidth=2, markersize=6)
508
ax3.axvline(T_c, color='red', linestyle='--', linewidth=2, label=f'T_c = {T_c:.3f}')
509
ax3.set_xlabel('Temperature T', fontsize=12)
510
ax3.set_ylabel('Energy per site ⟨E⟩/N²', fontsize=12)
511
ax3.set_title('Internal Energy: Thermodynamic Behavior', fontsize=14, fontweight='bold')
512
ax3.legend()
513
ax3.grid(True, alpha=0.3)
514
515
# Spin configuration
516
im = ax4.imshow(final_spins, cmap='RdBu', vmin=-1, vmax=1, interpolation='nearest')
517
ax4.set_title(f'Spin Configuration at T = {temperatures[-1]:.2f}', fontsize=14, fontweight='bold')
518
ax4.set_xlabel('x', fontsize=12)
519
ax4.set_ylabel('y', fontsize=12)
520
521
# Add colorbar
522
cbar = plt.colorbar(im, ax=ax4, shrink=0.8)
523
cbar.set_label('Spin Value', fontsize=12)
524
cbar.set_ticks([-1, 0, 1])
525
cbar.set_ticklabels(['↓ (-1)', '0', '↑ (+1)'])
526
527
plt.tight_layout()
528
plt.savefig('assets/ising_model.pdf', dpi=300, bbox_inches='tight')
529
plt.close()
530
531
print("Ising model visualization saved to assets/ising_model.pdf")
532
533
534
pytex.after()
535
pytex.command = 'code'
536
pytex.set_context('')
537
pytex.args = ''
538
pytex.instance = '8'
539
pytex.line = '583'
540
541
print('=>PYTHONTEX:STDOUT#8#code#')
542
sys.stderr.write('=>PYTHONTEX:STDERR#8#code#\n')
543
pytex.before()
544
545
# 1D Ising model exact solution
546
def ising_1d_exact(T, J, h, N):
547
"""Exact solution for 1D Ising model using transfer matrix"""
548
beta = 1.0 / T
549
550
# Transfer matrix elements
551
T11 = np.exp(beta * (J + h)) # ↑↑
552
T12 = np.exp(beta * (-J)) # ↑↓
553
T21 = np.exp(beta * (-J)) # ↓↑
554
T22 = np.exp(beta * (J - h)) # ↓↓
555
556
# Transfer matrix
557
T_matrix = np.array([[T11, T12], [T21, T22]])
558
559
# Eigenvalues
560
eigenvals = np.linalg.eigvals(T_matrix)
561
lambda_max = np.max(eigenvals)
562
563
# Thermodynamic quantities (thermodynamic limit)
564
f_per_site = -T * np.log(lambda_max) # Free energy per site
565
566
# For finite system
567
Z = np.trace(np.linalg.matrix_power(T_matrix, N)) # Partition function
568
F = -T * np.log(Z) # Free energy
569
570
return F, f_per_site, Z
571
572
# Calculate exact 1D results
573
T_range_1d = np.linspace(0.5, 5.0, 100)
574
J_1d = 1.0
575
h_1d = 0.1 # Small external field
576
N_1d = 50
577
578
free_energies = []
579
partition_functions = []
580
581
for T in T_range_1d:
582
F, f_per_site, Z = ising_1d_exact(T, J_1d, h_1d, N_1d)
583
free_energies.append(f_per_site)
584
partition_functions.append(Z)
585
586
print(f"1D Ising model exact calculation: {len(T_range_1d)} temperature points")
587
print(f"System size: N = {N_1d}, coupling J = {J_1d}, field h = {h_1d}")
588
589
590
pytex.after()
591
pytex.command = 'code'
592
pytex.set_context('')
593
pytex.args = ''
594
pytex.instance = '9'
595
pytex.line = '629'
596
597
print('=>PYTHONTEX:STDOUT#9#code#')
598
sys.stderr.write('=>PYTHONTEX:STDERR#9#code#\n')
599
pytex.before()
600
601
# Visualize thermodynamic properties
602
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))
603
604
# Free energy per site
605
ax1.plot(T_range_1d, free_energies, 'b-', linewidth=2)
606
ax1.set_xlabel('Temperature T', fontsize=12)
607
ax1.set_ylabel('Free Energy per Site f', fontsize=12)
608
ax1.set_title('1D Ising Model: Free Energy (Exact Solution)', fontsize=14, fontweight='bold')
609
ax1.grid(True, alpha=0.3)
610
611
# Partition function (log scale)
612
ax2.semilogy(T_range_1d, partition_functions, 'r-', linewidth=2)
613
ax2.set_xlabel('Temperature T', fontsize=12)
614
ax2.set_ylabel('Partition Function Z', fontsize=12)
615
ax2.set_title('Partition Function: Statistical Weight', fontsize=14, fontweight='bold')
616
ax2.grid(True, alpha=0.3)
617
618
plt.tight_layout()
619
plt.savefig('assets/thermodynamics.pdf', dpi=300, bbox_inches='tight')
620
plt.close()
621
622
print("Thermodynamics visualization saved to assets/thermodynamics.pdf")
623
624
625
pytex.after()
626
pytex.command = 'code'
627
pytex.set_context('')
628
pytex.args = ''
629
pytex.instance = '10'
630
pytex.line = '674'
631
632
print('=>PYTHONTEX:STDOUT#10#code#')
633
sys.stderr.write('=>PYTHONTEX:STDERR#10#code#\n')
634
pytex.before()
635
636
# 2D square lattice tight-binding model
637
def tight_binding_2d(kx, ky, t, epsilon_0):
638
"""Energy dispersion for 2D square lattice"""
639
return epsilon_0 - 2*t*(np.cos(kx) + np.cos(ky))
640
641
def graphene_dispersion(kx, ky, t):
642
"""Energy dispersion for graphene (honeycomb lattice)"""
643
# Nearest neighbor phase factors
644
f = 1 + np.exp(1j * kx) + np.exp(1j * (kx/2 + np.sqrt(3)*ky/2))
645
return t * np.abs(f), -t * np.abs(f) # Two bands
646
647
# Parameters
648
t = 1.0 # Hopping parameter
649
epsilon_0 = 0.0 # Onsite energy
650
651
# Create k-space grid
652
k_points = 100
653
kx = np.linspace(-np.pi, np.pi, k_points)
654
ky = np.linspace(-np.pi, np.pi, k_points)
655
KX, KY = np.meshgrid(kx, ky)
656
657
# Calculate band structure
658
E_square = tight_binding_2d(KX, KY, t, epsilon_0)
659
E_graphene_plus, E_graphene_minus = graphene_dispersion(KX, KY, t)
660
661
# Density of states calculation
662
def calculate_dos(energies, n_bins=200):
663
"""Calculate density of states"""
664
E_flat = energies.flatten()
665
E_min, E_max = E_flat.min(), E_flat.max()
666
E_bins = np.linspace(E_min, E_max, n_bins)
667
hist, bin_edges = np.histogram(E_flat, bins=E_bins)
668
E_centers = (bin_edges[:-1] + bin_edges[1:]) / 2
669
dos = hist / (E_bins[1] - E_bins[0]) / len(E_flat)
670
return E_centers, dos
671
672
E_dos_square, dos_square = calculate_dos(E_square)
673
E_dos_graphene, dos_graphene = calculate_dos(np.concatenate([E_graphene_plus.flatten(),
674
E_graphene_minus.flatten()]))
675
676
print(f"Band structure calculation completed: {k_points}×{k_points} k-points")
677
print(f"Square lattice bandwidth: {E_square.max() - E_square.min():.3f}")
678
print(f"Graphene bandwidth: {E_graphene_plus.max() - E_graphene_minus.min():.3f}")
679
680
681
pytex.after()
682
pytex.command = 'code'
683
pytex.set_context('')
684
pytex.args = ''
685
pytex.instance = '11'
686
pytex.line = '720'
687
688
print('=>PYTHONTEX:STDOUT#11#code#')
689
sys.stderr.write('=>PYTHONTEX:STDERR#11#code#\n')
690
pytex.before()
691
692
# Visualize band structure
693
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
694
695
# Square lattice band structure
696
im1 = ax1.contourf(KX, KY, E_square, levels=50, cmap='viridis')
697
ax1.set_xlabel('kₓ', fontsize=12)
698
ax1.set_ylabel('kᵧ', fontsize=12)
699
ax1.set_title('Square Lattice: Energy Dispersion E(k)', fontsize=14, fontweight='bold')
700
plt.colorbar(im1, ax=ax1, label='Energy E/t')
701
702
# Graphene band structure (valence band)
703
im2 = ax2.contourf(KX, KY, E_graphene_minus, levels=50, cmap='plasma')
704
ax2.set_xlabel('kₓ', fontsize=12)
705
ax2.set_ylabel('kᵧ', fontsize=12)
706
ax2.set_title('Graphene: Valence Band Dispersion', fontsize=14, fontweight='bold')
707
plt.colorbar(im2, ax=ax2, label='Energy E/t')
708
709
# Density of states - square lattice
710
ax3.plot(E_dos_square, dos_square, 'b-', linewidth=2, label='Square lattice')
711
ax3.fill_between(E_dos_square, 0, dos_square, alpha=0.3)
712
ax3.set_xlabel('Energy E/t', fontsize=12)
713
ax3.set_ylabel('Density of States', fontsize=12)
714
ax3.set_title('Electronic Density of States: Square Lattice', fontsize=14, fontweight='bold')
715
ax3.legend()
716
ax3.grid(True, alpha=0.3)
717
718
# Density of states - graphene
719
ax4.plot(E_dos_graphene, dos_graphene, 'r-', linewidth=2, label='Graphene')
720
ax4.fill_between(E_dos_graphene, 0, dos_graphene, alpha=0.3, color='red')
721
ax4.axvline(0, color='black', linestyle='--', alpha=0.7, label='Dirac point')
722
ax4.set_xlabel('Energy E/t', fontsize=12)
723
ax4.set_ylabel('Density of States', fontsize=12)
724
ax4.set_title('Electronic Density of States: Graphene', fontsize=14, fontweight='bold')
725
ax4.legend()
726
ax4.grid(True, alpha=0.3)
727
728
plt.tight_layout()
729
plt.savefig('assets/band_structure.pdf', dpi=300, bbox_inches='tight')
730
plt.close()
731
732
print("Band structure visualization saved to assets/band_structure.pdf")
733
734
735
pytex.after()
736
pytex.command = 'code'
737
pytex.set_context('')
738
pytex.args = ''
739
pytex.instance = '12'
740
pytex.line = '776'
741
742
print('=>PYTHONTEX:STDOUT#12#code#')
743
sys.stderr.write('=>PYTHONTEX:STDERR#12#code#\n')
744
pytex.before()
745
746
# Fermi surface calculation
747
def fermi_surface_2d(kx, ky, t, mu, T=0.01):
748
"""Calculate Fermi surface for 2D system"""
749
E = tight_binding_2d(kx, ky, t, 0)
750
751
# Fermi-Dirac distribution
752
if T > 0:
753
f = 1.0 / (1.0 + np.exp((E - mu) / T))
754
else:
755
f = (E < mu).astype(float)
756
757
return E, f
758
759
# Parameters for different filling levels
760
t_fermi = 1.0
761
mu_values = [-3.0, -2.0, 0.0, 2.0] # Different chemical potentials
762
filling_names = ['Low filling', 'Quarter filling', 'Half filling', 'High filling']
763
764
# Higher resolution for Fermi surface
765
k_fermi = 200
766
kx_fermi = np.linspace(-np.pi, np.pi, k_fermi)
767
ky_fermi = np.linspace(-np.pi, np.pi, k_fermi)
768
KX_fermi, KY_fermi = np.meshgrid(kx_fermi, ky_fermi)
769
770
# Calculate Fermi surfaces
771
fermi_data = []
772
for mu in mu_values:
773
E, f = fermi_surface_2d(KX_fermi, KY_fermi, t_fermi, mu, T=0.1)
774
fermi_data.append((E, f))
775
776
print(f"Fermi surface calculation: {k_fermi}×{k_fermi} k-points")
777
print(f"Chemical potentials: {mu_values}")
778
779
780
pytex.after()
781
pytex.command = 'code'
782
pytex.set_context('')
783
pytex.args = ''
784
pytex.instance = '13'
785
pytex.line = '811'
786
787
print('=>PYTHONTEX:STDOUT#13#code#')
788
sys.stderr.write('=>PYTHONTEX:STDERR#13#code#\n')
789
pytex.before()
790
791
# Visualize Fermi surfaces
792
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
793
axes = axes.flatten()
794
795
for i, ((E, f), mu, name) in enumerate(zip(fermi_data, mu_values, filling_names)):
796
ax = axes[i]
797
798
# Plot Fermi surface as contour
799
contour = ax.contour(KX_fermi, KY_fermi, E, levels=[mu], colors='red', linewidths=3)
800
801
# Fill occupied states
802
filled = ax.contourf(KX_fermi, KY_fermi, f, levels=50, cmap='Blues', alpha=0.7)
803
804
ax.set_xlabel('kₓ/π', fontsize=12)
805
ax.set_ylabel('kᵧ/π', fontsize=12)
806
ax.set_title(f'{name}: μ = {mu:.1f}t', fontsize=14, fontweight='bold')
807
ax.set_xlim(-np.pi, np.pi)
808
ax.set_ylim(-np.pi, np.pi)
809
810
# Add Brillouin zone boundary
811
ax.plot([-np.pi, np.pi, np.pi, -np.pi, -np.pi],
812
[-np.pi, -np.pi, np.pi, np.pi, -np.pi],
813
'k--', alpha=0.5, linewidth=1)
814
815
# Colorbar for occupation
816
if i == 1: # Add colorbar to one plot
817
cbar = plt.colorbar(filled, ax=ax, shrink=0.8)
818
cbar.set_label('Occupation f(k)', fontsize=10)
819
820
plt.tight_layout()
821
plt.savefig('assets/fermi_surface.pdf', dpi=300, bbox_inches='tight')
822
plt.close()
823
824
print("Fermi surface visualization saved to assets/fermi_surface.pdf")
825
826
827
pytex.after()
828
pytex.command = 'code'
829
pytex.set_context('')
830
pytex.args = ''
831
pytex.instance = '14'
832
pytex.line = '860'
833
834
print('=>PYTHONTEX:STDOUT#14#code#')
835
sys.stderr.write('=>PYTHONTEX:STDERR#14#code#\n')
836
pytex.before()
837
838
# 1D monoatomic chain phonon dispersion
839
def phonon_monoatomic(k, K, M):
840
"""Phonon frequency for 1D monoatomic chain"""
841
return np.sqrt(4*K/M * np.sin(k/2)**2)
842
843
# 1D diatomic chain phonon dispersion
844
def phonon_diatomic(k, K, M1, M2):
845
"""Phonon frequencies for 1D diatomic chain"""
846
M_sum = M1 + M2
847
M_prod = M1 * M2
848
849
# Discriminant
850
disc = (M_sum)**2 - 4*M_prod*np.cos(k)**2
851
852
# Optical and acoustic branches
853
omega_plus = np.sqrt(K * (M_sum + np.sqrt(disc)) / (2*M_prod))
854
omega_minus = np.sqrt(K * (M_sum - np.sqrt(disc)) / (2*M_prod))
855
856
return omega_plus, omega_minus
857
858
# Parameters
859
K = 1.0 # Spring constant
860
M = 1.0 # Mass (monoatomic)
861
M1, M2 = 1.0, 2.0 # Masses (diatomic)
862
863
# k-point path
864
k_points_1d = np.linspace(-np.pi, np.pi, 500)
865
866
# Calculate dispersions
867
omega_mono = phonon_monoatomic(k_points_1d, K, M)
868
omega_optical, omega_acoustic = phonon_diatomic(k_points_1d, K, M1, M2)
869
870
# Density of phonon states
871
def phonon_dos(k_vals, omega_vals, n_bins=100):
872
"""Calculate phonon density of states"""
873
# Use only positive k values to avoid double counting
874
k_pos = k_vals[k_vals >= 0]
875
omega_pos = omega_vals[k_vals >= 0]
876
877
omega_min, omega_max = 0, omega_pos.max()
878
omega_bins = np.linspace(omega_min, omega_max, n_bins)
879
880
hist, bin_edges = np.histogram(omega_pos, bins=omega_bins)
881
omega_centers = (bin_edges[:-1] + bin_edges[1:]) / 2
882
dos = hist / (omega_bins[1] - omega_bins[0]) / len(omega_pos)
883
884
return omega_centers, dos
885
886
# Calculate phonon DOS
887
omega_dos_mono, dos_mono = phonon_dos(k_points_1d, omega_mono)
888
omega_dos_opt, dos_opt = phonon_dos(k_points_1d, omega_optical)
889
omega_dos_ac, dos_ac = phonon_dos(k_points_1d, omega_acoustic)
890
891
print(f"Phonon dispersion calculation: {len(k_points_1d)} k-points")
892
print(f"Monoatomic max frequency: {omega_mono.max():.3f}")
893
print(f"Diatomic optical max: {omega_optical.max():.3f}")
894
print(f"Diatomic acoustic max: {omega_acoustic.max():.3f}")
895
896
897
pytex.after()
898
pytex.command = 'code'
899
pytex.set_context('')
900
pytex.args = ''
901
pytex.instance = '15'
902
pytex.line = '920'
903
904
print('=>PYTHONTEX:STDOUT#15#code#')
905
sys.stderr.write('=>PYTHONTEX:STDERR#15#code#\n')
906
pytex.before()
907
908
# Visualize phonon dispersion
909
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8))
910
911
# Dispersion relations
912
ax1.plot(k_points_1d/np.pi, omega_mono, 'b-', linewidth=2, label='Monoatomic chain')
913
ax1.plot(k_points_1d/np.pi, omega_optical, 'r-', linewidth=2, label='Optical branch')
914
ax1.plot(k_points_1d/np.pi, omega_acoustic, 'g-', linewidth=2, label='Acoustic branch')
915
916
ax1.set_xlabel('Wave vector k/π', fontsize=12)
917
ax1.set_ylabel('Frequency ω√(M/K)', fontsize=12)
918
ax1.set_title('Phonon Dispersion Relations', fontsize=14, fontweight='bold')
919
ax1.legend()
920
ax1.grid(True, alpha=0.3)
921
ax1.set_xlim(-1, 1)
922
923
# Density of states
924
ax2.plot(omega_dos_mono, dos_mono, 'b-', linewidth=2, label='Monoatomic')
925
ax2.fill_between(omega_dos_mono, 0, dos_mono, alpha=0.3, color='blue')
926
927
ax2.plot(omega_dos_opt, dos_opt, 'r-', linewidth=2, label='Optical')
928
ax2.fill_between(omega_dos_opt, 0, dos_opt, alpha=0.3, color='red')
929
930
ax2.plot(omega_dos_ac, dos_ac, 'g-', linewidth=2, label='Acoustic')
931
ax2.fill_between(omega_dos_ac, 0, dos_ac, alpha=0.3, color='green')
932
933
ax2.set_xlabel('Frequency ω√(M/K)', fontsize=12)
934
ax2.set_ylabel('Density of States', fontsize=12)
935
ax2.set_title('Phonon Density of States', fontsize=14, fontweight='bold')
936
ax2.legend()
937
ax2.grid(True, alpha=0.3)
938
939
plt.tight_layout()
940
plt.savefig('assets/phonon_dispersion.pdf', dpi=300, bbox_inches='tight')
941
plt.close()
942
943
print("Phonon dispersion visualization saved to assets/phonon_dispersion.pdf")
944
945
946
pytex.after()
947
pytex.command = 'code'
948
pytex.set_context('')
949
pytex.args = ''
950
pytex.instance = '16'
951
pytex.line = '979'
952
953
print('=>PYTHONTEX:STDOUT#16#code#')
954
sys.stderr.write('=>PYTHONTEX:STDERR#16#code#\n')
955
pytex.before()
956
957
# Simple mean-field solution of Hubbard model
958
def hubbard_mean_field(t, U, n, T=0.1, max_iter=1000, tol=1e-6):
959
"""
960
Mean-field solution of Hubbard model on 2D square lattice
961
Returns self-consistent chemical potential and magnetization
962
"""
963
# Initial guess
964
mu = U * n / 2 # Chemical potential
965
m = 0.1 # Magnetization (small initial value)
966
967
for iteration in range(max_iter):
968
# Mean-field Hamiltonian eigenvalues
969
# For 2D square lattice: epsilon_k = -2t(cos(kx) + cos(ky))
970
# With mean-field correction: E_k^± = epsilon_k ± U*m/2
971
972
k_mesh = 64
973
kx = np.linspace(-np.pi, np.pi, k_mesh)
974
ky = np.linspace(-np.pi, np.pi, k_mesh)
975
KX, KY = np.meshgrid(kx, ky)
976
977
epsilon_k = -2*t*(np.cos(KX) + np.cos(KY))
978
E_plus = epsilon_k - mu + U*m/2 # Spin-up band
979
E_minus = epsilon_k - mu - U*m/2 # Spin-down band
980
981
# Fermi-Dirac distribution
982
f_plus = 1.0 / (1.0 + np.exp(E_plus / T))
983
f_minus = 1.0 / (1.0 + np.exp(E_minus / T))
984
985
# New density and magnetization
986
n_new = np.mean(f_plus + f_minus)
987
m_new = np.mean(f_plus - f_minus)
988
989
# Check convergence
990
if abs(m_new - m) < tol:
991
break
992
993
# Update with mixing
994
m = 0.7 * m + 0.3 * m_new
995
996
# Adjust chemical potential to maintain target density
997
mu = mu + 0.1 * (n - n_new)
998
999
return mu, m, f_plus, f_minus, epsilon_k
1000
1001
# Parameters for different interaction strengths
1002
t_hub = 1.0
1003
density = 0.8 # Filling factor
1004
U_values = [0.0, 2.0, 4.0, 6.0] # Interaction strengths
1005
1006
results = []
1007
for U in U_values:
1008
mu, m, f_up, f_dn, eps_k = hubbard_mean_field(t_hub, U, density)
1009
results.append((U, mu, m, f_up, f_dn, eps_k))
1010
print(f"U/t = {U/t_hub:.1f}: μ = {mu:.3f}, m = {m:.4f}")
1011
1012
print(f"Hubbard model mean-field calculation completed")
1013
1014
1015
pytex.after()
1016
pytex.command = 'code'
1017
pytex.set_context('')
1018
pytex.args = ''
1019
pytex.instance = '17'
1020
pytex.line = '1038'
1021
1022
print('=>PYTHONTEX:STDOUT#17#code#')
1023
sys.stderr.write('=>PYTHONTEX:STDERR#17#code#\n')
1024
pytex.before()
1025
1026
# Plot Hubbard model results
1027
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
1028
1029
# Magnetization vs interaction strength
1030
U_plot = [result[0] for result in results]
1031
m_plot = [abs(result[2]) for result in results] # Take absolute value
1032
1033
ax1.plot(U_plot, m_plot, 'ro-', linewidth=2, markersize=8)
1034
ax1.set_xlabel('Interaction U/t', fontsize=12)
1035
ax1.set_ylabel('Magnetization |m|', fontsize=12)
1036
ax1.set_title('Hubbard Model: Magnetic Instability', fontsize=14, fontweight='bold')
1037
ax1.grid(True, alpha=0.3)
1038
1039
# Chemical potential vs interaction
1040
mu_plot = [result[1] for result in results]
1041
ax2.plot(U_plot, mu_plot, 'bo-', linewidth=2, markersize=8)
1042
ax2.set_xlabel('Interaction U/t', fontsize=12)
1043
ax2.set_ylabel('Chemical Potential μ/t', fontsize=12)
1044
ax2.set_title('Chemical Potential: Correlation Effects', fontsize=14, fontweight='bold')
1045
ax2.grid(True, alpha=0.3)
1046
1047
# Spin-resolved occupations for strong coupling case
1048
U_strong = results[-1] # Strongest coupling
1049
f_up_strong = U_strong[3]
1050
f_dn_strong = U_strong[4]
1051
1052
im3 = ax3.contourf(f_up_strong, levels=50, cmap='Reds')
1053
ax3.set_title(f'Spin-Up Occupation (U = {U_strong[0]:.1f}t)', fontsize=14, fontweight='bold')
1054
ax3.set_xlabel('kₓ index', fontsize=12)
1055
ax3.set_ylabel('kᵧ index', fontsize=12)
1056
plt.colorbar(im3, ax=ax3, shrink=0.8)
1057
1058
im4 = ax4.contourf(f_dn_strong, levels=50, cmap='Blues')
1059
ax4.set_title(f'Spin-Down Occupation (U = {U_strong[0]:.1f}t)', fontsize=14, fontweight='bold')
1060
ax4.set_xlabel('kₓ index', fontsize=12)
1061
ax4.set_ylabel('kᵧ index', fontsize=12)
1062
plt.colorbar(im4, ax=ax4, shrink=0.8)
1063
1064
plt.tight_layout()
1065
plt.savefig('assets/hubbard_model.pdf', dpi=300, bbox_inches='tight')
1066
plt.close()
1067
1068
print("Hubbard model visualization saved to assets/hubbard_model.pdf")
1069
1070
1071
pytex.after()
1072
pytex.command = 'code'
1073
pytex.set_context('')
1074
pytex.args = ''
1075
pytex.instance = '18'
1076
pytex.line = '1097'
1077
1078
print('=>PYTHONTEX:STDOUT#18#code#')
1079
sys.stderr.write('=>PYTHONTEX:STDERR#18#code#\n')
1080
pytex.before()
1081
1082
# Demonstrate numerical precision considerations
1083
def convergence_study():
1084
"""Study convergence of numerical methods"""
1085
1086
# Test case: numerical integration of oscillatory function
1087
def integrand(x):
1088
return np.sin(10*x) * np.exp(-x**2)
1089
1090
# Analytical result (approximate)
1091
analytical = 0.4995 # Pre-computed high-precision result
1092
1093
# Different grid sizes
1094
N_values = [10, 20, 50, 100, 200, 500, 1000]
1095
errors_trapz = []
1096
errors_simpson = []
1097
1098
for N in N_values:
1099
x = np.linspace(0, 3, N)
1100
y = integrand(x)
1101
1102
# Trapezoidal rule
1103
integral_trapz = np.trapz(y, x)
1104
error_trapz = abs(integral_trapz - analytical)
1105
errors_trapz.append(error_trapz)
1106
1107
# Simpson's rule (if N is odd)
1108
if N % 2 == 1:
1109
from scipy.integrate import simpson
1110
integral_simpson = simpson(y, x)
1111
error_simpson = abs(integral_simpson - analytical)
1112
else:
1113
error_simpson = np.nan
1114
errors_simpson.append(error_simpson)
1115
1116
return N_values, errors_trapz, errors_simpson
1117
1118
N_vals, err_trapz, err_simp = convergence_study()
1119
1120
print("Numerical integration convergence study completed")
1121
print(f"Grid sizes tested: {N_vals}")
1122
1123
1124
pytex.after()
1125
pytex.command = 'code'
1126
pytex.set_context('')
1127
pytex.args = ''
1128
pytex.instance = '19'
1129
pytex.line = '1140'
1130
1131
print('=>PYTHONTEX:STDOUT#19#code#')
1132
sys.stderr.write('=>PYTHONTEX:STDERR#19#code#\n')
1133
pytex.before()
1134
1135
# Plot convergence study
1136
fig, ax = plt.subplots(figsize=(12, 8))
1137
1138
ax.loglog(N_vals, err_trapz, 'bo-', linewidth=2, markersize=6, label='Trapezoidal Rule')
1139
1140
# Filter out NaN values for Simpson's rule
1141
N_simp = [N for N, err in zip(N_vals, err_simp) if not np.isnan(err)]
1142
err_simp_clean = [err for err in err_simp if not np.isnan(err)]
1143
ax.loglog(N_simp, err_simp_clean, 'rs-', linewidth=2, markersize=6, label="Simpson's Rule")
1144
1145
# Theoretical scaling lines
1146
N_theory = np.array(N_vals)
1147
ax.loglog(N_theory, 1e-1 * (N_theory[0]/N_theory)**2, 'k--', alpha=0.7, label='N⁻² scaling')
1148
ax.loglog(N_theory, 1e-3 * (N_theory[0]/N_theory)**4, 'k:', alpha=0.7, label='N⁻⁴ scaling')
1149
1150
ax.set_xlabel('Number of Grid Points N', fontsize=12)
1151
ax.set_ylabel('Absolute Error', fontsize=12)
1152
ax.set_title('Numerical Integration: Convergence Analysis', fontsize=14, fontweight='bold')
1153
ax.legend()
1154
ax.grid(True, alpha=0.3)
1155
1156
plt.tight_layout()
1157
plt.savefig('assets/convergence_study.pdf', dpi=300, bbox_inches='tight')
1158
plt.close()
1159
1160
print("Convergence study visualization saved to assets/convergence_study.pdf")
1161
1162
1163
pytex.after()
1164
1165
1166
pytex.cleanup()
1167
1168