-
Notifications
You must be signed in to change notification settings - Fork 0
/
metropolis.c
125 lines (99 loc) · 4.28 KB
/
metropolis.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <gsl/gsl_rng.h>
#include <omp.h>
#include "structs.h"
#include "geometry.h"
#include "vmath.h"
void step_mc(char *s, gsl_rng * r, parameters params) {
static long int *neighbours = NULL;
static long int prev_N, prev_D, L;
double r_max = gsl_rng_max(r);
//Check if geometry parameters have changed. If yes, free, reallocate and recalculate the next neighbours the array again
if((neighbours == NULL) || (prev_N != params.N) || (prev_D != params.D)){
if(neighbours != NULL){free(neighbours);}
neighbours = malloc(2*params.D*params.L*sizeof(long int));
nneighbour_init(neighbours, params.N, params.D);
prev_N = params.N;
prev_D = params.D;
}
//Loop over all points i in the lattice
for(long int i=0; i<params.L; i++){
double diff_H = 0;
// loop over all dimensions, for there are 2 next neighbours of point i in each dimension
for(int d=0; d<params.D; d++){
diff_H += s[i]*(s[neighbours[2*(i*params.D+d)]]+s[neighbours[2*(i*params.D+d)+1]]);
}
diff_H = 2*(diff_H + params.B*s[i]);
// now calculate p as exponential
double p = exp(-1*params.beta*diff_H);
// if p is greater than one, the energy is smaller with flipped spin,
// so the spin is flipped
if (p >= 1) {
s[i] *= -1;
} else if (gsl_rng_get (r)/r_max < p) { // if p is smaller than 1, flip spin with probability p
s[i] *= -1;
}
}
// after iterating over all lattice points, the MC step is completed
}
void step_mc_omp(char *s, gsl_rng * r, parameters params) {
static long int *neighbours = NULL;
static long int prev_N, prev_D, L;
double r_max = gsl_rng_max(r);
//Check if geometry parameters have changed. If yes, free, reallocate and recalculate the next neighbours the array again
if((neighbours == NULL) || (prev_N != params.N) || (prev_D != params.D)){
if(neighbours != NULL){free(neighbours);}
neighbours = malloc(2*params.D*params.L*sizeof(long int));
nneighbour_init(neighbours, params.N, params.D);
prev_N = params.N;
prev_D = params.D;
}
//Loop over all points i in the lattice
#pragma omp parallel for
for(long int i=0; i<params.L; i++){
double diff_H = 0;
// loop over all dimensions, for there are 2 next neighbours of point i in each dimension
for(int d=0; d<params.D; d++){
diff_H += s[i]*(s[neighbours[2*(i*params.D+d)]]+s[neighbours[2*(i*params.D+d)+1]]);
}
diff_H = 2*(diff_H + params.B*s[i]);
// now calculate p as exponential
double p = exp(-1*params.beta*diff_H);
// if p is greater than one, the energy is smaller with flipped spin,
// so the spin is flipped
if (p >= 1) {
s[i] *= -1;
} else if (gsl_rng_get (r)/r_max < p) { // if p is smaller than 1, flip spin with probability p
s[i] *= -1;
}
}
// after iterating over all lattice points, the MC step is completed
}
// this function calculates the sum over the b(z) * s(z) extracted from step_mc
double calc_b(char *s, parameters params) {
static long int *neighbours = NULL;
static long int prev_N, prev_D, L;
//Check if geometry parameters have changed. If yes, free, reallocate and recalculate the next neighbours the array again
if((neighbours == NULL) || (prev_N != params.N) || (prev_D != params.D)){
if(neighbours != NULL){free(neighbours);}
neighbours = malloc(2*params.D*params.L*sizeof(long int));
nneighbour_init(neighbours, params.N, params.D);
prev_N = params.N;
prev_D = params.D;
}
double diff_H_test = 0;
//Loop over all points i in the lattice
for(long int i=0; i<params.L; i++){
double diff_H = 0;
// loop over all dimensions, for there are 2 next neighbours of point i in each dimension
// this is the first term of the sum in eq. (35)
for(int d=0; d<params.D; d++){
diff_H += s[i]*(s[neighbours[2*(i*params.D+d)]]+s[neighbours[2*(i*params.D+d)+1]]);
}
// add the second term of the sum an add them all up
diff_H_test += diff_H + params.B*s[i];
}
return diff_H_test;
}