1
0
mirror of https://github.com/paboyle/Grid.git synced 2024-11-15 02:05:37 +00:00
Grid/lib/algorithms/CoarsenedMatrix.h

487 lines
14 KiB
C
Raw Normal View History

2018-01-15 00:23:51 +00:00
/*************************************************************************************
Grid physics library, www.github.com/paboyle/Grid
Source file: ./lib/algorithms/CoarsenedMatrix.h
Copyright (C) 2015
Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk>
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local>
Author: paboyle <paboyle@ph.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
2018-01-15 00:23:51 +00:00
*************************************************************************************/
/* END LEGAL */
#ifndef GRID_ALGORITHM_COARSENED_MATRIX_H
#define GRID_ALGORITHM_COARSENED_MATRIX_H
2018-01-15 00:23:51 +00:00
NAMESPACE_BEGIN(Grid);
2018-01-15 00:23:51 +00:00
class Geometry {
// int dimension;
public:
int npoint;
std::vector<int> directions ;
std::vector<int> displacements;
2015-06-09 10:26:19 +01:00
Geometry(int _d) {
2018-01-15 00:23:51 +00:00
int base = (_d==5) ? 1:0;
// make coarse grid stencil for 4d , not 5d
if ( _d==5 ) _d=4;
npoint = 2*_d+1;
directions.resize(npoint);
displacements.resize(npoint);
for(int d=0;d<_d;d++){
directions[2*d ] = d+base;
directions[2*d+1] = d+base;
displacements[2*d ] = +1;
displacements[2*d+1] = -1;
2015-06-09 10:26:19 +01:00
}
2018-01-15 00:23:51 +00:00
directions [2*_d]=0;
displacements[2*_d]=0;
//// report back
std::cout<<GridLogMessage<<"directions :";
for(int d=0;d<npoint;d++) std::cout<< directions[d]<< " ";
std::cout <<std::endl;
std::cout<<GridLogMessage<<"displacements :";
for(int d=0;d<npoint;d++) std::cout<< displacements[d]<< " ";
std::cout<<std::endl;
}
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
/*
// Original cleaner code
Geometry(int _d) : dimension(_d), npoint(2*_d+1), directions(npoint), displacements(npoint) {
for(int d=0;d<dimension;d++){
directions[2*d ] = d;
directions[2*d+1] = d;
displacements[2*d ] = +1;
displacements[2*d+1] = -1;
}
directions [2*dimension]=0;
displacements[2*dimension]=0;
}
std::vector<int> GetDelta(int point) {
std::vector<int> delta(dimension,0);
delta[directions[point]] = displacements[point];
return delta;
};
2018-01-15 00:23:51 +00:00
*/
};
2018-01-15 00:23:51 +00:00
template<class Fobj,class CComplex,int nbasis>
class Aggregation {
public:
typedef iVector<CComplex,nbasis > siteVector;
typedef Lattice<siteVector> CoarseVector;
typedef Lattice<iMatrix<CComplex,nbasis > > CoarseMatrix;
2018-01-15 00:23:51 +00:00
typedef Lattice< CComplex > CoarseScalar; // used for inner products on fine field
typedef Lattice<Fobj > FineField;
2018-01-15 00:23:51 +00:00
GridBase *CoarseGrid;
GridBase *FineGrid;
std::vector<Lattice<Fobj> > subspace;
int checkerboard;
2018-01-27 23:51:40 +00:00
int Checkerboard(void){return checkerboard;}
Aggregation(GridBase *_CoarseGrid,GridBase *_FineGrid,int _checkerboard) :
CoarseGrid(_CoarseGrid),
2018-01-15 00:23:51 +00:00
FineGrid(_FineGrid),
subspace(nbasis,_FineGrid),
checkerboard(_checkerboard)
{
};
2018-01-15 00:23:51 +00:00
void Orthogonalise(void){
CoarseScalar InnerProd(CoarseGrid);
std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"<<std::endl;
blockOrthogonalise(InnerProd,subspace);
std::cout << GridLogMessage <<" Gramm-Schmidt pass 2"<<std::endl;
blockOrthogonalise(InnerProd,subspace);
// std::cout << GridLogMessage <<" Gramm-Schmidt checking orthogonality"<<std::endl;
// CheckOrthogonal();
}
void CheckOrthogonal(void){
CoarseVector iProj(CoarseGrid);
CoarseVector eProj(CoarseGrid);
for(int i=0;i<nbasis;i++){
blockProject(iProj,subspace[i],subspace);
2018-01-27 23:51:40 +00:00
eProj=Zero();
thread_loop( (int ss=0;ss<CoarseGrid->oSites();ss++),{
2018-01-26 23:07:34 +00:00
eProj[ss](i)=CComplex(1.0);
});
2018-01-15 00:23:51 +00:00
eProj=eProj - iProj;
std::cout<<GridLogMessage<<"Orthog check error "<<i<<" " << norm2(eProj)<<std::endl;
}
2018-01-15 00:23:51 +00:00
std::cout<<GridLogMessage <<"CheckOrthog done"<<std::endl;
}
void ProjectToSubspace(CoarseVector &CoarseVec,const FineField &FineVec){
blockProject(CoarseVec,FineVec,subspace);
}
void PromoteFromSubspace(const CoarseVector &CoarseVec,FineField &FineVec){
2018-01-26 23:07:34 +00:00
FineVec.Checkerboard() = subspace[0].Checkerboard();
2018-01-15 00:23:51 +00:00
blockPromote(CoarseVec,FineVec,subspace);
}
void CreateSubspaceRandom(GridParallelRNG &RNG){
for(int i=0;i<nbasis;i++){
random(RNG,subspace[i]);
std::cout<<GridLogMessage<<" norm subspace["<<i<<"] "<<norm2(subspace[i])<<std::endl;
}
2018-01-15 00:23:51 +00:00
Orthogonalise();
}
2016-03-17 10:36:16 +00:00
2018-01-15 00:23:51 +00:00
/*
2016-03-17 10:36:16 +00:00
virtual void CreateSubspaceLanczos(GridParallelRNG &RNG,LinearOperatorBase<FineField> &hermop,int nn=nbasis)
{
2018-01-15 00:23:51 +00:00
// Run a Lanczos with sloppy convergence
const int Nstop = nn;
const int Nk = nn+20;
const int Np = nn+20;
const int Nm = Nk+Np;
const int MaxIt= 10000;
RealD resid = 1.0e-3;
2016-03-17 10:36:16 +00:00
2018-01-15 00:23:51 +00:00
Chebyshev<FineField> Cheb(0.5,64.0,21);
ImplicitlyRestartedLanczos<FineField> IRL(hermop,Cheb,Nstop,Nk,Nm,resid,MaxIt);
// IRL.lock = 1;
2016-03-17 10:36:16 +00:00
2018-01-15 00:23:51 +00:00
FineField noise(FineGrid); gaussian(RNG,noise);
FineField tmp(FineGrid);
std::vector<RealD> eval(Nm);
std::vector<FineField> evec(Nm,FineGrid);
2016-03-17 10:36:16 +00:00
2018-01-15 00:23:51 +00:00
int Nconv;
IRL.calc(eval,evec,
noise,
Nconv);
2016-03-17 10:36:16 +00:00
2018-01-15 00:23:51 +00:00
// pull back nn vectors
for(int b=0;b<nn;b++){
2016-03-30 08:16:02 +01:00
2018-01-15 00:23:51 +00:00
subspace[b] = evec[b];
2016-03-30 08:16:02 +01:00
2018-01-15 00:23:51 +00:00
std::cout << GridLogMessage <<"subspace["<<b<<"] = "<<norm2(subspace[b])<<std::endl;
2016-03-30 08:16:02 +01:00
2018-01-15 00:23:51 +00:00
hermop.Op(subspace[b],tmp);
std::cout<<GridLogMessage << "filtered["<<b<<"] <f|MdagM|f> "<<norm2(tmp)<<std::endl;
2016-03-30 08:16:02 +01:00
2018-01-15 00:23:51 +00:00
noise = tmp - sqrt(eval[b])*subspace[b] ;
2016-03-30 08:16:02 +01:00
2018-01-15 00:23:51 +00:00
std::cout<<GridLogMessage << " lambda_"<<b<<" = "<< eval[b] <<" ; [ M - Lambda ]_"<<b<<" vec_"<<b<<" = " <<norm2(noise)<<std::endl;
2016-03-30 08:16:02 +01:00
2018-01-15 00:23:51 +00:00
noise = tmp + eval[b]*subspace[b] ;
2016-03-30 08:16:02 +01:00
2018-01-15 00:23:51 +00:00
std::cout<<GridLogMessage << " lambda_"<<b<<" = "<< eval[b] <<" ; [ M - Lambda ]_"<<b<<" vec_"<<b<<" = " <<norm2(noise)<<std::endl;
2016-03-30 08:16:02 +01:00
2016-03-17 10:36:16 +00:00
}
2018-01-15 00:23:51 +00:00
Orthogonalise();
for(int b=0;b<nn;b++){
std::cout << GridLogMessage <<"subspace["<<b<<"] = "<<norm2(subspace[b])<<std::endl;
}
}
*/
virtual void CreateSubspace(GridParallelRNG &RNG,LinearOperatorBase<FineField> &hermop,int nn=nbasis) {
2018-01-15 00:23:51 +00:00
RealD scale;
2018-01-15 00:23:51 +00:00
ConjugateGradient<FineField> CG(1.0e-2,10000);
FineField noise(FineGrid);
FineField Mn(FineGrid);
2018-01-15 00:23:51 +00:00
for(int b=0;b<nn;b++){
2018-01-15 00:23:51 +00:00
gaussian(RNG,noise);
scale = std::pow(norm2(noise),-0.5);
noise=noise*scale;
2018-01-15 00:23:51 +00:00
hermop.Op(noise,Mn); std::cout<<GridLogMessage << "noise ["<<b<<"] <n|MdagM|n> "<<norm2(Mn)<<std::endl;
2018-01-15 00:23:51 +00:00
for(int i=0;i<1;i++){
2018-01-15 00:23:51 +00:00
CG(hermop,noise,subspace[b]);
2018-01-15 00:23:51 +00:00
noise = subspace[b];
scale = std::pow(norm2(noise),-0.5);
noise=noise*scale;
}
2018-01-15 00:23:51 +00:00
hermop.Op(noise,Mn); std::cout<<GridLogMessage << "filtered["<<b<<"] <f|MdagM|f> "<<norm2(Mn)<<std::endl;
subspace[b] = noise;
}
2018-01-15 00:23:51 +00:00
Orthogonalise();
}
};
// Fine Object == (per site) type of fine field
// nbasis == number of deflation vectors
template<class Fobj,class CComplex,int nbasis>
class CoarsenedMatrix : public SparseMatrixBase<Lattice<iVector<CComplex,nbasis > > > {
public:
2018-01-15 00:23:51 +00:00
typedef iVector<CComplex,nbasis > siteVector;
typedef Lattice<siteVector> CoarseVector;
typedef Lattice<iMatrix<CComplex,nbasis > > CoarseMatrix;
2018-01-15 00:23:51 +00:00
typedef Lattice< CComplex > CoarseScalar; // used for inner products on fine field
typedef Lattice<Fobj > FineField;
2018-01-15 00:23:51 +00:00
////////////////////
// Data members
////////////////////
Geometry geom;
GridBase * _grid;
CartesianStencil<siteVector,siteVector> Stencil;
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
std::vector<CoarseMatrix> A;
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
///////////////////////
// Interface
///////////////////////
GridBase * Grid(void) { return _grid; }; // this is all the linalg routines need to know
2018-01-15 00:23:51 +00:00
RealD M (const CoarseVector &in, CoarseVector &out){
2018-01-27 00:04:12 +00:00
conformable(_grid,in.Grid());
conformable(in.Grid(),out.Grid());
2018-01-15 00:23:51 +00:00
SimpleCompressor<siteVector> compressor;
Stencil.HaloExchange(in,compressor);
auto in_v = in.View();
auto out_v = in.View();
thread_loop( (int ss=0;ss<Grid()->oSites();ss++),{
2018-01-27 23:51:40 +00:00
siteVector res = Zero();
2018-01-15 00:23:51 +00:00
siteVector nbr;
int ptype;
StencilEntry *SE;
for(int point=0;point<geom.npoint;point++){
2018-01-15 00:23:51 +00:00
SE=Stencil.GetEntry(ptype,point,ss);
2018-01-15 00:23:51 +00:00
if(SE->_is_local&&SE->_permute) {
permute(nbr,in_v[SE->_offset],ptype);
2018-01-15 00:23:51 +00:00
} else if(SE->_is_local) {
nbr = in_v[SE->_offset];
2018-01-15 00:23:51 +00:00
} else {
nbr = Stencil.CommBuf()[SE->_offset];
}
auto A_point = A[point].View();
res = res + A_point[ss]*nbr;
}
vstream(out_v[ss],res);
});
2018-01-15 00:23:51 +00:00
return norm2(out);
};
2018-01-15 00:23:51 +00:00
RealD Mdag (const CoarseVector &in, CoarseVector &out){
return M(in,out);
};
2018-01-15 00:23:51 +00:00
// Defer support for further coarsening for now
void Mdiag (const CoarseVector &in, CoarseVector &out){};
void Mdir (const CoarseVector &in, CoarseVector &out,int dir, int disp){};
2018-01-15 00:23:51 +00:00
CoarsenedMatrix(GridCartesian &CoarseGrid) :
2018-01-15 00:23:51 +00:00
_grid(&CoarseGrid),
geom(CoarseGrid._ndimension),
Stencil(&CoarseGrid,geom.npoint,Even,geom.directions,geom.displacements),
A(geom.npoint,&CoarseGrid)
{
};
2018-01-15 00:23:51 +00:00
void CoarsenOperator(GridBase *FineGrid,LinearOperatorBase<Lattice<Fobj> > &linop,
Aggregation<Fobj,CComplex,nbasis> & Subspace){
2018-01-15 00:23:51 +00:00
FineField iblock(FineGrid); // contributions from within this block
FineField oblock(FineGrid); // contributions from outwith this block
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
FineField phi(FineGrid);
FineField tmp(FineGrid);
2018-01-27 23:51:40 +00:00
FineField zz(FineGrid); zz=Zero();
2018-01-15 00:23:51 +00:00
FineField Mphi(FineGrid);
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
Lattice<iScalar<vInteger> > coor(FineGrid);
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
CoarseVector iProj(Grid());
CoarseVector oProj(Grid());
CoarseScalar InnerProd(Grid());
2018-01-15 00:23:51 +00:00
// Orthogonalise the subblocks over the basis
blockOrthogonalise(InnerProd,Subspace.subspace);
2018-01-15 00:23:51 +00:00
// Compute the matrix elements of linop between this orthonormal
// set of vectors.
int self_stencil=-1;
for(int p=0;p<geom.npoint;p++){
2018-01-27 23:51:40 +00:00
A[p]=Zero();
2018-01-15 00:23:51 +00:00
if( geom.displacements[p]==0){
self_stencil=p;
2015-06-09 10:26:19 +01:00
}
2018-01-15 00:23:51 +00:00
}
assert(self_stencil!=-1);
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
for(int i=0;i<nbasis;i++){
phi=Subspace.subspace[i];
2015-11-29 00:53:54 +00:00
2018-01-15 00:23:51 +00:00
std::cout<<GridLogMessage<<"("<<i<<").."<<std::endl;
2015-11-29 00:53:54 +00:00
2018-01-15 00:23:51 +00:00
for(int p=0;p<geom.npoint;p++){
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
int dir = geom.directions[p];
int disp = geom.displacements[p];
2018-01-15 00:23:51 +00:00
Integer block=(FineGrid->_rdimensions[dir])/(Grid()->_rdimensions[dir]);
2018-01-15 00:23:51 +00:00
LatticeCoordinate(coor,dir);
2018-01-15 00:23:51 +00:00
if ( disp==0 ){
linop.OpDiag(phi,Mphi);
}
else {
linop.OpDir(phi,Mphi,dir,disp);
}
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
////////////////////////////////////////////////////////////////////////
// Pick out contributions coming from this cell and neighbour cell
////////////////////////////////////////////////////////////////////////
if ( disp==0 ) {
iblock = Mphi;
2018-01-27 23:51:40 +00:00
oblock = Zero();
2018-01-15 00:23:51 +00:00
} else if ( disp==1 ) {
oblock = where(mod(coor,block)==(block-1),Mphi,zz);
iblock = where(mod(coor,block)!=(block-1),Mphi,zz);
} else if ( disp==-1 ) {
oblock = where(mod(coor,block)==(Integer)0,Mphi,zz);
iblock = where(mod(coor,block)!=(Integer)0,Mphi,zz);
} else {
assert(0);
}
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
Subspace.ProjectToSubspace(iProj,iblock);
Subspace.ProjectToSubspace(oProj,oblock);
// blockProject(iProj,iblock,Subspace.subspace);
// blockProject(oProj,oblock,Subspace.subspace);
auto iProj_v = iProj.View() ;
auto oProj_v = oProj.View() ;
auto A_p = A[p].View();
auto A_self = A[self_stencil].View();
thread_loop( (int ss=0;ss<Grid()->oSites();ss++),{
2018-01-15 00:23:51 +00:00
for(int j=0;j<nbasis;j++){
if( disp!= 0 ) {
A_p[ss](j,i) = oProj_v[ss](j);
}
A_self[ss](j,i) = A_self[ss](j,i) + iProj_v[ss](j);
}
});
2015-06-09 10:26:19 +01:00
}
2018-01-15 00:23:51 +00:00
}
2015-06-09 10:26:19 +01:00
#if 0
2018-01-15 00:23:51 +00:00
///////////////////////////
// test code worth preserving in if block
///////////////////////////
std::cout<<GridLogMessage<< " Computed matrix elements "<< self_stencil <<std::endl;
for(int p=0;p<geom.npoint;p++){
std::cout<<GridLogMessage<< "A["<<p<<"]" << std::endl;
std::cout<<GridLogMessage<< A[p] << std::endl;
}
std::cout<<GridLogMessage<< " picking by block0 "<< self_stencil <<std::endl;
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
phi=Subspace.subspace[0];
std::vector<int> bc(FineGrid->_ndimension,0);
2015-06-09 10:26:19 +01:00
2018-01-15 00:23:51 +00:00
blockPick(Grid(),phi,tmp,bc); // Pick out a block
linop.Op(tmp,Mphi); // Apply big dop
blockProject(iProj,Mphi,Subspace.subspace); // project it and print it
std::cout<<GridLogMessage<< " Computed matrix elements from block zero only "<<std::endl;
std::cout<<GridLogMessage<< iProj <<std::endl;
std::cout<<GridLogMessage<<"Computed Coarse Operator"<<std::endl;
2015-06-09 10:26:19 +01:00
#endif
2018-01-15 00:23:51 +00:00
// ForceHermitian();
AssertHermitian();
// ForceDiagonal();
}
void ForceDiagonal(void) {
std::cout<<GridLogMessage<<"**************************************************"<<std::endl;
std::cout<<GridLogMessage<<"**** Forcing coarse operator to be diagonal ****"<<std::endl;
std::cout<<GridLogMessage<<"**************************************************"<<std::endl;
for(int p=0;p<8;p++){
2018-01-27 23:51:40 +00:00
A[p]=Zero();
}
2018-01-15 00:23:51 +00:00
GridParallelRNG RNG(Grid()); RNG.SeedFixedIntegers(std::vector<int>({55,72,19,17,34}));
Lattice<iScalar<CComplex> > val(Grid()); random(RNG,val);
2018-01-15 00:23:51 +00:00
Complex one(1.0);
2018-01-15 00:23:51 +00:00
iMatrix<CComplex,nbasis> ident; ident=one;
2018-01-15 00:23:51 +00:00
val = val*adj(val);
val = val + 1.0;
2018-01-15 00:23:51 +00:00
A[8] = val*ident;
2018-01-15 00:23:51 +00:00
// for(int s=0;s<Grid()->oSites();s++) {
2018-01-26 23:07:34 +00:00
// A[8][s]=val[s];
2018-01-15 00:23:51 +00:00
// }
}
void ForceHermitian(void) {
for(int d=0;d<4;d++){
int dd=d+1;
A[2*d] = adj(Cshift(A[2*d+1],dd,1));
}
2018-01-15 00:23:51 +00:00
// A[8] = 0.5*(A[8] + adj(A[8]));
}
void AssertHermitian(void) {
CoarseMatrix AA (Grid());
CoarseMatrix AAc (Grid());
CoarseMatrix Diff (Grid());
for(int d=0;d<4;d++){
2018-01-15 00:23:51 +00:00
int dd=d+1;
AAc = Cshift(A[2*d+1],dd,1);
AA = A[2*d];
2018-01-15 00:23:51 +00:00
Diff = AA - adj(AAc);
2018-01-15 00:23:51 +00:00
std::cout<<GridLogMessage<<"Norm diff dim "<<d<<" "<< norm2(Diff)<<std::endl;
std::cout<<GridLogMessage<<"Norm dim "<<d<<" "<< norm2(AA)<<std::endl;
}
2018-01-15 00:23:51 +00:00
Diff = A[8] - adj(A[8]);
std::cout<<GridLogMessage<<"Norm diff local "<< norm2(Diff)<<std::endl;
std::cout<<GridLogMessage<<"Norm local "<< norm2(A[8])<<std::endl;
}
2018-01-15 00:23:51 +00:00
};
2018-01-15 00:23:51 +00:00
NAMESPACE_END(Grid);
#endif