kmclab 0.1.4__py3-none-any.whl → 0.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
kmclab/square.py CHANGED
@@ -7,102 +7,135 @@ import matplotlib.pyplot as plt
7
7
  import matplotlib.patches as patches
8
8
  from scipy.stats import linregress
9
9
 
10
-
11
-
12
10
  class square_kmc:
13
11
 
14
- def __init__(self, n_atoms, n_defects, n_adsorbates, lattice_size, n_steps, defect_type = 1, adsorbates_freq = 0, seed=1):
12
+ def __init__(self, n_atoms, n_defects, n_adsorbates, lattice_size,
13
+ T= 300,
14
+ defect_type = 1,
15
+ k_0=1,
16
+ seed=1,
17
+ len_vertical = 0.297e-3,
18
+ len_horizontal = 0.660e-3,
19
+ adsorbates_freq = -1,
20
+ energy_barrier_north = 0.26,
21
+ energy_barrier_south = 0.26,
22
+ energy_barrier_east = 0.91,
23
+ energy_barrier_west = 0.91,
24
+ energy_barrier_northeast = 0.91,
25
+ energy_barrier_northwest = 0.91,
26
+ energy_barrier_southeast = 0.91,
27
+ energy_barrier_southwest = 0.91,
28
+ energy_barrier_trapping_defect_north = 0.99,
29
+ energy_barrier_trapping_defect_south = 0.99,
30
+ energy_barrier_trapping_defect_northeast = 0.99,
31
+ energy_barrier_trapping_defect_northwest = 0.99,
32
+ energy_barrier_trapping_defect_southeast = 0.99,
33
+ energy_barrier_trapping_defect_southwest = 0.99,
34
+ energy_barrier_blocking_defect_north = 0.99,
35
+ energy_barrier_blocking_defect_south = 0.99,
36
+ energy_barrier_blocking_defect_east = 0.99,
37
+ energy_barrier_blocking_defect_west = 0.99,
38
+ energy_barrier_blocking_defect_northeast = 0.99,
39
+ energy_barrier_blocking_defect_northwest = 0.99,
40
+ energy_barrier_blocking_defect_southeast = 0.99,
41
+ energy_barrier_blocking_defect_southwest = 0.99,
42
+ energy_barrier_adsorbate_north = 0.72,
43
+ energy_barrier_adsorbate_south = 0.72,
44
+ energy_barrier_adsorbate_east = 0.72,
45
+ energy_barrier_adsorbate_west = 0.72,
46
+ energy_barrier_adsorbate_northeast = 0.72,
47
+ energy_barrier_adsorbate_northwest = 0.72,
48
+ energy_barrier_adsorbate_southeast = 0.72,
49
+ energy_barrier_adsorbate_southwest = 0.72):
15
50
 
16
51
  np.random.seed(seed)
17
- # what is you desired coverage= n_atom/lattice * lattice
18
52
  self.n_atoms = n_atoms # Number of atoms
19
53
  self.n_defects = n_defects
20
54
  self.n_adsorbates= n_adsorbates
21
55
  self.lattice_size = lattice_size # Lattice size
22
- self.n_steps = n_steps # Number of steps
23
56
  self.defect_type = defect_type
24
- self.adsorbates_freq = adsorbates_freq
25
- T = 300 # Temperature in Kelvin
57
+ self.T = T # Temperature in Kelvin
58
+ self.k_0 = k_0
59
+ self.len_vertical = len_horizontal
60
+ self.len_horizontal = len_horizontal
61
+ self.adsorbates_freq = adsorbates_freq
26
62
  k_B = 8.617e-5 # Boltzmann constant in eV/K
27
- k_0 = 1
28
63
  h = 4.1357e-15 #Planck Constant (eV.s)
29
- self.len_vertical = 0.297e-3 # in micrometer
30
- self.len_horizontal = 0.660e-3 # in micrometer
64
+ # in micrometer
31
65
 
32
66
  # DFT calculated vaues for diffusion on the stoichiometric surface in different directions (eV)
33
- energy_barrier_north = 0.26
34
- energy_barrier_south = 0.26
35
- energy_barrier_east = 0.91
36
- energy_barrier_west = 0.91
37
- energy_barrier_northeast = 0.91
38
- energy_barrier_northwest = 0.91
39
- energy_barrier_southeast = 0.91
40
- energy_barrier_southwest = 0.91
67
+ self.energy_barrier_north = energy_barrier_north
68
+ self.energy_barrier_south = energy_barrier_south
69
+ self.energy_barrier_east = energy_barrier_east
70
+ self.energy_barrier_west = energy_barrier_west
71
+ self.energy_barrier_northeast = energy_barrier_northeast
72
+ self.energy_barrier_northwest = energy_barrier_northwest
73
+ self.energy_barrier_southeast = energy_barrier_southeast
74
+ self.energy_barrier_southwest = energy_barrier_southwest
41
75
 
