2019-01-18 13:14:28 +00:00
/*************************************************************************************
Grid physics library , www . github . com / paboyle / Grid
Source file : Hadrons / Modules / MDistil / LapEvec . hpp
2019-04-26 07:39:05 +01:00
Copyright ( C ) 2019
2019-01-18 13:14:28 +00:00
Author : Felix Erben < ferben @ ed . ac . uk >
Author : Michael Marshall < Michael . Marshall @ ed . ac . uk >
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 */
# ifndef Hadrons_MDistil_LapEvec_hpp_
# define Hadrons_MDistil_LapEvec_hpp_
# include <Hadrons/Global.hpp>
# include <Hadrons/Module.hpp>
# include <Hadrons/ModuleFactory.hpp>
2019-01-23 21:17:56 +00:00
# include <Hadrons/EigenPack.hpp>
2019-01-18 13:14:28 +00:00
2019-01-22 17:59:55 +00:00
// These are members of Distillation
2019-04-26 07:24:56 +01:00
# include <Hadrons/Distil.hpp>
2019-01-22 17:59:55 +00:00
2019-01-18 13:14:28 +00:00
BEGIN_HADRONS_NAMESPACE
2019-01-22 13:19:39 +00:00
BEGIN_MODULE_NAMESPACE ( MDistil )
2019-01-18 13:14:28 +00:00
/******************************************************************************
2019-01-22 13:19:39 +00:00
2019-01-23 12:59:55 +00:00
Laplacian eigenvectors - parameters
2019-01-18 13:14:28 +00:00
2019-01-23 12:59:55 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct StoutParameters : Serializable {
GRID_SERIALIZABLE_CLASS_MEMBERS ( StoutParameters ,
2019-01-22 13:19:39 +00:00
int , steps ,
2019-04-30 23:53:57 +01:00
double , rho ) // TODO: change name of this to rho
2019-01-23 12:59:55 +00:00
StoutParameters ( ) = default ;
template < class ReaderClass > StoutParameters ( Reader < ReaderClass > & Reader ) { read ( Reader , " StoutSmearing " , * this ) ; }
} ;
struct ChebyshevParameters : Serializable {
GRID_SERIALIZABLE_CLASS_MEMBERS ( ChebyshevParameters ,
2019-01-22 13:19:39 +00:00
int , PolyOrder ,
double , alpha ,
2019-01-23 12:59:55 +00:00
double , beta )
ChebyshevParameters ( ) = default ;
template < class ReaderClass > ChebyshevParameters ( Reader < ReaderClass > & Reader ) { read ( Reader , " Chebyshev " , * this ) ; }
} ;
struct LanczosParameters : Serializable {
GRID_SERIALIZABLE_CLASS_MEMBERS ( LanczosParameters ,
2019-01-22 13:19:39 +00:00
int , Nvec ,
int , Nk ,
int , Np ,
int , MaxIt ,
2019-04-29 18:40:38 +01:00
double , resid ,
2019-04-29 22:18:29 +01:00
int , IRLLog )
2019-01-23 12:59:55 +00:00
LanczosParameters ( ) = default ;
template < class ReaderClass > LanczosParameters ( Reader < ReaderClass > & Reader ) { read ( Reader , " Lanczos " , * this ) ; }
} ;
// These are the actual parameters passed to the module during construction
2019-04-30 23:53:57 +01:00
struct LapEvecPar : Serializable {
GRID_SERIALIZABLE_CLASS_MEMBERS ( LapEvecPar
, std : : string , gauge
, StoutParameters , Stout
2019-01-24 18:50:18 +00:00
, ChebyshevParameters , Cheby
2019-04-30 23:53:57 +01:00
, LanczosParameters , Lanczos )
2019-01-23 12:59:55 +00:00
} ;
/******************************************************************************
Laplacian eigenvectors - Module ( class ) definition
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-28 12:28:35 +00:00
template < typename GImpl >
2019-01-18 13:14:28 +00:00
class TLapEvec : public Module < LapEvecPar >
{
public :
2019-01-28 12:28:35 +00:00
GAUGE_TYPE_ALIASES ( GImpl , ) ;
2019-01-23 21:17:56 +00:00
// constructor
TLapEvec ( const std : : string name ) ;
// destructor
virtual ~ TLapEvec ( void ) ;
// dependency relation
virtual std : : vector < std : : string > getInput ( void ) ;
virtual std : : vector < std : : string > getOutput ( void ) ;
// setup
virtual void setup ( void ) ;
// execution
virtual void execute ( void ) ;
protected :
// These variables are created in setup() and freed in Cleanup()
GridCartesian * gridLD ; // Owned by me, so I must delete it
GridCartesian * gridHD ; // Owned by environment (so I won't delete it)
2019-04-30 23:53:57 +01:00
std : : string sGaugeName ;
2019-01-23 21:17:56 +00:00
protected :
2019-01-30 21:16:09 +00:00
virtual void Cleanup ( void ) ;
2019-01-18 13:14:28 +00:00
} ;
2019-01-28 12:28:35 +00:00
MODULE_REGISTER_TMP ( LapEvec , TLapEvec < GIMPL > , MDistil ) ;
2019-01-18 13:14:28 +00:00
/******************************************************************************
2019-01-23 21:17:56 +00:00
TLapEvec implementation
2019-01-18 13:14:28 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-23 21:17:56 +00:00
2019-01-18 13:14:28 +00:00
// constructor /////////////////////////////////////////////////////////////////
2019-01-28 12:28:35 +00:00
template < typename GImpl >
TLapEvec < GImpl > : : TLapEvec ( const std : : string name ) : gridLD { nullptr } , Module < LapEvecPar > ( name )
2019-01-23 15:19:51 +00:00
{
}
// destructor /////////////////////////////////////////////////////////////////
2019-01-28 12:28:35 +00:00
template < typename GImpl >
TLapEvec < GImpl > : : ~ TLapEvec ( )
2019-01-23 15:19:51 +00:00
{
2019-01-23 21:17:56 +00:00
Cleanup ( ) ;
2019-01-23 15:19:51 +00:00
}
2019-01-18 13:14:28 +00:00
// dependencies/products ///////////////////////////////////////////////////////
2019-01-28 12:28:35 +00:00
template < typename GImpl >
std : : vector < std : : string > TLapEvec < GImpl > : : getInput ( void )
2019-01-18 13:14:28 +00:00
{
2019-04-30 23:53:57 +01:00
sGaugeName = par ( ) . gauge ;
if ( sGaugeName . size ( ) = = 0 ) {
sGaugeName = getName ( ) ;
sGaugeName . append ( " _gauge " ) ;
}
return std : : vector < std : : string > { sGaugeName } ;
2019-01-18 13:14:28 +00:00
}
2019-01-28 12:28:35 +00:00
template < typename GImpl >
std : : vector < std : : string > TLapEvec < GImpl > : : getOutput ( void )
2019-01-18 13:14:28 +00:00
{
2019-01-24 12:44:06 +00:00
std : : vector < std : : string > out = { getName ( ) } ; // This is the higher dimensional eigenpack
2019-01-18 13:14:28 +00:00
return out ;
}
// setup ///////////////////////////////////////////////////////////////////////
2019-01-28 12:28:35 +00:00
template < typename GImpl >
void TLapEvec < GImpl > : : setup ( void )
2019-01-18 13:14:28 +00:00
{
2019-01-23 21:17:56 +00:00
Cleanup ( ) ;
Environment & e { env ( ) } ;
gridHD = e . getGrid ( ) ;
gridLD = MakeLowerDimGrid ( gridHD ) ;
2019-05-03 16:03:56 +01:00
const int Ntlocal { gridHD - > LocalDimensions ( ) [ Tdir ] } ;
2019-01-23 21:17:56 +00:00
// Temporaries
envTmpLat ( GaugeField , " Umu_stout " ) ;
envTmpLat ( GaugeField , " Umu_smear " ) ;
2019-01-24 12:44:06 +00:00
envTmp ( LatticeGaugeField , " UmuNoTime " , 1 , LatticeGaugeField ( gridLD ) ) ;
envTmp ( LatticeColourVector , " src " , 1 , LatticeColourVector ( gridLD ) ) ;
2019-05-03 16:03:56 +01:00
envTmp ( std : : vector < LapEvecs > , " eig " , 1 , std : : vector < LapEvecs > ( Ntlocal ) ) ;
2019-01-23 21:17:56 +00:00
// Output objects
2019-04-30 23:53:57 +01:00
envCreate ( LapEvecs , getName ( ) , 1 , par ( ) . Lanczos . Nvec , gridHD ) ;
2019-01-23 21:17:56 +00:00
}
// clean up any temporaries created by setup (that aren't stored in the environment)
2019-01-28 12:28:35 +00:00
template < typename GImpl >
void TLapEvec < GImpl > : : Cleanup ( void )
2019-01-23 21:17:56 +00:00
{
if ( gridLD ! = nullptr ) {
2019-01-23 15:19:51 +00:00
delete gridLD ;
2019-01-23 21:17:56 +00:00
gridLD = nullptr ;
2019-01-23 15:19:51 +00:00
}
2019-01-24 12:44:06 +00:00
gridHD = nullptr ;
2019-01-18 13:14:28 +00:00
}
2019-01-24 12:44:06 +00:00
/******************************************************************************
Calculate low - mode eigenvalues of the Laplacian
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-18 13:14:28 +00:00
// execution ///////////////////////////////////////////////////////////////////
2019-01-28 12:28:35 +00:00
template < typename GImpl >
void TLapEvec < GImpl > : : execute ( void )
2019-01-18 13:14:28 +00:00
{
2019-01-24 12:44:06 +00:00
const ChebyshevParameters & ChebPar { par ( ) . Cheby } ;
2019-01-24 18:50:18 +00:00
const LanczosParameters & LPar { par ( ) . Lanczos } ;
2019-01-24 12:44:06 +00:00
2019-04-29 22:18:29 +01:00
// Disable IRL logging if requested
LOG ( Message ) < < " IRLLog= " < < LPar . IRLLog < < std : : endl ;
const int PreviousIRLLogState { GridLogIRL . isActive ( ) } ;
GridLogIRL . Active ( LPar . IRLLog = = 0 ? 0 : 1 ) ;
2019-01-24 13:26:05 +00:00
2019-01-24 12:44:06 +00:00
// Stout smearing
2019-04-30 23:53:57 +01:00
envGetTmp ( GaugeField , Umu_smear ) ;
2019-05-02 18:20:49 +01:00
Umu_smear = envGet ( GaugeField , sGaugeName ) ; // The smeared field starts off as the Gauge field
LOG ( Message ) < < " Initial plaquette: " < < WilsonLoops < PeriodicGimplR > : : avgPlaquette ( Umu_smear ) < < std : : endl ;
2019-05-01 13:04:51 +01:00
const StoutParameters & Stout { par ( ) . Stout } ;
if ( Stout . steps )
2019-01-24 12:44:06 +00:00
{
envGetTmp ( GaugeField , Umu_stout ) ;
2019-04-30 23:53:57 +01:00
Smear_Stout < PeriodicGimplR > LS ( Stout . rho , Tdir ) ; // spatial smearing only
2019-01-24 18:50:18 +00:00
for ( int i = 0 ; i < Stout . steps ; i + + ) {
2019-01-24 12:44:06 +00:00
LS . smear ( Umu_stout , Umu_smear ) ;
Umu_smear = Umu_stout ;
}
2019-05-02 18:20:49 +01:00
LOG ( Message ) < < " Smeared plaquette: " < < WilsonLoops < PeriodicGimplR > : : avgPlaquette ( Umu_smear ) < < std : : endl ;
2019-01-24 12:44:06 +00:00
}
////////////////////////////////////////////////////////////////////////
// Invert Peardon Nabla operator separately on each time-slice
////////////////////////////////////////////////////////////////////////
2019-04-30 23:53:57 +01:00
auto & eig4d = envGet ( LapEvecs , getName ( ) ) ;
envGetTmp ( std : : vector < LapEvecs > , eig ) ; // Eigenpack for each timeslice
2019-01-24 12:44:06 +00:00
envGetTmp ( LatticeGaugeField , UmuNoTime ) ; // Gauge field without time dimension
envGetTmp ( LatticeColourVector , src ) ;
const int Ntlocal { gridHD - > LocalDimensions ( ) [ Tdir ] } ;
const int Ntfirst { gridHD - > LocalStarts ( ) [ Tdir ] } ;
2019-05-03 16:03:56 +01:00
uint32_t ConvergenceErrors { 0 } ;
for ( int t = 0 ; t < Ntlocal ; t + + ) {
2019-04-29 18:40:38 +01:00
LOG ( Message ) < < " ------------------------------------------------------------ " < < std : : endl ;
2019-05-03 16:03:56 +01:00
LOG ( Message ) < < " Compute eigenpack, local timeslice = " < < t < < " / " < < Ntlocal < < std : : endl ;
2019-04-29 18:40:38 +01:00
LOG ( Message ) < < " ------------------------------------------------------------ " < < std : : endl ;
2019-01-24 12:44:06 +00:00
eig [ t ] . resize ( LPar . Nk + LPar . Np , gridLD ) ;
// Construct smearing operator
2019-09-13 13:30:00 +01:00
ExtractSliceLocal ( UmuNoTime , Umu_smear , 0 , t , Tdir ) ; // switch to 3d/4d objects
2019-01-24 12:44:06 +00:00
LinOpPeardonNabla < LatticeColourVector > PeardonNabla ( UmuNoTime ) ;
2019-04-29 18:40:38 +01:00
LOG ( Debug ) < < " Chebyshev preconditioning to order " < < ChebPar . PolyOrder
< < " with parameters (alpha,beta) = ( " < < ChebPar . alpha < < " , " < < ChebPar . beta < < " ) " < < std : : endl ;
2019-01-24 12:44:06 +00:00
Chebyshev < LatticeColourVector > Cheb ( ChebPar . alpha , ChebPar . beta , ChebPar . PolyOrder ) ;
// Construct source vector according to Test_dwf_compressed_lanczos.cc
2019-04-29 18:40:38 +01:00
src = 11.0 ;
2019-01-24 12:44:06 +00:00
RealD nn = norm2 ( src ) ;
nn = Grid : : sqrt ( nn ) ;
src = src * ( 1.0 / nn ) ;
LinOpPeardonNablaHerm < LatticeColourVector > PeardonNablaCheby ( Cheb , PeardonNabla ) ;
2019-04-29 18:40:38 +01:00
ImplicitlyRestartedLanczos < LatticeColourVector >
IRL ( PeardonNablaCheby , PeardonNabla , LPar . Nvec , LPar . Nk , LPar . Nk + LPar . Np , LPar . resid , LPar . MaxIt ) ;
2019-01-24 12:44:06 +00:00
int Nconv = 0 ;
IRL . calc ( eig [ t ] . eval , eig [ t ] . evec , src , Nconv ) ;
2019-05-03 16:03:56 +01:00
if ( Nconv < LPar . Nvec ) {
// NB: Can't assert here since we are processing local slices - i.e. not all nodes would assert
ConvergenceErrors = 1 ;
LOG ( Error ) < < " MDistil::LapEvec : Not enough eigenvectors converged. If this occurs in practice, we should modify the eigensolver to iterate once more to ensure the second convergence test does not take us below the requested number of eigenvectors " < < std : : endl ;
}
if ( Nconv ! = LPar . Nvec )
2019-04-29 18:40:38 +01:00
eig [ t ] . resize ( LPar . Nvec , gridLD ) ;
RotateEigen ( eig [ t ] . evec ) ; // Rotate the eigenvectors into our phase convention
2019-01-24 12:44:06 +00:00
for ( int i = 0 ; i < LPar . Nvec ; i + + ) {
2019-09-13 13:30:00 +01:00
InsertSliceLocal ( eig [ t ] . evec [ i ] , eig4d . evec [ i ] , 0 , t , Tdir ) ;
2019-05-03 16:03:56 +01:00
if ( t = = 0 & & Ntfirst = = 0 )
2019-04-29 18:40:38 +01:00
eig4d . eval [ i ] = eig [ t ] . eval [ i ] ; // TODO: Discuss: is this needed? Is there a better way?
2019-01-24 12:44:06 +00:00
}
}
2019-05-01 09:50:23 +01:00
GridLogIRL . Active ( PreviousIRLLogState ) ;
2019-05-03 16:03:56 +01:00
gridHD - > GlobalSum ( ConvergenceErrors ) ;
assert ( ConvergenceErrors = = 0 & & " The eingensolver failed to find enough eigenvectors on at least one node " ) ;
2019-05-01 09:50:23 +01:00
# if DEBUG
2019-01-24 16:30:13 +00:00
// Now write out the 4d eigenvectors
2019-05-01 09:50:23 +01:00
eig4d . record . operatorXml = " <OPERATOR>Distillation</OPERATOR> " ;
eig4d . record . solverXml = " <SOLVER>CG</SOLVER> " ;
2019-04-19 14:09:36 +01:00
std : : string sEigenPackName ( getName ( ) ) ;
sEigenPackName . append ( " . " ) ;
sEigenPackName . append ( std : : to_string ( vm ( ) . getTrajectory ( ) ) ) ;
eig4d . write ( sEigenPackName , false ) ;
2019-05-01 09:50:23 +01:00
# endif
2019-01-18 13:14:28 +00:00
}
END_MODULE_NAMESPACE
END_HADRONS_NAMESPACE
# endif // Hadrons_MDistil_LapEvec_hpp_