Published/scientific-latex-templates/computational-physics / pythontex-files-main / py_default_default.py
287 viewsubuntu2404
# -*- coding: UTF-8 -*-1234import os5import sys6import codecs78if '--interactive' not in sys.argv[1:]:9if sys.version_info[0] == 2:10sys.stdout = codecs.getwriter('UTF-8')(sys.stdout, 'strict')11sys.stderr = codecs.getwriter('UTF-8')(sys.stderr, 'strict')12else:13sys.stdout = codecs.getwriter('UTF-8')(sys.stdout.buffer, 'strict')14sys.stderr = codecs.getwriter('UTF-8')(sys.stderr.buffer, 'strict')1516if '/usr/share/texlive/texmf-dist/scripts/pythontex' and '/usr/share/texlive/texmf-dist/scripts/pythontex' not in sys.path:17sys.path.append('/usr/share/texlive/texmf-dist/scripts/pythontex')18from pythontex_utils import PythonTeXUtils19pytex = PythonTeXUtils()2021pytex.docdir = os.getcwd()22if os.path.isdir('.'):23os.chdir('.')24if os.getcwd() not in sys.path:25sys.path.append(os.getcwd())26else:27if len(sys.argv) < 2 or sys.argv[1] != '--manual':28sys.exit('Cannot find directory .')29if pytex.docdir not in sys.path:30sys.path.append(pytex.docdir)31323334pytex.id = 'py_default_default'35pytex.family = 'py'36pytex.session = 'default'37pytex.restart = 'default'3839pytex.command = 'code'40pytex.set_context('')41pytex.args = ''42pytex.instance = '0'43pytex.line = '96'4445print('=>PYTHONTEX:STDOUT#0#code#')46sys.stderr.write('=>PYTHONTEX:STDERR#0#code#\n')47pytex.before()4849import numpy as np50import matplotlib.pyplot as plt51from scipy.sparse import diags52from scipy.linalg import expm53import matplotlib54matplotlib.use('Agg') # Use non-interactive backend5556# Set random seed for reproducibility57np.random.seed(42)5859# Parameters for quantum simulation60hbar = 1.0 # Reduced Planck constant (natural units)61m = 1.0 # Particle mass (natural units)62L = 10.0 # Box length63N = 1000 # Number of grid points64dx = L / N # Grid spacing65dt = 0.001 # Time step6667# Create spatial grid68x = np.linspace(0, L, N)6970# Define potential: harmonic oscillator + barrier71omega = 1.0 # Oscillator frequency72V = 0.5 * m * omega**2 * (x - L/2)**2 # Harmonic potential73V += 2.0 * np.exp(-((x - L/3)/(L/20))**2) # Gaussian barrier for tunneling7475# Create kinetic energy operator (finite difference)76kinetic_diag = -2 * np.ones(N)77kinetic_off = np.ones(N-1)78T_matrix = -(hbar**2 / (2*m*dx**2)) * (79diags([kinetic_off, kinetic_diag, kinetic_off], [-1, 0, 1], shape=(N, N))80)8182# Hamiltonian matrix83H = T_matrix + diags(V, 0)8485# Initial wavefunction: Gaussian wave packet86x0 = L/4 # Initial position87sigma = L/20 # Wave packet width88k0 = 5.0 # Initial momentum89psi_initial = np.exp(-(x - x0)**2 / (2*sigma**2)) * np.exp(1j * k0 * x)90psi_initial = psi_initial / np.sqrt(np.trapezoid(np.abs(psi_initial)**2, x))9192# Time evolution operator93U = expm(-1j * H.toarray() * dt / hbar)9495# Evolve the wavefunction96times = np.arange(0, 5.0, dt)97psi = psi_initial.copy()9899# Store some snapshots100snapshot_times = [0, 1.0, 2.0, 3.0, 4.0]101snapshots = []102snapshot_indices = []103104for i, t in enumerate(times):105if any(abs(t - st) < dt/2 for st in snapshot_times):106snapshots.append(psi.copy())107snapshot_indices.append(i)108psi = U @ psi109110print(f"Quantum simulation completed: {len(times)} time steps")111print(f"Stored {len(snapshots)} wavefunction snapshots")112print(f"Conservation check - final norm: {np.trapezoid(np.abs(psi)**2, x):.6f}")113114115pytex.after()116pytex.command = 'code'117pytex.set_context('')118pytex.args = ''119pytex.instance = '1'120pytex.line = '165'121122print('=>PYTHONTEX:STDOUT#1#code#')123sys.stderr.write('=>PYTHONTEX:STDERR#1#code#\n')124pytex.before()125126# Create quantum mechanics visualization127fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))128129# Plot potential130ax1.plot(x, V, 'k-', linewidth=2, label='Potential V(x)')131ax1.set_ylabel('Energy (natural units)', fontsize=12)132ax1.set_title('Quantum Tunneling Through Potential Barrier', fontsize=14, fontweight='bold')133ax1.legend()134ax1.grid(True, alpha=0.3)135136# Plot wavefunction snapshots137colors = plt.cm.viridis(np.linspace(0, 1, len(snapshots)))138for i, (psi_snap, color) in enumerate(zip(snapshots, colors)):139probability = np.abs(psi_snap)**2140ax2.fill_between(x, 0, probability, alpha=0.6, color=color,141label=f't = {snapshot_times[i]:.1f}')142143ax2.set_xlabel('Position x (natural units)', fontsize=12)144ax2.set_ylabel('Probability Density |ψ(x,t)|²', fontsize=12)145ax2.set_title('Wavefunction Evolution: Quantum Tunneling Dynamics', fontsize=14, fontweight='bold')146ax2.legend(bbox_to_anchor=(1.05, 1), loc='upper left')147ax2.grid(True, alpha=0.3)148149plt.tight_layout()150plt.savefig('assets/quantum_tunneling.pdf', dpi=300, bbox_inches='tight')151plt.close()152153print("Quantum tunneling visualization saved to assets/quantum_tunneling.pdf")154155156pytex.after()157pytex.command = 'code'158pytex.set_context('')159pytex.args = ''160pytex.instance = '2'161pytex.line = '215'162163print('=>PYTHONTEX:STDOUT#2#code#')164sys.stderr.write('=>PYTHONTEX:STDERR#2#code#\n')165pytex.before()166167from scipy.special import hermite168from scipy.special import factorial169170# Quantum harmonic oscillator parameters171omega = 1.0 # Angular frequency172m = 1.0 # Mass173hbar = 1.0 # Reduced Planck constant174175# Length scale176x0 = np.sqrt(hbar / (m * omega))177178# Create position grid179x_osc = np.linspace(-4*x0, 4*x0, 1000)180181# Calculate first 6 energy eigenstates182n_states = 6183wavefunctions = []184energies = []185186for n in range(n_states):187# Energy eigenvalue188E_n = hbar * omega * (n + 0.5)189energies.append(E_n)190191# Normalization factor192norm = 1.0 / np.sqrt(2**n * factorial(n)) * (m*omega/(np.pi*hbar))**(1/4)193194# Hermite polynomial195H_n = hermite(n)196197# Wavefunction198xi = x_osc / x0 # Dimensionless coordinate199psi_n = norm * np.exp(-xi**2 / 2) * H_n(xi)200wavefunctions.append(psi_n)201202print(f"Calculated {n_states} harmonic oscillator eigenstates")203print(f"Energy levels: {[f'{E:.2f}' for E in energies[:4]]}")204205206pytex.after()207pytex.command = 'code'208pytex.set_context('')209pytex.args = ''210pytex.instance = '3'211pytex.line = '255'212213print('=>PYTHONTEX:STDOUT#3#code#')214sys.stderr.write('=>PYTHONTEX:STDERR#3#code#\n')215pytex.before()216217# Visualize harmonic oscillator eigenstates218fig, ax = plt.subplots(figsize=(12, 10))219220# Plot potential221V_osc = 0.5 * m * omega**2 * x_osc**2222ax.plot(x_osc/x0, V_osc/(hbar*omega), 'k-', linewidth=3, label='Potential V(x)')223224# Plot energy levels and wavefunctions225colors = plt.cm.Set1(np.linspace(0, 1, n_states))226for n, (psi, E, color) in enumerate(zip(wavefunctions, energies, colors)):227# Energy level228ax.axhline(E/(hbar*omega), color=color, linestyle='--', alpha=0.7)229230# Wavefunction (scaled and shifted)231psi_scaled = psi * 2 + E/(hbar*omega) # Scale and shift232ax.plot(x_osc/x0, psi_scaled, color=color, linewidth=2,233label=f'n={n}, E={E/(hbar*omega):.1f}ℏω')234235ax.set_xlabel('Position x/x₀', fontsize=14)236ax.set_ylabel('Energy / ℏω', fontsize=14)237ax.set_title('Quantum Harmonic Oscillator: Energy Eigenstates and Wavefunctions',238fontsize=16, fontweight='bold')239ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')240ax.grid(True, alpha=0.3)241ax.set_xlim(-4, 4)242ax.set_ylim(0, 6)243244plt.tight_layout()245plt.savefig('assets/harmonic_oscillator.pdf', dpi=300, bbox_inches='tight')246plt.close()247248print("Harmonic oscillator visualization saved to assets/harmonic_oscillator.pdf")249250251pytex.after()252pytex.command = 'code'253pytex.set_context('')254pytex.args = ''255pytex.instance = '4'256pytex.line = '307'257258print('=>PYTHONTEX:STDOUT#4#code#')259sys.stderr.write('=>PYTHONTEX:STDERR#4#code#\n')260pytex.before()261262# Particle in a box simulation263L_box = 1.0 # Box length264m_box = 1.0 # Particle mass265hbar = 1.0 # Reduced Planck constant266267# Position grid268x_box = np.linspace(0, L_box, 1000)269270# Calculate first 5 energy levels and wavefunctions271n_levels = 5272box_energies = []273box_wavefunctions = []274275for n in range(1, n_levels + 1):276# Energy eigenvalue277E_n = (n**2 * np.pi**2 * hbar**2) / (2 * m_box * L_box**2)278box_energies.append(E_n)279280# Wavefunction281psi_n = np.sqrt(2/L_box) * np.sin(n * np.pi * x_box / L_box)282box_wavefunctions.append(psi_n)283284# Calculate probability current for superposition state285# Create superposition of n=1 and n=2 states286c1, c2 = 1/np.sqrt(2), 1/np.sqrt(2) # Equal superposition287psi_superposition = c1 * box_wavefunctions[0] + c2 * box_wavefunctions[1]288289print(f"Particle in box: calculated {n_levels} energy levels")290print(f"Energy ratios E_n/E_1: {[E/box_energies[0] for E in box_energies]}")291292293pytex.after()294pytex.command = 'code'295pytex.set_context('')296pytex.args = ''297pytex.instance = '5'298pytex.line = '339'299300print('=>PYTHONTEX:STDOUT#5#code#')301sys.stderr.write('=>PYTHONTEX:STDERR#5#code#\n')302pytex.before()303304# Visualize particle in a box305fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8))306307# Left panel: Energy levels and wavefunctions308colors = plt.cm.viridis(np.linspace(0, 1, n_levels))309for n, (psi, E, color) in enumerate(zip(box_wavefunctions, box_energies, colors)):310# Energy level311ax1.axhline(E, color=color, linestyle='--', alpha=0.7, linewidth=1)312313# Wavefunction (scaled and shifted)314psi_scaled = psi * 0.3 + E # Scale and shift315ax1.plot(x_box, psi_scaled, color=color, linewidth=2,316label=f'n={n+1}, E={E:.2f}')317318# Draw box walls319ax1.axvline(0, color='black', linewidth=4)320ax1.axvline(L_box, color='black', linewidth=4)321ax1.axhline(0, color='black', linewidth=2)322323ax1.set_xlabel('Position x', fontsize=12)324ax1.set_ylabel('Energy', fontsize=12)325ax1.set_title('Particle in a Box: Quantum Energy Levels', fontsize=14, fontweight='bold')326ax1.legend()327ax1.grid(True, alpha=0.3)328329# Right panel: Superposition state and probability density330ax2.plot(x_box, psi_superposition, 'b-', linewidth=2, label='ψ(x) = (ψ₁ + ψ₂)/√2')331ax2.fill_between(x_box, 0, np.abs(psi_superposition)**2, alpha=0.5, color='red',332label='|ψ(x)|²')333334ax2.axvline(0, color='black', linewidth=4)335ax2.axvline(L_box, color='black', linewidth=4)336ax2.set_xlabel('Position x', fontsize=12)337ax2.set_ylabel('Amplitude / Probability Density', fontsize=12)338ax2.set_title('Quantum Superposition: Interference Pattern', fontsize=14, fontweight='bold')339ax2.legend()340ax2.grid(True, alpha=0.3)341342plt.tight_layout()343plt.savefig('assets/particle_in_box.pdf', dpi=300, bbox_inches='tight')344plt.close()345346print("Particle in box visualization saved to assets/particle_in_box.pdf")347348349pytex.after()350pytex.command = 'code'351pytex.set_context('')352pytex.args = ''353pytex.instance = '6'354pytex.line = '407'355356print('=>PYTHONTEX:STDOUT#6#code#')357sys.stderr.write('=>PYTHONTEX:STDERR#6#code#\n')358pytex.before()359360import numpy as np361import matplotlib.pyplot as plt362from numba import jit363364# Set random seed for reproducibility365np.random.seed(42)366367@jit(nopython=True)368def ising_energy(spins, J, h):369"""Calculate total energy of Ising model configuration"""370N = spins.shape[0]371energy = 0.0372373# Nearest neighbor interactions374for i in range(N):375for j in range(N):376# Periodic boundary conditions377right = spins[i, (j+1) % N]378down = spins[(i+1) % N, j]379energy -= J * spins[i, j] * (right + down)380381# External field382energy -= h * np.sum(spins)383return energy384385@jit(nopython=True)386def metropolis_step(spins, beta, J, h):387"""Single Metropolis Monte Carlo step"""388N = spins.shape[0]389390for _ in range(N * N):391# Random site392i, j = np.random.randint(0, N, 2)393394# Calculate energy change for spin flip395neighbors = (spins[i, (j+1) % N] + spins[i, (j-1) % N] +396spins[(i+1) % N, j] + spins[(i-1) % N, j])397398delta_E = 2 * J * spins[i, j] * neighbors + 2 * h * spins[i, j]399400# Metropolis acceptance401if delta_E < 0 or np.random.random() < np.exp(-beta * delta_E):402spins[i, j] *= -1403404@jit(nopython=True)405def magnetization(spins):406"""Calculate magnetization per site"""407return np.mean(spins)408409# Ising model parameters410N = 64 # Lattice size411J = 1.0 # Ferromagnetic coupling412h = 0.0 # No external field413414# Temperature range for phase transition study415T_min, T_max = 1.0, 4.0416n_temps = 20417temperatures = np.linspace(T_min, T_max, n_temps)418419# Critical temperature (analytical result for 2D Ising)420T_c = 2 * J / np.log(1 + np.sqrt(2)) # ≈ 2.269421422print(f"2D Ising model simulation: {N}×{N} lattice")423print(f"Theoretical critical temperature: T_c = {T_c:.3f}")424425# Monte Carlo simulation426n_steps = 5000427n_equilibration = 1000428429magnetizations = []430susceptibilities = []431energies = []432heat_capacities = []433434for T in temperatures:435beta = 1.0 / T436437# Initialize random configuration438spins = np.random.choice([-1, 1], size=(N, N))439440# Equilibration441for step in range(n_equilibration):442metropolis_step(spins, beta, J, h)443444# Measurement phase445mag_samples = []446energy_samples = []447448for step in range(n_steps):449metropolis_step(spins, beta, J, h)450451if step % 10 == 0: # Sample every 10 steps452mag_samples.append(abs(magnetization(spins)))453energy_samples.append(ising_energy(spins, J, h) / (N*N))454455# Calculate thermodynamic quantities456mag_mean = np.mean(mag_samples)457mag_var = np.var(mag_samples)458energy_mean = np.mean(energy_samples)459energy_var = np.var(energy_samples)460461magnetizations.append(mag_mean)462susceptibilities.append(beta * mag_var * N * N)463energies.append(energy_mean)464heat_capacities.append(beta**2 * energy_var * N * N)465466# Store final configuration for visualization467final_spins = spins.copy()468469print(f"Monte Carlo simulation completed: {len(temperatures)} temperatures")470print(f"Final magnetization at T={T:.2f}: {magnetizations[-1]:.4f}")471472473pytex.after()474pytex.command = 'code'475pytex.set_context('')476pytex.args = ''477pytex.instance = '7'478pytex.line = '521'479480print('=>PYTHONTEX:STDOUT#7#code#')481sys.stderr.write('=>PYTHONTEX:STDERR#7#code#\n')482pytex.before()483484# Visualize Ising model results485fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))486487# Magnetization vs temperature488ax1.plot(temperatures, magnetizations, 'bo-', linewidth=2, markersize=6)489ax1.axvline(T_c, color='red', linestyle='--', linewidth=2, label=f'T_c = {T_c:.3f}')490ax1.set_xlabel('Temperature T', fontsize=12)491ax1.set_ylabel('Magnetization |⟨m⟩|', fontsize=12)492ax1.set_title('Ising Model: Magnetic Phase Transition', fontsize=14, fontweight='bold')493ax1.legend()494ax1.grid(True, alpha=0.3)495496# Magnetic susceptibility497ax2.plot(temperatures, susceptibilities, 'ro-', linewidth=2, markersize=6)498ax2.axvline(T_c, color='red', linestyle='--', linewidth=2, label=f'T_c = {T_c:.3f}')499ax2.set_xlabel('Temperature T', fontsize=12)500ax2.set_ylabel('Susceptibility χ', fontsize=12)501ax2.set_title('Magnetic Susceptibility: Critical Behavior', fontsize=14, fontweight='bold')502ax2.legend()503ax2.grid(True, alpha=0.3)504505# Energy vs temperature506ax3.plot(temperatures, energies, 'go-', linewidth=2, markersize=6)507ax3.axvline(T_c, color='red', linestyle='--', linewidth=2, label=f'T_c = {T_c:.3f}')508ax3.set_xlabel('Temperature T', fontsize=12)509ax3.set_ylabel('Energy per site ⟨E⟩/N²', fontsize=12)510ax3.set_title('Internal Energy: Thermodynamic Behavior', fontsize=14, fontweight='bold')511ax3.legend()512ax3.grid(True, alpha=0.3)513514# Spin configuration515im = ax4.imshow(final_spins, cmap='RdBu', vmin=-1, vmax=1, interpolation='nearest')516ax4.set_title(f'Spin Configuration at T = {temperatures[-1]:.2f}', fontsize=14, fontweight='bold')517ax4.set_xlabel('x', fontsize=12)518ax4.set_ylabel('y', fontsize=12)519520# Add colorbar521cbar = plt.colorbar(im, ax=ax4, shrink=0.8)522cbar.set_label('Spin Value', fontsize=12)523cbar.set_ticks([-1, 0, 1])524cbar.set_ticklabels(['↓ (-1)', '0', '↑ (+1)'])525526plt.tight_layout()527plt.savefig('assets/ising_model.pdf', dpi=300, bbox_inches='tight')528plt.close()529530print("Ising model visualization saved to assets/ising_model.pdf")531532533pytex.after()534pytex.command = 'code'535pytex.set_context('')536pytex.args = ''537pytex.instance = '8'538pytex.line = '583'539540print('=>PYTHONTEX:STDOUT#8#code#')541sys.stderr.write('=>PYTHONTEX:STDERR#8#code#\n')542pytex.before()543544# 1D Ising model exact solution545def ising_1d_exact(T, J, h, N):546"""Exact solution for 1D Ising model using transfer matrix"""547beta = 1.0 / T548549# Transfer matrix elements550T11 = np.exp(beta * (J + h)) # ↑↑551T12 = np.exp(beta * (-J)) # ↑↓552T21 = np.exp(beta * (-J)) # ↓↑553T22 = np.exp(beta * (J - h)) # ↓↓554555# Transfer matrix556T_matrix = np.array([[T11, T12], [T21, T22]])557558# Eigenvalues559eigenvals = np.linalg.eigvals(T_matrix)560lambda_max = np.max(eigenvals)561562# Thermodynamic quantities (thermodynamic limit)563f_per_site = -T * np.log(lambda_max) # Free energy per site564565# For finite system566Z = np.trace(np.linalg.matrix_power(T_matrix, N)) # Partition function567F = -T * np.log(Z) # Free energy568569return F, f_per_site, Z570571# Calculate exact 1D results572T_range_1d = np.linspace(0.5, 5.0, 100)573J_1d = 1.0574h_1d = 0.1 # Small external field575N_1d = 50576577free_energies = []578partition_functions = []579580for T in T_range_1d:581F, f_per_site, Z = ising_1d_exact(T, J_1d, h_1d, N_1d)582free_energies.append(f_per_site)583partition_functions.append(Z)584585print(f"1D Ising model exact calculation: {len(T_range_1d)} temperature points")586print(f"System size: N = {N_1d}, coupling J = {J_1d}, field h = {h_1d}")587588589pytex.after()590pytex.command = 'code'591pytex.set_context('')592pytex.args = ''593pytex.instance = '9'594pytex.line = '629'595596print('=>PYTHONTEX:STDOUT#9#code#')597sys.stderr.write('=>PYTHONTEX:STDERR#9#code#\n')598pytex.before()599600# Visualize thermodynamic properties601fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))602603# Free energy per site604ax1.plot(T_range_1d, free_energies, 'b-', linewidth=2)605ax1.set_xlabel('Temperature T', fontsize=12)606ax1.set_ylabel('Free Energy per Site f', fontsize=12)607ax1.set_title('1D Ising Model: Free Energy (Exact Solution)', fontsize=14, fontweight='bold')608ax1.grid(True, alpha=0.3)609610# Partition function (log scale)611ax2.semilogy(T_range_1d, partition_functions, 'r-', linewidth=2)612ax2.set_xlabel('Temperature T', fontsize=12)613ax2.set_ylabel('Partition Function Z', fontsize=12)614ax2.set_title('Partition Function: Statistical Weight', fontsize=14, fontweight='bold')615ax2.grid(True, alpha=0.3)616617plt.tight_layout()618plt.savefig('assets/thermodynamics.pdf', dpi=300, bbox_inches='tight')619plt.close()620621print("Thermodynamics visualization saved to assets/thermodynamics.pdf")622623624pytex.after()625pytex.command = 'code'626pytex.set_context('')627pytex.args = ''628pytex.instance = '10'629pytex.line = '674'630631print('=>PYTHONTEX:STDOUT#10#code#')632sys.stderr.write('=>PYTHONTEX:STDERR#10#code#\n')633pytex.before()634635# 2D square lattice tight-binding model636def tight_binding_2d(kx, ky, t, epsilon_0):637"""Energy dispersion for 2D square lattice"""638return epsilon_0 - 2*t*(np.cos(kx) + np.cos(ky))639640def graphene_dispersion(kx, ky, t):641"""Energy dispersion for graphene (honeycomb lattice)"""642# Nearest neighbor phase factors643f = 1 + np.exp(1j * kx) + np.exp(1j * (kx/2 + np.sqrt(3)*ky/2))644return t * np.abs(f), -t * np.abs(f) # Two bands645646# Parameters647t = 1.0 # Hopping parameter648epsilon_0 = 0.0 # Onsite energy649650# Create k-space grid651k_points = 100652kx = np.linspace(-np.pi, np.pi, k_points)653ky = np.linspace(-np.pi, np.pi, k_points)654KX, KY = np.meshgrid(kx, ky)655656# Calculate band structure657E_square = tight_binding_2d(KX, KY, t, epsilon_0)658E_graphene_plus, E_graphene_minus = graphene_dispersion(KX, KY, t)659660# Density of states calculation661def calculate_dos(energies, n_bins=200):662"""Calculate density of states"""663E_flat = energies.flatten()664E_min, E_max = E_flat.min(), E_flat.max()665E_bins = np.linspace(E_min, E_max, n_bins)666hist, bin_edges = np.histogram(E_flat, bins=E_bins)667E_centers = (bin_edges[:-1] + bin_edges[1:]) / 2668dos = hist / (E_bins[1] - E_bins[0]) / len(E_flat)669return E_centers, dos670671E_dos_square, dos_square = calculate_dos(E_square)672E_dos_graphene, dos_graphene = calculate_dos(np.concatenate([E_graphene_plus.flatten(),673E_graphene_minus.flatten()]))674675print(f"Band structure calculation completed: {k_points}×{k_points} k-points")676print(f"Square lattice bandwidth: {E_square.max() - E_square.min():.3f}")677print(f"Graphene bandwidth: {E_graphene_plus.max() - E_graphene_minus.min():.3f}")678679680pytex.after()681pytex.command = 'code'682pytex.set_context('')683pytex.args = ''684pytex.instance = '11'685pytex.line = '720'686687print('=>PYTHONTEX:STDOUT#11#code#')688sys.stderr.write('=>PYTHONTEX:STDERR#11#code#\n')689pytex.before()690691# Visualize band structure692fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))693694# Square lattice band structure695im1 = ax1.contourf(KX, KY, E_square, levels=50, cmap='viridis')696ax1.set_xlabel('kₓ', fontsize=12)697ax1.set_ylabel('kᵧ', fontsize=12)698ax1.set_title('Square Lattice: Energy Dispersion E(k)', fontsize=14, fontweight='bold')699plt.colorbar(im1, ax=ax1, label='Energy E/t')700701# Graphene band structure (valence band)702im2 = ax2.contourf(KX, KY, E_graphene_minus, levels=50, cmap='plasma')703ax2.set_xlabel('kₓ', fontsize=12)704ax2.set_ylabel('kᵧ', fontsize=12)705ax2.set_title('Graphene: Valence Band Dispersion', fontsize=14, fontweight='bold')706plt.colorbar(im2, ax=ax2, label='Energy E/t')707708# Density of states - square lattice709ax3.plot(E_dos_square, dos_square, 'b-', linewidth=2, label='Square lattice')710ax3.fill_between(E_dos_square, 0, dos_square, alpha=0.3)711ax3.set_xlabel('Energy E/t', fontsize=12)712ax3.set_ylabel('Density of States', fontsize=12)713ax3.set_title('Electronic Density of States: Square Lattice', fontsize=14, fontweight='bold')714ax3.legend()715ax3.grid(True, alpha=0.3)716717# Density of states - graphene718ax4.plot(E_dos_graphene, dos_graphene, 'r-', linewidth=2, label='Graphene')719ax4.fill_between(E_dos_graphene, 0, dos_graphene, alpha=0.3, color='red')720ax4.axvline(0, color='black', linestyle='--', alpha=0.7, label='Dirac point')721ax4.set_xlabel('Energy E/t', fontsize=12)722ax4.set_ylabel('Density of States', fontsize=12)723ax4.set_title('Electronic Density of States: Graphene', fontsize=14, fontweight='bold')724ax4.legend()725ax4.grid(True, alpha=0.3)726727plt.tight_layout()728plt.savefig('assets/band_structure.pdf', dpi=300, bbox_inches='tight')729plt.close()730731print("Band structure visualization saved to assets/band_structure.pdf")732733734pytex.after()735pytex.command = 'code'736pytex.set_context('')737pytex.args = ''738pytex.instance = '12'739pytex.line = '776'740741print('=>PYTHONTEX:STDOUT#12#code#')742sys.stderr.write('=>PYTHONTEX:STDERR#12#code#\n')743pytex.before()744745# Fermi surface calculation746def fermi_surface_2d(kx, ky, t, mu, T=0.01):747"""Calculate Fermi surface for 2D system"""748E = tight_binding_2d(kx, ky, t, 0)749750# Fermi-Dirac distribution751if T > 0:752f = 1.0 / (1.0 + np.exp((E - mu) / T))753else:754f = (E < mu).astype(float)755756return E, f757758# Parameters for different filling levels759t_fermi = 1.0760mu_values = [-3.0, -2.0, 0.0, 2.0] # Different chemical potentials761filling_names = ['Low filling', 'Quarter filling', 'Half filling', 'High filling']762763# Higher resolution for Fermi surface764k_fermi = 200765kx_fermi = np.linspace(-np.pi, np.pi, k_fermi)766ky_fermi = np.linspace(-np.pi, np.pi, k_fermi)767KX_fermi, KY_fermi = np.meshgrid(kx_fermi, ky_fermi)768769# Calculate Fermi surfaces770fermi_data = []771for mu in mu_values:772E, f = fermi_surface_2d(KX_fermi, KY_fermi, t_fermi, mu, T=0.1)773fermi_data.append((E, f))774775print(f"Fermi surface calculation: {k_fermi}×{k_fermi} k-points")776print(f"Chemical potentials: {mu_values}")777778779pytex.after()780pytex.command = 'code'781pytex.set_context('')782pytex.args = ''783pytex.instance = '13'784pytex.line = '811'785786print('=>PYTHONTEX:STDOUT#13#code#')787sys.stderr.write('=>PYTHONTEX:STDERR#13#code#\n')788pytex.before()789790# Visualize Fermi surfaces791fig, axes = plt.subplots(2, 2, figsize=(16, 12))792axes = axes.flatten()793794for i, ((E, f), mu, name) in enumerate(zip(fermi_data, mu_values, filling_names)):795ax = axes[i]796797# Plot Fermi surface as contour798contour = ax.contour(KX_fermi, KY_fermi, E, levels=[mu], colors='red', linewidths=3)799800# Fill occupied states801filled = ax.contourf(KX_fermi, KY_fermi, f, levels=50, cmap='Blues', alpha=0.7)802803ax.set_xlabel('kₓ/π', fontsize=12)804ax.set_ylabel('kᵧ/π', fontsize=12)805ax.set_title(f'{name}: μ = {mu:.1f}t', fontsize=14, fontweight='bold')806ax.set_xlim(-np.pi, np.pi)807ax.set_ylim(-np.pi, np.pi)808809# Add Brillouin zone boundary810ax.plot([-np.pi, np.pi, np.pi, -np.pi, -np.pi],811[-np.pi, -np.pi, np.pi, np.pi, -np.pi],812'k--', alpha=0.5, linewidth=1)813814# Colorbar for occupation815if i == 1: # Add colorbar to one plot816cbar = plt.colorbar(filled, ax=ax, shrink=0.8)817cbar.set_label('Occupation f(k)', fontsize=10)818819plt.tight_layout()820plt.savefig('assets/fermi_surface.pdf', dpi=300, bbox_inches='tight')821plt.close()822823print("Fermi surface visualization saved to assets/fermi_surface.pdf")824825826pytex.after()827pytex.command = 'code'828pytex.set_context('')829pytex.args = ''830pytex.instance = '14'831pytex.line = '860'832833print('=>PYTHONTEX:STDOUT#14#code#')834sys.stderr.write('=>PYTHONTEX:STDERR#14#code#\n')835pytex.before()836837# 1D monoatomic chain phonon dispersion838def phonon_monoatomic(k, K, M):839"""Phonon frequency for 1D monoatomic chain"""840return np.sqrt(4*K/M * np.sin(k/2)**2)841842# 1D diatomic chain phonon dispersion843def phonon_diatomic(k, K, M1, M2):844"""Phonon frequencies for 1D diatomic chain"""845M_sum = M1 + M2846M_prod = M1 * M2847848# Discriminant849disc = (M_sum)**2 - 4*M_prod*np.cos(k)**2850851# Optical and acoustic branches852omega_plus = np.sqrt(K * (M_sum + np.sqrt(disc)) / (2*M_prod))853omega_minus = np.sqrt(K * (M_sum - np.sqrt(disc)) / (2*M_prod))854855return omega_plus, omega_minus856857# Parameters858K = 1.0 # Spring constant859M = 1.0 # Mass (monoatomic)860M1, M2 = 1.0, 2.0 # Masses (diatomic)861862# k-point path863k_points_1d = np.linspace(-np.pi, np.pi, 500)864865# Calculate dispersions866omega_mono = phonon_monoatomic(k_points_1d, K, M)867omega_optical, omega_acoustic = phonon_diatomic(k_points_1d, K, M1, M2)868869# Density of phonon states870def phonon_dos(k_vals, omega_vals, n_bins=100):871"""Calculate phonon density of states"""872# Use only positive k values to avoid double counting873k_pos = k_vals[k_vals >= 0]874omega_pos = omega_vals[k_vals >= 0]875876omega_min, omega_max = 0, omega_pos.max()877omega_bins = np.linspace(omega_min, omega_max, n_bins)878879hist, bin_edges = np.histogram(omega_pos, bins=omega_bins)880omega_centers = (bin_edges[:-1] + bin_edges[1:]) / 2881dos = hist / (omega_bins[1] - omega_bins[0]) / len(omega_pos)882883return omega_centers, dos884885# Calculate phonon DOS886omega_dos_mono, dos_mono = phonon_dos(k_points_1d, omega_mono)887omega_dos_opt, dos_opt = phonon_dos(k_points_1d, omega_optical)888omega_dos_ac, dos_ac = phonon_dos(k_points_1d, omega_acoustic)889890print(f"Phonon dispersion calculation: {len(k_points_1d)} k-points")891print(f"Monoatomic max frequency: {omega_mono.max():.3f}")892print(f"Diatomic optical max: {omega_optical.max():.3f}")893print(f"Diatomic acoustic max: {omega_acoustic.max():.3f}")894895896pytex.after()897pytex.command = 'code'898pytex.set_context('')899pytex.args = ''900pytex.instance = '15'901pytex.line = '920'902903print('=>PYTHONTEX:STDOUT#15#code#')904sys.stderr.write('=>PYTHONTEX:STDERR#15#code#\n')905pytex.before()906907# Visualize phonon dispersion908fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8))909910# Dispersion relations911ax1.plot(k_points_1d/np.pi, omega_mono, 'b-', linewidth=2, label='Monoatomic chain')912ax1.plot(k_points_1d/np.pi, omega_optical, 'r-', linewidth=2, label='Optical branch')913ax1.plot(k_points_1d/np.pi, omega_acoustic, 'g-', linewidth=2, label='Acoustic branch')914915ax1.set_xlabel('Wave vector k/π', fontsize=12)916ax1.set_ylabel('Frequency ω√(M/K)', fontsize=12)917ax1.set_title('Phonon Dispersion Relations', fontsize=14, fontweight='bold')918ax1.legend()919ax1.grid(True, alpha=0.3)920ax1.set_xlim(-1, 1)921922# Density of states923ax2.plot(omega_dos_mono, dos_mono, 'b-', linewidth=2, label='Monoatomic')924ax2.fill_between(omega_dos_mono, 0, dos_mono, alpha=0.3, color='blue')925926ax2.plot(omega_dos_opt, dos_opt, 'r-', linewidth=2, label='Optical')927ax2.fill_between(omega_dos_opt, 0, dos_opt, alpha=0.3, color='red')928929ax2.plot(omega_dos_ac, dos_ac, 'g-', linewidth=2, label='Acoustic')930ax2.fill_between(omega_dos_ac, 0, dos_ac, alpha=0.3, color='green')931932ax2.set_xlabel('Frequency ω√(M/K)', fontsize=12)933ax2.set_ylabel('Density of States', fontsize=12)934ax2.set_title('Phonon Density of States', fontsize=14, fontweight='bold')935ax2.legend()936ax2.grid(True, alpha=0.3)937938plt.tight_layout()939plt.savefig('assets/phonon_dispersion.pdf', dpi=300, bbox_inches='tight')940plt.close()941942print("Phonon dispersion visualization saved to assets/phonon_dispersion.pdf")943944945pytex.after()946pytex.command = 'code'947pytex.set_context('')948pytex.args = ''949pytex.instance = '16'950pytex.line = '979'951952print('=>PYTHONTEX:STDOUT#16#code#')953sys.stderr.write('=>PYTHONTEX:STDERR#16#code#\n')954pytex.before()955956# Simple mean-field solution of Hubbard model957def hubbard_mean_field(t, U, n, T=0.1, max_iter=1000, tol=1e-6):958"""959Mean-field solution of Hubbard model on 2D square lattice960Returns self-consistent chemical potential and magnetization961"""962# Initial guess963mu = U * n / 2 # Chemical potential964m = 0.1 # Magnetization (small initial value)965966for iteration in range(max_iter):967# Mean-field Hamiltonian eigenvalues968# For 2D square lattice: epsilon_k = -2t(cos(kx) + cos(ky))969# With mean-field correction: E_k^± = epsilon_k ± U*m/2970971k_mesh = 64972kx = np.linspace(-np.pi, np.pi, k_mesh)973ky = np.linspace(-np.pi, np.pi, k_mesh)974KX, KY = np.meshgrid(kx, ky)975976epsilon_k = -2*t*(np.cos(KX) + np.cos(KY))977E_plus = epsilon_k - mu + U*m/2 # Spin-up band978E_minus = epsilon_k - mu - U*m/2 # Spin-down band979980# Fermi-Dirac distribution981f_plus = 1.0 / (1.0 + np.exp(E_plus / T))982f_minus = 1.0 / (1.0 + np.exp(E_minus / T))983984# New density and magnetization985n_new = np.mean(f_plus + f_minus)986m_new = np.mean(f_plus - f_minus)987988# Check convergence989if abs(m_new - m) < tol:990break991992# Update with mixing993m = 0.7 * m + 0.3 * m_new994995# Adjust chemical potential to maintain target density996mu = mu + 0.1 * (n - n_new)997998return mu, m, f_plus, f_minus, epsilon_k9991000# Parameters for different interaction strengths1001t_hub = 1.01002density = 0.8 # Filling factor1003U_values = [0.0, 2.0, 4.0, 6.0] # Interaction strengths10041005results = []1006for U in U_values:1007mu, m, f_up, f_dn, eps_k = hubbard_mean_field(t_hub, U, density)1008results.append((U, mu, m, f_up, f_dn, eps_k))1009print(f"U/t = {U/t_hub:.1f}: μ = {mu:.3f}, m = {m:.4f}")10101011print(f"Hubbard model mean-field calculation completed")101210131014pytex.after()1015pytex.command = 'code'1016pytex.set_context('')1017pytex.args = ''1018pytex.instance = '17'1019pytex.line = '1038'10201021print('=>PYTHONTEX:STDOUT#17#code#')1022sys.stderr.write('=>PYTHONTEX:STDERR#17#code#\n')1023pytex.before()10241025# Plot Hubbard model results1026fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))10271028# Magnetization vs interaction strength1029U_plot = [result[0] for result in results]1030m_plot = [abs(result[2]) for result in results] # Take absolute value10311032ax1.plot(U_plot, m_plot, 'ro-', linewidth=2, markersize=8)1033ax1.set_xlabel('Interaction U/t', fontsize=12)1034ax1.set_ylabel('Magnetization |m|', fontsize=12)1035ax1.set_title('Hubbard Model: Magnetic Instability', fontsize=14, fontweight='bold')1036ax1.grid(True, alpha=0.3)10371038# Chemical potential vs interaction1039mu_plot = [result[1] for result in results]1040ax2.plot(U_plot, mu_plot, 'bo-', linewidth=2, markersize=8)1041ax2.set_xlabel('Interaction U/t', fontsize=12)1042ax2.set_ylabel('Chemical Potential μ/t', fontsize=12)1043ax2.set_title('Chemical Potential: Correlation Effects', fontsize=14, fontweight='bold')1044ax2.grid(True, alpha=0.3)10451046# Spin-resolved occupations for strong coupling case1047U_strong = results[-1] # Strongest coupling1048f_up_strong = U_strong[3]1049f_dn_strong = U_strong[4]10501051im3 = ax3.contourf(f_up_strong, levels=50, cmap='Reds')1052ax3.set_title(f'Spin-Up Occupation (U = {U_strong[0]:.1f}t)', fontsize=14, fontweight='bold')1053ax3.set_xlabel('kₓ index', fontsize=12)1054ax3.set_ylabel('kᵧ index', fontsize=12)1055plt.colorbar(im3, ax=ax3, shrink=0.8)10561057im4 = ax4.contourf(f_dn_strong, levels=50, cmap='Blues')1058ax4.set_title(f'Spin-Down Occupation (U = {U_strong[0]:.1f}t)', fontsize=14, fontweight='bold')1059ax4.set_xlabel('kₓ index', fontsize=12)1060ax4.set_ylabel('kᵧ index', fontsize=12)1061plt.colorbar(im4, ax=ax4, shrink=0.8)10621063plt.tight_layout()1064plt.savefig('assets/hubbard_model.pdf', dpi=300, bbox_inches='tight')1065plt.close()10661067print("Hubbard model visualization saved to assets/hubbard_model.pdf")106810691070pytex.after()1071pytex.command = 'code'1072pytex.set_context('')1073pytex.args = ''1074pytex.instance = '18'1075pytex.line = '1097'10761077print('=>PYTHONTEX:STDOUT#18#code#')1078sys.stderr.write('=>PYTHONTEX:STDERR#18#code#\n')1079pytex.before()10801081# Demonstrate numerical precision considerations1082def convergence_study():1083"""Study convergence of numerical methods"""10841085# Test case: numerical integration of oscillatory function1086def integrand(x):1087return np.sin(10*x) * np.exp(-x**2)10881089# Analytical result (approximate)1090analytical = 0.4995 # Pre-computed high-precision result10911092# Different grid sizes1093N_values = [10, 20, 50, 100, 200, 500, 1000]1094errors_trapz = []1095errors_simpson = []10961097for N in N_values:1098x = np.linspace(0, 3, N)1099y = integrand(x)11001101# Trapezoidal rule1102integral_trapz = np.trapz(y, x)1103error_trapz = abs(integral_trapz - analytical)1104errors_trapz.append(error_trapz)11051106# Simpson's rule (if N is odd)1107if N % 2 == 1:1108from scipy.integrate import simpson1109integral_simpson = simpson(y, x)1110error_simpson = abs(integral_simpson - analytical)1111else:1112error_simpson = np.nan1113errors_simpson.append(error_simpson)11141115return N_values, errors_trapz, errors_simpson11161117N_vals, err_trapz, err_simp = convergence_study()11181119print("Numerical integration convergence study completed")1120print(f"Grid sizes tested: {N_vals}")112111221123pytex.after()1124pytex.command = 'code'1125pytex.set_context('')1126pytex.args = ''1127pytex.instance = '19'1128pytex.line = '1140'11291130print('=>PYTHONTEX:STDOUT#19#code#')1131sys.stderr.write('=>PYTHONTEX:STDERR#19#code#\n')1132pytex.before()11331134# Plot convergence study1135fig, ax = plt.subplots(figsize=(12, 8))11361137ax.loglog(N_vals, err_trapz, 'bo-', linewidth=2, markersize=6, label='Trapezoidal Rule')11381139# Filter out NaN values for Simpson's rule1140N_simp = [N for N, err in zip(N_vals, err_simp) if not np.isnan(err)]1141err_simp_clean = [err for err in err_simp if not np.isnan(err)]1142ax.loglog(N_simp, err_simp_clean, 'rs-', linewidth=2, markersize=6, label="Simpson's Rule")11431144# Theoretical scaling lines1145N_theory = np.array(N_vals)1146ax.loglog(N_theory, 1e-1 * (N_theory[0]/N_theory)**2, 'k--', alpha=0.7, label='N⁻² scaling')1147ax.loglog(N_theory, 1e-3 * (N_theory[0]/N_theory)**4, 'k:', alpha=0.7, label='N⁻⁴ scaling')11481149ax.set_xlabel('Number of Grid Points N', fontsize=12)1150ax.set_ylabel('Absolute Error', fontsize=12)1151ax.set_title('Numerical Integration: Convergence Analysis', fontsize=14, fontweight='bold')1152ax.legend()1153ax.grid(True, alpha=0.3)11541155plt.tight_layout()1156plt.savefig('assets/convergence_study.pdf', dpi=300, bbox_inches='tight')1157plt.close()11581159print("Convergence study visualization saved to assets/convergence_study.pdf")116011611162pytex.after()116311641165pytex.cleanup()116611671168