42
76
  # DFT calculated vaues for diffusion out of trapping deffect in different directions (eV)
43
- energy_barrier_trapping_defect_north = 0.99
44
- energy_barrier_trapping_defect_south = 0.99
45
- energy_barrier_trapping_defect_northeast = 0.99
46
- energy_barrier_trapping_defect_northwest = 0.99
47
- energy_barrier_trapping_defect_southeast = 0.99
48
- energy_barrier_trapping_defect_southwest = 0.99
77
+ self.energy_barrier_trapping_defect_north = energy_barrier_trapping_defect_north
78
+ self.energy_barrier_trapping_defect_south = energy_barrier_trapping_defect_south
79
+ self.energy_barrier_trapping_defect_northeast = energy_barrier_trapping_defect_northeast
80
+ self.energy_barrier_trapping_defect_northwest = energy_barrier_trapping_defect_northwest
81
+ self.energy_barrier_trapping_defect_southeast = energy_barrier_trapping_defect_southeast
82
+ self.energy_barrier_trapping_defect_southwest = energy_barrier_trapping_defect_southwest
49
83
 
50
84
  # DFT calculated vaues for diffusion out of trapping deffect in different directions (eV)
51
- energy_barrier_blocking_defect_north = 0.99
52
- energy_barrier_blocking_defect_south = 0.99
53
- energy_barrier_blocking_defect_east = 0.99
54
- energy_barrier_blocking_defect_west = 0.99
55
- energy_barrier_blocking_defect_northeast = 0.99
56
- energy_barrier_blocking_defect_northwest = 0.99
57
- energy_barrier_blocking_defect_southeast = 0.99
58
- energy_barrier_blocking_defect_southwest = 0.99
85
+ self.energy_barrier_blocking_defect_north = energy_barrier_blocking_defect_north
86
+ self.energy_barrier_blocking_defect_south = energy_barrier_blocking_defect_south
87
+ self.energy_barrier_blocking_defect_east = energy_barrier_blocking_defect_east
88
+ self.energy_barrier_blocking_defect_west = energy_barrier_blocking_defect_west
89
+ self.energy_barrier_blocking_defect_northeast = energy_barrier_blocking_defect_northeast
90
+ self.energy_barrier_blocking_defect_northwest = energy_barrier_blocking_defect_northwest
91
+ self.energy_barrier_blocking_defect_southeast = energy_barrier_blocking_defect_southeast
92
+ self.energy_barrier_blocking_defect_southwest = energy_barrier_blocking_defect_southwest
59
93
 
60
94
 
61
- # DFT calculated vaues for diffusion over an adsorbate in different directions (eV)
62
-
63
- energy_barrier_adsorbate_north = 0.72
64
- energy_barrier_adsorbate_south = 0.72
65
- energy_barrier_adsorbate_east = 0.72
66
- energy_barrier_adsorbate_west = 0.72
67
- energy_barrier_adsorbate_northeast = 0.72
68
- energy_barrier_adsorbate_northwest = 0.72
69
- energy_barrier_adsorbate_southeast = 0.72
70
- energy_barrier_adsorbate_southwest = 0.72
95
+ # DFT calculated vaues for diffusion over an adsorbate in different directions (eV)
96
+ self.energy_barrier_adsorbate_north = energy_barrier_adsorbate_north
97
+ self.energy_barrier_adsorbate_south = energy_barrier_adsorbate_south
98
+ self.energy_barrier_adsorbate_east = energy_barrier_adsorbate_east
99
+ self.energy_barrier_adsorbate_west = energy_barrier_adsorbate_west
100
+ self.energy_barrier_adsorbate_northeast = energy_barrier_adsorbate_northeast
101
+ self.energy_barrier_adsorbate_northwest = energy_barrier_adsorbate_northwest
102
+ self.energy_barrier_adsorbate_southeast = energy_barrier_adsorbate_southeast
103
+ self.energy_barrier_adsorbate_southwest = energy_barrier_adsorbate_southwest
71
104
 
72
105
  # Calculate rate constants
