92 KiB
92 KiB
In [1]:
import numpy as np
import matplotlib.pyplot as plt
import os
import sysIn [2]:
# Define parameters
N = 10 # Size of the cubic lattice (N x N x N)
J = 1.0 # Interaction strength
kB = 1.0 # Boltzmann constant
T_values = [2.5, 2.4, 2.3, 2.2, 2.1, 2.0, 1.9, 1.8, 1.7, 1.6, 1.54, 1.52, 1.50, 1.49, 1.48, 1.47, 1.46,
1.45, 1.44, 1.43, 1.42, 1.41, 1.40, 1.39, 1.38, 1.37, 1.36, 1.34, 1.32, 1.30, 1.25, 1.20,
1.1, 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1]
total_steps = 10**6
equilibration_steps = total_steps/10
start_save_config = total_steps - 1000
progress = 0In [3]:
# Function to initialize the lattice with random unit vectors
def initialize_lattice(N):
lattice = np.random.rand(N, N, N, 3) * 2 - 1.0 # Random values in [-1.0, 1.0]
lattice /= np.linalg.norm(lattice, axis=-1, keepdims=True)
return latticeIn [4]:
# Function to get the neighbors of a spin
def get_neighbors(lattice, i, j, k):
neighbors = []
for di, dj, dk in [(-1, 0, 0), (1, 0, 0), (0, -1, 0), (0, 1, 0), (0, 0, -1), (0, 0, 1)]:
ni, nj, nk = (i + di) % N, (j + dj) % N, (k + dk) % N # Apply periodic boundary conditions
neighbors.append(lattice[ni, nj, nk])
return neighborsIn [5]:
# Function to calculate the energy of a spin and its neighbors
def calculate_energy(spin, neighbors):
neighbor_sum = np.sum(neighbors, axis=0)
energy = -J * np.dot(spin, neighbor_sum)
return energyIn [6]:
# Function to calculate the magnetization magnitude of the lattice
def calculate_magnetization(lattice):
magnetization = [0.0, 0.0, 0.0]
for i in range(N):
for j in range(N):
for k in range(N):
# Access the lattice element at position (i, j, k)
magnetization[0] += lattice[i, j, k, 0]
magnetization[1] += lattice[i, j, k, 1]
magnetization[2] += lattice[i, j, k, 2]
magnitude = magnetization[0]*magnetization[0] + magnetization[1]*magnetization[1] + magnetization[2]*magnetization[2]
magnitude = np.sqrt(magnitude)
magnitude = magnitude/(N**3)
return magnitudeIn [7]:
# Function to perform a Metropolis update
def metropolis_update(lattice, temperature):
global acc_rate
i, j, k = np.random.randint(0, N, size=3)
spin = lattice[i, j, k]
neighbors = get_neighbors(lattice, i, j, k)
# Calculate energy before the update
energy_before = calculate_energy(spin, neighbors)
# Propose a new spin configuration
new_spin = (np.random.rand(3) * 2 - 1.0) # Random values between -1.0 and 1.0 for each component
new_spin /= np.linalg.norm(new_spin)
# Calculate energy after the update
energy_after = calculate_energy(new_spin, neighbors)
# Calculate energy difference
delta_energy = energy_after - energy_before
# Metropolis acceptance criteria
if delta_energy <= 0 or np.random.rand() < np.exp(-delta_energy / (kB * temperature)):
lattice[i, j, k] = new_spin
acc_rate += 1In [8]:
# Function to save Configurations as an .npy file (Only the X Components)
def save_configuration_X(config, temperature, step, lattice_size):
folder_name = f"{lattice_size}X{lattice_size}X{lattice_size}_Steps{total_steps}/{temperature:.2f}/X_Comp"
file_name = f"X_ConfigFile_Size{lattice_size}x{lattice_size}x{lattice_size}_M0.00_T{temperature:.2f}_StepNum{step}.npy"
folder_path = os.path.join(os.getcwd(), folder_name)
file_path = os.path.join(folder_path, file_name)
if not os.path.exists(folder_path):
os.makedirs(folder_path)
np.save(file_path, config)In [9]:
# Function to save Configurations as an .npy file (Only the Y Components)
def save_configuration_Y(config, temperature, step, lattice_size):
folder_name = f"{lattice_size}X{lattice_size}X{lattice_size}_Steps{total_steps}/{temperature:.2f}/Y_Comp"
file_name = f"Y_ConfigFile_Size{lattice_size}x{lattice_size}x{lattice_size}_M0.00_T{temperature:.2f}_StepNum{step}.npy"
folder_path = os.path.join(os.getcwd(), folder_name)
file_path = os.path.join(folder_path, file_name)
if not os.path.exists(folder_path):
os.makedirs(folder_path)
np.save(file_path, config)In [10]:
# Function to save Configurations as an .npy file (Only the Z Components)
def save_configuration_Z(config, temperature, step, lattice_size):
folder_name = f"{lattice_size}X{lattice_size}X{lattice_size}_Steps{total_steps}/{temperature:.2f}/Z_Comp"
file_name = f"Z_ConfigFile_Size{lattice_size}x{lattice_size}x{lattice_size}_M0.00_T{temperature:.2f}_StepNum{step}.npy"
folder_path = os.path.join(os.getcwd(), folder_name)
file_path = os.path.join(folder_path, file_name)
if not os.path.exists(folder_path):
os.makedirs(folder_path)
np.save(file_path, config)In [11]:
# Function to save the lattice as an .npy file
def save_lattice(lattice, temperature, step, lattice_size):
folder_name = f"{lattice_size}X{lattice_size}X{lattice_size}_Steps{total_steps}/{temperature:.2f}/Lattice"
file_name = f"LatticeFile_Size{lattice_size}x{lattice_size}x{lattice_size}_T{temperature:.2f}_StepNum{step}.npy"
folder_path = os.path.join(os.getcwd(), folder_name)
file_path = os.path.join(folder_path, file_name)
if not os.path.exists(folder_path):
os.makedirs(folder_path)
np.save(file_path, lattice)In [12]:
# Function to perform the Monte Carlo simulation
def monte_carlo_simulation(lattice, temperature, equilibration_steps, total_steps):
magnetization_values = []
for step in range(total_steps):
metropolis_update(lattice, temperature)
if step >= equilibration_steps and (step - equilibration_steps) % (total_steps // 100) == 0:
# Calculate magnetization and save measurements
magnetization = calculate_magnetization(lattice)
magnetization_values.append(magnetization)
if step >= start_save_config:
x_components = lattice[:, :, :, 0] # Extract x components (index 0)
y_components = lattice[:, :, :, 1] # Extract y components (index 1)
z_components = lattice[:, :, :, 2] # Extract z components (index 2)
save_configuration_X(x_components,temperature,step,N)
save_configuration_Y(y_components,temperature,step,N)
save_configuration_Z(z_components,temperature,step,N)
# Save the lattice as well
save_lattice(lattice, temperature, step, N)
# Calculate average magnetization and error bar
avg_magnetization = np.mean(magnetization_values)
error_bar = np.std(magnetization_values) / np.sqrt(len(magnetization_values))
# Calculating magnetic susceptibility
Chi = (np.var(magnetization_values))/temperature
# Return average magnetization, error bar
return avg_magnetization, error_bar, ChiIn [13]:
# Main simulation loop
global lattice
lattice = initialize_lattice(N)
avg_magnetizations = []
error_bars = []
susceptibility_values = []
file_name_ = f"simulation_results_{N}X{N}X{N}_Steps{total_steps}.txt"
file = open(file_name_ , 'w')
for T in T_values:
acc_rate = 0
avg_mag, error, Chi = monte_carlo_simulation(lattice, T, equilibration_steps, total_steps)
avg_magnetizations.append(avg_mag)
error_bars.append(error)
susceptibility_values.append(Chi)
progress = progress + 1
num_of_temp = len(T_values)
print(f"{progress:02d}/{num_of_temp} - Temperature: {T:.2f}, Magnetization: {avg_mag:.8f}, Error: {error:.8f}, Susceptibility: {Chi:.8f}, Acc_Rate: {acc_rate}")
line = f"Temperature: {T:.2f}, Magnetization: {avg_mag:.8f}, Error: {error:.8f}, Susceptibility: {Chi:.8f}, Acc_Rate: {acc_rate}\n"
sys.stdout.flush() # Force flushing the output buffer
file.write(line)
file.flush() # Force flushing the file buffer
file.close()01/43 - Temperature: 2.50, Magnetization: 0.05067800, Error: 0.00231309, Susceptibility: 0.00019261, Acc_Rate: 694993 02/43 - Temperature: 2.40, Magnetization: 0.05701614, Error: 0.00233589, Susceptibility: 0.00020461, Acc_Rate: 682533 03/43 - Temperature: 2.30, Magnetization: 0.05745391, Error: 0.00228808, Susceptibility: 0.00020486, Acc_Rate: 667664 04/43 - Temperature: 2.20, Magnetization: 0.06127256, Error: 0.00251489, Susceptibility: 0.00025874, Acc_Rate: 653054 05/43 - Temperature: 2.10, Magnetization: 0.06650248, Error: 0.00342411, Susceptibility: 0.00050248, Acc_Rate: 636446 06/43 - Temperature: 2.00, Magnetization: 0.07177253, Error: 0.00282175, Susceptibility: 0.00035830, Acc_Rate: 617125 07/43 - Temperature: 1.90, Magnetization: 0.07764729, Error: 0.00349707, Susceptibility: 0.00057929, Acc_Rate: 595959 08/43 - Temperature: 1.80, Magnetization: 0.07969424, Error: 0.00346145, Susceptibility: 0.00059908, Acc_Rate: 572639 09/43 - Temperature: 1.70, Magnetization: 0.10794836, Error: 0.00536923, Susceptibility: 0.00152622, Acc_Rate: 542048 10/43 - Temperature: 1.60, Magnetization: 0.12627725, Error: 0.00551466, Susceptibility: 0.00171065, Acc_Rate: 510216 11/43 - Temperature: 1.54, Magnetization: 0.23756270, Error: 0.00701833, Susceptibility: 0.00287865, Acc_Rate: 477083 12/43 - Temperature: 1.52, Magnetization: 0.19669505, Error: 0.00680513, Susceptibility: 0.00274203, Acc_Rate: 475510 13/43 - Temperature: 1.50, Magnetization: 0.26928236, Error: 0.00633434, Susceptibility: 0.00240743, Acc_Rate: 460500 14/43 - Temperature: 1.49, Magnetization: 0.28233166, Error: 0.00660430, Susceptibility: 0.00263457, Acc_Rate: 450501 15/43 - Temperature: 1.48, Magnetization: 0.31488006, Error: 0.00634694, Susceptibility: 0.00244968, Acc_Rate: 442054 16/43 - Temperature: 1.47, Magnetization: 0.27167505, Error: 0.00687240, Susceptibility: 0.00289162, Acc_Rate: 444030 17/43 - Temperature: 1.46, Magnetization: 0.28125360, Error: 0.00782904, Susceptibility: 0.00377839, Acc_Rate: 438247 18/43 - Temperature: 1.45, Magnetization: 0.31897099, Error: 0.00630256, Susceptibility: 0.00246552, Acc_Rate: 430177 19/43 - Temperature: 1.44, Magnetization: 0.33826857, Error: 0.00640851, Susceptibility: 0.00256681, Acc_Rate: 421624 20/43 - Temperature: 1.43, Magnetization: 0.33619013, Error: 0.00484151, Susceptibility: 0.00147526, Acc_Rate: 420482 21/43 - Temperature: 1.42, Magnetization: 0.40093416, Error: 0.00546004, Susceptibility: 0.00188949, Acc_Rate: 402824 22/43 - Temperature: 1.41, Magnetization: 0.40223867, Error: 0.00544269, Susceptibility: 0.00189082, Acc_Rate: 398312 23/43 - Temperature: 1.40, Magnetization: 0.41361242, Error: 0.00584992, Susceptibility: 0.00219996, Acc_Rate: 393440 24/43 - Temperature: 1.39, Magnetization: 0.42797076, Error: 0.00391937, Susceptibility: 0.00099463, Acc_Rate: 387163 25/43 - Temperature: 1.38, Magnetization: 0.45036921, Error: 0.00567672, Susceptibility: 0.00210164, Acc_Rate: 375626 26/43 - Temperature: 1.37, Magnetization: 0.45859763, Error: 0.00481411, Susceptibility: 0.00152249, Acc_Rate: 371869 27/43 - Temperature: 1.36, Magnetization: 0.44461117, Error: 0.00410840, Susceptibility: 0.00111699, Acc_Rate: 370419 28/43 - Temperature: 1.34, Magnetization: 0.46889421, Error: 0.00420211, Susceptibility: 0.00118597, Acc_Rate: 359287 29/43 - Temperature: 1.32, Magnetization: 0.51931686, Error: 0.00361887, Susceptibility: 0.00089292, Acc_Rate: 339340 30/43 - Temperature: 1.30, Magnetization: 0.54039866, Error: 0.00271472, Susceptibility: 0.00051021, Acc_Rate: 328362 31/43 - Temperature: 1.25, Magnetization: 0.59450172, Error: 0.00322554, Susceptibility: 0.00074909, Acc_Rate: 301172 32/43 - Temperature: 1.20, Magnetization: 0.61688533, Error: 0.00239843, Susceptibility: 0.00043144, Acc_Rate: 282441 33/43 - Temperature: 1.10, Magnetization: 0.70057186, Error: 0.00213217, Susceptibility: 0.00037196, Acc_Rate: 237369 34/43 - Temperature: 1.00, Magnetization: 0.75602324, Error: 0.00144626, Susceptibility: 0.00018825, Acc_Rate: 202588 35/43 - Temperature: 0.90, Magnetization: 0.79911328, Error: 0.00110576, Susceptibility: 0.00012227, Acc_Rate: 173813 36/43 - Temperature: 0.80, Magnetization: 0.83435035, Error: 0.00086618, Susceptibility: 0.00008440, Acc_Rate: 148781 37/43 - Temperature: 0.70, Magnetization: 0.86724151, Error: 0.00071909, Susceptibility: 0.00006648, Acc_Rate: 126742 38/43 - Temperature: 0.60, Magnetization: 0.89348401, Error: 0.00049948, Susceptibility: 0.00003742, Acc_Rate: 107594 39/43 - Temperature: 0.50, Magnetization: 0.91464745, Error: 0.00044023, Susceptibility: 0.00003488, Acc_Rate: 90697 40/43 - Temperature: 0.40, Magnetization: 0.93373802, Error: 0.00033215, Susceptibility: 0.00002482, Acc_Rate: 74396 41/43 - Temperature: 0.30, Magnetization: 0.95149632, Error: 0.00027094, Susceptibility: 0.00002202, Acc_Rate: 58787 42/43 - Temperature: 0.20, Magnetization: 0.96750309, Error: 0.00013980, Susceptibility: 0.00000879, Acc_Rate: 42481 43/43 - Temperature: 0.10, Magnetization: 0.98301393, Error: 0.00006677, Susceptibility: 0.00000401, Acc_Rate: 25197
In [14]:
# Set plot size and create the figure
fig, ax = plt.subplots(figsize=(9, 5))
# Ensure error_bars has the same number of elements as T_values
error_bars = error_bars[:len(T_values)]
# Plot results with error bars and lines
plt.errorbar(T_values, avg_magnetizations, yerr=error_bars, fmt='o-', label='Magnetization',
ecolor='red', markersize=1, elinewidth=1, linewidth=1)
plt.xscale('linear') # Set the x-axis scale to linear
plt.xlabel('Temperature (T)')
plt.ylabel('Average Magnetization per spin')
# Add legend
legend = plt.legend()
power = int(np.log10(total_steps))
# Create the lattice_info string with dynamic steps value
lattice_info = f'Lattice Type: Cubic\nLattice Size: ${N}^3$\nSteps: $10^{power}$'
plt.text(0.78, 0.8, lattice_info, transform=ax.transAxes, fontsize=10, ha='left', va='center')
# Set legend font size
legend.get_texts()[0].set_fontsize('10')
plt.title('Classical 3D Heisenberg Model - Monte Carlo Simulation using Metropolis Algorithm')
# Customize the grid
ax.grid(color='lightgray', linestyle='--', linewidth=0.5)
# Save the figure to a file (e.g., a PNG image)
file_name_image = f"Magnetization_vs_Temperature_Simulation_results_{N}X{N}X{N}_Steps{total_steps}.png"
plt.savefig(file_name_image, dpi=300, bbox_inches='tight')
plt.show()
In [15]:
# Plot magnetic susceptibility vs temperature
plt.figure(figsize=(9, 5))
plt.plot(T_values, susceptibility_values, 'o-', label='Susceptibility', color='blue', markersize=3, linewidth=0.7)
plt.xscale('linear') # Set the x-axis scale to linear
plt.xlabel('Temperature (T)')
plt.ylabel('Magnetic Susceptibility')
plt.legend()
lattice_info = f'Lattice Type: Cubic\nLattice Size: ${N}^3$\nSteps: $10^{power}$'
plt.text(0.72, 0.8, lattice_info, transform=ax.transAxes, fontsize=10, ha='left', va='center')
# Set legend font size
legend.get_texts()[0].set_fontsize('10')
plt.title('Classical 3D Heisenberg Model - Monte Carlo Simulation using Metropolis Algorithm')
plt.grid(True)
# Save the figure to a file (e.g., a PNG image)
file_name_image = f"Susceptibility_vs_Temperature_Simulation_results_{N}X{N}X{N}_Steps{total_steps}.png"
plt.savefig(file_name_image, dpi=300, bbox_inches='tight')
plt.show()In [ ]: