00001
00002
00003
00004 template<class GaugeClass, class FermiClass>
00005 class HMC {
00006
00007 private:
00008
00009 GaugeClass * to_U;
00010 GaugeClass * to_V;
00011 FermiClass * to_F;
00012 GaugeClass * to_f_U;
00013 GaugeClass * to_p_U;
00014 GaugeClass * to_old_U;
00015 GaugeClass * to_old_f_U;
00016 FermiClass * to_f_F;
00017 FermiClass * to_p_F;
00018 FermiClass * to_old_F;
00019 FermiClass * to_old_f_F;
00020
00021 public:
00022 static const int FUNDAMENTAL = 0;
00023 static const int SYMMETRIC = 1;
00024 static const int ANTISYMMETRIC = 2;
00025 coefficients coeff;
00026 double bs, bs_old;
00027 double fs, fs_old;
00028 mdp_real s_old;
00029 int dimrep;
00030 int accepted;
00031 int steps;
00032 vector<mdp_matrix> S;
00033 vector<mdp_matrix> lambda;
00034
00035 HMC(GaugeClass &U, FermiClass &F, coefficients &coeff) {
00036
00037 this->coeff = coeff;
00038 this->accepted = 0;
00039 this->steps = 0;
00040
00041 this->to_F = &F;
00042 this->to_U = &U;
00043 this->to_V = &U;
00044
00045 this->to_f_U = new GaugeClass(U.lattice(),U.nc);
00046 this->to_p_U = new GaugeClass(U.lattice(),U.nc);
00047 this->to_old_U = new GaugeClass(U.lattice(),U.nc);
00048 this->to_old_f_U = new GaugeClass(U.lattice(),U.nc);
00049
00050 this->to_f_F = new FermiClass(F.lattice(),F.nc);
00051 this->to_p_F = new FermiClass(F.lattice(),F.nc);
00052 this->to_old_F = new FermiClass(F.lattice(),F.nc);
00053 this->to_old_f_F = new FermiClass(F.lattice(),F.nc);
00054
00055 cout << to_p_U->lattice().ndim << endl;
00056
00057 initialize();
00058 }
00059
00060 ~HMC() {
00061 delete this->to_f_U;
00062 delete this->to_p_U;
00063 delete this->to_old_U;
00064 delete this->to_old_f_U;
00065 delete this->to_f_F;
00066 delete this->to_p_F;
00067 delete this->to_old_F;
00068 delete this->to_old_f_F;
00069 if(this->to_V != this->to_U) delete this->to_V;
00070 }
00071
00072 void step() {
00073 GaugeClass &U = *(this->to_U);
00074 GaugeClass &V = *(this->to_V);
00075 FermiClass &F = *(this->to_F);
00076 GaugeClass &f_U = *(this->to_f_U);
00077 FermiClass &f_F = *(this->to_f_F);
00078
00079 GaugeClass &p_U = *(this->to_p_U);
00080 GaugeClass &old_U = *(this->to_old_U);
00081 GaugeClass &old_f_U = *(this->to_old_f_U);
00082 FermiClass &p_F = *(this->to_p_F);
00083 FermiClass &old_F = *(this->to_old_F);
00084 FermiClass &old_f_F = *(this->to_old_f_F);
00085
00086 double h_old, k_old, k_new, s_new, h_new;
00087
00088
00089
00090
00091
00092
00093
00094 if(steps == 0) {
00095 bs_old = bs;
00096 fs_old = fs;
00097 s_old = compute_action(U, V, F);
00098 compute_force(U, f_U, F, f_F);
00099 }
00100
00101 compute_gaussian_momenta(p_U);
00102 set_gaussian(p_F);
00103 k_old = compute_kinetic_energy(p_U, p_F);
00104
00106
00107 h_old = s_old + k_old;
00108 old_U = U;
00109 old_F = F;
00110 old_f_U = f_U;
00111 old_f_F = f_F;
00112
00113 for(int i = 0; i<coeff["trajectory_length"]; i++)
00114 compute_fields_evolution(U, p_U, f_U, F, p_F, f_F);
00115
00116 s_new = compute_action(U, V, F);
00117 k_new = compute_kinetic_energy(p_U, p_F);
00118 h_new = s_new + k_new;
00119
00120 cout << "h_new " << h_new << endl;
00121
00122
00123 float random_number = mdp_random.plain();
00124 mdp.broadcast(random_number, 0);
00125 if(random_number<exp(h_old - h_new)) {
00126
00127 mdp << "DH: " << abs(h_new - h_old)/h_new << endl;
00128 s_old = s_new;
00129 bs_old = bs;
00130 fs_old = fs;
00131 accepted++;
00132 } else {
00133
00134 bs = bs_old;
00135 fs = fs_old;
00136 U = old_U;
00137 F = old_F;
00138 f_F = old_f_F;
00139 f_U = old_f_U;
00140 }
00141 steps++;
00142 }
00143
00144 mdp_real acceptance_rate() {
00145 return (mdp_real) accepted/steps;
00146 }
00147
00148
00149 void initialize() {
00150 GaugeClass &U = * to_U;
00151 SU_Generators g(U.nc);
00152 dimrep = U.nc*(U.nc+1)/2;
00153 lambda.resize(g.ngenerators);
00154 for(int a=0; a<lambda.size(); a++) lambda[a] = g.lambda[a];
00155 if(coeff["representation"] == FUNDAMENTAL) to_V = to_U;
00156 else if(coeff["representation"] == SYMMETRIC) {
00157 to_V = new GaugeClass(U.lattice(), dimrep);
00158 mdp_matrix tmp(U.nc, U.nc);
00159 S.resize(g.ngenerators);
00160
00161 tmp(0,0)=1.0/sqrt(2.0)*mdp_complex(1.0,0.0);
00162 tmp(1,1)=1.0/sqrt(2.0)*mdp_complex(1.0,0.0);
00163 S[0]=tmp;
00164 tmp(0,0)=mdp_complex(0.0,0.0);
00165 tmp(1,1)=mdp_complex(0.0,0.0);
00166
00167 tmp(0,1)=1.0/sqrt(2.0)*mdp_complex(1.0,0.0);
00168 tmp(1,0)=1.0/sqrt(2.0)*mdp_complex(1.0,0.0);
00169 S[1]=tmp;
00170 tmp(0,1)=mdp_complex(0.0,0.0);
00171 tmp(1,0)=mdp_complex(0.0,0.0);
00172
00173 tmp(0,0)=1.0/sqrt(2.0)*mdp_complex(1.0,0.0);
00174 tmp(1,1)=1.0/sqrt(2.0)*mdp_complex(-1.0,0.0);
00175 S[2]=tmp;
00176
00177
00178 } else if(coeff["representation"] == ANTISYMMETRIC) {
00179 throw string("ANTISYMMETRIC representation is not defined yet");
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 }
00200
00201 mdp_real compute_gaussian_momenta(GaugeClass &U) {
00202 mdp_site x(U.lattice());
00203 mdp_real re, im;
00204 forallsites(x) {
00205 for(int mu = 0; mu<U.ndim; mu++) {
00206 U(x, mu) = 0;
00207 for(int a = 0; a<dimrep; a++) {
00208 re = U.lattice().random(x).gaussian();
00209
00210
00211 U(x, mu) += re * lambda[a];
00212 }
00213 }
00214 }
00215 U.update();
00216 }
00217
00218 void set_gaussian(FermiClass &F) {
00219 mdp_site x(F.lattice());
00220 mdp_real re, im;
00221 forallsites(x) {
00222 for(int alpha = 0; alpha<F.nspin; alpha++) {
00223 for(int i = 0; i<F.nc; i++) {
00224 re = F.lattice().random(x).gaussian();
00225 im = F.lattice().random(x).gaussian();
00226 F(x, alpha, i) = (re + I * im)/sqrt(2);
00227 }
00228 }
00229 }
00230 F.update();
00231 }
00232
00233 mdp_real compute_kinetic_energy(GaugeClass &p_U, FermiClass &p_F) {
00234 mdp_complex tmp = 0;
00235 mdp_site x(p_U.lattice());
00236 forallsites(x)
00237 for(int mu = 0; mu<p_U.ndim; mu++)
00238 tmp -= 0.5 * trace(p_U(x,mu) * p_U(x,mu));
00239 mdp.add(tmp);
00240 tmp += p_F * p_F;
00241 return tmp.real();
00242 }
00243
00244 void compute_effective_links(GaugeClass &U, GaugeClass &V) {
00245 if(coeff["representation"] == FUNDAMENTAL && &U != &V)
00246 V = U;
00247 else if(coeff["representation"] == SYMMETRIC) {
00248 mdp_site x(U.lattice());
00249 forallsitesandcopies(x) {
00250 for(int mu = 0; mu<U.ndim; mu++) {
00251 for(int a = 0; a<V.nc; a++) {
00252 for(int b = 0; b<V.nc; b++) {
00253 V(x, mu, a, b) = trace(S[a] * U(x, mu) * S[b] * transpose(U(x, mu)));
00254 }
00255 }
00256 }
00257 }
00258 } else if(coeff["representation"] == ANTISYMMETRIC) {
00259 throw string("ANTISYMMETRIC representation is not defined yet");
00260 }
00261 }
00262
00263 mdp_real compute_action(GaugeClass &U, GaugeClass &V, FermiClass &F) {
00264 double action_gauge = 0.0, action_fermi = 0.0;
00265 mdp_site x(U.lattice());
00266 FermiClass inverse_F(F);
00267 double c = coeff["beta"] *(U.ndim *(U.ndim - 1) * U.lattice().nvol_gl)/2;
00268 action_gauge = - c * average_plaquette(U);
00269 if (coeff["dynamical_fermions"]>0) {
00270 compute_effective_links(U, V);
00271 CG2::inverter(inverse_F, F, V, coeff,
00272 coeff["cg_absolute_precision"],
00273 coeff["cg_relative_precision"],
00274 coeff["cg_max_steps"], true);
00275 action_fermi += real_scalar_product(F, inverse_F);
00276 }
00277 return action_gauge + action_fermi;
00278 }
00279 void compute_fields_evolution(GaugeClass &U,
00280 GaugeClass &p_U,
00281 GaugeClass &f_U,
00282 FermiClass &F,
00283 FermiClass &p_F,
00284 FermiClass &f_F) {
00285
00286 int dynamical_fermions = coeff["dynamical_fermions"];
00287 GaugeClass nf_U(f_U);
00288 FermiClass nf_F(f_F);
00289 mdp_real dt = coeff["timestep"];
00290 mdp_site x(U.lattice());
00291 GaugeClass U_temp(U);
00292 FermiClass F_temp(p_F);
00293
00294
00295
00296
00297 mdp_add_scaled_field(F_temp, 0.5 * dt, f_F);
00298
00299 mdp_add_scaled_field(F, dt, F_temp);
00300 F.update();
00301
00302 forallsites(x)
00303 for(int mu = 0; mu<U.ndim; mu++)
00304 U(x, mu) = exp(dt * p_U(x, mu) + 0.5 * dt * dt * f_U(x, mu)) * U(x, mu);
00305 U.update();
00306
00307 compute_force(U, nf_U, F, nf_F);
00308
00309 F_temp = 0;
00310
00311 mdp_add_scaled_field(F_temp, 0.5 * dt, nf_F);
00312
00313
00314 mdp_add_scaled_field(F_temp, 0.5 * dt, f_F);
00315
00316 mdp_add_scaled_field(p_F, 1, F_temp);
00317 p_F.update();
00318
00319 forallsites(x)
00320 for(int mu=0; mu<U_temp.ndim; mu++)
00321 U_temp(x,mu) = 0;
00322
00323 mdp_add_scaled_field(U_temp, 0.5 * dt, nf_U);
00324
00325
00326 mdp_add_scaled_field(U_temp, 0.5 * dt, f_U);
00327
00328 mdp_add_scaled_field(p_U, 1, U_temp);
00329 p_U.update();
00330
00331 f_U = nf_U;
00332 f_U.update();
00333 f_F = nf_F;
00334 f_F.update();
00335 }
00336
00337 void compute_force(GaugeClass &U,
00338 GaugeClass &f_U,
00339 FermiClass &F,
00340 FermiClass &f_F) {
00341
00342 int dynamical_fermions = coeff["dynamical_fermions"];
00343 mdp_site x(U.lattice());
00344 mdp_matrix staple(U.nc, U.nc);
00345 GaugeClass Udag(U.lattice(), U.nc), utmp(U.lattice(), U.nc);
00346 FermiClass sol(F.lattice(), F.nc, F.nspin);
00347 FermiClass psol(F.lattice(), F.nc, F.nspin);
00348 GaugeClass &V = *to_V;
00349
00350 forallsitesandcopies(x)
00351 for(int mu=0; mu<U.ndim; mu++)
00352 Udag(x, mu) = hermitian(U(x, mu));
00353
00354 forallsites(x) {
00355 for(int mu = 0; mu<U.ndim; mu++) {
00356 staple = 0;
00357 for(int nu = 0; nu<U.ndim; nu++)
00358 if(nu != mu)
00359 staple = staple + U(x + mu, nu) * Udag(x + nu, mu) * Udag(x, nu) +
00360 Udag(x + mu - nu, nu) * Udag(x - nu, mu) * U(x - nu, nu);
00361 staple = U(x, mu) * staple - hermitian(U(x, mu) * staple);
00362 staple -= trace(staple) * mdp_identity(U.nc)/U.nc;
00363 f_U(x, mu) = - coeff["beta"]/(2.0 * U.nc) * staple;
00364 }
00365 }
00366 f_U.update();
00367
00368 if (coeff["dynamical_fermions"] > 0) {
00369 compute_effective_links(U, V);
00370 CG2::inverter(sol, F, V, coeff,
00371 coeff["cg_absolute_precision"],
00372 coeff["cg_relative_precision"],
00373 coeff["cg_max_steps"], true);
00374 mul_Q(psol, sol, V, coeff);
00375 psol/= 2.0 * coeff["kappa"];
00376 psol.update();
00377 compute_fermion_forces(U, utmp, sol, psol);
00378
00379 f_F = 0;
00380 f_F.update();
00381 mdp_add_scaled_field(f_F, - 1, sol);
00382 f_F.update();
00383 forallsites(x)
00384 for(int mu = 0; mu<U.ndim; mu++)
00385 f_U(x, mu) -= utmp(x, mu);
00386 f_U.update();
00387 }
00388 }
00389 void compute_fermion_forces(GaugeClass &U,
00390 GaugeClass &f_U,
00391 FermiClass &sol,
00392 FermiClass &psol) {
00393
00394 mdp_site x(U.lattice());
00395 int fnc = U.nc *(U.nc + 1)/2;
00396 mdp_matrix dum(U.nc, U.nc);
00397 mdp_matrix tmp1(U.nc, U.nc);
00398 mdp_matrix tmp2(U.nc, U.nc);
00399 mdp_matrix stemp;
00400 GaugeClass Utr(U);
00401 GaugeClass Udag(U);
00402 GaugeClass Udagtr(U);
00403
00404 forallsites(x) {
00405 for(int mu = 0; mu<U.ndim; mu++) {
00406 Udag(x, mu) = hermitian(U(x, mu));
00407 Utr(x, mu) = transpose(U(x, mu));
00408 Udagtr(x, mu) = transpose(Udag(x, mu));
00409 }
00410 }
00411 Udag.update();
00412 Utr.update();
00413 Udagtr.update();
00414
00415 if(coeff["representation"] == FUNDAMENTAL) {
00416 forallsites(x) {
00417 for(int mu = 0; mu<U.ndim; mu++) {
00418 dum = 0;
00419 for(int a = 0; a<U.nc; a++) {
00420 for(int b = 0; b<U.nc; b++) {
00421 stemp = 0.5 * hermitian(spinor(psol, x, a)) *((1 - Gamma[mu]) * spinor(sol, x + mu, b));
00422 tmp1(b, a) = stemp(0, 0);
00423 stemp = 0.5 * hermitian(spinor(psol, x + mu, a)) *((1 + Gamma[mu]) * spinor(sol, x, b));
00424 tmp2(b, a) = stemp(0, 0);
00425 }
00426 }
00427 dum = tmp2 * Udag(x, mu) - U(x, mu) * tmp1;
00428 dum -= hermitian(dum);
00429 dum -= trace(dum) * mdp_identity(U.nc)/U.nc;
00430 f_U(x, mu) = dum;
00431 }
00432 }
00433 } else if(coeff["representation"] == SYMMETRIC) {
00434 forallsites(x) {
00435 for(int mu = 0; mu<U.ndim; mu++) {
00436 dum = 0;
00437 for(int a = 0; a<fnc; a++) {
00438 for(int b = 0; b<fnc; b++) {
00439 stemp = hermitian(spinor(psol, x, a)) *((1 - Gamma[mu]) * spinor(sol, x + mu, b));
00440 dum -= stemp(0, 0) * U(x, mu) * S[b] * Utr(x, mu) * S[a];
00441 stemp = hermitian(spinor(psol, x + mu, a)) *((1 + Gamma[mu]) * spinor(sol, x, b));
00442 dum += stemp(0, 0) * S[b] * Udagtr(x, mu) * S[a] * Udag(x, mu);
00443 }
00444 }
00445 dum -= hermitian(dum);
00446 dum -= trace(dum) * mdp_identity(U.nc)/U.nc;
00447 f_U(x, mu) = dum;
00448 }
00449 }
00450 } else throw string("representation not supported");
00451 f_U.update();
00452 }
00453
00454 static mdp_matrix spinor(FermiClass &psi, mdp_site x, int b) {
00455 mdp_matrix temp(psi.nspin,1);
00456 for(int i=0; i<psi.nspin; i++) temp(i,0)=psi(x,i,b);
00457 return temp;
00458 }
00459 };
00460