73
- rate_north = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_north / (k_B * T))
74
- rate_south = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_south / (k_B * T))
75
- rate_east = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_east / (k_B * T))
76
- rate_west = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_west / (k_B * T))
77
- rate_northeast = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_northeast / (k_B * T))
78
- rate_northwest = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_northwest / (k_B * T))
79
- rate_southeast = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_southeast / (k_B * T))
80
- rate_southwest = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_southwest / (k_B * T))
106
+ rate_north = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_north / (k_B * self.T))
107
+ rate_south = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_south / (k_B * self.T))
108
+ rate_east = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_east / (k_B * self.T))
109
+ rate_west = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_west / (k_B * self.T))
110
+ rate_northeast = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_northeast / (k_B * self.T))
111
+ rate_northwest = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_northwest / (k_B * self.T))
112
+ rate_southeast = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_southeast / (k_B * self.T))
113
+ rate_southwest = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_southwest / (k_B * self.T))
81
114
 
82
- rate_trapping_defect_north = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_trapping_defect_north / (k_B * T))
83
- rate_trapping_defect_south = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_trapping_defect_south / (k_B * T))
84
- rate_trapping_defect_northeast = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_trapping_defect_northeast / (k_B * T))
85
- rate_trapping_defect_northwest = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_trapping_defect_northwest / (k_B * T))
86
- rate_trapping_defect_southeast = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_trapping_defect_southeast / (k_B * T))
87
- rate_trapping_defect_southwest = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_trapping_defect_southwest / (k_B * T))
115
+ rate_trapping_defect_north = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_trapping_defect_north / (k_B * self.T))
116
+ rate_trapping_defect_south = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_trapping_defect_south / (k_B * self.T))
117
+ rate_trapping_defect_northeast = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_trapping_defect_northeast / (k_B * self.T))
118
+ rate_trapping_defect_northwest = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_trapping_defect_northwest / (k_B * self.T))
119
+ rate_trapping_defect_southeast = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_trapping_defect_southeast / (k_B * self.T))
120
+ rate_trapping_defect_southwest = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_trapping_defect_southwest / (k_B * self.T))
88
121
 
89
- rate_blocking_defect_north = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_blocking_defect_north / (k_B * T))
90
- rate_blocking_defect_south = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_blocking_defect_south / (k_B * T))
91
- rate_blocking_defect_east = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_blocking_defect_east / (k_B * T))
92
- rate_blocking_defect_west = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_blocking_defect_west / (k_B * T))
93
- rate_blocking_defect_northeast = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_blocking_defect_northeast / (k_B * T))
94
- rate_blocking_defect_northwest = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_blocking_defect_northwest / (k_B * T))
95
- rate_blocking_defect_southeast = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_blocking_defect_southeast / (k_B * T))
96
- rate_blocking_defect_southwest = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_blocking_defect_southwest / (k_B * T))
122
+ rate_blocking_defect_north = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_blocking_defect_north / (k_B * self.T))
123
+ rate_blocking_defect_south = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_blocking_defect_south / (k_B * self.T))
124
+ rate_blocking_defect_east = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_blocking_defect_east / (k_B * self.T))
125
+ rate_blocking_defect_west = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_blocking_defect_west / (k_B * self.T))
126
+ rate_blocking_defect_northeast = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_blocking_defect_northeast / (k_B * self.T))
127
+ rate_blocking_defect_northwest = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_blocking_defect_northwest / (k_B * self.T))
128
+ rate_blocking_defect_southeast = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_blocking_defect_southeast / (k_B * self.T))
129
+ rate_blocking_defect_southwest = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_blocking_defect_southwest / (k_B * self.T))
97
130
 
98
- rate_adsorbate_north = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_adsorbate_north / (k_B * T))
99
- rate_adsorbate_south = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_adsorbate_south / (k_B * T))
100
- rate_adsorbate_east = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_adsorbate_east / (k_B * T))
101
- rate_adsorbate_west = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_adsorbate_west / (k_B * T))
102
- rate_adsorbate_northeast = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_adsorbate_northeast / (k_B * T))
103
- rate_adsorbate_northwest = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_adsorbate_northwest / (k_B * T))
104
- rate_adsorbate_southeast = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_adsorbate_southeast / (k_B * T))
105
- rate_adsorbate_southwest = k_0 * ((k_B * T)/h) * np.exp(-energy_barrier_adsorbate_southwest / (k_B * T))
131
+ rate_adsorbate_north = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_adsorbate_north / (k_B * self.T))
132
+ rate_adsorbate_south = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_adsorbate_south / (k_B * self.T))
133
+ rate_adsorbate_east = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_adsorbate_east / (k_B * self.T))
134
+ rate_adsorbate_west = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_adsorbate_west / (k_B * self.T))
135
+ rate_adsorbate_northeast = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_adsorbate_northeast / (k_B * self.T))
136
+ rate_adsorbate_northwest = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_adsorbate_northwest / (k_B * self.T))
137
+ rate_adsorbate_southeast = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_adsorbate_southeast / (k_B * self.T))
138
+ rate_adsorbate_southwest = self.k_0 * ((k_B * self.T)/h) * np.exp(-self.energy_barrier_adsorbate_southwest / (k_B * self.T))
106
139
 
