-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMarkov.cpp
312 lines (272 loc) · 9.54 KB
/
Markov.cpp
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#include <vector>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class IsingSystem;
ostream& operator<<(ostream& os,const IsingSystem& sys);
//this vector will hold the possible values for exp
//This class holds the ising system as an vector<vector<bool>> -> bool = true or false
class IsingSystem{
////////////////
//PRIVATE FIELDS
////////////////
private:
vector<vector<int>> _system; // the system
unsigned int _size;//the size of the system
double _J; //coupling from spin spin interactions/kT
double _h; //external magnetic field*coupling/kT
double _mag; //magnetisation of the system in units of 1 spin magnetisation
double _energy; //energy of the system in units 1/kT
bool _periodic;
//////////
//SETTERS
/////////
public:
void setSpin(unsigned int row, unsigned int column, int a){
this->_system[row][column] = a;
}
void addMag(double a){
this->_mag += a;
}
void addEnergy(double a){
this->_energy += a;
}
///////////
//GETTERS
///////////
public:
int getSpin(unsigned int row, unsigned int column)const{
return this->_system[row][column];
}
unsigned int getSize()const{
return this->_size;
}
double getJ()const{
return this->_J;
}
double getH()const{
return this->_h;
}
double getMag()const{
return this->_mag;
}
double getEnergy()const{
return this->_energy;
}
//THis function will take one object in the system als argument (row, colomn) and return the amount of neighbours have the same spin
//this is needed for the calculation of the potential energy of the system
public:
unsigned int getSameneighbours(unsigned int row, unsigned int column)const{
//init the returnvalue at -1 in order to correct for the element-element count that will be made...
unsigned int returnvalue = -1;
//first we retrieve the spin of the current object
int centralspin = getSpin(row, column);
for(int i = -1; i<=1; i++ ){
for(int j = -1; j<=1; j++){
int thisspin;
if(!_periodic){
//we will need to check that we are not out of bounds !
if(row + i >= 0 && row + i < _size && column + j >= 0 && column + j < _size){
//in this case we are safely in the system and will get no OOB error
thisspin = getSpin(row + i, column + j);
}
}else{
//now we will take it into account even when we are OOB. to always get the copy inside the system
//we simply do row+i+_size%_size idd for column.
thisspin = getSpin((row + i + _size)%_size, (column+j+_size)%_size);
}
if(thisspin == centralspin){
returnvalue++;
}
}
}
return returnvalue;
}
//THis function retursn the total amount of neighbours for that particle.
public:
unsigned int getAmountneighbours(unsigned int row, unsigned int column)const{
if(_periodic){
return 8;
}
//check if the particle is on the left side or right side
unsigned int neighbours = 8;
bool a = false;
bool b = false;
if(row == 0 || row == _size-1){
a = true;
}
if(column == 0 || column == _size-1){
b = true;
}
if(a == true || b == true){
neighbours = 5;
if(a == true && b == true){
neighbours = 3;
}
}
return neighbours;
}
//this function calculates the total spin in the system
//this is needed for the init of the system
public:
int calcSpin()const{
int spin = 0;
for(unsigned int i = 0;i<_size; i++){
for(unsigned int j =0; j<_size; j++){
spin += getSpin(i,j);
}
}
return spin;
}
//this function calculates the total energy in the system
//this is needed for the init of the system
public:
double calcEnergy()const{
double energy = 0;
//loop over all the particles in the system
for(unsigned int i = 0; i< _size; i++){
for(unsigned int j = 0; j<_size; j++){
//add the same spin contribution of the particle
energy -= 0.5*_J*getSameneighbours(i,j);
//add the contribution of the spin/field interation of that particle
energy -= _h*getSpin(i,j);
}
}
return energy;
}
//this function calculates the energy change in the system if i,j were to be flipped
public:
double calcEnergydifference(unsigned int row, unsigned int column)const{
//energy b4 = -_J*(-{neigbours - sameneighbours} + sameneighbours ) + spincont
// = -_J*(+2*SN - N)
//energy a = -_J*(+{neigbours - sameneighbours} - sameneighbours ) - spincont
// = -_J*(-2*SN + N)
// a - b4 = -_J*(-4*SN + 2*N)
//TODO This formula is not reversible ! It should be adapted ?!
double a = -this->_J*(-4.*this->getSameneighbours(row, column) + 2.*this->getAmountneighbours(row, column)) + 2*this->getSpin(row, column)*this->_h;
return a;
}
public:
//constructor of the Isingsystem class. The arguments are:
//->a systemsize, amount of particles will be this squared!
//->a coupling constant(in units of inverse temperature*kB). How hard is it to flip one spin ?!
//->All particles will be initialised on the true value!
IsingSystem(unsigned int size, double J,double h, bool periodic){
for(unsigned int row = 0; row < size; row++){
vector<int> a(size, 1);
_system.push_back(a);
}
_size = size;//the size of the system
_J = J; //coupling from spin spin interactions/kT
_h = h; //external magnetic field*coupling/kT
_mag = calcSpin(); //magnetisation of the system in units of 1 spin magnetisation
_energy = calcEnergy(); //energy of the system in units 1/kT
_periodic = periodic;
}
//This function will get an i,j location. Get the amount of same spin friends.
//calculate the odds of that spin changing using the metropolis principle
//generate a random number and see if it actually spins
//returns true if spin, false if not spint
public:
bool getsSpinned(unsigned int row, unsigned int column)const{
//first we calculate the exp(-Benergy difference)
double diff = calcEnergydifference(row, column);
double probability = exp(-diff);
//generate a random number from zero to one
double random = (double)rand()/RAND_MAX;
if(probability >= random ){
return true;
}else{
return false;
}
}
//this function will get an i,j location and flip the spin
void flipSpin(unsigned int row, unsigned int column){
//adjust the energy
this->addEnergy(this->calcEnergydifference(row, column));
//adjust the magnetisation
this->addMag(-2*this->getSpin(row, column));
//adjust the actual spin
this->setSpin(row, column, -this->getSpin(row, column));
}
//this function will make one markov step --> check if one has to be spinned and spin it accordingly
void MarkovStep(){
//loop over the system
for(unsigned int i =0; i<this->getSize(); i++){
for(unsigned int j = 0; j<this->getSize(); j++){
if(this->getsSpinned(i, j)){
this->flipSpin(i,j);
}
}
}
}
//this fucntion wil excectute n markov steps for a given system
void MarkovSteps(unsigned int amount){
ofstream spins("Results.md");
ofstream data("energyandmag.md");
cout << "Simulating for " << amount << " MC steps" << endl;
cout << "-------------------------------------------------------------------" << endl;
spins << *this << endl << endl;
data << 0 << "\t" << this->getEnergy() << "\t" << this->getMag()/this->getSize()/this->getSize() << endl;
for(unsigned int i = 1; i <= amount; i++){
this->MarkovStep();
cout << "Progres: " << i << '\r';
cout.flush();
spins << *this << endl << endl;
data << i << "\t" << this->getEnergy() << "\t" << this->getMag()/this->getSize()/this->getSize() << endl;
}
cout << "Simulation completed" << endl;
//////////////////////////////////////////////////
//DANGER REGION!!!!
//THIS REGION IS NOT COMPATIBLE FOR ALL USERS!!!
//From here on I assume that you have GNUplot installed! comment this out when you do'nt have this software
cout << "Making the plots" << endl;
cout << "-------------------------------------------------------------------" << endl;
string a = "gnuplot -e \"amount = "+to_string(amount)+"\" Plot.gnu";
//The call to system will only work when you run on Linux/GNU comment this out when you don't
system(a.c_str());
cout << endl;
cout << "Making a call to ffmpeg to make a movie out of the simulation" << endl;
cout << "-------------------------------------------------------------------" << endl;
//Here i make a movie using the made plots, coomment this out when you don't have ffmpeg of gnuplot!
system("ffmpeg -y -framerate 5 -i Plot%03d.png -c:v libx264 -r 30 -pix_fmt bgr565 out.mp4");
system("rm Plot*.png");
cout << endl << endl <<"done" << endl;
}
};
ostream& operator<<(ostream& os,const IsingSystem& sys){
double size = sys.getSize();
for(unsigned int i = 0; i<size; i++){
for(unsigned int j = 0; j<size; j++){
os << i/size << "\t" << j/size << "\t" << sys.getSpin(i,j) << endl;
}
}
return os;
}
int main(){
unsigned int size;
double J;
double h;
unsigned int amount;
bool periodic;
cout << "What should the size of the system be ? size >= 3 for valid results" << endl;
cin >> size;
if(size > 5000){
cout << "THis system size will likely crash the system" << endl;
cout << "Killing progres for safety" << endl;
exit(0);
}
cout << "What should the spin-spin coupling be ? This is in units of coupling*single spin field/kT, >0" << endl;
cin >> J;
cout << "What should the spin-field coupling be ? This is in units of coupling*external field/kT" << endl;
cin >> h;
cout << "how many Mc steps do you want to do ?" << endl;
cin >> amount;
cout << "Do you want to impose periodic boundary conditions? " << endl;
cin >> periodic;
IsingSystem sys(size, J, h, periodic);
sys.MarkovSteps(amount);
}