Annotation of /home/cljanss/src/SC/src/lib/chemistry/qc/scf/scfvector.cc for ./mpqc.vmon.0018

    1                                                             //
    2                                                             // scfvector.cc --- implementation of SCF::compute_vector
    3                                                             //
    4                                                             // Copyright (C) 1996 Limit Point Systems, Inc.
    5                                                             //
    6                                                             // Author: Edward Seidl <seidl@janed.com>
    7                                                             // Maintainer: LPS
    8                                                             //
    9                                                             // This file is part of the SC Toolkit.
   10                                                             //
   11                                                             // The SC Toolkit is free software; you can redistribute it and/or modify
   12                                                             // it under the terms of the GNU Library General Public License as published by
   13                                                             // the Free Software Foundation; either version 2, or (at your option)
   14                                                             // any later version.
   15                                                             //
   16                                                             // The SC Toolkit is distributed in the hope that it will be useful,
   17                                                             // but WITHOUT ANY WARRANTY; without even the implied warranty of
   18                                                             // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19                                                             // GNU Library General Public License for more details.
   20                                                             //
   21                                                             // You should have received a copy of the GNU Library General Public License
   22                                                             // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
   23                                                             // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
   24                                                             //
   25                                                             // The U.S. Government is granted a limited license as per AL 91-7.
   26                                                             //
   27                                                             
   28                                                             #include <util/misc/timer.h>
   29                                                             #include <util/misc/formio.h>
   30                                                             
   31                                                             #include <math/scmat/offset.h>
   32                                                             #include <math/scmat/blocked.h>
   33                                                             #include <math/scmat/blkiter.h>
   34                                                             
   35                                                             #include <math/optimize/diis.h>
   36                                                             #include <math/optimize/scextrapmat.h>
   37                                                             
   38                                                             #include <chemistry/qc/basis/symmint.h>
   39                                                             
   40                                                             #include <chemistry/qc/scf/scf.h>
   41                                                             #include <chemistry/qc/scf/scfops.h>
   42                                                             #include <chemistry/qc/scf/scflocal.h>
   43                                                             
   44                                                             using namespace std;
   45                                                             
   46                                                             #undef GENERALIZED_EIGENSOLVER
   47                                                             
   48                                                             ///////////////////////////////////////////////////////////////////////////
   49                                                             
   50                                                             extern "C" {
   51                                                               void
   52                                                               dsygv_(int *ITYPE, const char *JOBZ, const char *UPLO,
   53                                                                      int *N, double *A, int *LDA, double *B, int *LDB,
   54                                                                      double *W, double *WORK, int *LWORK, int *INFO);
   55                                                             }
   56                                                             
   57                                                             double
   58                                                             SCF::compute_vector(double& eelec)
   59                                                             {
   60                                                               tim_enter("vector");
   61                                                               int i;
   62                                                             
   63                                                               // reinitialize the extrapolation object
   64                                                               extrap_->reinitialize();
   65                                                               
   66                                                               // create level shifter
   67                                                               LevelShift *level_shift = new LevelShift(this);
   68                                                               level_shift->reference();
   69                                                               
   70                                                               // calculate the core Hamiltonian
   71                                                               hcore_ = core_hamiltonian();
   72                                                             
   73                                                               // add density independant contributions to Hcore
   74                                                               accumdih_->accum(hcore_);
   75                                                             
   76                                                               // set up subclass for vector calculation
   77                                                               init_vector();
   78                                                               
   79                                                               // calculate the nuclear repulsion energy
   80                                                               double nucrep = molecule()->nuclear_repulsion_energy();
   81                                                               ExEnv::out() << node0 << indent
   82                                                                    << scprintf("nuclear repulsion energy = %15.10f", nucrep)
   83                                                                    << endl << endl;
   84                                                             
   85                                                               RefDiagSCMatrix evals(oso_dimension(), basis_matrixkit());
   86                                                             
   87                                                               double delta = 1.0;
   88                                                               int iter, iter_since_reset = 0;
   89                                                               double accuracy = 1.0;
   90                                                               for (iter=0; iter < maxiter_; iter++, iter_since_reset++) {
   91                                                                 // form the density from the current vector 
   92                                                                 tim_enter("density");
   93                                                                 delta = new_density();
   94                                                                 tim_exit("density");
   95                                                                 
   96                                                                 // check convergence
   97                                                                 if (delta < desired_value_accuracy()
   98                                                                     && accuracy < desired_value_accuracy()) break;
   99                                                             
  100                                                                 // reset the density from time to time
  101                                                                 if (iter_since_reset && !(iter_since_reset%dens_reset_freq_)) {
  102                                                                   reset_density();
  103                                                                   iter_since_reset = 0;
  104                                                                 }
  105                                                                   
  106                                                                 // form the AO basis fock matrix & add density dependant H
  107                                                                 tim_enter("fock");
  108                                                                 double base_accuracy = delta;
  109                                                                 if (base_accuracy < desired_value_accuracy())
  110                                                                   base_accuracy = desired_value_accuracy();
  111                                                                 double new_accuracy = 0.01 * base_accuracy;
  112                                                                 if (new_accuracy > 0.001) new_accuracy = 0.001;
  113                                                                 if (iter == 0) accuracy = new_accuracy;
  114                                                                 else if (new_accuracy < accuracy) {
  115                                                                   accuracy = new_accuracy/10.0;
  116                                                                   if (iter_since_reset > 0) {
  117                                                                     reset_density();
  118                                                                     iter_since_reset = 0;
  119                                                                   }
  120                                                                 }
  121                                                                 ao_fock(accuracy);
  122                                                                 tim_exit("fock");
  123                                                             
  124                                                                 // calculate the electronic energy
  125                                                                 eelec = scf_energy();
  126                                                                 double eother = 0.0;
  127                                                                 if (accumddh_.nonnull()) eother = accumddh_->e();
  128                                                                 ExEnv::out() << node0 << indent
  129                                                                      << scprintf("iter %5d energy = %15.10f delta = %10.5e",
  130                                                                                  iter+1, eelec+eother+nucrep, delta)
  131                                                                      << endl;
  132                                                             
  133                                                                 // now extrapolate the fock matrix
  134                                                                 tim_enter("extrap");
  135                                                                 Ref<SCExtrapData> data = extrap_data();
  136                                                                 Ref<SCExtrapError> error = extrap_error();
  137                                                                 extrap_->extrapolate(data,error);
  138                                                                 data=0;
  139                                                                 error=0;
  140                                                                 tim_exit("extrap");
  141                                                             
  142                                                             #ifdef GENERALIZED_EIGENSOLVER
  143                                                                 // Get the fock matrix and overlap in the SO basis.  The fock matrix
  144                                                                 // used here works for CLOSED SHELL ONLY.
  145                                                                 RefSymmSCMatrix bfmatref = fock(0);
  146                                                                 RefSymmSCMatrix bsmatref = overlap();
  147                                                                 BlockedSymmSCMatrix *bfmat
  148                                                                   = dynamic_cast<BlockedSymmSCMatrix*>(bfmatref.pointer());
  149                                                                 BlockedSymmSCMatrix *bsmat
  150                                                                   = dynamic_cast<BlockedSymmSCMatrix*>(bsmatref.pointer());
  151                                                                 BlockedDiagSCMatrix *bevals
  152                                                                   = dynamic_cast<BlockedDiagSCMatrix*>(evals.pointer());
  153                                                                 BlockedSCMatrix *bvec
  154                                                                   = dynamic_cast<BlockedSCMatrix*>(oso_scf_vector_.pointer());
  155                                                             
  156                                                                 ExEnv::out() << node0 << indent
  157                                                                              << "solving generalized eigenvalue problem" << endl;
  158                                                             
  159                                                                 for (int iblock=0; iblock<bfmat->nblocks(); iblock++) {
  160                                                                   RefSymmSCMatrix fmat = bfmat->block(iblock);
  161                                                                   RefSymmSCMatrix smat = bsmat->block(iblock);
  162                                                                   RefDiagSCMatrix evalblock = bevals->block(iblock);
  163                                                                   RefSCMatrix oso_scf_vector_block = bvec->block(iblock);
  164                                                                   int nbasis = fmat.dim().n();
  165                                                                   int nbasis2 = nbasis*nbasis;
  166                                                             
  167                                                                   if (!nbasis) continue;
  168                                                             
  169                                                                   // Convert to the lapack storage format.
  170                                                                   double *fso = new double[nbasis2];
  171                                                                   double *sso = new double[nbasis2];
  172                                                                   int ij=0;
  173                                                                   for (int i=0; i<nbasis; i++) {
  174                                                                     for (int j=0; j<nbasis; j++,ij++) {
  175                                                                       fso[ij] = fmat(i,j);
  176                                                                       sso[ij] = smat(i,j);
  177                                                                     }
  178                                                                   }
  179                                                             
  180                                                                   // solve generalized eigenvalue problem with DSYGV
  181                                                                   int itype = 1;
  182                                                                   double *epsilon = new double[nbasis];
  183                                                                   int lwork = -1;
  184                                                                   int info;
  185                                                                   double optlwork;
  186                                                                   dsygv_(&itype,"V","U",&nbasis,fso,&nbasis,sso,&nbasis,
  187                                                                          epsilon,&optlwork,&lwork,&info);
  188                                                                   if (info) {
  189                                                                     ExEnv::out() << "dsygv could not determine work size: info = "
  190                                                                                  << info << endl;
  191                                                                     abort();
  192                                                                   }
  193                                                                   lwork = (int)optlwork;
  194                                                                   double *work = new double[lwork];
  195                                                                   dsygv_(&itype,"V","U",&nbasis,fso,&nbasis,sso,&nbasis,
  196                                                                          epsilon,work,&lwork,&info);
  197                                                                   if (info) {
  198                                                                     ExEnv::out() << "dsygv could not diagonalize matrix: info = "
  199                                                                                  << info << endl;
  200                                                                     abort();
  201                                                                   }
  202                                                                   double *z = fso; // the vector is placed in fso
  203                                                             
  204                                                                   // make sure everyone agrees on the new arrays
  205                                                                   scf_grp_->bcast(z, nbasis2);
  206                                                                   scf_grp_->bcast(epsilon, nbasis);
  207                                                             
  208                                                                   evalblock->assign(epsilon);
  209                                                                   oso_scf_vector_block->assign(z);
  210                                                             
  211                                                                   // cleanup
  212                                                                   delete[] fso;
  213                                                                   delete[] work;
  214                                                                   delete[] sso;
  215                                                                   delete[] epsilon;
  216                                                                 }
  217                                                             
  218                                                                 oso_scf_vector_ = (oso_scf_vector_ * so_to_orthog_so_inverse()).t();
  219                                                             #else
  220                                                                 // diagonalize effective MO fock to get MO vector
  221                                                                 tim_enter("evals");
  222                                                                 RefSCMatrix nvector(oso_dimension(),oso_dimension(),basis_matrixkit());
  223                                                               
  224     0     0     0     0     1     0     0     0     0     0     RefSymmSCMatrix eff = effective_fock();
  225                                                             
  226                                                                 // level shift effective fock
  227                                                                 level_shift->set_shift(level_shift_);
  228                                                                 eff.element_op(level_shift);
  229                                                             
  230                                                                 if (debug_>1) {
  231                                                                   eff.print("effective 1 body hamiltonian in current mo basis");
  232                                                                 }
  233                                                             
  234                                                                 // transform eff to the oso basis to diagonalize it
  235                                                                 RefSymmSCMatrix oso_eff(oso_dimension(), basis_matrixkit());
  236                                                                 oso_eff.assign(0.0);
  237                                                                 oso_eff.accumulate_transform(oso_scf_vector_,eff);
  238                                                                 eff = 0;
  239                                                                 oso_eff.diagonalize(evals, oso_scf_vector_);
  240                                                             
  241                                                                 tim_exit("evals");
  242                                                             
  243     1     0     0     0     0     0     0     0     0     0     if (debug_>0 && level_shift_ != 0.0) {
  244                                                                   evals.print("level shifted scf eigenvalues");
  245                                                                 }
  246                                                             
  247                                                                 // now un-level shift eigenvalues
  248                                                                 level_shift->set_shift(-level_shift_);
  249                                                                 evals.element_op(level_shift);
  250                                                             #endif
  251                                                             
  252                                                                 if (debug_>0) {
  253                                                                   evals.print("scf eigenvalues");
  254                                                                 }
  255                                                                 
  256                                                                 if (reset_occ_)
  257                                                                   set_occupations(evals);
  258                                                             
  259                                                                 if (debug_>1) {
  260                                                                   oso_scf_vector_.print("OSO basis scf vector");
  261                                                                   (oso_scf_vector_.t()*oso_scf_vector_).print(
  262                                                                     "vOSO.t()*vOSO",ExEnv::out(),14);
  263                                                                 }
  264                                                               }
  265                                                                   
  266                                                               eigenvalues_ = evals;
  267                                                               eigenvalues_.computed() = 1;
  268                                                               eigenvalues_.set_actual_accuracy(accuracy<delta?delta:accuracy);
  269                                                             
  270                                                               // search for HOMO and LUMO
  271                                                               // first convert evals to something we can deal with easily
  272                                                               BlockedDiagSCMatrix *evalsb = require_dynamic_cast<BlockedDiagSCMatrix*>(evals,
  273                                                                                                              "SCF::compute_vector");
  274                                                               
  275                                                               CharacterTable ct = molecule()->point_group()->char_table();
  276                                                               
  277                                                               int homo_ir=0, lumo_ir=0;
  278                                                               int homo_mo = -1, lumo_mo = -1;
  279                                                               double homo=-1e99, lumo=1e99;
  280                                                               for (i=0; i < oso_dimension()->blocks()->nblock(); i++) {
  281                                                                 int nf=oso_dimension()->blocks()->size(i);
  282                                                                 if (nf) {
  283                                                                   double *vals = new double[nf];
  284                                                                   evalsb->block(i)->convert(vals);
  285                                                             
  286                                                                   for (int mo=0; mo < nf; mo++) {
  287                                                                     if (occupation(i, mo) > 0.0) {
  288                                                                       if (vals[mo] > homo) {
  289                                                                         homo = vals[mo];
  290                                                                         homo_ir = i;
  291                                                                         homo_mo = mo;
  292                                                                       }
  293                                                                     } else {
  294                                                                       if (vals[mo] < lumo) {
  295                                                                         lumo = vals[mo];
  296                                                                         lumo_ir = i;
  297                                                                         lumo_mo = mo;
  298                                                                       }
  299                                                                     }
  300                                                                   }
  301                                                             
  302                                                                   if (print_all_evals_ || print_occ_evals_) {
  303                                                                     ExEnv::out() << node0 << endl
  304                                                                          << indent << ct.gamma(i).symbol() << endl << incindent;
  305                                                                     for (int m=0; m < nf; m++) {
  306                                                                       if (occupation(i,m) < 1e-8 && !print_all_evals_)
  307                                                                         break;
  308                                                                       ExEnv::out() << node0 << indent
  309                                                                            << scprintf("%5d %10.5f %10.5f", m+1, vals[m], occupation(i,m))
  310                                                                            << endl;
  311                                                                     }
  312                                                                     ExEnv::out() << node0 << decindent;
  313                                                                   }
  314                                                             
  315                                                                   delete[] vals;
  316                                                                 }
  317                                                               }
  318                                                             
  319                                                               if (homo_mo >= 0) {
  320                                                                 ExEnv::out() << node0 << endl << indent
  321                                                                      << scprintf("HOMO is %5d %3s = %10.6f",
  322                                                                                  homo_mo+1, 
  323                                                                                  ct.gamma(homo_ir).symbol(),
  324                                                                                  homo)
  325                                                                      << endl;
  326                                                               }
  327                                                               if (lumo_mo >= 0) {
  328                                                                 ExEnv::out() << node0 << indent
  329                                                                      << scprintf("LUMO is %5d %3s = %10.6f",
  330                                                                                  lumo_mo+1, 
  331                                                                                  ct.gamma(lumo_ir).symbol(),
  332                                                                                  lumo)
  333                                                                      << endl;
  334                                                               }
  335                                                             
  336                                                               // free up evals
  337                                                               evals = 0;
  338                                                               
  339                                                               oso_eigenvectors_ = oso_scf_vector_;
  340                                                               oso_eigenvectors_.computed() = 1;
  341                                                               oso_eigenvectors_.set_actual_accuracy(delta);
  342                                                             
  343                                                               // now clean up
  344                                                               done_vector();
  345                                                               hcore_ = 0;
  346                                                             
  347                                                               level_shift->dereference();
  348                                                               delete level_shift;
  349                                                             
  350                                                               tim_exit("vector");
  351                                                               //tim_print(0);
  352                                                             
  353                                                               return delta;
  354                                                             }
  355                                                             
  356                                                             ////////////////////////////////////////////////////////////////////////////
  357                                                             
  358                                                             class ExtrapErrorOp : public BlockedSCElementOp {
  359                                                               private:
  360                                                                 SCF *scf_;
  361                                                             
  362                                                               public:
  363                                                                 ExtrapErrorOp(SCF *s) : scf_(s) {}
  364                                                                 ~ExtrapErrorOp() {}
  365                                                             
  366                                                                 int has_side_effects() { return 1; }
  367                                                             
  368                                                                 void process(SCMatrixBlockIter& bi) {
  369                                                                   int ir=current_block();
  370                                                                   
  371                                                                   for (bi.reset(); bi; bi++) {
  372     7     0     2     0     4     0     0     0     0     0         int i=bi.i();
  373     3     0     1     0     0     0     0     0     0     0         int j=bi.j();
  374    10     0     9     2     7     2     0     0     0     0         if (scf_->occupation(ir,i) == scf_->occupation(ir,j))
  375     2     0     3     0     3     0     0     0     0     0           bi.set(0.0);
  376                                                                   }
  377                                                                 }
  378                                                             };
  379                                                             
  380                                                             Ref<SCExtrapError>
  381                                                             SCF::extrap_error()
  382                                                             {
  383                                                               RefSymmSCMatrix mofock = effective_fock();
  384                                                               
  385                                                               Ref<SCElementOp> op = new ExtrapErrorOp(this);
  386                                                               mofock.element_op(op);
  387                                                               
  388                                                               RefSymmSCMatrix aoerror(so_dimension(), basis_matrixkit());
  389                                                               aoerror.assign(0.0);
  390                                                               aoerror.accumulate_transform(so_to_orthog_so().t()*oso_scf_vector_, mofock);
  391     0     0     0     0     0     0     1     0     0     0   mofock=0;
  392                                                             
  393                                                               Ref<SCExtrapError> error = new SymmSCMatrixSCExtrapError(aoerror);
  394                                                               aoerror=0;
  395                                                             
  396                                                               return error;
  397                                                             }
  398                                                             
  399                                                             /////////////////////////////////////////////////////////////////////////////
  400                                                             
  401                                                             // Local Variables:
  402                                                             // mode: c++
  403                                                             // c-file-style: "ETS"
  404                                                             // End:
  405