Skip to content

Commit 6afb7e1

Browse files
author
Weiwei Wang
authored
Merge pull request #45 from computationalmodelling/monte_carlo
Monte carlo
2 parents ba3aa6a + 6b45ee8 commit 6afb7e1

File tree

18 files changed

+555
-264
lines changed

18 files changed

+555
-264
lines changed

doc/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ Contents:
1919
install
2020
core_eqs
2121
extended_eqs
22+
monte_carlo
2223
develop
2324
ipynb/tutorial-basics

doc/monte_carlo.rst

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Monte Carlo Simulation
2+
=======================
3+
4+
In the atomistic part of Fidimag, Monte Carlo based on Metropolis algorithm is integrated.
5+
The supported interactions include the exchange interaction, the bulk DMI, the external field and
6+
cubic anisotropy. The total Hamiltonian of the system is therefore given by
7+
8+
.. math::
9+
\mathcal{H} = \mathcal{H}_{ex} + \mathcal{H}_{dmi} + \mathcal{H}_{ext} + \mathcal{H}_{c}
10+
11+
where :math:`\mathcal{H}_{ex}` is the nearest-neighbor exchange interaction,
12+
13+
.. math::
14+
\mathcal{H}_{ex} = -J \sum_{<i,j>}\vec{m}_i \cdot \vec{m}_j
15+
16+
Note that the summation is taken only once for each pair and :math:`\vec{m}_i` is the unit vector of spin :math:`\vec{S}` at site :math:`i`.
17+
18+
The Hamiltonian of bulk DMI can be expressed as,
19+
20+
.. math::
21+
\mathcal{H}_{dmi}= \sum_{<i,j>} \vec{D}_{ij}\cdot [\vec{m}_i \times \vec{m}_j]
22+
23+
where :math:`\vec{D}_{ij} = D \vec{e}_{ij}` with :math:`\vec{e}_{ij}` is the unit vector between :math:`\vec{S}_{i}` and :math:`\vec{S}_{j}`.
24+
25+
The Hamiltonian of external field is
26+
27+
.. math::
28+
\mathcal{H}_{dmi}= - \sum_{i} \mu_s \vec{H}\cdot \vec{m}_i
29+
30+
where :math:`\mu_s = g \mu_B S`.
31+
32+
The cubic anisotropy implemented in Fidimag is,
33+
34+
.. math::
35+
\mathcal{H}_{c}= - \sum_{i} (K_c/2) (m_{i,x}^4 + m_{i,y}^4 + m_{i,z}^4)
36+
37+
which is equivalent to the form
38+
39+
.. math::
40+
\mathcal{H}_{c}= \sum_{i} K_c (m_{i,x}^2 m_{i,y}^2 + m_{i,y}^2 m_{i,z}^2 + m_{i,z}^2 m_{i,x}^2)
41+
42+

examples/atomic/PRL_111_067203/single.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,4 @@ def excite_system(mesh):
105105
if __name__ == '__main__':
106106
mesh = CuboidMesh(nx=150, ny=50, nz=1, periodicity=(True, True, False))
107107
relax_system(mesh)
108-
#excite_system(mesh)
108+
excite_system(mesh)

examples/mc/skx.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import matplotlib.pyplot as plt
44

55
import numpy as np
6-
from fidimag.atomistic.mc import MonteCarlo
6+
from fidimag.atomistic import MonteCarlo
77
from fidimag.common import DataReader, CuboidMesh
88

99

@@ -19,9 +19,9 @@ def random_m(pos):
1919
def run(mesh):
2020

2121
mc = MonteCarlo(mesh, name='test1')
22-
mc.set_m(init_m)
23-
mc.set_options(H=[0,0,0.0], J=50.0, D=0.27*50, T=5.0)
24-
mc.run(steps=200000, save_m_steps=None, save_vtk_steps=1000, save_data_steps=10)
22+
mc.set_m(random_m)
23+
mc.set_options(H=[0,0,0.0], J=50.0, D=0.27*50, T=5.0, Kc=50*0.1)
24+
mc.run(steps=20000, save_m_steps=None, save_vtk_steps=1000, save_data_steps=10)
2525

2626
if __name__=='__main__':
2727

fidimag/atomistic/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
from .zeeman import Zeeman, TimeZeeman
55
from .demag import Demag
66
from .demag_hexagonal import DemagHexagonal
7+
from .hexagonal_mesh import HexagonalMesh
78
from .demag_full import DemagFull
89
from .dmi import DMI
10+
from .monte_carlo import MonteCarlo
911
import fidimag.common.constant as const
1012
from .materials import UnitMaterial, Nickel