107
140
 
108
141
 
@@ -170,8 +203,8 @@ class square_kmc:
170
203
 
171
204
  self.generate_adsorbates()
172
205
 
173
- def run(self):
174
-
206
+ def run(self, n_steps):
207
+ self.n_steps = n_steps
175
208
  self.time = np.zeros(self.n_steps + 1)
176
209
  self.msd = np.zeros(self.n_steps)
177
210
  self.md = np.zeros(self.n_steps)
@@ -472,8 +505,7 @@ class square_kmc:
472
505
  self.msd[step] = squared_displacements.mean()
473
506
 
474
507
  return self.time[:-1], self.msd
475
-
476
-
508
+
477
509
  def square_lattice(self):
478
510
  def generate_square_lattice(rows, cols):
479
511
  square_lattice = []
@@ -483,8 +515,7 @@ class square_kmc:
483
515
  return square_lattice
484
516
 
485
517
  self.square_lattice = generate_square_lattice(self.lattice_size, self.lattice_size)
486
-
487
-
518
+
488
519
  def init_atoms(self):
489
520
 
490
521
  self.positions_atoms = []
@@ -614,8 +645,7 @@ class square_kmc:
614
645
  arr = self.positions_defects
615
646
  self.defects_pairs = [[tuple(arr[j]), tuple(arr[int(j + 0.5 * len(arr))])] for j in range(int(0.5 * len(arr)))]
616
647
 
617
-
618
-
648
+
619
649
  def generate_adsorbates(self):
620
650
 
621
651
  self.positions_adsorbates = []
@@ -640,15 +670,11 @@ class square_kmc:
640
670
 
641
671
  self.positions_adsorbates = np.array(self.positions_adsorbates)
642
672
 
643
-
644
-
645
-
646
-
647
- def anim1panels(self, filename):
673
+ def anim1panel(self, filename = "movie1panel", figsize = (6,6)):
648
674
 
649
675
 
650
676
  # ===================== Figure & Axes =====================
651
- fig, ax_main = plt.subplots(figsize=(6, 6))
677
+ fig, ax_main = plt.subplots(figsize=figsize)
652
678
  ax_main.set_xlim(-1, self.lattice_size + 1)
653
679
  ax_main.set_ylim(-1, self.lattice_size + 1)
654
680
  ax_main.set_xticks(range(self.lattice_size))
@@ -782,14 +808,10 @@ class square_kmc:
782
808
  ani = FuncAnimation(fig, update_with_pause, frames=self.n_steps + pause_frames, interval=interval_ms)
783
809
  ani.save(f"{filename}.gif", writer=PillowWriter(fps=20))
784
810
  plt.show()
785
-
786
-
787
-
788
811
 
789
-
790
- def anim2panels(self, filename):
812
+ def anim2panel(self, filename = "movie2panel", figsize = (12, 6)):
791
813
 
792
- fig, axes = plt.subplots(1, 2, figsize=(12, 6), gridspec_kw={'width_ratios': [2, 1]})
814
+ fig, axes = plt.subplots(1, 2, figsize=figsize, gridspec_kw={'width_ratios': [2, 1]})
793
815
  ax_main, ax_msd = axes[0], axes[1]
794
816
 
795
817
  # ---- Main lattice view ----
@@ -971,13 +993,8 @@ class square_kmc:
971
993
  ani = FuncAnimation(fig, update_with_pause, frames=self.n_steps + pause_frames, interval=interval_ms)
972
994
  ani.save(f"{filename}.gif", writer=PillowWriter(fps=20))
973
995
  plt.show()
974
-
975
-
976
-
977
-
978
-
979
-
980
- def msdplot(self, filename):
996
+
997
+ def msdplot(self, filename = "msd"):
981
998
 
982
999
  time = self.time[:-1]
983
1000
 
@@ -996,7 +1013,7 @@ class square_kmc:
996
1013
 
997
1014
  # Plot MSD vs. time with fit line
998
1015
  plt.figure(figsize=(8, 6))
999
- plt.plot(time, self.msd, color="#89CFF0", label="Individual MSD Trajectory")
1016
+ plt.plot(time, self.msd, color= '#89CFF0', label="Individual MSD Trajectory")
1000
1017
  plt.plot(valid_time, fit_line, linestyle="--", color="blue", label="Linear Fit")
1001
1018
  #plt.axvline(x=time[transient_cutoff], color='r', linestyle='--', label="Transient cutoff")
1002
1019
  plt.xlabel("Time (s)")
@@ -1004,7 +1021,7 @@ class square_kmc:
1004
1021
  plt.legend()
1005
1022
  plt.title(f"Mean Squared Displacement vs Time - {self.n_steps} steps")
1006
1023
  plt.text(0.05 * max(time), 0.8 * max(self.msd), # Adjust placement (x, y) as needed
1007
- f" Diffusion Coefficient = {diffusion_coefficient_corrected:.4f} µm²/s",
1024
+ f" Diffusion Coefficient = {diffusion_coefficient_corrected:.1e} µm²/s",
1008
1025
  fontsize=12, color='blue', bbox=dict(facecolor="white", alpha=0.5))
1009
1026
  plt.minorticks_on()
1010
1027
  plt.grid(True, which='major', linestyle='-', linewidth=0.6)
@@ -1012,15 +1029,12 @@ class square_kmc:
1012
1029
  plt.savefig(f'{filename}.png', dpi = 600)
1013
1030
  plt.show()
1014
1031
 
1032
+ def msd_histogram(self, filename = "average_msd", n_seeds = 25):
1015
1033
 
1016
-
1017
- def msd_histogram(self, n_seeds, msd_folder = "random_seeds/msd",
1018
- time_folder = "random_seeds/time",
1019
- save_folder = "random_seeds/average_msd.png",
1020
- msd_trajs_color = "pink",
1021
- msd_average_color = "#C71585"):
1022
-
1023
-
1034
+ msd_folder = "random_seeds/msd"
1035
+ time_folder = "random_seeds/time"
1036
+ save_folder = f"random_seeds/{filename}.png"
1037
+
1024
1038
  msd_list = []
1025
1039
  time_list = []
1026
1040
 
@@ -1040,7 +1054,7 @@ class square_kmc:
1040
1054
  time_avg = np.mean(time_array, axis=0)
1041
1055
 
1042
1056
  # Fit a linear function: MSD = a * Time + b
1043
- # slope, intercept = np.polyfit(time_avg, msd_avg, 1)
1057
+ # slope, intercept = np.polyfit(time_avg, msd_avg, 1)
1044
1058
  slope, intercept, r_value, p_value, slope_std_err = linregress(time_avg, msd_avg)
1045
1059
  fitted_line = slope * time_avg + intercept # Compute the fitted line
1046
1060
 
@@ -1051,11 +1065,11 @@ class square_kmc:
1051
1065
  # Plot all MSD curves in light pink
1052
1066
  plt.figure(figsize=(8, 6))
1053
1067
  for i in range(n_seeds):
1054
- plt.plot(time_array[i], msd_array[i], color=msd_trajs_color, alpha=0.5, linewidth=1)
1068
+ plt.plot(time_array[i], msd_array[i], color="pink", alpha=0.5, linewidth=1)
1055
1069
 
1056
1070
  # Plot average MSD with error bars at 20 selected points in dark pink
1057
- plt.plot(time_avg, msd_avg, color=msd_average_color, linewidth=2, label="Average MSD")
1058
- plt.errorbar(time_avg[indices], msd_avg[indices], yerr=msd_std[indices], fmt='o', color=msd_average_color, capsize=3)
1071
+ plt.plot(time_avg, msd_avg, color="#C71585", linewidth=2, label="Average MSD")
1072
+ plt.errorbar(time_avg[indices], msd_avg[indices], yerr=msd_std[indices], fmt='o', color="#C71585", capsize=3)
1059
1073
 
1060
1074
  # Plot fitted line
1061
1075
  #plt.plot(time_avg, fitted_line, linestyle="--", color="blue", linewidth=2, label=f"Linear Fit: Slope = {slope:.4f} ± {slope_std_err:.2f} (um²/s)")
@@ -1064,10 +1078,10 @@ class square_kmc:
1064
1078
  # Labels and legend
1065
1079
  plt.xlabel("Time(s)")
1066
1080
  plt.ylabel("MSD (µm²)")
1067
- plt.title("T=300K - Lattice Size =10*10 - OH Coverage=0.5ML - OH Frequency=OFF")
1081
+ plt.title("Average Mean Square Displacement vs Time")
1068
1082
 
1069
1083
  # Display slope inside the plot
1070
- plt.text(0.05 * max(time_avg), 0.8 * max(msd_avg), f"Diffusion Coefficient = {slope/4:.6f} ± {slope_std_err/4:.1e} (µm²/s)", fontsize=12, color="blue", bbox=dict(facecolor="white", alpha=0.5))
1084
+ plt.text(0.05 * max(time_avg), 0.8 * max(msd_avg), f"Diffusion Coefficient = {slope/4:.1e} ± {slope_std_err/4:.1e} (µm²/s)", fontsize=12, color="blue", bbox=dict(facecolor="white", alpha=0.5))
1071
1085
  plt.legend()
1072
1086
  plt.minorticks_on()
1073
1087
  plt.grid(True, which='major', linestyle='-', linewidth=0.6)
@@ -1075,4 +1089,3 @@ class square_kmc:
1075
1089
  plt.savefig(save_folder, dpi = 600)
1076
1090
  plt.show()
1077
1091
 
