/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/qcd/hmc/integrators/Integrator.h Copyright (C) 2015 Author: Azusa Yamaguchi Author: Peter Boyle Author: neo Author: paboyle This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. See the full license in the file "LICENSE" in the top level distribution directory *************************************************************************************/ /* END LEGAL */ //-------------------------------------------------------------------- /*! @file Integrator.h * @brief Classes for the Molecular Dynamics integrator * * @author Guido Cossu * Time-stamp: <2015-07-30 16:21:29 neo> */ //-------------------------------------------------------------------- #ifndef INTEGRATOR_INCLUDED #define INTEGRATOR_INCLUDED // class Observer; #include namespace Grid { namespace QCD { struct IntegratorParameters { int Nexp; int MDsteps; // number of outer steps RealD trajL; // trajectory length RealD stepsize; IntegratorParameters(int MDsteps_, RealD trajL_ = 1.0, int Nexp_ = 12) : Nexp(Nexp_), MDsteps(MDsteps_), trajL(trajL_), stepsize(trajL / MDsteps){ // empty body constructor }; }; /*! @brief Class for Molecular Dynamics management */ template class Integrator { protected: typedef IntegratorParameters ParameterType; IntegratorParameters Params; const ActionSetHirep as; int levels; // double t_U; // Track time passing on each level and for U and for P std::vector t_P; // GaugeField P; SmearingPolicy& Smearer; RepresentationPolicy Representations; // Should match any legal (SU(n)) gauge field // Need to use this template to match Ncol to pass to SU class template void generate_momenta(Lattice >, Nd> >& P, GridParallelRNG& pRNG) { typedef Lattice > > > GaugeLinkField; GaugeLinkField Pmu(P._grid); Pmu = zero; for (int mu = 0; mu < Nd; mu++) { SU::GaussianFundamentalLieAlgebraMatrix(pRNG, Pmu); PokeIndex(P, Pmu, mu); } } // ObserverList observers; // not yet // typedef std::vector ObserverList; // void register_observers(); // void notify_observers(); void update_P(GaugeField& U, int level, double ep) { t_P[level] += ep; update_P(P, U, level, ep); std::cout << GridLogIntegrator << "[" << level << "] P " << " dt " << ep << " : t_P " << t_P[level] << std::endl; } // to be used by the actionlevel class to iterate // over the representations struct _updateP { template void operator()(std::vector*> repr_set, Repr& Rep, GF& Mom, GF& U, double ep) { for (int a = 0; a < repr_set.size(); ++a) { FieldType forceR(U._grid); // Implement smearing only for the fundamental representation now repr_set.at(a)->deriv(Rep.U, forceR); GF force = Rep.RtoFundamentalProject(forceR); // Ta for the fundamental rep std::cout << GridLogIntegrator << "Hirep Force average: " << norm2(force) / (U._grid->gSites()) << std::endl; Mom -= force * ep ; } } } update_P_hireps{}; void update_P(GaugeField& Mom, GaugeField& U, int level, double ep) { // input U actually not used in the fundamental case // Fundamental updates, include smearing for (int a = 0; a < as[level].actions.size(); ++a) { GaugeField force(U._grid); GaugeField& Us = Smearer.get_U(as[level].actions.at(a)->is_smeared); as[level].actions.at(a)->deriv(Us, force); // deriv should NOT include Ta std::cout << GridLogIntegrator << "Smearing (on/off): " << as[level].actions.at(a)->is_smeared << std::endl; if (as[level].actions.at(a)->is_smeared) Smearer.smeared_force(force); force = Ta(force); std::cout << GridLogIntegrator << "Force average: " << norm2(force) / (U._grid->gSites()) << std::endl; Mom -= force * ep; } // Force from the other representations as[level].apply(update_P_hireps, Representations, Mom, U, ep); } void update_U(GaugeField& U, double ep) { update_U(P, U, ep); t_U += ep; int fl = levels - 1; std::cout << GridLogIntegrator << " " << "[" << fl << "] U " << " dt " << ep << " : t_U " << t_U << std::endl; } void update_U(GaugeField& Mom, GaugeField& U, double ep) { // rewrite exponential to deal internally with the lorentz index? for (int mu = 0; mu < Nd; mu++) { auto Umu = PeekIndex(U, mu); auto Pmu = PeekIndex(Mom, mu); Umu = expMat(Pmu, ep, Params.Nexp) * Umu; PokeIndex(U, ProjectOnGroup(Umu), mu); } // Update the smeared fields, can be implemented as observer Smearer.set_GaugeField(U); // Update the higher representations fields Representations.update(U); // void functions if fundamental representation } virtual void step(GaugeField& U, int level, int first, int last) = 0; public: Integrator(GridBase* grid, IntegratorParameters Par, ActionSetHirep& Aset, SmearingPolicy& Sm) : Params(Par), as(Aset), P(grid), levels(Aset.size()), Smearer(Sm), Representations(grid) { t_P.resize(levels, 0.0); t_U = 0.0; // initialization of smearer delegated outside of Integrator }; virtual ~Integrator() {} // to be used by the actionlevel class to iterate // over the representations struct _refresh { template void operator()(std::vector*> repr_set, Repr& Rep, GridParallelRNG& pRNG) { for (int a = 0; a < repr_set.size(); ++a){ repr_set.at(a)->refresh(Rep.U, pRNG); std::cout << GridLogDebug << "Hirep refreshing pseudofermions" << std::endl; } } } refresh_hireps{}; // Initialization of momenta and actions void refresh(GaugeField& U, GridParallelRNG& pRNG) { std::cout << GridLogIntegrator << "Integrator refresh\n"; generate_momenta(P, pRNG); // Update the smeared fields, can be implemented as observer // necessary to keep the fields updated even after a reject // of the Metropolis Smearer.set_GaugeField(U); // Set the (eventual) representations gauge fields Representations.update(U); // The Smearer is attached to a pointer of the gauge field // automatically gets the correct field // whether or not has been accepted in the previous sweep for (int level = 0; level < as.size(); ++level) { for (int actionID = 0; actionID < as[level].actions.size(); ++actionID) { // get gauge field from the SmearingPolicy and // based on the boolean is_smeared in actionID GaugeField& Us = Smearer.get_U(as[level].actions.at(actionID)->is_smeared); as[level].actions.at(actionID)->refresh(Us, pRNG); } // Refresh the higher representation actions as[level].apply(refresh_hireps, Representations, pRNG); } } // to be used by the actionlevel class to iterate // over the representations struct _S { template void operator()(std::vector*> repr_set, Repr& Rep, int level, RealD& H) { for (int a = 0; a < repr_set.size(); ++a) { RealD Hterm = repr_set.at(a)->S(Rep.U); std::cout << GridLogMessage << "S Level " << level << " term " << a << " H Hirep = " << Hterm << std::endl; H += Hterm; } } } S_hireps{}; // Calculate action RealD S(GaugeField& U) { // here also U not used LatticeComplex Hloc(U._grid); Hloc = zero; // Momenta for (int mu = 0; mu < Nd; mu++) { auto Pmu = PeekIndex(P, mu); Hloc -= trace(Pmu * Pmu); } Complex Hsum = sum(Hloc); RealD H = Hsum.real(); RealD Hterm; std::cout << GridLogMessage << "Momentum action H_p = " << H << "\n"; // Actions for (int level = 0; level < as.size(); ++level) { for (int actionID = 0; actionID < as[level].actions.size(); ++actionID) { // get gauge field from the SmearingPolicy and // based on the boolean is_smeared in actionID GaugeField& Us = Smearer.get_U(as[level].actions.at(actionID)->is_smeared); Hterm = as[level].actions.at(actionID)->S(Us); std::cout << GridLogMessage << "S Level " << level << " term " << actionID << " H = " << Hterm << std::endl; H += Hterm; } as[level].apply(S_hireps, Representations, level, H); } return H; } void integrate(GaugeField& U) { // reset the clocks t_U = 0; for (int level = 0; level < as.size(); ++level) { t_P[level] = 0; } for (int step = 0; step < Params.MDsteps; ++step) { // MD step int first_step = (step == 0); int last_step = (step == Params.MDsteps - 1); this->step(U, 0, first_step, last_step); } // Check the clocks all match on all levels for (int level = 0; level < as.size(); ++level) { assert(fabs(t_U - t_P[level]) < 1.0e-6); // must be the same std::cout << GridLogIntegrator << " times[" << level << "]= " << t_P[level] << " " << t_U << std::endl; } // and that we indeed got to the end of the trajectory assert(fabs(t_U - Params.trajL) < 1.0e-6); } }; } } #endif // INTEGRATOR_INCLUDED