fidimag/atomistic/lib/clib.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@
66
#include<fftw3.h>
77
//#include<omp.h>
88

9-
#define WIDE_PI 3.1415926535897932384626433832795L
9+
#include"fidimag_random.h"
1010

11-
double single_random(void);
12-
void gauss_random_vec(double *x, int n);
13-
void random_spin_uniform(double *spin, int n);
11+
#define WIDE_PI 3.1415926535897932384626433832795L
1412

1513
/* 3 components for the cross product calculations */
1614
inline double cross_x(double a0, double a1, double a2,
@@ -92,8 +90,8 @@ void llg_rhs_dw_c(double *m, double *h, double *dm, double *T, double *alpha,
9290
double *mu_s_inv, int *pins, double *eta, int n, double gamma, double dt);
9391

9492
//======================================================================
95-
void run_step_mc(double *spin, double *new_spin, int *ngbs, double J, double D, double *h, int n, double T);
9693

94+
void run_step_mc(mt19937_state *state, double *spin, double *new_spin, int *ngbs, int *nngbs, double J, double J1, double D, double D1, double *h, double Kc, int n, double T, int hexagnoal_mesh);
9795

9896

9997
#endif

fidimag/atomistic/lib/clib.pyx

Lines changed: 79 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,25 @@ import numpy
22
cimport numpy as np
33
np.import_array()
44

5-
cdef extern from "clib.h":
6-
void initial_random(int seed)
7-
double single_random()
8-
void gauss_random_vec(double *x, int n)
9-
void random_spin_uniform(double *spin, int n)
10-
void run_step_mc(double *spin, double *new_spin, int *ngbs, double J, double D, double *h, int n, double T)
5+
cdef extern from "fidimag_random.h":
6+
ctypedef struct mt19937_state:
7+
pass
8+
9+
mt19937_state *create_mt19937_state()
10+
void finalize_mt19937_state(mt19937_state *state)
11+
12+
void initial_rng_mt19973(mt19937_state *state, int seed)
13+
double random_double_half_open(mt19937_state *state)
14+
void gauss_random_vector(mt19937_state *state, double *x, int n)
15+
void uniform_random_sphere(mt19937_state *state, double *spin, int n)
1116

17+
cdef extern from "time.h":
18+
ctypedef int time_t
19+
time_t time(time_t *timer)
20+
21+
cdef extern from "clib.h":
22+
void run_step_mc(mt19937_state *state, double *spin, double *new_spin, int *ngbs, int *nngbs,
23+
double J, double J1, double D, double D1, double *h, double Kc, int n, double T, int hexagnoal_mesh)
1224
double skyrmion_number(double *spin, double *charge,
1325
int nx, int ny, int nz, int *ngbs)
1426

@@ -264,31 +276,6 @@ def normalise_spin(np.ndarray[double, ndim=1, mode="c"] spin,
264276
normalise(&spin[0], &pins[0], n)
265277

266278

267-
def init_random(seed):
268-
initial_random(seed)
269-
270-
def random_number_array(np.ndarray[double, ndim=1, mode="c"] v):
271-
272-
cdef int n = len(v)
273-
274-
gauss_random_vec(&v[0], n)
275-
276-
def random_spin_uniform_sphere(np.ndarray[double, ndim=1, mode="c"] v, n):
277-
278-
random_spin_uniform(&v[0], n)
279-
280-
def random_number():
281-
cdef double res = single_random()
282-
return res
283-
284-
def run_mc_step(np.ndarray[double, ndim=1, mode="c"] spin,
285-
np.ndarray[double, ndim=1, mode="c"] new_spin,
286-
np.ndarray[int, ndim=2, mode="c"] ngbs,
287-
J, D, np.ndarray[double, ndim=1, mode="c"] h,
288-
n, T):
289-
run_step_mc(&spin[0], &new_spin[0], &ngbs[0,0], J, D, &h[0], n, T)
290-
291-
292279
def compute_llg_rhs_dw(np.ndarray[double, ndim=1, mode="c"] dm,
293280
np.ndarray[double, ndim=1, mode="c"] spin,
294281
np.ndarray[double, ndim=1, mode="c"] field,
@@ -298,3 +285,64 @@ def compute_llg_rhs_dw(np.ndarray[double, ndim=1, mode="c"] dm,
298285
np.ndarray[double, ndim=1, mode="c"] eta,
299286
np.ndarray[int, ndim=1, mode="c"] pin, n, gamma, dt):
300287
llg_rhs_dw_c(&spin[0], &field[0], &dm[0], &T[0], &alpha[0], &mu_s_inv[0], &pin[0], &eta[0], n, gamma, dt)
288+
289+
290+
cdef class rng_mt19937(object):
291+
cdef mt19937_state *_c_state
292+
cdef public int seed
293+
def __init__(self, seed=None):
294+
if seed:
295+
self.seed = int(seed)
296+
else:
297+
self.seed = time(NULL)
298+
299+
self._c_state = create_mt19937_state()
300+
if self._c_state is NULL:
301+
raise MemoryError()
302+
303+
initial_rng_mt19973(self._c_state, self.seed)
304+
305+
def set_seed(self, seed):
306+
self.seed = int(seed)
307+
initial_rng_mt19973(self._c_state, self.seed)
308+
309+
def random(self):
310+
"""
311+
return a random number in [0,1)
312+
"""
313+
return random_double_half_open(self._c_state)
314+
315+
def fill_vector_gaussian(self, np.ndarray[np.float64_t, ndim=1] vector):
316+
gauss_random_vector(self._c_state, &vector[0], vector.shape[0])
317+
318+
def fill_vector_uniform_sphere(self, np.ndarray[double, ndim=1, mode="c"] spin, n):
319+
uniform_random_sphere(self._c_state,&spin[0], n)
320+
321+
def __dealloc__(self):
322+
if self._c_state is not NULL:
323+
finalize_mt19937_state(self._c_state)
324+
self._c_state = NULL
325+
326+
cdef class monte_carlo(object):
327+
cdef mt19937_state *_c_state
328+
329+
def __init__(self, seed=-1):
330+
331+
self._c_state = create_mt19937_state()
332+
if self._c_state is NULL:
333+
raise MemoryError()
334+
335+
initial_rng_mt19973(self._c_state, seed)
336+
337+
def set_seed(self, seed):
338+
initial_rng_mt19973(self._c_state, seed)
339+
340+
def run_step(self,np.ndarray[double, ndim=1, mode="c"] spin,
341+
np.ndarray[double, ndim=1, mode="c"] new_spin,
342+
np.ndarray[int, ndim=2, mode="c"] ngbs,
343+
np.ndarray[int, ndim=2, mode="c"] nngbs,
344+
J, J1, D, D1, np.ndarray[double, ndim=1, mode="c"] h,
345+
Kc, n, T, hexagnoal_mesh):
346+
347+
run_step_mc(self._c_state, &spin[0], &new_spin[0], &ngbs[0,0], &nngbs[0,0], J, J1, D, D1, &h[0], Kc, n, T, hexagnoal_mesh)
348+
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#include <stdlib.h> // rand(), srand()
2+
#include <time.h>
3+
#include <math.h>
4+
#include "fidimag_random.h"
5+
6+
mt19937_state *create_mt19937_state(void) {
7+
8+
mt19937_state *state = (mt19937_state*) malloc(sizeof(mt19937_state));
9+
state->seed = 1;
10+
state->index_t = 0;
11+
state->matrix[0] = 0;
12+
state->matrix[1] = 0x9908b0dfU;
13+
14+
return state;
15+
}
16+
17+
void finalize_mt19937_state(mt19937_state *state) {
18+
free(state);
19+
}
20+
21+
22+
void initial_rng_mt19973(mt19937_state *state, int seed) {
23+
24+
if (seed<0){
25+
state->seed = (unsigned int) time(NULL);
26+
}else{
27+
state->seed = seed;
28+
}
29+
30+
state->MT[0] = state->seed & 0xFFFFFFFFU;
31+
for (int i = 1; i < 624; i++) {
32+
state->MT[i] = (state->MT[i - 1] ^ (state->MT[i - 1] >> 30)) + i;
33+
state->MT[i] *= 0x6c078965U;
34+
state->MT[i] &= 0xFFFFFFFFU;
35+
}
36+
}
37+
38+
//return a integer in [0, MT19973_RAND_MAX]
39+
inline unsigned int rand_int(mt19937_state *state) {
40+
41+
unsigned int x;
42+
int index_t = state->index_t;
43+
44+
x = (state->MT[index_t] & 0x1U) + (state->MT[(index_t + 1) % 624] & 0xFFFFFFFEU);
45+
state->MT[index_t] = (state->MT[(index_t + 397) % 624] ^ (x >> 1))^ state->matrix[x & 1];
46+
47+
x = state->MT[index_t];
48+
x ^= (x >> 11);
49+
x ^= (x << 7) & 0x9d2c5680U;
50+
x ^= (x << 15) & 0xefc60000U;
51+
x ^= (x >> 18);
52+
53+
state->index_t = (index_t + 1) % 624;
54+
55+
return x;
56+
}
57+
58+
//return a double number in (0,1) with uniform distribution
59+
double random_double_open(mt19937_state *state) {
60+
return (((double) rand_int(state))+0.5) / 4294967296.0;
61+
}
62+
63+
//return a double number in [0,1) with uniform distribution
64+
double random_double_half_open(mt19937_state *state) {
65+
return ((double) rand_int(state)) / 4294967296.0;
66+
}
67+
68+
//return a double number in [0,1] with uniform distribution
69+
inline double random_double(mt19937_state *state) {
70+
return ((double) rand_int(state)) / 4294967295.0;
71+
}
72+
73+
//return a integer in [0, n-1]
74+
int rand_int_n(mt19937_state *state, int n){
75+
double x = (double) rand_int(state) / 4294967296.0;
76+
return (int)(n*x);
77+
}
78+
79+
const double inv_a[] = { -3.969683028665376e+01, 2.209460984245205e+02,
80+
-2.759285104469687e+02, 1.383577518672690e+02, -3.066479806614716e+01,
81+
2.506628277459239e+00 };
82+
83+
const double inv_b[] = { -5.447609879822406e+01, 1.615858368580409e+02,
84+
-1.556989798598866e+02, 6.680131188771972e+01, -1.328068155288572e+01 };
85+
86+
const double inv_c[] = { -7.784894002430293e-03, -3.223964580411365e-01,
87+
-2.400758277161838e+00, -2.549732539343734e+00, 4.374664141464968e+00,
88+
2.938163982698783e+00 };
89+
90+
const double inv_d[] = { 7.784695709041462e-03, 3.224671290700398e-01,
91+
2.445134137142996e+00, 3.754408661907416e+00 };
92+
93+
//inverse normal distribution function, see http://home.online.no/~pjacklam/notes/invnorm/
94+
//it seems the link is broken, see http://www.psychometrica.de/norming/NormalDistribution.java for the jave implementation
95+
// or see https://github.com/stan-dev/stan/issues/1157 for another example
96+
inline double invnorm(mt19937_state *state) {
97+
double q, r;
98+
double p = (((double) rand_int(state))+0.5) / 4294967296.0; //0<p<1
99+
100+
if (p < 0.02425) {
101+
q = sqrt(-2 * log(p));
102+
return (((((inv_c[0] * q + inv_c[1]) * q + inv_c[2]) * q + inv_c[3]) * q + inv_c[4]) * q
103+
+ inv_c[5]) / ((((inv_d[0] * q + inv_d[1]) * q + inv_d[2]) * q + inv_d[3]) * q + 1);
104+
} else if (p > 0.97575) {
105+
q = sqrt(-2 * log(1 - p));
106+
return -(((((inv_c[0] * q + inv_c[1]) * q + inv_c[2]) * q + inv_c[3]) * q + inv_c[4]) * q
107+
+ inv_c[5]) / ((((inv_d[0] * q + inv_d[1]) * q + inv_d[2]) * q + inv_d[3]) * q + 1);
108+
} else {
109+
q = p - 0.5;
110+
r = q * q;
111+
return (((((inv_a[0] * r + inv_a[1]) * r + inv_a[2]) * r + inv_a[3]) * r + inv_a[4]) * r
112+
+ inv_a[5]) * q / (((((inv_b[0] * r + inv_b[1]) * r + inv_b[2]) * r + inv_b[3]) * r
113+
+ inv_b[4]) * r + 1);
114+
}
115+
}
116+
117+
void gauss_random_vector(mt19937_state *state, double *x, int n) {
118+
for (int i = 0; i < n; i++) {
119+
x[i] = invnorm(state);
120+
}
121+
}
122+
123+
//generate an array with numbers in [0, n-1]
124+
void random_integer_vector(mt19937_state *state, int *ids, int n) {
125+
for (int i = 0; i < n; i++) {
126+
ids[i] = rand_int_n(state, n);
127+
}
128+
}
129+
130+
131+
/*
132+
* generate an uniform distribution in a spherical surface
133+
* n is the total spin number, so len(spin) == 3*n
134+
*/
135+
void uniform_random_sphere(mt19937_state *state, double *spin, int n){
136+
for (int i=0;i<n;i++){
137+
int j=3*i;
138+
double phi= random_double(state)*2*WIDE_PI;
139+
double ct = 2*random_double(state)-1;
140+
double st = sqrt(1-ct*ct);
141+
spin[j] = st*cos(phi); //mx = sin(theta)*cos(phi)
142+
spin[j+1] = st*sin(phi); //my = sin(theta)*sin(phi)
143+
spin[j+2] = ct; //mz = cos(theta)
144+
}
145+
}

0 commit comments

Comments
 (0)