1078
-
@@ -0,0 +1,262 @@
1
+ Metadata-Version: 2.4
2
+ Name: kmclab
3
+ Version: 0.1.5
4
+ Summary: Hex and square lattice KMC classes.
5
+ Author: Shirin Asadi
6
+ License: MIT
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: numpy>=1.21
10
+ Requires-Dist: matplotlib>=3.5
11
+ Requires-Dist: scipy>=1.8
12
+
13
+ # kmclab
14
+
15
+ A lightweight Python package for lattice-based kinetic Monte Carlo (KMC) utilities.
16
+ Currently includes simple hexagonal and square lattice KMC classes.
17
+
18
+ ## Installation
19
+
20
+ Install using pip
21
+ ```
22
+ pip install kmclab
23
+ ```
24
+
25
+ To upgrade to the latest version
26
+ ```
27
+ pip install -U kmclab
28
+ ```
29
+
30
+ Or you may clone the repository and install in editable mode:
31
+
32
+ ```bash
33
+ git clone https://github.com/shirinasadix/kmclab.git
34
+ cd kmclab
35
+ pip install -e .
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```
41
+ from kmclab import hex_kmc
42
+
43
+ GoombKMC = hex_kmc(n_atoms = 5, n_defects = 5, n_adsorbates = 2, lattice_size = 10, n_steps = 50)
44
+
45
+ GoombKMC.run()
46
+
47
+ GoombKMC.anim1panels(filename = 'wtf1')
48
+
49
+ GoombKMC.anim2panels(filename = 'ov10hy0')
50
+
51
+ GoombKMC.msdplot(filename = 'MSD_Trajectory')
52
+ ```
53
+
54
+ ## Package Structure
55
+
56
+ ```
57
+ kmclab/
58
+ ├── src/
59
+ │ └── kmclab/
60
+ │ ├── hexa.py
61
+ │ ├── square.py
62
+ │ └── __init__.py
63
+ ├── tests/
64
+ ├── pyproject.toml
65
+ └── README.md
66
+ ```
67
+ ## Examples
68
+
69
+ ### Square Lattice - Single Run
70
+
71
+ Here is the step by step guide:
72
+
73
+ ```
74
+ from square import square_kmc
75
+ ```
76
+ Now to define system parameters:
77
+ ```
78
+ square_params = {
79
+
80
+ # System composition
81
+ 'n_atoms': 5, # Number of mobile adatoms
82
+ 'n_defects': 5, # Number of surface defects
83
+ 'n_adsorbates': 5, # Number of surface adsorbates
84
+
85
+ # Lattice and simulation control
86
+ 'lattice_size': 10, # Linear size of the lattice
87
+ 'T': 300, # Temperature (K)
88
+ 'seed': 1, # Random number seed
89
+
90
+ 'len_vertical' : 0.297e-3, # Vertical lattice hop distances (µm)
91
+ 'len_horizontal' : 0.660e-3, # Horizontal lattice hop distances (µm)
92
+ 'adsorbates_freq' : 3, # Adsorbate redistribution frequency (required only if n_adsorbates > 0) (-1 disables)
93
+
94
+ # Defect behavior
95
+ 'defect_type': 1, # 1 = trapping defects, 2 = blocking defects (required only if n_defects > 0 )
96
+
97
+ # Kinetic prefactor
98
+ 'k_0': 1,
99
+
100
+ # Diffusion energy barriers on stoichiometric sites along defferent directions (eV)
101
+ 'energy_barrier_north' : 0.26,
102
+ 'energy_barrier_south' : 0.26,
103
+ 'energy_barrier_east' : 0.91,
104
+ 'energy_barrier_west' : 0.91,
105
+ 'energy_barrier_northeast' : 0.91,
106
+ 'energy_barrier_northwest' : 0.91,
107
+ 'energy_barrier_southeast' : 0.91,
108
+ 'energy_barrier_southwest' : 0.91,
109
+
110
+ # Trapping defect energy barriers (required only if n_defects > 0 and defect_type == 1)
111
+ 'energy_barrier_trapping_defect_north' : 0.99,
112
+ 'energy_barrier_trapping_defect_south' : 0.99,
113
+ 'energy_barrier_trapping_defect_northeast' : 0.99,
114
+ 'energy_barrier_trapping_defect_northwest' : 0.99,
115
+ 'energy_barrier_trapping_defect_southeast' : 0.99,
116
+ 'energy_barrier_trapping_defect_southwest' : 0.99,
117
+
118
+ # Blocking defect energy barriers (required only if n_defects > 0 and defect_type == 2)
119
+ 'energy_barrier_blocking_defect_north' : 0.99,
120
+ 'energy_barrier_blocking_defect_south' : 0.99,
121
+ 'energy_barrier_blocking_defect_east' : 0.99,
122
+ 'energy_barrier_blocking_defect_west' :0.99,
123
+ 'energy_barrier_blocking_defect_northeast' : 0.99,
124
+ 'energy_barrier_blocking_defect_northwest' : 0.99,
125
+ 'energy_barrier_blocking_defect_southeast' : 0.99,
126
+ 'energy_barrier_blocking_defect_southwest' : 0.99,
127
+
128
+ # Adsorbate-related diffusion barriers (required only if n_adsorbates > 0)
129
+ 'energy_barrier_adsorbate_north' : 0.72,
130
+ 'energy_barrier_adsorbate_south' : 0.72,
131
+ 'energy_barrier_adsorbate_east' : 0.72,
132
+ 'energy_barrier_adsorbate_west' : 0.72,
133
+ 'energy_barrier_adsorbate_northeast' : 0.72,
134
+ 'energy_barrier_adsorbate_northwest' : 0.72,
135
+ 'energy_barrier_adsorbate_southeast' : 0.72,
136
+ 'energy_barrier_adsorbate_southwest' : 0.72}
137
+ ```
138
+ Now to run the actual KMC:
139
+ ```
140
+ KMC = square_kmc(**square_params)
141
+
142
+ KMC.run(n_steps = 30) # Total KMC steps (must be > 10)
143
+ ```
144
+ Now to see the results you have multiple options:
145
+ ```
146
+ KMC.anim1panel()
147
+
148
+ KMC.anim2panel()
149
+
150
+ KMC.msdplot()
151
+ ```
152
+
153
+ ### Hexagonal Lattice - Multi Run (Histograms)
154
+
155
+ Here is the step by step guide:
156
+
157
+ ```
158
+ from hexa import hexa_kmc
159
+ import numpy as np
160
+ from pathlib import Path
161
+ import shutil
162
+
163
+ rs_p = Path("random_seeds")
164
+
165
+ if rs_p.exists():
166
+ shutil.rmtree(rs_p)
167
+
168
+ (rs_p / "time").mkdir(parents=True)
169
+ (rs_p / "msd").mkdir(parents=True)
170
+
171
+
172
+ n_seeds = 5 # Number of trials
173
+
174
+ hexa_params = {
175
+ # System composition
176
+ 'n_atoms': 5, # Number of mobile adatoms
177
+ 'n_defects': 5, # Number of surface defects
178
+ 'n_adsorbates': 5, # Number of surface adsorbates
179
+
180
+ # Lattice and simulation control
181
+ 'lattice_size': 10, # Linear size of the lattice
182
+ 'T': 300, # Temperature (K)
183
+ 'seed': 1, # Random number seed
184
+
185
+ 'len_vertical' : 0.38e-3, # Vertical lattice hop distances (µm)
186
+ 'len_horizontal' : 0.51e-3, # Horizontal lattice hop distances (µm)
187
+ 'adsorbates_freq' : 3, # Adsorbate redistribution frequency (required only if n_adsorbates > 0) (-1 disables)
188
+
189
+ # Defect behavior
190
+ 'defect_type': 1, # 1 = trapping defects, 2 = blocking defects (required only if n_defects > 0 )
191
+
192
+ # Kinetic prefactor
193
+ 'k_0': 1,
194
+
195
+ # Diffusion energy barriers on stoichiometric sites along defferent directions (eV)
196
+ 'energy_barrier_north': 0.46,
197
+ 'energy_barrier_south': 0.46,
198
+ 'energy_barrier_northeast': 0.65,
199
+ 'energy_barrier_northwest': 0.65,
200
+ 'energy_barrier_southeast': 0.65,
201
+ 'energy_barrier_southwest': 0.65,
202
+
203
+ # Trapping defect energy barriers (required only if n_defects > 0 and defect_type == 1)
204
+ 'energy_barrier_trapping_defect_north': 1.2,
205
+ 'energy_barrier_trapping_defect_south': 1.2,
206
+ 'energy_barrier_trapping_defect_east': 1.1,
207
+ 'energy_barrier_trapping_defect_west': 1.1,
208
+ 'energy_barrier_trapping_defect_northeast': 1.1,
209
+ 'energy_barrier_trapping_defect_northwest': 1.1,
210
+ 'energy_barrier_trapping_defect_southeast': 1.1,
211
+ 'energy_barrier_trapping_defect_southwest': 1.1,
212
+
213
+ # Blocking defect energy barriers (required only if n_defects > 0 and defect_type == 2)
214
+ 'energy_barrier_blocking_defect_north': 1.2,
215
+ 'energy_barrier_blocking_defect_south': 1.2,
216
+ 'energy_barrier_blocking_defect_northeast': 1.2,
217
+ 'energy_barrier_blocking_defect_northwest': 1.2,
218
+ 'energy_barrier_blocking_defect_southeast': 1.2,
219
+ 'energy_barrier_blocking_defect_southwest': 1.2,
220
+
221
+ # Adsorbate-related diffusion barriers (required only if n_adsorbates > 0)
222
+ 'energy_barrier_adsorbate_north': 0.72,
223
+ 'energy_barrier_adsorbate_south': 0.72,
224
+ 'energy_barrier_adsorbate_northeast': 0.72,
225
+ 'energy_barrier_adsorbate_northwest': 0.72,
226
+ 'energy_barrier_adsorbate_southeast': 0.72,
227
+ 'energy_barrier_adsorbate_southwest': 0.72
228
+ }
229
+
230
+
231
+ for i in range(n_seeds):
232
+
233
+ hexa_params['seed'] = i,
234
+ print(f'current random_seed = {i}')
235
+
236
+ KMC = hexa_kmc(**hexa_params)
237
+
238
+ time, msd = KMC.run(n_steps = 2500)
239
+
240
+ msd_path = f'random_seeds/msd/rs_{i}'
241
+ time_path = f'random_seeds/time/rs_{i}'
242
+ np.save(msd_path, msd)
243
+ np.save(time_path, time)
244
+
245
+ KMC.msd_histogram(n_seeds = n_seeds)
246
+ ```
247
+
248
+ ## Demo
249
+
250
+ ![demo](wtf1.gif)
251
+
252
+
253
+ ## License
254
+
255
+ ```
256
+ XXX
257
+ ```
258
+
259
+
260
+
261
+
262
+
@@ -0,0 +1,7 @@
1
+ kmclab/__init__.py,sha256=g8ZeOWAp2l5XYTN77dLjRqAEmL2jvCBx2r8w0k6v1AQ,118
2
+ kmclab/hexa.py,sha256=xKEWb6p4RoWEry83gMPQCMmOqtRqjM1if7ieBz-CS9k,53436
3
+ kmclab/square.py,sha256=XGOTGZUn3Dxj34rZo-4VFmTFyxQzZNWNfcjM0Jy6-ac,55515
4
+ kmclab-0.1.5.dist-info/METADATA,sha256=vsS1_mO01RHsiIij0MCXv5ENV8I6Z4S0g7e_R9wuj1o,7497
5
+ kmclab-0.1.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
6
+ kmclab-0.1.5.dist-info/top_level.txt,sha256=y0neMRTLriRK2Sv_F3m9WUcs2JHEEVpCOC71fkrBrAY,7
7
+ kmclab-0.1.5.dist-info/RECORD,,