⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 efc.cc

📁 大型并行量子化学软件;支持密度泛函(DFT)。可以进行各种量子化学计算。支持CHARMM并行计算。非常具有应用价值。
💻 CC
字号:
//// efc.cc//// Copyright (C) 1996 Limit Point Systems, Inc.//// Author: Edward Seidl <seidl@janed.com>// Maintainer: LPS//// This file is part of the SC Toolkit.//// The SC Toolkit is free software; you can redistribute it and/or modify// it under the terms of the GNU Library General Public License as published by// the Free Software Foundation; either version 2, or (at your option)// any later version.//// The SC Toolkit is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU Library General Public License for more details.//// You should have received a copy of the GNU Library General Public License// along with the SC Toolkit; see the file COPYING.LIB.  If not, write to// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.//// The U.S. Government is granted a limited license as per AL 91-7.//#ifdef __GNUC__#pragma implementation#endif#include <math.h>#include <float.h>#include <util/state/stateio.h>#include <math/optimize/efc.h>#include <util/misc/formio.h>#include <util/keyval/keyval.h>#include <math/scmat/local.h>using namespace std;using namespace sc;/////////////////////////////////////////////////////////////////////////// EFCOptstatic ClassDesc EFCOpt_cd(  typeid(EFCOpt),"EFCOpt",2,"public Optimize",  0, create<EFCOpt>, create<EFCOpt>);EFCOpt::EFCOpt(const Ref<KeyVal>&keyval):  Optimize(keyval),  maxabs_gradient(-1.0){  update_ << keyval->describedclassvalue("update");    accuracy_ = keyval->doublevalue("accuracy");  if (keyval->error() != KeyVal::OK) accuracy_ = 0.0001;  tstate = keyval->booleanvalue("transition_state");  if (keyval->error() != KeyVal::OK) tstate = 0;  modef = keyval->booleanvalue("mode_following");  if (keyval->error() != KeyVal::OK) modef = 0;  if (tstate)    ExEnv::out0() << endl << indent         << "performing a transition state search\n\n";    RefSymmSCMatrix hessian(dimension(),matrixkit());  // get a guess hessian from function  function()->guess_hessian(hessian);    // see if any hessian matrix elements have been given in the input  if (keyval->exists("hessian")) {    int n = hessian.n();    for (int i=0; i<n; i++) {      if (keyval->exists("hessian",i)) {        for (int j=0; j<=i; j++) {          double tmp = keyval->doublevalue("hessian",i,j);          if (keyval->error() == KeyVal::OK) hessian(i,j) = tmp;        }      }    }  }  hessian_ = hessian;  last_mode_ = 0;}EFCOpt::EFCOpt(StateIn&s):  SavableState(s),  Optimize(s){  s.get(tstate);  s.get(modef);  hessian_ = matrixkit()->symmmatrix(dimension());  hessian_.restore(s);  update_ << SavableState::restore_state(s);  last_mode_ = matrixkit()->vector(dimension());  last_mode_.restore(s);  if (s.version(::class_desc<EFCOpt>()) < 2) {    double convergence;    s.get(convergence);  }  s.get(accuracy_);  s.get(maxabs_gradient);}EFCOpt::~EFCOpt(){}voidEFCOpt::save_data_state(StateOut&s){  Optimize::save_data_state(s);  s.put(tstate);  s.put(modef);  hessian_.save(s);  SavableState::save_state(update_.pointer(),s);  last_mode_.save(s);  s.put(accuracy_);  s.put(maxabs_gradient);}voidEFCOpt::init(){  Optimize::init();  maxabs_gradient = -1.0;}intEFCOpt::update(){  int i,j;    // these are good candidates to be input options  const double maxabs_gradient_to_desired_accuracy = 0.05;  const double maxabs_gradient_to_next_desired_accuracy = 0.005;  const double roundoff_error_factor = 1.1;  // the gradient convergence criterion.  double old_maxabs_gradient = maxabs_gradient;  RefSCVector xcurrent;  RefSCVector gcurrent;  ExEnv::out0().flush();      // get the next gradient at the required level of accuracy.  // usually only one pass is needed, unless we happen to find  // that the accuracy was set too low.  int accurate_enough;  do {    // compute the current point    function()->set_desired_gradient_accuracy(accuracy_);        xcurrent = function()->get_x();    gcurrent = function()->gradient().copy();    // compute the gradient convergence criterion now so i can see if    // the accuracy needs to be tighter    maxabs_gradient = gcurrent.maxabs();    // compute the required accuracy    accuracy_ = maxabs_gradient * maxabs_gradient_to_desired_accuracy;    if (accuracy_ < DBL_EPSILON) accuracy_ = DBL_EPSILON;    // The roundoff_error_factor is thrown in to allow for round off making    // the current gcurrent.maxabs() a bit smaller than the previous,    // which would make the current required accuracy less than the    // gradient's actual accuracy and cause everything to be recomputed.    accurate_enough = (function()->actual_gradient_accuracy() <=                       accuracy_*roundoff_error_factor);    if (!accurate_enough) {      ExEnv::out0() << indent           << "NOTICE: function()->actual_gradient_accuracy() > accuracy_:\n"           << indent << scprintf(             "        function()->actual_gradient_accuracy() = %15.8e",             function()->actual_gradient_accuracy()) << endl           << scprintf(             "                                     accuracy_ = %15.8e",             accuracy_) << endl;    }  } while(!accurate_enough);  if (old_maxabs_gradient >= 0.0 && old_maxabs_gradient < maxabs_gradient) {    ExEnv::out0() << indent         << scprintf("NOTICE: maxabs_gradient increased from %8.4e to %8.4e",                     old_maxabs_gradient, maxabs_gradient) << endl;  }  // update the hessian  if (update_.nonnull()) {    update_->update(hessian_,function(),xcurrent,gcurrent);  }  // begin efc junk  // first diagonalize hessian  RefSCMatrix evecs(dimension(),dimension(),matrixkit());  RefDiagSCMatrix evals(dimension(),matrixkit());  hessian_.diagonalize(evals,evecs);  //evals.print("hessian eigenvalues");  //evecs.print("hessian eigenvectors");  // form gradient to local hessian modes F = Ug  RefSCVector F = evecs.t() * gcurrent;  //F.print("F");  // figure out if hessian has the right number of negative eigenvalues  int ncoord = evals.n();  int npos=0,nneg=0;  for (i=0; i < ncoord; i++) {    if (evals.get_element(i) >= 0.0) npos++;    else nneg++;  }  RefSCVector xdisp(dimension(),matrixkit());  xdisp.assign(0.0);    // for now, we always take the P-RFO for tstate (could take NR if  // nneg==1, but we won't make that an option yet)  if (tstate) {    int mode = 0;    if (modef) {      // which mode are we following.  find mode with maximum overlap with      // last mode followed      if (last_mode_.nonnull()) {        double overlap=0;        for (i=0; i < ncoord; i++) {          double S=0;          for (j=0; j < ncoord; j++) {            S += last_mode_.get_element(j)*evecs.get_element(j,i);          }          S = fabs(S);          if (S > overlap) {            mode = i;            overlap = S;          }        }      } else {        last_mode_ = matrixkit()->vector(dimension());              // find mode with max component = coord 0 which should be the        // mode being followed        double comp=0;        for (i=0; i < ncoord; i++) {          double S = fabs(evecs.get_element(0,i));          if (S>comp) {            mode=i;            comp=S;          }        }      }          for (i=0; i < ncoord; i++)        last_mode_(i) = evecs(i,mode);      ExEnv::out0() << endl << indent << "\n following mode " << mode << endl;    }        double bk = evals(mode);    double Fk = F(mode);    double lambda_p = 0.5*bk + 0.5*sqrt(bk*bk + 4*Fk*Fk);        double lambda_n;    double nlambda=1.0;    do {      lambda_n=nlambda;      nlambda=0;      for (i=0; i < ncoord; i++) {        if (i==mode) continue;                nlambda += F.get_element(i)*F.get_element(i) /                    (lambda_n - evals.get_element(i));      }    } while(fabs(nlambda-lambda_n) > 1.0e-8);    ExEnv::out0()         << indent << scprintf("lambda_p = %8.5g",lambda_p) << endl         << indent << scprintf("lambda_n = %8.5g",lambda_n) << endl;    // form Xk    double Fkobkl = F(mode)/(evals(mode)-lambda_p);    for (j=0; j < F.n(); j++)      xdisp(j) = xdisp(j) - evecs(j,mode) * Fkobkl;        // form displacement x = sum -Fi*Vi/(bi-lam)    for (i=0; i < F.n(); i++) {      if (i==mode) continue;            double Fiobil = F(i) / (evals(i)-lambda_n);      for (j=0; j < F.n(); j++) {        xdisp(j) = xdisp(j) - evecs(j,i) * Fiobil;      }    }     // minimum search  } else {    // evaluate lambda    double lambda;    double nlambda=1.0;    do {      lambda=nlambda;      nlambda=0;      for (i=0; i < F.n(); i++) {        double Fi = F(i);        nlambda += Fi*Fi / (lambda - evals.get_element(i));      }    } while(fabs(nlambda-lambda) > 1.0e-8);    ExEnv::out0() << indent << scprintf("lambda = %8.5g", lambda) << endl;  // form displacement x = sum -Fi*Vi/(bi-lam)    for (i=0; i < F.n(); i++) {      double Fiobil = F(i) / (evals(i)-lambda);      for (j=0; j < F.n(); j++) {        xdisp(j) = xdisp(j) - evecs(j,i) * Fiobil;      }    }  }  // scale the displacement vector if it's too large  double tot = sqrt(xdisp.scalar_product(xdisp));  if (tot > max_stepsize_) {    double scal = max_stepsize_/tot;    ExEnv::out0() << endl << indent         << scprintf("stepsize of %f is too big, scaling by %f",tot,scal)         << endl;    xdisp.scale(scal);    tot *= scal;  }  //xdisp.print("xdisp");  // try steepest descent  // RefSCVector xdisp = -1.0*gcurrent;  RefSCVector xnext = xcurrent + xdisp;  conv_->reset();  conv_->get_grad(function());  conv_->get_x(function());  conv_->set_nextx(xnext);  // check for conergence before resetting the geometry  int converged = conv_->converged();  if (converged)    return converged;  ExEnv::out0() << endl       << indent << scprintf("taking step of size %f",tot) << endl;                      function()->set_x(xnext);  Ref<NonlinearTransform> t = function()->change_coordinates();  apply_transform(t);  // make the next gradient computed more accurate, since it will  // be smaller  accuracy_ = maxabs_gradient * maxabs_gradient_to_next_desired_accuracy;    return converged;}voidEFCOpt::apply_transform(const Ref<NonlinearTransform> &t){  if (t.null()) return;  Optimize::apply_transform(t);  if (last_mode_.nonnull()) t->transform_gradient(last_mode_);  if (hessian_.nonnull()) t->transform_hessian(hessian_);  if (update_.nonnull()) update_->apply_transform(t);}/////////////////////////////////////////////////////////////////////////////// Local Variables:// mode: c++// c-file-style: "ETS"// End:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -