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/__init__.py +3 -3
- kmclab/{hex.py → hexa.py} +166 -159
- kmclab/square.py +129 -116
- kmclab-0.1.5.dist-info/METADATA +262 -0
- kmclab-0.1.5.dist-info/RECORD +7 -0
- kmclab-0.1.4.dist-info/METADATA +0 -63
- kmclab-0.1.4.dist-info/RECORD +0 -7
- {kmclab-0.1.4.dist-info → kmclab-0.1.5.dist-info}/WHEEL +0 -0
- {kmclab-0.1.4.dist-info → kmclab-0.1.5.dist-info}/top_level.txt +0 -0
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,
|
|
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.
|
|
25
|
-
|
|
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
|
-
|
|
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 =
|
|
34
|
-
energy_barrier_south =
|
|
35
|
-
energy_barrier_east =
|
|
36
|
-
energy_barrier_west =
|
|
37
|
-
energy_barrier_northeast =
|
|
38
|
-
energy_barrier_northwest =
|
|
39
|
-
energy_barrier_southeast =
|
|
40
|
-
energy_barrier_southwest =
|
|
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 =
|
|
44
|
-
energy_barrier_trapping_defect_south =
|
|
45
|
-
energy_barrier_trapping_defect_northeast =
|
|
46
|
-
energy_barrier_trapping_defect_northwest =
|
|
47
|
-
energy_barrier_trapping_defect_southeast =
|
|
48
|
-
energy_barrier_trapping_defect_southwest =
|
|
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 =
|
|
52
|
-
energy_barrier_blocking_defect_south =
|
|
53
|
-
energy_barrier_blocking_defect_east =
|
|
54
|
-
energy_barrier_blocking_defect_west =
|
|
55
|
-
energy_barrier_blocking_defect_northeast =
|
|
56
|
-
energy_barrier_blocking_defect_northwest =
|
|
57
|
-
energy_barrier_blocking_defect_southeast =
|
|
58
|
-
energy_barrier_blocking_defect_southwest =
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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=
|
|
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=
|
|
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=
|
|
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:.
|
|
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
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
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
|
-
|
|
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=
|
|
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=
|
|
1058
|
-
plt.errorbar(time_avg[indices], msd_avg[indices], yerr=msd_std[indices], fmt='o', color=
|
|
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("
|
|
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:.
|
|
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
|
+

|
|
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,,
|