#ifndef GRID_CONJUGATE_MULTI_SHIFT_GRADIENT_H #define GRID_CONJUGATE_MULTI_SHIFT_GRADIENT_H namespace Grid { ///////////////////////////////////////////////////////////// // Base classes for iterative processes based on operators // single input vec, single output vec. ///////////////////////////////////////////////////////////// template class ConjugateGradientMultiShift : public OperatorMultiFunction, public OperatorFunction { public: RealD Tolerance; Integer MaxIterations; int verbose; MultiShiftFunction shifts; ConjugateGradientMultiShift(Integer maxit,MultiShiftFunction &_shifts) : MaxIterations(maxit), shifts(_shifts) { verbose=1; } void operator() (LinearOperatorBase &Linop, const Field &src, Field &psi) { GridBase *grid = src._grid; int nshift = shifts.order; std::vector results(nshift,grid); (*this)(Linop,src,results); psi = shifts.norm*src; for(int i=0;i &Linop, const Field &src, std::vector &psi) { GridBase *grid = src._grid; //////////////////////////////////////////////////////////////////////// // Convenience references to the info stored in "MultiShiftFunction" //////////////////////////////////////////////////////////////////////// int nshift = shifts.order; std::vector &mass(shifts.poles); // Make references to array in "shifts" std::vector &mresidual(shifts.tolerances); std::vector alpha(nshift,1.0); std::vector ps(nshift,grid);// Search directions assert(psi.size()==nshift); assert(mass.size()==nshift); assert(mresidual.size()==nshift); // dynamic sized arrays on stack; 2d is a pain with vector RealD bs[nshift]; RealD rsq[nshift]; RealD z[nshift][2]; int converged[nshift]; const int primary =0; //Primary shift fields CG iteration RealD a,b,c,d; RealD cp,bp,qq; //prev // Matrix mult fields Field r(grid); Field p(grid); Field tmp(grid); Field mmp(grid); // Check lightest mass for(int s=0;s= mass[primary] ); converged[s]=0; } // Wire guess to zero // Residuals "r" are src // First search direction "p" is also src cp = norm2(src); for(int s=0;s 2+Ls, so ~ 3x saving // Pipelined CG gain: // // New Kernel: Load r, vector of coeffs, vector of pointers ps // New Kernel: Load psi[0], vector of coeffs, vector of pointers ps // If can predict the coefficient bs then we can fuse these and avoid write reread cyce // on ps[s]. // Before: 3 x npole + 3 x npole // After : 2 x npole (ps[s]) => 3x speed up of multishift CG. if( (!converged[s]) ) { axpy(psi[ss],-bs[s]*alpha[s],ps[s],psi[ss]); } } // Convergence checks int all_converged = 1; for(int s=0;s