From d4fa09137aeb452c31f4f6e50d3816064258b14b Mon Sep 17 00:00:00 2001 From: jiri Date: Tue, 4 Apr 2006 02:16:46 +0000 Subject: [PATCH] *** empty log message *** --- davidson.h | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 221 insertions(+), 1 deletion(-) diff --git a/davidson.h b/davidson.h index 223d044..81959d9 100644 --- a/davidson.h +++ b/davidson.h @@ -1,12 +1,15 @@ +#ifndef _davidson_h +#define _davidson_h #include "vec.h" #include "smat.h" #include "mat.h" #include "sparsemat.h" #include "nonclass.h" +#include "auxstorage.h" //Davidson diagonalization of real symmetric matrix (modified Lanczos) -//matrix can be any class which has nrows(), ncols(), diagonalof() and NRVec::gemv() available +//matrix can be any class which has nrows(), ncols(), diagonalof(), issymmetric(), and gemv() available //does not even have to be explicitly stored - direct CI export template @@ -17,3 +20,220 @@ extern void davidson(const Matrix &bigmat, NRVec &eivals, NRVec *eivecs, c //@@@options: left eigenvectors by matrix transpose, overridesymmetric (for nrmat) //@@@small matrix gdiagonalize - shift complex roots up (option to gdiagonalize?) //@@@test gdiagonalize whether it sorts the roots and what for complex ones + + +//Davidson algorithm: J. Comp. Phys. 17:817 (1975) + +//@@@implement left eigenvectors for nonsymmetric case + +template +void davidson(const Matrix &bigmat, NRVec &eivals, NRVec *eivecs, const char *eivecsfile, + int nroots, const bool verbose, const double eps, + const bool incore, int maxit, const int maxkrylov) +{ +bool flag=0; +int n=bigmat.nrows(); +if ( n!= (int)bigmat.ncols()) laerror("non-square matrix in davidson"); +if(eivals.size() vec1(n),vec2(n); +NRMat smallH(maxkrylov,maxkrylov),smallS(maxkrylov,maxkrylov),smallV; +NRVec r(maxkrylov); +NRVec *v0,*v1; +AuxStorage *s0,*s1; + +if(incore) + { + v0 = new NRVec[maxkrylov]; + v1 = new NRVec[maxkrylov]; + } +else + { + s0 = new AuxStorage; + s1 = new AuxStorage; + } + +int i,j; + +if(maxkrylov=maxkrylov) nroots =maxkrylov-1; +int nroot=0; +int oldnroot; +smallS=0; +smallH=0; +//guess based on lowest diagonal element of the matrix +bigmat.diagonalof(vec2); +vec1=0; +{T t=1e100; int i,j; +for(i=0, j= -1; iput(vec1,0); +if(incore) v1[0]=vec2; else s1->put(vec2,0); + + +//iterative Davidson loop +int it; +for(it=0; it0) //if this is the first iteration just need to diagonalise the matrix + { + //update reduced overlap matrix + if(incore) v0[krylovsize]=vec1; else s0->put(vec1,krylovsize); + for(j=0; jget(vec2,j); + smallS(krylovsize,j) = smallS(j,krylovsize) = vec1*(incore?v0[j]:vec2); + } + smallS(krylovsize,krylovsize) = vec1*vec1; + bigmat.gemv(0,vec2,'n',1,vec1); + if(incore) v1[krylovsize]=vec2; else s1->put(vec2,krylovsize); + + //update reduced hamiltonian matrix + smallH(krylovsize,krylovsize) = vec1*vec2; + for(j=0; jget(vec1,j); + smallH(j,krylovsize) = (incore?v0[j]:vec1)*vec2; + if(bigmat.issymmetric()) smallH(krylovsize,j) = smallH(j,krylovsize); + } + if(!bigmat.issymmetric()) + { + if(!incore) s0->get(vec1,krylovsize); + for(j=0; jget(vec2,j); + smallH(krylovsize,j) = incore? v1[j]*v0[krylovsize] :vec1*vec2; + } + } + } +smallV=smallH; +NRMat smallSwork=smallS; +if(bigmat.issymmetric()) + diagonalize(smallV,r,1,1,krylovsize+1,&smallSwork,1); //for symmetric matrix they have already been sorted to ascending order in lapack +else + { + NRVec ri(krylovsize+1),beta(krylovsize+1); + NRMat scratch; + scratch=smallV; + gdiagonalize(scratch, r, ri,NULL, &smallV, 1, krylovsize+1, 2, 0, &smallSwork, &beta); + for(int i=0; i<=krylovsize; ++i) {r[i]/=beta[i]; ri[i]/=beta[i];} + } + +T eival_n=r[nroot]; +oldnroot=nroot; +typename LA_traits::normtype test=abs(smallV(krylovsize,nroot)); +if(testeps) nroot=min(nroot,iroot); + if(verbose && iroot<=max(oldnroot,nroot)) + { + cout <<"Davidson: iter="<=nroots) goto converged; +if (it==maxit-1) break; //not converged + +if (krylovsize==maxkrylov) //restart, krylov space exceeded + { + if(nroot!=0) {flag=1; goto finished;} + smallH=0; + smallS=0; + vec1=0; + for(i=0; i<=krylovsize; ++i) + { + if(!incore) s0->get(vec2,i); + vec1.axpy(smallV(i,0),incore?v0[i]:vec2); + } + s0->put(vec1,0); + vec1.normalize(); + krylovsize = 0; + continue; + } + +//generate the update vector +vec1=0; +for(j=0; j<=krylovsize; ++j) + { + if(!incore) s0->get(vec2,j); + vec1.axpy(-r[nroot]*smallV(j,nroot),incore?v0[j]:vec2); + if(!incore) s1->get(vec2,j); + vec1.axpy(smallV(j,nroot),incore?v1[j]:vec2); + } +bigmat.diagonalof(vec2); +eival_n = r[nroot]; +for(i=0; i::normtype vnorm; + if(!incore) s0->get(vec2,j); + do { + T ab = vec1*(incore?v0[j]:vec2) /smallS(j,j); + vec1.axpy(-ab,incore?v0[j]:vec2); + vnorm = vec1.norm(); + vec1 *= (1./vnorm); + } while (vnorm<0.99); + } + +//here it is possible to apply some purification procedure if the eivector has to fulfill other conditions +//vec1.normalize(); //after the purification + +++krylovsize; //enlarge Krylov space +} +flag=1; +goto finished; + +converged: +AuxStorage::elementtype> *ev; +if(eivecsfile) ev = new AuxStorage::elementtype>(eivecsfile); +if(verbose) cout << "Davidson converged in "<get(vec2,j); + vec1.axpy(smallV(j,nroot),incore?v0[j]:vec2); + } + vec1.normalize(); + if(eivecs) eivecs[nroot]|=vec1; + if(eivecsfile) + { + ev->put(vec1,nroot); + } + } + } + +if(eivecsfile) delete ev; + +finished: +if(incore) {delete[] v0; delete[] v1;} +else {delete s0; delete s1;} + +if(flag) laerror("no convergence in davidson"); +} + + + +#endif