/
energy.cpp
137 lines (120 loc) · 4.04 KB
/
energy.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
#include "readatomslinks.h"
#include "limits.h"
#include "spin.h"
#include "energy.h"
std::vector<Atom> atoms;
/**
* Computes the energy of the system.
* <p>
* Using the atom, the spin and the neighbors, it is computed the energy of the
* system.
* @param atoms vector with the spin values of the atom
* @param spin random spin orientation of the atom
* @param csr compressed sparse row that contains the information of the atoms' neighbors
* @return double ener the energy of the system.
*/
double compute_energy (
const std::vector<Atom>& atoms,
const std::vector<Spin>& spins,
const CSRMatrix& csr
)
{
/** Energy of the system. */
double ener{0};
/** Spin value of the atom and the neighbors. */
double spinValue;
for (size_t i = 0; i < atoms.size(); ++i)
{
for (int j = csr.limits[i] ; j < csr.limits[i+1]; ++j)
{
spinValue = spins[i] * spins[csr.neighboors[j]];
ener -= csr.exchanges[j] * atoms[i].s * atoms[csr.neighboors[j]].s * spinValue;
}
}
return ener * 0.5;
}
double delta_energy (
const std::vector<Atom>& atoms,
const std::vector<Spin>& spins,
const CSRMatrix& csr,
const Spin& newSpin,
int pos
)
{
double energyDiff{0};
Spin spinDiff = newSpin - spins[pos];
for (int i = csr.limits[pos] ; i < csr.limits[pos+1]; ++i)
{
double spinDot = spinDiff * spins[csr.neighboors[i]];
energyDiff -= csr.exchanges[i] * atoms[pos].s * atoms[csr.neighboors[i]].s * spinDot;
}
return energyDiff;
}
/**
* Metropolis Algorithm.
* <p>
* The Metropolis algorithm is used to accept or reject a change in the state
* of the sample. Randomly changing a spin direction, the energy of the system
* is computed. If the energy is lower than the energy before the change, the
* new state is accepted. If not, an exponential function is calculated and
* compared with a random number between zero and one. If the exponential is
* greater than the random number the change is accepted. If not the initial
* state is preserved.
*
* @param tempMax Maximum loop temperature
* @param atoms Atom type vector with the characteristics of each atom in the sample
* @param al ReadAtomLinks type that contain information about the number of atoms in the sample
* @param iterations number of changes of spin direction in each temperature
* @param csr compressed sparse row that contains the information of the atoms' neighbors
*/
void metropolis(
int tempMax,
int tempStep,
const std::vector<Atom>& atoms,
const ReadAtomsLinks& al,
long int iterations,
const CSRMatrix& csr
)
{
int natoms{al.natoms()};
std::mt19937 sequence;
std::uniform_int_distribution<> dis(0, natoms-1);
std::uniform_real_distribution<> met(0, 1);
RandomSpinGenerator randSpinGen(sequence);
std::vector<Spin> state(al.natoms(), Spin::null());
std::generate(state.begin(), state.end(), randSpinGen);
double energy = compute_energy(atoms, state, csr);
/*std::ofstream myfile;
myfile.open ("Experiments/energias.dat");*/
for (int Temp = tempMax; Temp >= 0; Temp -= tempStep)
{
//myfile << energy << "\n";
//std::cout << "Temperature = " << Temp << std::endl;
for (int i = 0; i < iterations; ++i)
{
int site{dis(sequence)};
Spin aleatorio = Spin::randSpin(sequence);
double energyDiff = delta_energy(atoms, state, csr, aleatorio, site);
if (energyDiff < 0)
{
state[site] = aleatorio;
energy += energyDiff;
//myfile << energy << "\n";
}
else
{
if (std::exp(- (energyDiff)/Temp) >= met(sequence))
{
state[site] = aleatorio;
energy += energyDiff;
//myfile << energy << "\n";
}
else
{
//myfile << energy << "\n";
}
}
}
//myfile.close();
}
}