-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmetropolis.hpp
187 lines (168 loc) · 7.36 KB
/
metropolis.hpp
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
/**
* @file metropolis-u1.hpp
* @author Simone Romiti ([email protected])
* @brief class for Metropolis Algorithm for U(1) gauge theory
* @version 0.1
* @date 2022-09-01
*
* @copyright Copyright (c) 2022
*
*/
#include "base_program.hpp"
template <class Group> class metropolis_algo : public base_program<Group, gp::metropolis> {
private:
std::vector<double> rate = {0., 0.};
public:
metropolis_algo() { (*this).algo_name = "metropolis"; }
~metropolis_algo() {}
void print_program_info() const {
std::cout << "## Metropolis Algorithm for U(1) gauge theory\n";
}
void parse_input_file(const YAML::Node &nd) {
namespace in_metropolis = input_file_parsing::metropolis;
in_metropolis::parse_input_file(nd, (*this).pparams, (*this).sparams);
(*this).omeas = (*this).sparams.omeas;
(*this).conf_path_basename =
io::get_conf_path_basename((*this).pparams, (*this).sparams);
}
void set_omp_threads() {
#ifdef _USE_OMP_
/**
* the parallelisation of the sweep-function first iterates over all odd points in t
* and then over all even points because the nearest neighbours must not change
* during the updates, this is not possible for an uneven number of points in T
* */
if ((*this).pparams.Lt % 2 != 0) {
std::cerr << "For parallel computing an even number of points in T is needed!"
<< std::endl;
omp_set_num_threads(1);
std::cerr << "Continuing with one thread." << std::endl;
}
// set things up for parallel computing in sweep
(*this).threads = omp_get_max_threads();
#else
(*this).threads = 1;
#endif
std::cout << "threads " << (*this).threads << std::endl;
}
template <class URNG>
std::vector<double> sweep(const gp::physics &pparams,
gaugeconfig<Group> &U,
std::vector<URNG> engines,
const double &delta,
const size_t &N_hit,
const double &beta,
const double &xi = 1.0,
const bool &anisotropic = false) {
if (pparams.flat_metric) {
return flat_spacetime::sweep(U, engines, delta, N_hit, pparams.beta, pparams.xi,
pparams.anisotropic);
}
if (pparams.rotating_frame) {
spacetime_lattice::fatal_error("Rotating metric not supported yet.", __func__);
return {};
// return rotating_spacetime::sweep(U, pparams.Omega, engines, delta, N_hit,
// pparams.beta, pparams.xi,
// pparams.anisotropic);
} else {
spacetime_lattice::fatal_error("Invalid metric.", __func__);
return {};
}
}
void open_output_data() {
if ((*this).g_icounter == 0) {
(*this).os.open((*this).sparams.conf_dir + "/output.u1-metropolis.data",
std::ios::out);
} else {
(*this).os.open((*this).sparams.conf_dir + "/output.u1-metropolis.data",
std::ios::app);
}
}
/**
* @brief do the i-th sweep of the metropolis algorithm
*
* @param i trajectory index
* @param inew
*/
void do_sweep(const size_t &i, const size_t &inew) {
if ((*this).sparams.do_mcmc) {
std::vector<std::mt19937> engines((*this).threads);
for (size_t engine = 0; engine < (*this).threads; engine += 1) {
engines[engine].seed((*this).sparams.seed + i + engine);
}
rate += this->sweep((*this).pparams, (*this).U, engines, (*this).sparams.delta,
(*this).sparams.N_hit, (*this).pparams.beta, (*this).pparams.xi,
(*this).pparams.anisotropic);
double E = 0., Q = 0., energy, spatialnorm;
// number of plaquettes is different for spatial-spatial and total
double facnorm = ((*this).pparams.ndims > 2) ? (*this).pparams.ndims / ((*this).pparams.ndims - 2) : 0;
// total number of plaquettes, factor 2 because we only sum up mu>nu
double normalisation = 2.0 / (*this).pparams.ndims / ((*this).pparams.ndims - 1) / (*this).U.getVolume() / double((*this).U.getNc());
std::cout << inew;
(*this).os << inew;
for (bool ss : {false, true}) {
this->energy_density((*this).pparams, (*this).U, E, Q, false, ss);
energy = this->gauge_energy((*this).pparams, (*this).U, ss);
spatialnorm = ss ? facnorm : 1.0;
std::cout << " " << std::scientific << std::setprecision(15) << energy*normalisation*spatialnorm << " " << E << " " << Q;
(*this).os << " " << std::scientific << std::setprecision(15) << energy*normalisation*spatialnorm << " " << E << " " << Q;
}
std::cout << "\n";
(*this).os << "\n";
if (inew > 0 && (inew % (*this).sparams.N_save) == 0) {
std::ostringstream oss_i;
oss_i << (*this).conf_path_basename << "." << inew << std::ends;
((*this).U).save(oss_i.str());
}
}
return;
}
// save acceptance rates to additional file to keep track of measurements
void save_acceptance_rates() {
if ((*this).sparams.do_mcmc) {
std::cout << "## Acceptance rate " << rate[0] / double((*this).sparams.n_meas)
<< " temporal acceptance rate "
<< rate[1] / double((*this).sparams.n_meas) << std::endl;
(*this).acceptancerates.open((*this).sparams.conf_dir + "/acceptancerates.data",
std::ios::app);
(*this).acceptancerates << rate[0] / double((*this).sparams.n_meas) << " "
<< rate[1] / double((*this).sparams.n_meas) << " "
<< (*this).pparams.beta << " " << (*this).pparams.Lx << " "
<< (*this).pparams.Lt << " " << (*this).pparams.xi << " "
<< (*this).sparams.delta << " " << (*this).sparams.heat
<< " " << (*this).threads << " " << (*this).sparams.N_hit
<< " " << (*this).sparams.n_meas << " "
<< (*this).sparams.seed << " " << std::endl;
(*this).acceptancerates.close();
std::ostringstream oss;
oss << (*this).conf_path_basename << ".final" << std::ends;
((*this).U).save((*this).sparams.conf_dir + "/" + oss.str());
}
return;
}
void run(const YAML::Node &nd) {
this->pre_run(nd);
this->init_gauge_conf_mcmc();
this->set_omp_threads();
(*this).os << "## i P E Q P_ss E_ss Q_ss\n";
size_t i_min = (*this).g_icounter;
size_t i_max = (*this).sparams.n_meas * ((*this).threads) + (*this).g_icounter;
size_t i_step = (*this).threads;
/**
* do measurements:
* sweep: do N_hit Metropolis-Updates of every link in the lattice
* calculate plaquette, spacial plaquette, energy density with and without cloverdef
* and write to stdout and output-file save every nave configuration
* */
for (size_t i = i_min; i < i_max; i += i_step) {
// inew counts loops, loop-variable needed to have one RNG per thread with
// different seeds for every measurement
size_t inew = (i - (*this).g_icounter) / (*this).threads + (*this).g_icounter;
this->do_sweep(i, inew);
bool do_omeas =
((*this).sparams.do_omeas && inew != 0 && (inew % (*this).sparams.N_save) == 0);
this->after_MCMC_step(inew, do_omeas);
}
this->save_acceptance_rates();
}
};