/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/algorithms/iterative/AdefGeneric.h Copyright (C) 2015 Author: Peter Boyle 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 GRID_ALGORITHMS_ITERATIVE_GENERIC_PCG #define GRID_ALGORITHMS_ITERATIVE_GENERIC_PCG /* * Compared to Tang-2009: P=Pleft. P^T = PRight Q=MssInv. * Script A = SolverMatrix * Script P = Preconditioner * * Implement ADEF-2 * * Vstart = P^Tx + Qb * M1 = P^TM + Q * M2=M3=1 */ NAMESPACE_BEGIN(Grid); template class TwoLevelCG : public LinearFunction { public: RealD Tolerance; Integer MaxIterations; GridBase *grid; // Fine operator, Smoother, CoarseSolver LinearOperatorBase &_FineLinop; LinearFunction &_Smoother; // more most opertor functions TwoLevelCG(RealD tol, Integer maxit, LinearOperatorBase &FineLinop, LinearFunction &Smoother, GridBase *fine) : Tolerance(tol), MaxIterations(maxit), _FineLinop(FineLinop), _Smoother(Smoother) { grid = fine; }; virtual void operator() (const Field &src, Field &x) { std::cout << GridLogMessage<<"HDCG: fPcg starting single RHS"< p(mmax,grid); std::vector mmp(mmax,grid); std::vector pAp(mmax); Field z(grid); Field tmp(grid); Field mp (grid); Field r (grid); Field mu (grid); std::cout << GridLogMessage<<"HDCG: fPcg allocated"< z + b p b = (rtzp)/rtz; int northog; // k=zero <=> peri_kp=1; northog = 1 // k=1 <=> peri_kp=2; northog = 2 // ... ... ... // k=mmax-2<=> peri_kp=mmax-1; northog = mmax-1 // k=mmax-1<=> peri_kp=0; northog = 1 // northog = (peri_kp==0)?1:peri_kp; // This is the fCG(mmax) algorithm northog = (k>mmax-1)?(mmax-1):k; // This is the fCG-Tr(mmax-1) algorithm std::cout< &src, std::vector &x) { std::cout << GridLogMessage<<"HDCG: mrhs fPcg starting"<Barrier(); int nrhs = src.size(); std::vector f(nrhs); std::vector rtzp(nrhs); std::vector rtz(nrhs); std::vector a(nrhs); std::vector d(nrhs); std::vector b(nrhs); std::vector rptzp(nrhs); ///////////////////////////// // Set up history vectors ///////////////////////////// int mmax = 3; std::cout << GridLogMessage<<"HDCG: fPcg allocating"<Barrier(); std::vector > p(nrhs); for(int r=0;rBarrier(); std::vector > mmp(nrhs); for(int r=0;rBarrier(); std::vector > pAp(nrhs); for(int r=0;rBarrier(); std::vector z(nrhs,grid); std::vector mp (nrhs,grid); std::vector r (nrhs,grid); std::vector mu (nrhs,grid); std::cout << GridLogMessage<<"HDCG: fPcg allocated z,mp,r,mu"<Barrier(); //Initial residual computation & set up std::vector src_nrm(nrhs); for(int rhs=0;rhs tn(nrhs); GridStopWatch HDCGTimer; HDCGTimer.Start(); ////////////////////////// // x0 = Vstart -- possibly modify guess ////////////////////////// Vstart(x,src); for(int rhs=0;rhs ssq(nrhs); std::vector rsq(nrhs); std::vector pp(nrhs,grid); for(int rhs=0;rhs rn(nrhs); for (int k=0;k<=MaxIterations;k++){ int peri_k = k % mmax; int peri_kp = (k+1) % mmax; for(int rhs=0;rhsBarrier(); RealD max_rn=0.0; for(int rhs=0;rhsmmax-1)?(mmax-1):k; // This is the fCG-Tr(mmax-1) algorithm std::cout< max_rn ) max_rn = rrn; } // Stopping condition based on worst case if ( max_rn <= Tolerance ) { HDCGTimer.Stop(); std::cout< & in,std::vector & out) { std::cout << "PcgM1 default (cheat) mrhs version"<PcgM1(in[rhs],out[rhs]); } } virtual void PcgM1(Field & in, Field & out) =0; virtual void Vstart(std::vector & x,std::vector & src) { std::cout << "Vstart default (cheat) mrhs version"<Vstart(x[rhs],src[rhs]); } } virtual void Vstart(Field & x,const Field & src)=0; virtual void PcgM2(const Field & in, Field & out) { out=in; } virtual RealD PcgM3(const Field & p, Field & mmp){ RealD dd; _FineLinop.HermOp(p,mmp); ComplexD dot = innerProduct(p,mmp); dd=real(dot); return dd; } ///////////////////////////////////////////////////////////////////// // Only Def1 has non-trivial Vout. ///////////////////////////////////////////////////////////////////// }; template class TwoLevelADEF2 : public TwoLevelCG { public: /////////////////////////////////////////////////////////////////////////////////// // Need something that knows how to get from Coarse to fine and back again // void ProjectToSubspace(CoarseVector &CoarseVec,const FineField &FineVec){ // void PromoteFromSubspace(const CoarseVector &CoarseVec,FineField &FineVec){ /////////////////////////////////////////////////////////////////////////////////// GridBase *coarsegrid; Aggregation &_Aggregates; LinearFunction &_CoarseSolver; LinearFunction &_CoarseSolverPrecise; /////////////////////////////////////////////////////////////////////////////////// // more most opertor functions TwoLevelADEF2(RealD tol, Integer maxit, LinearOperatorBase &FineLinop, LinearFunction &Smoother, LinearFunction &CoarseSolver, LinearFunction &CoarseSolverPrecise, Aggregation &Aggregates ) : TwoLevelCG(tol,maxit,FineLinop,Smoother,Aggregates.FineGrid), _CoarseSolver(CoarseSolver), _CoarseSolverPrecise(CoarseSolverPrecise), _Aggregates(Aggregates) { coarsegrid = Aggregates.CoarseGrid; }; virtual void PcgM1(Field & in, Field & out) { GRID_TRACE("MultiGridPreconditioner "); // [PTM+Q] in = [1 - Q A] M in + Q in = Min + Q [ in -A Min] Field tmp(this->grid); Field Min(this->grid); CoarseField PleftProj(this->coarsegrid); CoarseField PleftMss_proj(this->coarsegrid); GridStopWatch SmootherTimer; GridStopWatch MatrixTimer; SmootherTimer.Start(); this->_Smoother(in,Min); SmootherTimer.Stop(); MatrixTimer.Start(); this->_FineLinop.HermOp(Min,out); MatrixTimer.Stop(); axpy(tmp,-1.0,out,in); // tmp = in - A Min GridStopWatch ProjTimer; GridStopWatch CoarseTimer; GridStopWatch PromTimer; ProjTimer.Start(); this->_Aggregates.ProjectToSubspace(PleftProj,tmp); ProjTimer.Stop(); CoarseTimer.Start(); this->_CoarseSolver(PleftProj,PleftMss_proj); // Ass^{-1} [in - A Min]_s CoarseTimer.Stop(); PromTimer.Start(); this->_Aggregates.PromoteFromSubspace(PleftMss_proj,tmp);// tmp = Q[in - A Min] PromTimer.Stop(); std::cout << GridLogPerformance << "PcgM1 breakdown "<grid); Field mmp(this->grid); CoarseField PleftProj(this->coarsegrid); CoarseField PleftMss_proj(this->coarsegrid); std::cout << GridLogMessage<<"HDCG: fPcg Vstart projecting "<_Aggregates.ProjectToSubspace(PleftProj,src); std::cout << GridLogMessage<<"HDCG: fPcg Vstart coarse solve "<_CoarseSolverPrecise(PleftProj,PleftMss_proj); // Ass^{-1} r_s std::cout << GridLogMessage<<"HDCG: fPcg Vstart promote "<_Aggregates.PromoteFromSubspace(PleftMss_proj,x); } }; template class TwoLevelADEF1defl : public TwoLevelCG { public: const std::vector &evec; const std::vector &eval; TwoLevelADEF1defl(RealD tol, Integer maxit, LinearOperatorBase &FineLinop, LinearFunction &Smoother, std::vector &_evec, std::vector &_eval) : TwoLevelCG(tol,maxit,FineLinop,Smoother,_evec[0].Grid()), evec(_evec), eval(_eval) {}; // Can just inherit existing M2 // Can just inherit existing M3 // Simple vstart - do nothing virtual void Vstart(Field & x,const Field & src){ x=src; // Could apply Q }; // Override PcgM1 virtual void PcgM1(Field & in, Field & out) { GRID_TRACE("EvecPreconditioner "); int N=evec.size(); Field Pin(this->grid); Field Qin(this->grid); //MP + Q = M(1-AQ) + Q = M // // If we are eigenvector deflating in coarse space // // Q = Sum_i |phi_i> 1/lambda_i _Smoother(Pin,out); out = out + Qin; } }; NAMESPACE_END(Grid); #endif