Bridge++  Ver. 1.3.x
gradientFlow.cpp
Go to the documentation of this file.
1 
14 #include "gradientFlow.h"
15 
16 //- parameter entries
17 namespace {
18  void append_entry(Parameters& param)
19  {
20  param.Register_int("order_of_RungeKutta", 0);
21  param.Register_double("step_size", 0.0);
22  param.Register_int("order_of_approx_for_exp_iP", 0);
23  param.Register_double("tolerance", 0.0);
24  param.Register_double("safety_factor", 0.0);
25  param.Register_int("adaptive", 0);
26 
27  param.Register_string("verbose_level", "NULL");
28  }
29 
30 
31 #ifdef USE_PARAMETERS_FACTORY
32  bool init_param = ParametersFactory::Register("GradientFlow", append_entry);
33 #endif
34 }
35 //- end
36 
37 //- parameters class
39 //- end
40 
41 const std::string GradientFlow::class_name = "GradientFlow";
42 
43 //====================================================================
45  : m_vl(CommonParameters::Vlevel()),
46  m_action(action),
47  m_impl(0)
48 {
49  initialize();
50 }
51 
52 
53 //====================================================================
55  : m_vl(CommonParameters::Vlevel()),
56  m_action(action.get()),
57  m_impl(0)
58 {
59  initialize();
60 }
61 
62 
63 //====================================================================
65 {
66  m_Nprec = 0;
67  m_Estep = 0.0;
68 }
69 
70 
71 //====================================================================
73 {
74  const string str_vlevel = params.get_string("verbose_level");
75 
76  m_vl = vout.set_verbose_level(str_vlevel);
77 
78  //- fetch and check input parameters
79  int order_RK;
80  double Estep;
81  int Nprec;
82  double tol_RK, safety;
83  int is_adaptive;
84 
85  int err = 0;
86  err += params.fetch_int("order_of_RungeKutta", order_RK);
87  err += params.fetch_double("step_size", Estep);
88  err += params.fetch_int("order_of_approx_for_exp_iP", Nprec);
89 
90  err += params.fetch_int("adaptive", is_adaptive);
91 
92  if (is_adaptive != 0) { // mandatory only if adaptive is on.
93  err += params.fetch_double("tolerance", tol_RK);
94  err += params.fetch_double("safety_factor", safety);
95  } else {
96  params.fetch_double("tolerance", tol_RK);
97  params.fetch_double("safety_factor", safety);
98  }
99 
100  if (err) {
101  vout.crucial(m_vl, "%s: fetch error, input parameter not found.\n", class_name.c_str());
102  exit(EXIT_FAILURE);
103  }
104 
105  set_parameters(order_RK, Estep, Nprec, tol_RK, safety, is_adaptive);
106 }
107 
108 
109 //====================================================================
111  const int order_RK,
112  const double Estep, const int Nprec,
113  const double tol_RK, const double safety,
114  const int is_adaptive)
115 {
116  //- print input parameters
117  vout.general(m_vl, "Parameters of %s:\n", class_name.c_str());
118  vout.general(m_vl, " order_RK = %d\n", order_RK);
119  vout.general(m_vl, " Estep = %10.6f\n", Estep);
120  vout.general(m_vl, " Nprec = %d\n", Nprec);
121  vout.general(m_vl, " tol_RK = %10.6e\n", tol_RK);
122  vout.general(m_vl, " safety = %10.6f\n", safety);
123  vout.general(m_vl, " adaptive = %d\n", is_adaptive);
124 
125  //- range check
126  int err = 0;
127  err += ParameterCheck::non_negative(order_RK);
128  err += ParameterCheck::square_non_zero(Estep);
129  err += ParameterCheck::non_negative(Nprec);
130  err += ParameterCheck::non_negative(tol_RK);
131  err += ParameterCheck::non_negative(safety);
132 
133  if (err) {
134  vout.crucial(m_vl, "%s: parameter range check failed.\n", class_name.c_str());
135  exit(EXIT_FAILURE);
136  }
137 
138  //- store values
139  m_order_RK = order_RK; // order of Runge-Kutta
140  m_Estep = Estep; // step size (SA)
141  m_Nprec = Nprec; // order of approximation for e^{iP} (SA)
142  m_tol_RK = tol_RK;
143  m_safety = safety;
144  m_adaptive = (is_adaptive == 0) ? false : true;
145 
146  set_parameter_order(order_RK, m_adaptive);
147 }
148 
149 
150 //====================================================================
152 {
153  public:
155  : m_action(action),
156  m_Nprec(nprec),
157  m_Ndim(CommonParameters::Ndim()),
158  m_Nvol(CommonParameters::Nvol()),
159  m_vl(vl)
160  {}
161 
162  virtual ~RungeKutta() {}
163 
164  virtual void flow(double& t, double& Estep, Field_G& U) = 0;
165 
166  void update_u(Field_G& W, const double Estep, Field_G& iP, Field_G& U);
167 
168  virtual int order() const = 0;
169 
170  protected:
172  int m_Nprec;
173 
174  int m_Ndim;
175  int m_Nvol;
176 
178 };
179 
180 //====================================================================
181 namespace {
182  // w = exp(alpha iv) u
183  void exponential(Mat_SU_N& w, const double alpha, const Mat_SU_N& iv, const Mat_SU_N& u, const int nprec)
184  {
186 
187  w = u;
188 
189  for (int iprec = 0; iprec < nprec; ++iprec) {
190  double exf = alpha / (nprec - iprec);
191 
192  p = iv * w;
193  p *= exf;
194  w = p;
195  w += u; // w' = u + 1/(n-k) alpha iv ( w )
196  }
197 
198  w.reunit();
199  }
200 }
201 
202 //====================================================================
203 void GradientFlow::RungeKutta::update_u(Field_G& W, const double Estep, Field_G& iP, Field_G& U)
204 {
205  int Nvol = U.nvol();
206  int Nex = U.nex();
207  int Nc = CommonParameters::Nc();
208 
209  Mat_SU_N u0(Nc), v0(Nc), w0(Nc);
210 
211  for (int ex = 0; ex < Nex; ++ex) {
212  for (int site = 0; site < Nvol; ++site) {
213  u0 = U.mat(site, ex);
214  v0 = iP.mat(site, ex);
215 
216  exponential(w0, Estep, v0, u0, m_Nprec);
217 
218  W.set_mat(site, ex, w0);
219  }
220  }
221 }
222 
223 
224 //====================================================================
226 {
227  public:
229  : RungeKutta(action, nprec, vl)
230  {
231  z0.reset(m_Nvol, m_Ndim);
232  }
233 
234  void flow(double& t, double& Estep, Field_G& U);
235 
236  int order() const { return 1; }
237 
238  private:
239 
241 };
242 
243 //====================================================================
244 void GradientFlow::RungeKutta_1st::flow(double& t, double& Estep, Field_G& U)
245 {
246  Field_G& w0 = U;
247  Field_G& w1 = U;
248 
249  // Field_G z0 = w0.clone();
250 
251  //- step 0
252  // calculate gradient of m_action Z_0 (SA)
253  m_action->force(z0, &w0);
254 
255  // W_1=e^{Z_0}*U
256  update_u(w1, Estep, z0, w0); // assume it is ok for w = u case.
257 
258  t += Estep;
259 }
260 
261 
262 //====================================================================
264 {
265  public:
267  : RungeKutta(action, nprec, vl)
268  {
269  w1.reset(m_Nvol, m_Ndim);
270  z0.reset(m_Nvol, m_Ndim);
271  z1.reset(m_Nvol, m_Ndim);
272  }
273 
274  void flow(double& t, double& Estep, Field_G& U);
275 
276  int order() const { return 2; }
277 
278  private:
281 };
282 
283 //====================================================================
284 void GradientFlow::RungeKutta_2nd::flow(double& t, double& Estep, Field_G& U)
285 {
286  Field_G& w0 = U;
287  // Field_G w1 = w0.clone();
288  Field_G& w2 = U;
289 
290  // Field_G z0 = w0.clone();
291  // Field_G z1 = w0.clone();
292  // Field_G zt = w0.clone();
293 
294  //- step 0
295  // calculate gradient of m_action Z_0 (SA)
296  m_action->force(z0, &w0);
297 
298  // W_1=e^{c2*Z_0}*U
299  update_u(w1, 0.5 * Estep, z0, w0);
300 
301  //- step 1
302  // Z_1
303  m_action->force(z1, &w1);
304 
305  // V_out=e^{Z_1}*W_0
306  update_u(w2, Estep, z1, w0);
307 
308  t += Estep;
309 }
310 
311 
312 //====================================================================
314 {
315  public:
317  : RungeKutta(action, nprec, vl)
318  {
319  w1.reset(m_Nvol, m_Ndim);
320  w2.reset(m_Nvol, m_Ndim);
321 
322  z0.reset(m_Nvol, m_Ndim);
323  z1.reset(m_Nvol, m_Ndim);
324  z2.reset(m_Nvol, m_Ndim);
325 
326  zt.reset(m_Nvol, m_Ndim);
327  }
328 
329  void flow(double& t, double& Estep, Field_G& U);
330 
331  int order() const { return 3; }
332 
333  private:
337 };
338 
339 //====================================================================
340 void GradientFlow::RungeKutta_3rd::flow(double& t, double& Estep, Field_G& U)
341 {
342  const double a0 = 0.25;
343 
344  const double b0 = -17.0 / 36.0;
345  const double b1 = 8.0 / 9.0;
346 
347  const double c0 = 17.0 / 36.0;
348  const double c1 = -8.0 / 9.0;
349  const double c2 = 0.75;
350 
351  Field_G& w0 = U;
352  // Field_G w1 = w0.clone();
353  // Field_G w2 = w0.clone();
354  Field_G& w3 = U;
355 
356  // Field_G z0 = w0.clone();
357  // Field_G z1 = w0.clone();
358  // Field_G z2 = w0.clone();
359 
360  // Field_G zt = w0.clone();
361 
362  //- step 0
363  // calculate gradient of m_action Z_0 (SA)
364  m_action->force(z0, &w0);
365 
366  // zt = a0 * z0 = 1/4 z0
367  copy(zt, z0);
368  scal(zt, a0);
369 
370  // W_1=e^{Z_0/4}*U (SA)
371  update_u(w1, Estep, zt, w0);
372 
373  //- step 1
374  // Z_1 (SA)
375  m_action->force(z1, &w1);
376 
377  // zt = b1 * z1 + b0 * z0 = 8/9 z1 - 17/36 z0
378  copy(zt, z1);
379  scal(zt, b1);
380  axpy(zt, b0, z0);
381 
382  // W_2=e^{8*Z_1/9-17*Z_0/36}*W_1 (SA)
383  update_u(w2, Estep, zt, w1);
384 
385  //- step 2
386  // Z_2 (SA)
387  m_action->force(z2, &w2);
388 
389  // zt = c2 * z2 + c1 * z1 * c0 * z0
390  // = 3/4 z2 - 8/9 z1 + 17/36 z0
391  // = 3/4 z2 - zt_prev
392  copy(zt, z2);
393  scal(zt, c2);
394  axpy(zt, c1, z1);
395  axpy(zt, c0, z0);
396 
397  // V_out=e^{3*Z_2/4-8*Z_1/9+17*Z_0/36}*W_2 (SA)
398  update_u(w3, Estep, zt, w2);
399 
400  t += Estep;
401 }
402 
403 
404 //====================================================================
406 {
407  public:
409  : RungeKutta(action, nprec, vl)
410  {
411  w1.reset(m_Nvol, m_Ndim);
412  w2.reset(m_Nvol, m_Ndim);
413  w3.reset(m_Nvol, m_Ndim);
414  w4.reset(m_Nvol, m_Ndim);
415 
416  z0.reset(m_Nvol, m_Ndim);
417  z1.reset(m_Nvol, m_Ndim);
418  z2.reset(m_Nvol, m_Ndim);
419  z3.reset(m_Nvol, m_Ndim);
420  z4.reset(m_Nvol, m_Ndim);
421 
422  zt.reset(m_Nvol, m_Ndim);
423  }
424 
425  void flow(double& t, double& Estep, Field_G& U);
426 
427  int order() const { return 4; }
428 
429  private:
433 };
434 
435 //====================================================================
436 void GradientFlow::RungeKutta_4th::flow(double& t, double& Estep, Field_G& U)
437 {
438  Field_G& w0 = U;
439  // Field_G w1 = w0.clone();
440  // Field_G w2 = w0.clone();
441  // Field_G w3 = w0.clone();
442  // Field_G w4 = w0.clone();
443  Field_G& w5 = U;
444 
445  // Field_G z0 = w0.clone();
446  // Field_G z1 = w0.clone();
447  // Field_G z2 = w0.clone();
448  // Field_G z3 = w0.clone();
449  // Field_G z4 = w0.clone();
450 
451  // Field_G zt = w0.clone();
452 
453  //- step 0
454  // calculate gradient of m_action Z_0 (SA)
455  m_action->force(z0, &w0);
456 
457  copy(zt, z0);
458  scal(zt, 0.5);
459 
460  // W_1=e^{Z_0/2}*U (SA)
461  update_u(w1, Estep, zt, w0);
462 
463  //- step 1
464  // Z_1
465  m_action->force(z1, &w1);
466 
467  copy(zt, z1);
468  scal(zt, 0.5);
469 
470  // W_2=e^{(1/2)*Z_1}*W_0
471  update_u(w2, Estep, zt, w0);
472 
473  //- step 2
474  // Z_2
475  m_action->force(z2, &w2);
476 
477  // Z_2 - (1/2)*Z_0
478  copy(zt, z2);
479  axpy(zt, -0.5, z0);
480 
481  // W_3=e^{Z_2 - (1/2)*Z_0}*W_1 NB. not W_0
482  update_u(w3, Estep, zt, w1);
483 
484  //- step 3
485  // Z_3
486  m_action->force(z3, &w3);
487 
488  // 3*Z_0+2*Z_1+2*Z_2-Z_3
489  copy(zt, z0);
490  scal(zt, 0.25);
491  axpy(zt, 1.0 / 6.0, z1);
492  axpy(zt, 1.0 / 6.0, z2);
493  axpy(zt, -1.0 / 12.0, z3);
494 
495  // W_4=e^{(1/12)*(3*Z_0+2*Z_1+2*Z_2-Z_3)}*W_0
496  update_u(w4, Estep, zt, w0);
497 
498  //- step 4 (extra step)
499 
500  // 1/12*(-Z_0+2*Z_1+2*Z_2+3*Z_3)
501  copy(zt, z0);
502  scal(zt, -1.0 / 12.0);
503  axpy(zt, 1.0 / 6.0, z1);
504  axpy(zt, 1.0 / 6.0, z2);
505  axpy(zt, 0.25, z3);
506 
507  // V_t=e^{(1/12)*(-Z_0+2*Z_1+2*Z_2+3*Z_3)}*W_4 NB. not W_0
508  update_u(w5, Estep, zt, w4);
509 
510  t += Estep;
511 }
512 
513 
514 //====================================================================
516 {
517  public:
518  AdaptiveRungeKutta(RungeKutta *rk, double tol, double safety, Bridge::VerboseLevel vl)
519  : RungeKutta(0, 0, vl),
520  m_rk(rk),
521  m_tol_RK(tol),
522  m_safety(safety)
523  {
526  }
527 
528  ~AdaptiveRungeKutta() { if (m_rk) delete m_rk; }
529 
530  void flow(double& t, double& Estep, Field_G& U);
531 
532  int order() const { return m_rk ? m_rk->order() : 0; }
533 
534  double max_diff(const Field_G& u1, const Field_G& u2) const;
535 
536  protected:
538 
539  double m_tol_RK;
540  double m_safety;
541 
543 };
544 
545 //====================================================================
546 void GradientFlow::AdaptiveRungeKutta::flow(double& t, double& Estep, Field_G& U)
547 {
548  copy(u_rough, U);
549  copy(u_fine, U);
550 
551  while (true)
552  {
553  //- rough step
554  double t2 = t;
555  double estep2 = 2.0 * Estep;
556 
557  m_rk->flow(t2, estep2, u_rough);
558 
559  //- two original steps
560  double t1 = t;
561  double estep1 = Estep;
562 
563  m_rk->flow(t1, estep1, u_fine);
564  m_rk->flow(t1, estep1, u_fine);
565 
566  double diff = max_diff(u_rough, u_fine);
567 
568  vout.general(m_vl, " Estep,diff,m_tol_RK = %e %e %e\n", Estep, diff, m_tol_RK);
569 
570  if (diff < m_tol_RK) {
571  copy(U, u_fine);
572  t += estep2;
573 
574  // extend stepsize
575  Estep *= m_safety * pow(m_tol_RK / diff, 1.0 / (order() + 1));
576 
577  break; // exit loop
578  } else {
579  // shrink stepsize
580  Estep *= m_safety * pow(m_tol_RK / diff, 1.0 / (order() + 1));
581 
582  if (Estep < m_tol_RK) {
583  vout.crucial(m_vl, "%s: too small Estep = %e\n", class_name.c_str(), Estep);
584  exit(EXIT_FAILURE);
585  }
586 
587  // proceed to next trial
588  }
589  }
590 }
591 
592 
593 //====================================================================
595 {
596  int Nvol = f1.nvol();
597  int Nex = f2.nex();
598  int Nc = CommonParameters::Nc();
599 
600  Mat_SU_N u0(Nc), u1(Nc), u2(Nc);
601 
602  double max_norm = 0.0;
603 
604  for (int ex = 0; ex < Nex; ++ex) {
605  for (int site = 0; site < Nvol; ++site) {
606  f1.mat(u0, site, ex);
607  f2.mat(u1, site, ex);
608 
609  u2 = u0 - u1;
610 
611  double norm = sqrt(u2.norm2()) / Nc;
612 
613  if (norm > max_norm) max_norm = norm;
614  }
615  }
616 
617  max_norm = Communicator::reduce_max(max_norm);
618 
619  return max_norm;
620 }
621 
622 
623 //====================================================================
625 {
626  if (m_impl) delete m_impl;
627 }
628 
629 
630 //====================================================================
631 void GradientFlow::set_parameter_order(const int order, bool is_adaptive)
632 {
633  m_order_RK = order;
634 
635  switch (order)
636  {
637  case 1:
639  break;
640 
641  case 2:
643  break;
644 
645  case 3:
647  break;
648 
649  case 4:
651  break;
652 
653  default:
654  vout.crucial(m_vl, "%s: order of Runge-Kutta is out of range.\n", class_name.c_str());
655  exit(EXIT_FAILURE);
656  }
657 
658  if (is_adaptive) {
660  }
661 }
662 
663 
664 //====================================================================
665 double GradientFlow::evolve(double& t_flow, Field_G& U)
666 {
667  double plaq = m_staple.plaquette(U);
668 
669  vout.general(m_vl, " plaq_org = %.16f\n", plaq); // write-out
670 
671  //- time evolution (SA)
672  m_impl->flow(t_flow, m_Estep, U);
673 
674 // t_flow += m_Estep;
675 
676  plaq = m_staple.plaquette(U);
677  double Eplaq = t_flow * t_flow * 36.0 * (1.0 - plaq); // t^2*E=t^2*36*(1-Plaq)
678 
679  vout.general(m_vl, " (t, plaq, t^2 E_plaq) = %.8f %.16f %.16f\n", t_flow, plaq, Eplaq);
680 
681  double result = Eplaq;
682 
683  return result;
684 }
685 
686 
687 //====================================================================
688 //============================================================END=====
static const std::string class_name
Definition: gradientFlow.h:54
double m_Estep
Definition: gradientFlow.h:61
void scal(Field &x, const double a)
scal(x, a): x = a * x
Definition: field.cpp:282
AdaptiveRungeKutta(RungeKutta *rk, double tol, double safety, Bridge::VerboseLevel vl)
BridgeIO vout
Definition: bridgeIO.cpp:278
Action * m_action
Definition: gradientFlow.h:66
void Register_string(const string &, const string &)
Definition: parameters.cpp:351
static int reduce_max(int count, double *recv_buf, double *send_buf, int pattern=0)
find a global maximum of an array of double over the communicator. pattern specifies the dimensions t...
void general(const char *format,...)
Definition: bridgeIO.cpp:65
void set_parameter_order(const int order, const bool is_adaptive)
void Register_int(const string &, const int)
Definition: parameters.cpp:330
void flow(double &t, double &Estep, Field_G &U)
void reset(const int Nvol, const int Nex)
Definition: field_G.h:78
void flow(double &t, double &Estep, Field_G &U)
void flow(double &t, double &Estep, Field_G &U)
int nvol() const
Definition: field.h:116
double plaquette(const Field_G &)
calculates plaquette value.
Definition: staples.cpp:36
virtual int order() const =0
GradientFlow(Action *action)
Class for parameters.
Definition: parameters.h:38
void copy(Field &y, const Field &x)
copy(y, x): y = x
Definition: field.cpp:381
Bridge::VerboseLevel m_vl
Base class of HMC action class family.
Definition: action.h:42
void flow(double &t, double &Estep, Field_G &U)
Mat_SU_N & reunit()
Definition: mat_SU_N.h:71
int square_non_zero(const double v)
Definition: checker.cpp:41
RungeKutta_2nd(Action *action, int nprec, Bridge::VerboseLevel vl)
RungeKutta_3rd(Action *action, int nprec, Bridge::VerboseLevel vl)
SU(N) gauge field.
Definition: field_G.h:38
double max_diff(const Field_G &u1, const Field_G &u2) const
virtual void force(Field &)=0
returns force for molcular dynamical update of conjugate momenta.
int nex() const
Definition: field.h:117
Common parameter class: provides parameters as singleton.
RungeKutta(Action *action, int nprec, Bridge::VerboseLevel vl)
void axpy(Field &y, const double a, const Field &x)
axpy(y, a, x): y := a * x + y
Definition: field.cpp:168
void crucial(const char *format,...)
Definition: bridgeIO.cpp:48
double norm2()
Definition: mat_SU_N.h:155
static bool Register(const std::string &realm, const creator_callback &cb)
Bridge::VerboseLevel vl
Definition: checker.cpp:18
Bridge::VerboseLevel m_vl
Definition: gradientFlow.h:57
RungeKutta_4th(Action *action, int nprec, Bridge::VerboseLevel vl)
VerboseLevel
Definition: bridgeIO.h:39
void flow(double &t, double &Estep, Field_G &U)
double m_tol_RK
Definition: gradientFlow.h:63
RungeKutta * m_impl
Definition: gradientFlow.h:77
int non_negative(const int v)
Definition: checker.cpp:21
void Register_double(const string &, const double)
Definition: parameters.cpp:323
double evolve(double &t_flow, Field_G &U)
double m_safety
Definition: gradientFlow.h:63
int fetch_double(const string &key, double &val) const
Definition: parameters.cpp:124
string get_string(const string &key) const
Definition: parameters.cpp:87
void set_mat(const int site, const int mn, const Mat_SU_N &U)
Definition: field_G.h:159
void initialize()
Mat_SU_N mat(const int site, const int mn=0) const
Definition: field_G.h:113
int fetch_int(const string &key, int &val) const
Definition: parameters.cpp:141
void set_parameters(const Parameters &params)
RungeKutta_1st(Action *action, int nprec, Bridge::VerboseLevel vl)
virtual void flow(double &t, double &Estep, Field_G &U)=0
static VerboseLevel set_verbose_level(const std::string &str)
Definition: bridgeIO.cpp:28
Staples m_staple
Definition: gradientFlow.h:67
void update_u(Field_G &W, const double Estep, Field_G &iP, Field_G &U)