void Print(const DiagonalMatrix& X) { ++PCN; cout << "\nMatrix type: " << X.Type().Value() << " ("; cout << X.Nrows() << ", "; cout << X.Ncols() << ")\n\n"; if (X.IsZero()) { cout << "All elements are zero\n" << flush; return; } int nr=X.Nrows(); int nc=X.Ncols(); for (int i=1; i<=nr; i++) { for (int j=1; j<i; j++) cout << "\t"; if (i<=nc) cout << X(i,i) << "\t"; cout << "\n"; } cout << flush; ++PCZ; }
void SpinAdapted::Linear::block_davidson(vector<Wavefunction>& b, DiagonalMatrix& h_diag, double normtol, const bool &warmUp, Davidson_functor& h_multiply, bool& useprecond, int currentRoot, std::vector<Wavefunction> &lowerStates) { pout.precision (12); #ifndef SERIAL mpi::communicator world; #endif int iter = 0; double levelshift = 0.0; int nroots = b.size(); //normalise all the guess roots if(mpigetrank() == 0) { for(int i=0; i<nroots; ++i) { for(int j=0; j<i; ++j) { double overlap = DotProduct(b[j], b[i]); ScaleAdd(-overlap, b[j], b[i]); } Normalise(b[i]); } //if we are doing state specific, lowerstates has lower energy states if (lowerStates.size() != 0) { for (int i=0; i<lowerStates.size(); i++) { double overlap = DotProduct(b[0], lowerStates[i]); ScaleAdd(-overlap/DotProduct(lowerStates[i], lowerStates[i]), lowerStates[i], b[0]); } Normalise(b[0]); } } vector<Wavefunction> sigma; int converged_roots = 0; int maxiter = h_diag.Ncols() - lowerStates.size(); while(true) { if (dmrginp.outputlevel() > 0) pout << "\t\t\t Davidson Iteration :: " << iter << endl; ++iter; dmrginp.hmultiply -> start(); int sigmasize, bsize; if (mpigetrank() == 0) { sigmasize = sigma.size(); bsize = b.size(); } #ifndef SERIAL mpi::broadcast(world, sigmasize, 0); mpi::broadcast(world, bsize, 0); #endif //multiply all guess vectors with hamiltonian c = Hv for(int i=sigmasize; i<bsize; ++i) { Wavefunction sigmai, bi; Wavefunction* sigmaptr=&sigmai, *bptr = &bi; if (mpigetrank() == 0) { sigma.push_back(b[i]); sigma[i].Clear(); sigmaptr = &sigma[i]; bptr = &b[i]; } #ifndef SERIAL mpi::broadcast(world, *bptr, 0); #endif if (mpigetrank() != 0) { sigmai = bi; sigmai.Clear(); } h_multiply(*bptr, *sigmaptr); //if (mpigetrank() == 0) { // cout << *bptr << endl; // cout << *sigmaptr << endl; //} } dmrginp.hmultiply -> stop(); Wavefunction r; DiagonalMatrix subspace_eigenvalues; if (mpigetrank() == 0) { Matrix subspace_h(b.size(), b.size()); for (int i = 0; i < b.size(); ++i) for (int j = 0; j <= i; ++j) { subspace_h.element(i, j) = DotProduct(b[i], sigma[j]); subspace_h.element(j, i) = subspace_h.element(i, j); } Matrix alpha; diagonalise(subspace_h, subspace_eigenvalues, alpha); if (dmrginp.outputlevel() > 0) { for (int i = 1; i <= subspace_eigenvalues.Ncols (); ++i) pout << "\t\t\t " << i << " :: " << subspace_eigenvalues(i,i)+dmrginp.get_coreenergy() << endl; } //now calculate the ritz vectors which are approximate eigenvectors vector<Wavefunction> btmp = b; vector<Wavefunction> sigmatmp = sigma; for (int i = 0; i < b.size(); ++i) { Scale(alpha.element(i, i), b[i]); Scale(alpha.element(i, i), sigma[i]); } for (int i = 0; i < b.size(); ++i) for (int j = 0; j < b.size(); ++j) { if (i != j) { ScaleAdd(alpha.element(i, j), btmp[i], b[j]); ScaleAdd(alpha.element(i, j), sigmatmp[i], sigma[j]); } } // build residual for (int i=0; i<converged_roots; i++) { r = sigma[i]; ScaleAdd(-subspace_eigenvalues(i+1), b[i], r); double rnorm = DotProduct(r,r); if (rnorm > normtol) { converged_roots = i; if (dmrginp.outputlevel() > 0) pout << "\t\t\t going back to converged root "<<i<<" "<<rnorm<<" > "<<normtol<<endl; continue; } } r = sigma[converged_roots]; ScaleAdd(-subspace_eigenvalues(converged_roots+1), b[converged_roots], r); if (lowerStates.size() != 0) { for (int i=0; i<lowerStates.size(); i++) { double overlap = DotProduct(r, lowerStates[i]); ScaleAdd(-overlap/DotProduct(lowerStates[i], lowerStates[i]), lowerStates[i], r); //ScaleAdd(-overlap, lowerStates[i], r); } } } double rnorm; if (mpigetrank() == 0) rnorm = DotProduct(r,r); #ifndef SERIAL mpi::broadcast(world, converged_roots, 0); mpi::broadcast(world, rnorm, 0); #endif if (useprecond && mpigetrank() == 0) olsenPrecondition(r, b[converged_roots], subspace_eigenvalues(converged_roots+1), h_diag, levelshift); if (dmrginp.outputlevel() > 0) pout << "\t \t \t residual :: " << rnorm << endl; if (rnorm < normtol) { if (dmrginp.outputlevel() > 0) pout << "\t\t\t Converged root " << converged_roots << endl; ++converged_roots; if (converged_roots == nroots) { if (mpigetrank() == 0) { for (int i = 0; i < min((int)(b.size()), h_diag.Ncols()); ++i) h_diag.element(i) = subspace_eigenvalues.element(i); } break; } } else if (mpigetrank() == 0) { if(b.size() >= dmrginp.deflation_max_size()) { if (dmrginp.outputlevel() > 0) pout << "\t\t\t Deflating block Davidson...\n"; b.resize(dmrginp.deflation_min_size()); sigma.resize(dmrginp.deflation_min_size()); } for (int j = 0; j < b.size(); ++j) { //Normalize double normalization = DotProduct(r, r); Scale(1./sqrt(normalization), r); double overlap = DotProduct(r, b[j]); ScaleAdd(-overlap, b[j], r); } //if we are doing state specific, lowerstates has lower energy states if (lowerStates.size() != 0) { for (int i=0; i<lowerStates.size(); i++) { double overlap = DotProduct(r, lowerStates[i]); ScaleAdd(-overlap/DotProduct(lowerStates[i], lowerStates[i]), lowerStates[i], r); //ScaleAdd(-overlap, lowerStates[i], r); } } //double tau2 = DotProduct(r,r); Normalise(r); b.push_back(r); } } }