Beispiel #1
0
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;
}
Beispiel #2
0
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);

        }


    }
}