mcising 0.1__tar.gz
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.
- mcising-0.1/PKG-INFO +35 -0
- mcising-0.1/README.md +23 -0
- mcising-0.1/mcising/__init__.py +3 -0
- mcising-0.1/mcising/ising_data_generate.py +44 -0
- mcising-0.1/mcising/isinglattice.py +222 -0
- mcising-0.1/mcising/montecarlo.py +319 -0
- mcising-0.1/mcising.egg-info/PKG-INFO +35 -0
- mcising-0.1/mcising.egg-info/SOURCES.txt +15 -0
- mcising-0.1/mcising.egg-info/dependency_links.txt +1 -0
- mcising-0.1/mcising.egg-info/entry_points.txt +2 -0
- mcising-0.1/mcising.egg-info/requires.txt +3 -0
- mcising-0.1/mcising.egg-info/top_level.txt +2 -0
- mcising-0.1/setup.cfg +4 -0
- mcising-0.1/setup.py +33 -0
- mcising-0.1/tests/__init__.py +1 -0
- mcising-0.1/tests/test_isinglattice.py +21 -0
- mcising-0.1/tests/test_montecarlo.py +49 -0
mcising-0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mcising
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: A package for generating Ising model data using Metropolis algorithm on a square lattice for nearest neighbor and next nearest neighbor interactions.
|
|
5
|
+
Home-page: https://github.com/bcivitcioglu/mcising
|
|
6
|
+
Author: Burak Ç.
|
|
7
|
+
Author-email: bcivitcioglu@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# mcising
|
|
14
|
+
|
|
15
|
+
mcising is a Python package for generating Ising model data using Monte Carlo simulations.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
You can install the package using pip:
|
|
20
|
+
|
|
21
|
+
`pip install mcising`
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
You can generate Ising model data from the command line:
|
|
26
|
+
|
|
27
|
+
`generate_ising_data <seed> <lattice_size> <num_configs> <j1> <j2> [--T_init <T_init>] [--T_final <T_final>] [--T_step <T_step>] [--sweep_steps <sweep_steps>] [--thermalization_scans <thermalization_scans>] [--calculate_correlation]`
|
|
28
|
+
|
|
29
|
+
An example usage:
|
|
30
|
+
|
|
31
|
+
`generate_ising_data 42 10 100 1.0 0.5 --T_init 4.0 --T_final 0.1 --T_step 0.05 --sweep_steps 10 --thermalization_scans 5 --calculate_correlation`
|
|
32
|
+
|
|
33
|
+
## Licence
|
|
34
|
+
|
|
35
|
+
This project is licensed under the MIT License.
|
mcising-0.1/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# mcising
|
|
2
|
+
|
|
3
|
+
mcising is a Python package for generating Ising model data using Monte Carlo simulations.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
You can install the package using pip:
|
|
8
|
+
|
|
9
|
+
`pip install mcising`
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
You can generate Ising model data from the command line:
|
|
14
|
+
|
|
15
|
+
`generate_ising_data <seed> <lattice_size> <num_configs> <j1> <j2> [--T_init <T_init>] [--T_final <T_final>] [--T_step <T_step>] [--sweep_steps <sweep_steps>] [--thermalization_scans <thermalization_scans>] [--calculate_correlation]`
|
|
16
|
+
|
|
17
|
+
An example usage:
|
|
18
|
+
|
|
19
|
+
`generate_ising_data 42 10 100 1.0 0.5 --T_init 4.0 --T_final 0.1 --T_step 0.05 --sweep_steps 10 --thermalization_scans 5 --calculate_correlation`
|
|
20
|
+
|
|
21
|
+
## Licence
|
|
22
|
+
|
|
23
|
+
This project is licensed under the MIT License.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# mcising/ising_data_generate.py
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import argparse
|
|
5
|
+
import montecarlo
|
|
6
|
+
|
|
7
|
+
def main(args):
|
|
8
|
+
temperature = np.arange(args.T_init, args.T_final - args.T_step, -args.T_step)
|
|
9
|
+
|
|
10
|
+
montecarlo.collect_monte_carlo_data(
|
|
11
|
+
seed=args.seed,
|
|
12
|
+
lattice_size=args.lattice_size,
|
|
13
|
+
J1=args.j1,
|
|
14
|
+
J2=args.j2,
|
|
15
|
+
h=0.0,
|
|
16
|
+
num_scans=args.sweep_steps * (args.num_configs - 1),
|
|
17
|
+
temperature=temperature,
|
|
18
|
+
thermalization_scans=args.thermalization_scans,
|
|
19
|
+
frequency_sweeps_to_collect_magnetization=args.sweep_steps,
|
|
20
|
+
calculate_correlation=args.calculate_correlation
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
parser = argparse.ArgumentParser(description="Generate Ising model data using Monte Carlo simulation.")
|
|
25
|
+
parser.add_argument("seed", type=int, help="Random seed for the simulation")
|
|
26
|
+
parser.add_argument("lattice_size", type=int, help="Size of the lattice")
|
|
27
|
+
parser.add_argument("num_configs", type=int, help="Number of configurations to generate")
|
|
28
|
+
parser.add_argument("j1", type=float, help="Interaction parameter J1")
|
|
29
|
+
parser.add_argument("j2", type=float, help="Interaction parameter J2")
|
|
30
|
+
parser.add_argument("--T_init", type=float, default=4.0, help="Initial temperature (default: 4.0)")
|
|
31
|
+
parser.add_argument("--T_final", type=float, default=0.075, help="Final temperature (default: 0.075)")
|
|
32
|
+
parser.add_argument("--T_step", type=float, default=0.025, help="Temperature step (default: 0.025)")
|
|
33
|
+
parser.add_argument("--sweep_steps", type=int, default=1, help="Number of sweep steps (default: 1)")
|
|
34
|
+
parser.add_argument("--thermalization_scans", type=int, default=3, help="Number of thermalization scans (default: 3)")
|
|
35
|
+
parser.add_argument("--calculate_correlation", action="store_true", help="Calculate correlation function and length")
|
|
36
|
+
|
|
37
|
+
args = parser.parse_args()
|
|
38
|
+
|
|
39
|
+
if args.T_step <= 0:
|
|
40
|
+
print("Error: T_step must be greater than 0")
|
|
41
|
+
elif args.T_init <= args.T_final:
|
|
42
|
+
print("Error: T_init must be greater than T_final")
|
|
43
|
+
else:
|
|
44
|
+
main(args)
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
import random
|
|
4
|
+
|
|
5
|
+
class IsingLattice:
|
|
6
|
+
"""
|
|
7
|
+
A class to represent an Ising model lattice.
|
|
8
|
+
|
|
9
|
+
Attributes
|
|
10
|
+
----------
|
|
11
|
+
lattice_size : int
|
|
12
|
+
The size of the lattice.
|
|
13
|
+
num_sites : int
|
|
14
|
+
The total number of sites in the lattice.
|
|
15
|
+
J1 : float
|
|
16
|
+
Interaction parameter for nearest neighbors.
|
|
17
|
+
J2 : float
|
|
18
|
+
Interaction parameter for next nearest neighbors.
|
|
19
|
+
h : float
|
|
20
|
+
External magnetic field.
|
|
21
|
+
lattice_state : np.ndarray
|
|
22
|
+
The state of the lattice.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, lattice_size, J1, J2, h):
|
|
26
|
+
"""
|
|
27
|
+
Initializes the lattice with random spins.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
lattice_size : int
|
|
32
|
+
The size of the lattice.
|
|
33
|
+
J1 : float
|
|
34
|
+
Interaction parameter for nearest neighbors.
|
|
35
|
+
J2 : float
|
|
36
|
+
Interaction parameter for next nearest neighbors.
|
|
37
|
+
h : float
|
|
38
|
+
External magnetic field.
|
|
39
|
+
"""
|
|
40
|
+
self.lattice_size = lattice_size
|
|
41
|
+
self.num_sites = lattice_size * lattice_size
|
|
42
|
+
self.J1 = J1
|
|
43
|
+
self.J2 = J2
|
|
44
|
+
self.h = h
|
|
45
|
+
|
|
46
|
+
# Randomly initialize the lattice with -1 and 1
|
|
47
|
+
lattice_state = np.random.choice([-1, 1], size=(self.lattice_size, self.lattice_size))
|
|
48
|
+
self.lattice_state = lattice_state
|
|
49
|
+
|
|
50
|
+
def plot_lattice(self, print_info=False):
|
|
51
|
+
"""
|
|
52
|
+
Plot the current lattice configuration.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
print_info : bool, optional
|
|
57
|
+
If True, prints the lattice information. Default is False.
|
|
58
|
+
"""
|
|
59
|
+
plt.figure()
|
|
60
|
+
plt.imshow(self.lattice_state, cmap='gray')
|
|
61
|
+
plt.title("Ising Lattice")
|
|
62
|
+
plt.show()
|
|
63
|
+
if print_info:
|
|
64
|
+
self.print_info()
|
|
65
|
+
|
|
66
|
+
def print_info(self):
|
|
67
|
+
"""
|
|
68
|
+
Print information about the lattice.
|
|
69
|
+
"""
|
|
70
|
+
print(f"Lattice size: {self.lattice_size} x {self.lattice_size}. J1: {self.J1}, J2: {self.J2}, h: {self.h}")
|
|
71
|
+
|
|
72
|
+
def flip_spin(self, i, j):
|
|
73
|
+
"""
|
|
74
|
+
Flip the spin at the given site (i, j).
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
i : int
|
|
79
|
+
Row index of the site.
|
|
80
|
+
j : int
|
|
81
|
+
Column index of the site.
|
|
82
|
+
"""
|
|
83
|
+
self.lattice_state[i, j] *= -1
|
|
84
|
+
|
|
85
|
+
def spin_energy(self, i, j):
|
|
86
|
+
"""
|
|
87
|
+
Calculate the energy of the spin at the given site (i, j).
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
i : int
|
|
92
|
+
Row index of the site.
|
|
93
|
+
j : int
|
|
94
|
+
Column index of the site.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
float
|
|
99
|
+
The energy of the spin at the given site.
|
|
100
|
+
"""
|
|
101
|
+
spin_ij = self.lattice_state[i, j]
|
|
102
|
+
|
|
103
|
+
# Periodic boundary conditions
|
|
104
|
+
sum_neighbouring_spins = (
|
|
105
|
+
self.lattice_state[(i + 1) % self.lattice_size, j] +
|
|
106
|
+
self.lattice_state[i, (j + 1) % self.lattice_size] +
|
|
107
|
+
self.lattice_state[(i - 1) % self.lattice_size, j] +
|
|
108
|
+
self.lattice_state[i, (j - 1) % self.lattice_size]
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
sum_second_neighbouring_spins = (
|
|
112
|
+
self.lattice_state[(i + 1) % self.lattice_size, (j + 1) % self.lattice_size] +
|
|
113
|
+
self.lattice_state[(i + 1) % self.lattice_size, (j - 1) % self.lattice_size] +
|
|
114
|
+
self.lattice_state[(i - 1) % self.lattice_size, (j + 1) % self.lattice_size] +
|
|
115
|
+
self.lattice_state[(i - 1) % self.lattice_size, (j - 1) % self.lattice_size]
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
interaction_term = (
|
|
119
|
+
-self.J1 * spin_ij * sum_neighbouring_spins +
|
|
120
|
+
-self.J2 * spin_ij * sum_second_neighbouring_spins
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if self.h != 0:
|
|
124
|
+
magnetic_field_term = -self.h * spin_ij
|
|
125
|
+
return interaction_term + magnetic_field_term
|
|
126
|
+
|
|
127
|
+
return interaction_term
|
|
128
|
+
|
|
129
|
+
def energy(self):
|
|
130
|
+
"""
|
|
131
|
+
Calculate the total energy of the lattice.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
float
|
|
136
|
+
The total energy of the lattice.
|
|
137
|
+
"""
|
|
138
|
+
E = 0.0
|
|
139
|
+
for i in np.arange(self.lattice_size):
|
|
140
|
+
for j in np.arange(self.lattice_size):
|
|
141
|
+
E += self.spin_energy(i, j)
|
|
142
|
+
E /= 2.0 * self.num_sites
|
|
143
|
+
if self.h != 0:
|
|
144
|
+
E -= self.h * np.sum(self.lattice_state) / self.num_sites
|
|
145
|
+
return E
|
|
146
|
+
|
|
147
|
+
def magnetization(self):
|
|
148
|
+
"""
|
|
149
|
+
Calculate the net magnetization of the lattice.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
float
|
|
154
|
+
The net magnetization of the lattice.
|
|
155
|
+
"""
|
|
156
|
+
return np.sum(self.lattice_state) / self.num_sites
|
|
157
|
+
|
|
158
|
+
def correlation_function(self, plot=False):
|
|
159
|
+
"""
|
|
160
|
+
Calculate the correlation function of the lattice.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
plot : bool, optional
|
|
165
|
+
If True, plots the correlation function. Default is False.
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
tuple
|
|
170
|
+
The correlation function and the distances.
|
|
171
|
+
"""
|
|
172
|
+
counter = 0
|
|
173
|
+
correlation_function = np.zeros(self.num_sites**2)
|
|
174
|
+
r_sq = np.zeros(self.num_sites**2).astype(int)
|
|
175
|
+
|
|
176
|
+
for i in np.arange(self.lattice_size):
|
|
177
|
+
for j in np.arange(self.lattice_size):
|
|
178
|
+
for k in np.arange(i, self.lattice_size):
|
|
179
|
+
check_var = 0
|
|
180
|
+
if i == k:
|
|
181
|
+
check_var = j
|
|
182
|
+
for l in np.arange(check_var, self.lattice_size):
|
|
183
|
+
x_distance = abs(j - l)
|
|
184
|
+
y_distance = abs(i - k)
|
|
185
|
+
|
|
186
|
+
if x_distance > self.lattice_size / 2:
|
|
187
|
+
x_distance = abs(self.lattice_size - x_distance)
|
|
188
|
+
if y_distance > self.lattice_size / 2:
|
|
189
|
+
y_distance = abs(self.lattice_size - y_distance)
|
|
190
|
+
|
|
191
|
+
distance = x_distance**2 + y_distance**2
|
|
192
|
+
|
|
193
|
+
r_sq[counter] = distance
|
|
194
|
+
correlation_function[counter] = self.lattice_state[i, j] * self.lattice_state[k, l]
|
|
195
|
+
|
|
196
|
+
counter += 1
|
|
197
|
+
|
|
198
|
+
corr = correlation_function[:counter]
|
|
199
|
+
dist = r_sq[:counter]
|
|
200
|
+
|
|
201
|
+
sort_ind = np.argsort(dist)
|
|
202
|
+
sorted_d = np.sort(dist)
|
|
203
|
+
sorted_c = corr[sort_ind]
|
|
204
|
+
|
|
205
|
+
unique_d, unique_indices_d = np.unique(sorted_d, return_index=True)
|
|
206
|
+
averaged_c = np.zeros(unique_d.size)
|
|
207
|
+
|
|
208
|
+
for i in np.arange(averaged_c.size - 1):
|
|
209
|
+
denom = unique_indices_d[i + 1] - unique_indices_d[i]
|
|
210
|
+
averaged_c[i] = np.sum(sorted_c[unique_indices_d[i]:unique_indices_d[i + 1]]) / denom
|
|
211
|
+
|
|
212
|
+
denom = unique_indices_d[-1] - unique_indices_d[-2]
|
|
213
|
+
averaged_c[-1] = np.sum(sorted_c[unique_indices_d[-2]:unique_indices_d[-1]]) / denom
|
|
214
|
+
|
|
215
|
+
if plot:
|
|
216
|
+
plt.plot(np.sqrt(unique_d), averaged_c)
|
|
217
|
+
plt.xlabel("Distance")
|
|
218
|
+
plt.ylabel("Correlation Function")
|
|
219
|
+
plt.title("Correlation Function vs Distance")
|
|
220
|
+
plt.show()
|
|
221
|
+
|
|
222
|
+
return averaged_c - self.magnetization()**2, np.sqrt(unique_d)
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
import random
|
|
4
|
+
import pickle as pkl
|
|
5
|
+
import imageio
|
|
6
|
+
import time
|
|
7
|
+
import os
|
|
8
|
+
from .isinglattice import IsingLattice
|
|
9
|
+
|
|
10
|
+
INF_TEMP = 100
|
|
11
|
+
|
|
12
|
+
def get_index(data):
|
|
13
|
+
"""
|
|
14
|
+
Get the index where data falls below a threshold.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
data : np.ndarray
|
|
19
|
+
The array of data.
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
int
|
|
24
|
+
The index where data falls below 10^-8.
|
|
25
|
+
"""
|
|
26
|
+
for i in range(data.size):
|
|
27
|
+
if data[i] < 10**(-8):
|
|
28
|
+
return i
|
|
29
|
+
return data.size
|
|
30
|
+
|
|
31
|
+
def data2cut(data, index):
|
|
32
|
+
"""
|
|
33
|
+
Cut data up to a given index.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
data : np.ndarray
|
|
38
|
+
The array of data.
|
|
39
|
+
index : int
|
|
40
|
+
The index to cut data.
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
np.ndarray
|
|
45
|
+
The cut data.
|
|
46
|
+
"""
|
|
47
|
+
return data[:index]
|
|
48
|
+
|
|
49
|
+
def distance2cut(distance, index):
|
|
50
|
+
"""
|
|
51
|
+
Cut distances up to a given index.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
distance : np.ndarray
|
|
56
|
+
The array of distances.
|
|
57
|
+
index : int
|
|
58
|
+
The index to cut distances.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
np.ndarray
|
|
63
|
+
The cut distances.
|
|
64
|
+
"""
|
|
65
|
+
return distance[:index]
|
|
66
|
+
|
|
67
|
+
def get_cor_len(cor_func, dist, index):
|
|
68
|
+
"""
|
|
69
|
+
Calculate the correlation length.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
cor_func : np.ndarray
|
|
74
|
+
The correlation function values.
|
|
75
|
+
dist : np.ndarray
|
|
76
|
+
The distances.
|
|
77
|
+
index : int
|
|
78
|
+
The index up to which the data is considered.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
float
|
|
83
|
+
The correlation length.
|
|
84
|
+
"""
|
|
85
|
+
cor_func_cut = data2cut(cor_func, index)
|
|
86
|
+
distance_cut = distance2cut(dist, index)
|
|
87
|
+
|
|
88
|
+
correlation_negative_check = np.sum(cor_func_cut * (distance_cut ** 2))
|
|
89
|
+
correlation_zero_check = np.sum(6 * cor_func_cut)
|
|
90
|
+
|
|
91
|
+
if correlation_zero_check == 0:
|
|
92
|
+
return 0
|
|
93
|
+
elif correlation_negative_check / correlation_zero_check < 0:
|
|
94
|
+
return 0
|
|
95
|
+
else:
|
|
96
|
+
return np.sqrt(correlation_negative_check / correlation_zero_check)
|
|
97
|
+
|
|
98
|
+
def scan_lattice(ising_lattice, temperature):
|
|
99
|
+
"""
|
|
100
|
+
Perform a single Metropolis scan of the lattice.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
ising_lattice : IsingLattice
|
|
105
|
+
The Ising lattice.
|
|
106
|
+
temperature : float
|
|
107
|
+
The temperature of the system.
|
|
108
|
+
"""
|
|
109
|
+
for _ in range(ising_lattice.num_sites):
|
|
110
|
+
i = random.randint(0, ising_lattice.lattice_size - 1)
|
|
111
|
+
j = random.randint(0, ising_lattice.lattice_size - 1)
|
|
112
|
+
|
|
113
|
+
energy_initial = ising_lattice.spin_energy(i, j)
|
|
114
|
+
ising_lattice.flip_spin(i, j)
|
|
115
|
+
energy_final = ising_lattice.spin_energy(i, j)
|
|
116
|
+
energy_change = energy_final - energy_initial
|
|
117
|
+
ising_lattice.flip_spin(i, j)
|
|
118
|
+
|
|
119
|
+
if temperature != 0:
|
|
120
|
+
if energy_change <= 0 or random.uniform(0, 1) <= np.exp(-energy_change / temperature):
|
|
121
|
+
ising_lattice.flip_spin(i, j)
|
|
122
|
+
|
|
123
|
+
def calculate_corr_size(lattice_size):
|
|
124
|
+
"""
|
|
125
|
+
Calculate CORR_SIZE dynamically based on lattice size.
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
lattice_size : int
|
|
130
|
+
The size of the lattice.
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
int
|
|
135
|
+
The calculated CORR_SIZE.
|
|
136
|
+
"""
|
|
137
|
+
unique_distances = set()
|
|
138
|
+
|
|
139
|
+
for i in range(lattice_size):
|
|
140
|
+
for j in range(lattice_size):
|
|
141
|
+
for k in range(lattice_size):
|
|
142
|
+
for l in range(lattice_size):
|
|
143
|
+
x_distance = min(abs(i - k), lattice_size - abs(i - k))
|
|
144
|
+
y_distance = min(abs(j - l), lattice_size - abs(j - l))
|
|
145
|
+
distance_squared = x_distance**2 + y_distance**2
|
|
146
|
+
unique_distances.add(distance_squared)
|
|
147
|
+
|
|
148
|
+
return len(unique_distances)
|
|
149
|
+
|
|
150
|
+
def monte_carlo_simulation(ising_lattice, temperature, num_scans, frequency_sweeps_to_collect_magnetization, plot_result=False, print_info=False, calculate_correlation=False):
|
|
151
|
+
"""
|
|
152
|
+
Perform Monte Carlo simulation on the Ising lattice.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
ising_lattice : IsingLattice
|
|
157
|
+
The Ising lattice.
|
|
158
|
+
temperature : float
|
|
159
|
+
The temperature of the system.
|
|
160
|
+
num_scans : int
|
|
161
|
+
The number of scans to perform.
|
|
162
|
+
frequency_sweeps_to_collect_magnetization : int
|
|
163
|
+
The frequency of sweeps to collect magnetization.
|
|
164
|
+
plot_result : bool, optional
|
|
165
|
+
Whether to plot the result. Default is False.
|
|
166
|
+
print_info : bool, optional
|
|
167
|
+
Whether to print information. Default is False.
|
|
168
|
+
calculate_correlation : bool, optional
|
|
169
|
+
Whether to calculate correlation function and length. Default is False.
|
|
170
|
+
|
|
171
|
+
Returns
|
|
172
|
+
-------
|
|
173
|
+
tuple
|
|
174
|
+
Lattice configurations, energy records, magnetization records, correlation function records, correlation length records, distances.
|
|
175
|
+
"""
|
|
176
|
+
start_time = time.time()
|
|
177
|
+
|
|
178
|
+
if print_info:
|
|
179
|
+
ising_lattice.print_info()
|
|
180
|
+
|
|
181
|
+
total_num_records = int(num_scans / frequency_sweeps_to_collect_magnetization) + 1
|
|
182
|
+
energy_records = np.zeros(total_num_records)
|
|
183
|
+
magnetization_records = np.zeros(total_num_records)
|
|
184
|
+
|
|
185
|
+
corr_size = calculate_corr_size(ising_lattice.lattice_size) if calculate_correlation else 0
|
|
186
|
+
correlation_function_records = np.zeros((total_num_records, corr_size)) if calculate_correlation else None
|
|
187
|
+
correlation_length_records = np.zeros(total_num_records) if calculate_correlation else None
|
|
188
|
+
|
|
189
|
+
increment_records = 0
|
|
190
|
+
|
|
191
|
+
lattice_configs = np.zeros((total_num_records, ising_lattice.lattice_size, ising_lattice.lattice_size))
|
|
192
|
+
|
|
193
|
+
for k in range(num_scans + frequency_sweeps_to_collect_magnetization):
|
|
194
|
+
scan_lattice(ising_lattice, temperature)
|
|
195
|
+
if k % frequency_sweeps_to_collect_magnetization == 0:
|
|
196
|
+
energy_records[increment_records] = ising_lattice.energy()
|
|
197
|
+
magnetization_records[increment_records] = ising_lattice.magnetization()
|
|
198
|
+
lattice_configs[increment_records] = ising_lattice.lattice_state
|
|
199
|
+
|
|
200
|
+
if calculate_correlation:
|
|
201
|
+
correlations, distances = ising_lattice.correlation_function(False)
|
|
202
|
+
correlation_function_records[increment_records] = correlations[:corr_size]
|
|
203
|
+
|
|
204
|
+
index = get_index(correlations)
|
|
205
|
+
correlation_length_records[increment_records] = get_cor_len(correlations, distances, index)
|
|
206
|
+
|
|
207
|
+
increment_records += 1
|
|
208
|
+
print(f"{increment_records} / {total_num_records} samples saved.")
|
|
209
|
+
|
|
210
|
+
print(f"For temperature= {temperature}, MC simulation executed in: {round(time.time() - start_time, 2)} seconds")
|
|
211
|
+
|
|
212
|
+
if plot_result:
|
|
213
|
+
ising_lattice.plot_lattice()
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
lattice_configs,
|
|
217
|
+
energy_records,
|
|
218
|
+
magnetization_records,
|
|
219
|
+
correlation_function_records if calculate_correlation else None,
|
|
220
|
+
correlation_length_records if calculate_correlation else None,
|
|
221
|
+
distances if calculate_correlation else None
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def dir_name(lattice_size, J1, J2, h, temperature):
|
|
225
|
+
return f'SQ_L_{lattice_size}_J1_{J1:.3f}_J2_{J2:.3f}_h_{h:.3f}_T_{temperature:.3f}'
|
|
226
|
+
|
|
227
|
+
def file_name(lattice_size, J1, J2, h, temperature, seed):
|
|
228
|
+
return f'SQ_L_{lattice_size}_J1_{J1:.3f}_J2_{J2:.3f}_h_{h:.3f}_T_{temperature:.3f}_s_{seed}'
|
|
229
|
+
|
|
230
|
+
def write_to_sub_directory(quantity, dir_name, file_name):
|
|
231
|
+
if not os.path.exists(dir_name):
|
|
232
|
+
os.mkdir(dir_name)
|
|
233
|
+
with open(os.path.join(dir_name, file_name), "wb") as file:
|
|
234
|
+
pkl.dump(quantity, file)
|
|
235
|
+
|
|
236
|
+
def write_txt_files(quantity, dir_name, file_name):
|
|
237
|
+
if not os.path.exists(dir_name):
|
|
238
|
+
os.mkdir(dir_name)
|
|
239
|
+
np.savetxt(os.path.join(dir_name, file_name), quantity, fmt='%1.3f')
|
|
240
|
+
|
|
241
|
+
def save_image_to_sub_directory(data, directory_name, file_name):
|
|
242
|
+
if not os.path.exists(directory_name):
|
|
243
|
+
os.mkdir(directory_name)
|
|
244
|
+
imageio.imwrite(os.path.join(directory_name, f"{file_name}.png"), data)
|
|
245
|
+
|
|
246
|
+
def thermalize(ising_lattice, num_scans, from_T, to_T):
|
|
247
|
+
"""
|
|
248
|
+
Thermalize the lattice from a given temperature to a target temperature.
|
|
249
|
+
|
|
250
|
+
Parameters
|
|
251
|
+
----------
|
|
252
|
+
ising_lattice : IsingLattice
|
|
253
|
+
The Ising lattice.
|
|
254
|
+
num_scans : int
|
|
255
|
+
The number of scans for thermalization.
|
|
256
|
+
from_T : float
|
|
257
|
+
The initial temperature.
|
|
258
|
+
to_T : float
|
|
259
|
+
The target temperature.
|
|
260
|
+
"""
|
|
261
|
+
print(f"Equilibrating to T = {to_T:.2f} starting from T = {from_T:.2f}")
|
|
262
|
+
for k in np.linspace(from_T, to_T, num=num_scans):
|
|
263
|
+
scan_lattice(ising_lattice, k)
|
|
264
|
+
print(f"Reached T={to_T:.2f}. Beginning to collect data.")
|
|
265
|
+
|
|
266
|
+
def collect_monte_carlo_data(seed, lattice_size, J1, J2, h, num_scans, temperature, thermalization_scans, frequency_sweeps_to_collect_magnetization, calculate_correlation=False):
|
|
267
|
+
random.seed(seed)
|
|
268
|
+
print(f"Lattice size: {lattice_size} x {lattice_size}, J1= {J1}, J2= {J2}, h= {h}, SEED= {seed}\n")
|
|
269
|
+
temperature = np.append(INF_TEMP, temperature)
|
|
270
|
+
|
|
271
|
+
if 0 in temperature:
|
|
272
|
+
raise ValueError("Monte-Carlo does not work properly at T=0.")
|
|
273
|
+
if np.any(temperature < 0):
|
|
274
|
+
raise ValueError("Temperature cannot be a negative value.")
|
|
275
|
+
|
|
276
|
+
ising_lattice = IsingLattice(lattice_size, J1, J2, h)
|
|
277
|
+
num_temps = temperature.size
|
|
278
|
+
|
|
279
|
+
for i in range(num_temps - 1):
|
|
280
|
+
file_name_lattice = file_name(lattice_size, J1, J2, h, temperature[i+1], seed)
|
|
281
|
+
dir_name_data = dir_name(lattice_size, J1, J2, h, temperature[i+1])
|
|
282
|
+
|
|
283
|
+
total_num_configurations = int(num_scans / frequency_sweeps_to_collect_magnetization) + 1
|
|
284
|
+
file_exists = [os.path.isfile(os.path.join(dir_name_data, f"{file_name_lattice}_n_{configs * frequency_sweeps_to_collect_magnetization}.pkl")) for configs in range(total_num_configurations)]
|
|
285
|
+
|
|
286
|
+
if os.path.exists(dir_name_data) and not np.all(file_exists):
|
|
287
|
+
print(f"{np.argwhere(np.array(file_exists) == False)[0][0]} Previous configurations for SEED = {seed} with L = {lattice_size} T = {temperature[i+1]:.2f} J1 = {J1} J2 = {J2} h = {h}\n")
|
|
288
|
+
|
|
289
|
+
if np.all(file_exists):
|
|
290
|
+
print(f"ALL requested configurations for SEED = {seed} with L = {lattice_size} T = {temperature[i+1]:.2f} J1 = {J1} J2 = {J2} h = {h} already exist!\n")
|
|
291
|
+
continue
|
|
292
|
+
|
|
293
|
+
thermalize(ising_lattice, thermalization_scans, temperature[i], temperature[i+1])
|
|
294
|
+
print(f"START - MC simulation {i+1} / {num_temps-1}, T = {temperature[i+1]:.2f}")
|
|
295
|
+
|
|
296
|
+
lattice_configs, energy_records, magnetization_records, correlation_function_records, correlation_length_records, distances = monte_carlo_simulation(
|
|
297
|
+
ising_lattice, temperature[i+1], num_scans, frequency_sweeps_to_collect_magnetization, calculate_correlation=calculate_correlation)
|
|
298
|
+
|
|
299
|
+
for img in range(total_num_configurations):
|
|
300
|
+
file_name_img = f"{file_name_lattice}_n_{img * frequency_sweeps_to_collect_magnetization}"
|
|
301
|
+
data_sample = {
|
|
302
|
+
'configuration': lattice_configs[img],
|
|
303
|
+
'energy': energy_records[img],
|
|
304
|
+
'magnetization': magnetization_records[img],
|
|
305
|
+
'correlation_length': correlation_length_records[img] if calculate_correlation else None,
|
|
306
|
+
'correlation_function': correlation_function_records[img] if calculate_correlation else None,
|
|
307
|
+
'distances': distances if calculate_correlation else None
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
txt_data = np.array([data_sample['energy'], data_sample['magnetization'], data_sample['correlation_length']])
|
|
311
|
+
correlation_function_txt_data = np.array(data_sample['correlation_function']) if calculate_correlation else None
|
|
312
|
+
write_to_sub_directory(data_sample, dir_name_data, f"{file_name_img}.pkl")
|
|
313
|
+
save_image_to_sub_directory(lattice_configs[img].astype(np.uint8), dir_name_data, file_name_img)
|
|
314
|
+
write_txt_files(txt_data, dir_name_data, f"{file_name_img}.txt")
|
|
315
|
+
if calculate_correlation:
|
|
316
|
+
write_txt_files(correlation_function_txt_data, dir_name_data, f"{file_name_img}_correlation_function.txt")
|
|
317
|
+
write_txt_files(distances, dir_name_data, f"{file_name_img}_distances.txt")
|
|
318
|
+
|
|
319
|
+
print(f"END --- MC simulation {i+1} / {num_temps-1}, T = {temperature[i+1]:.2f}\n")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mcising
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: A package for generating Ising model data using Metropolis algorithm on a square lattice for nearest neighbor and next nearest neighbor interactions.
|
|
5
|
+
Home-page: https://github.com/bcivitcioglu/mcising
|
|
6
|
+
Author: Burak Ç.
|
|
7
|
+
Author-email: bcivitcioglu@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# mcising
|
|
14
|
+
|
|
15
|
+
mcising is a Python package for generating Ising model data using Monte Carlo simulations.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
You can install the package using pip:
|
|
20
|
+
|
|
21
|
+
`pip install mcising`
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
You can generate Ising model data from the command line:
|
|
26
|
+
|
|
27
|
+
`generate_ising_data <seed> <lattice_size> <num_configs> <j1> <j2> [--T_init <T_init>] [--T_final <T_final>] [--T_step <T_step>] [--sweep_steps <sweep_steps>] [--thermalization_scans <thermalization_scans>] [--calculate_correlation]`
|
|
28
|
+
|
|
29
|
+
An example usage:
|
|
30
|
+
|
|
31
|
+
`generate_ising_data 42 10 100 1.0 0.5 --T_init 4.0 --T_final 0.1 --T_step 0.05 --sweep_steps 10 --thermalization_scans 5 --calculate_correlation`
|
|
32
|
+
|
|
33
|
+
## Licence
|
|
34
|
+
|
|
35
|
+
This project is licensed under the MIT License.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
mcising/__init__.py
|
|
4
|
+
mcising/ising_data_generate.py
|
|
5
|
+
mcising/isinglattice.py
|
|
6
|
+
mcising/montecarlo.py
|
|
7
|
+
mcising.egg-info/PKG-INFO
|
|
8
|
+
mcising.egg-info/SOURCES.txt
|
|
9
|
+
mcising.egg-info/dependency_links.txt
|
|
10
|
+
mcising.egg-info/entry_points.txt
|
|
11
|
+
mcising.egg-info/requires.txt
|
|
12
|
+
mcising.egg-info/top_level.txt
|
|
13
|
+
tests/__init__.py
|
|
14
|
+
tests/test_isinglattice.py
|
|
15
|
+
tests/test_montecarlo.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
mcising-0.1/setup.cfg
ADDED
mcising-0.1/setup.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# setup.py
|
|
2
|
+
from setuptools import setup, find_packages
|
|
3
|
+
|
|
4
|
+
setup(
|
|
5
|
+
name="mcising",
|
|
6
|
+
version="0.1",
|
|
7
|
+
packages=find_packages(),
|
|
8
|
+
install_requires=[
|
|
9
|
+
"numpy",
|
|
10
|
+
"matplotlib",
|
|
11
|
+
"imageio"
|
|
12
|
+
],
|
|
13
|
+
tests_require=[
|
|
14
|
+
"unittest",
|
|
15
|
+
"pytest"
|
|
16
|
+
],
|
|
17
|
+
entry_points={
|
|
18
|
+
'console_scripts': [
|
|
19
|
+
'generate_ising_data=mcising.ising_data_generate:main',
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
author="Burak Ç.",
|
|
23
|
+
author_email="bcivitcioglu@gmail.com",
|
|
24
|
+
description="A package for generating Ising model data using Metropolis algorithm on a square lattice for nearest neighbor and next nearest neighbor interactions.",
|
|
25
|
+
long_description=open('README.md').read(),
|
|
26
|
+
long_description_content_type='text/markdown',
|
|
27
|
+
url="https://github.com/bcivitcioglu/mcising",
|
|
28
|
+
classifiers=[
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"License :: OSI Approved :: MIT License",
|
|
31
|
+
"Operating System :: OS Independent",
|
|
32
|
+
],
|
|
33
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# tests/__init__.py
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from mcising.isinglattice import IsingLattice
|
|
3
|
+
|
|
4
|
+
class TestIsingLattice(unittest.TestCase):
|
|
5
|
+
|
|
6
|
+
def test_initialization(self):
|
|
7
|
+
lattice = IsingLattice(lattice_size=10, J1=1.0, J2=0.5, h=0.0)
|
|
8
|
+
self.assertEqual(lattice.lattice_size, 10)
|
|
9
|
+
self.assertEqual(lattice.J1, 1.0)
|
|
10
|
+
self.assertEqual(lattice.J2, 0.5)
|
|
11
|
+
self.assertEqual(lattice.h, 0.0)
|
|
12
|
+
self.assertEqual(lattice.lattice_state.shape, (10, 10))
|
|
13
|
+
|
|
14
|
+
def test_flip_spin(self):
|
|
15
|
+
lattice = IsingLattice(lattice_size=10, J1=1.0, J2=0.5, h=0.0)
|
|
16
|
+
initial_spin = lattice.lattice_state[0, 0]
|
|
17
|
+
lattice.flip_spin(0, 0)
|
|
18
|
+
self.assertEqual(lattice.lattice_state[0, 0], -initial_spin)
|
|
19
|
+
|
|
20
|
+
if __name__ == '__main__':
|
|
21
|
+
unittest.main()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from mcising.isinglattice import IsingLattice
|
|
3
|
+
from mcising.montecarlo import scan_lattice, monte_carlo_simulation
|
|
4
|
+
|
|
5
|
+
class TestMonteCarlo(unittest.TestCase):
|
|
6
|
+
|
|
7
|
+
def setUp(self):
|
|
8
|
+
self.lattice = IsingLattice(lattice_size=10, J1=1.0, J2=0.5, h=0.0)
|
|
9
|
+
self.temperature = 1.0
|
|
10
|
+
self.num_scans = 100
|
|
11
|
+
self.frequency_sweeps_to_collect_magnetization = 10
|
|
12
|
+
|
|
13
|
+
def test_scan_lattice(self):
|
|
14
|
+
initial_energy = self.lattice.energy()
|
|
15
|
+
scan_lattice(self.lattice, self.temperature)
|
|
16
|
+
self.assertNotEqual(self.lattice.energy(), initial_energy)
|
|
17
|
+
|
|
18
|
+
def test_monte_carlo_simulation_without_correlation(self):
|
|
19
|
+
configs, energies, magnetizations, corrs, corr_lengths, distances = monte_carlo_simulation(
|
|
20
|
+
self.lattice,
|
|
21
|
+
self.temperature,
|
|
22
|
+
self.num_scans,
|
|
23
|
+
self.frequency_sweeps_to_collect_magnetization,
|
|
24
|
+
calculate_correlation=False
|
|
25
|
+
)
|
|
26
|
+
self.assertIsNotNone(configs)
|
|
27
|
+
self.assertIsNotNone(energies)
|
|
28
|
+
self.assertIsNotNone(magnetizations)
|
|
29
|
+
self.assertIsNone(corrs)
|
|
30
|
+
self.assertIsNone(corr_lengths)
|
|
31
|
+
self.assertIsNone(distances)
|
|
32
|
+
|
|
33
|
+
def test_monte_carlo_simulation_with_correlation(self):
|
|
34
|
+
configs, energies, magnetizations, corrs, corr_lengths, distances = monte_carlo_simulation(
|
|
35
|
+
self.lattice,
|
|
36
|
+
self.temperature,
|
|
37
|
+
self.num_scans,
|
|
38
|
+
self.frequency_sweeps_to_collect_magnetization,
|
|
39
|
+
calculate_correlation=True
|
|
40
|
+
)
|
|
41
|
+
self.assertIsNotNone(configs)
|
|
42
|
+
self.assertIsNotNone(energies)
|
|
43
|
+
self.assertIsNotNone(magnetizations)
|
|
44
|
+
self.assertIsNotNone(corrs)
|
|
45
|
+
self.assertIsNotNone(corr_lengths)
|
|
46
|
+
self.assertIsNotNone(distances)
|
|
47
|
+
|
|
48
|
+
if __name__ == '__main__':
|
|
49
|
+
unittest.main()
|