📄 hsosscf.cc
字号:
//// hsosscf.cc --- implementation of the high-spin open shell SCF class//// 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 <util/misc/timer.h>#include <util/misc/formio.h>#include <util/state/stateio.h>#include <math/scmat/block.h>#include <math/scmat/blocked.h>#include <math/scmat/blkiter.h>#include <math/scmat/local.h>#include <math/optimize/scextrapmat.h>#include <chemistry/qc/basis/petite.h>#include <chemistry/qc/scf/scflocal.h>#include <chemistry/qc/scf/scfops.h>#include <chemistry/qc/scf/effh.h>#include <chemistry/qc/scf/hsosscf.h>#include <chemistry/qc/scf/ltbgrad.h>#include <chemistry/qc/scf/hsoshftmpl.h>using namespace std;using namespace sc;///////////////////////////////////////////////////////////////////////////// HSOSSCFstatic ClassDesc HSOSSCF_cd( typeid(HSOSSCF),"HSOSSCF",2,"public SCF", 0, 0, 0);HSOSSCF::HSOSSCF(StateIn& s) : SavableState(s), SCF(s), cl_fock_(this), op_fock_(this){ cl_fock_.result_noupdate() = basis_matrixkit()->symmmatrix(so_dimension()); cl_fock_.restore_state(s); cl_fock_.result_noupdate().restore(s); op_fock_.result_noupdate() = basis_matrixkit()->symmmatrix(so_dimension()); op_fock_.restore_state(s); op_fock_.result_noupdate().restore(s); s.get(user_occupations_); s.get(tndocc_); s.get(tnsocc_); s.get(nirrep_); s.get(ndocc_); s.get(nsocc_); if (s.version(::class_desc<HSOSSCF>()) >= 2) { s.get(initial_ndocc_); s.get(initial_nsocc_); most_recent_pg_ << SavableState::restore_state(s); } else { initial_ndocc_ = new int[nirrep_]; memcpy(initial_ndocc_, ndocc_, sizeof(int)*nirrep_); initial_nsocc_ = new int[nirrep_]; memcpy(initial_nsocc_, nsocc_, sizeof(int)*nirrep_); } // now take care of memory stuff init_mem(4);}HSOSSCF::HSOSSCF(const Ref<KeyVal>& keyval) : SCF(keyval), cl_fock_(this), op_fock_(this){ int i; cl_fock_.compute()=0; cl_fock_.computed()=0; op_fock_.compute()=0; op_fock_.computed()=0; // calculate the total nuclear charge double Znuc=molecule()->nuclear_charge(); // check to see if this is to be a charged molecule double charge = keyval->doublevalue("total_charge"); int nelectrons = (int)(Znuc-charge+1.0e-4); // first let's try to figure out how many open shells there are if (keyval->exists("nsocc")) { tnsocc_ = keyval->intvalue("nsocc"); } else if (keyval->exists("multiplicity")) { tnsocc_ = keyval->intvalue("multiplicity")-1; } else { // if there's an odd number of electrons, then do a doublet, otherwise // do a triplet if (nelectrons%2) tnsocc_=1; else tnsocc_=2; } // now do the same for the number of doubly occupied shells if (keyval->exists("ndocc")) { tndocc_ = keyval->intvalue("ndocc"); } else { tndocc_ = (nelectrons-tnsocc_)/2; if ((nelectrons-tnsocc_)%2) { ExEnv::err0() << endl << indent << "HSOSSCF::init: Warning, there's a leftover electron.\n" << incindent << indent << "total_charge = " << charge << endl << indent << "total nuclear charge = " << Znuc << endl << indent << "ndocc_ = " << tndocc_ << endl << indent << "nsocc_ = " << tnsocc_ << endl << decindent; } } ExEnv::out0() << endl << indent << "HSOSSCF::init: total charge = " << Znuc-2*tndocc_-tnsocc_ << endl << endl; nirrep_ = molecule()->point_group()->char_table().ncomp(); ndocc_ = read_occ(keyval, "docc", nirrep_); nsocc_ = read_occ(keyval, "socc", nirrep_); if (ndocc_ && nsocc_) { user_occupations_=1; initial_ndocc_ = new int[nirrep_]; memcpy(initial_ndocc_, ndocc_, sizeof(int)*nirrep_); initial_nsocc_ = new int[nirrep_]; memcpy(initial_nsocc_, nsocc_, sizeof(int)*nirrep_); } else if (ndocc_ && !nsocc_ || !ndocc_ && nsocc_) { ExEnv::outn() << "ERROR: HSOSSCF: only one of docc and socc specified: " << "give both or none" << endl; abort(); } else { ndocc_=0; nsocc_=0; initial_ndocc_=0; initial_nsocc_=0; user_occupations_=0; set_occupations(0); } ExEnv::out0() << indent << "docc = ["; for (i=0; i < nirrep_; i++) ExEnv::out0() << " " << ndocc_[i]; ExEnv::out0() << " ]\n"; ExEnv::out0() << indent << "socc = ["; for (i=0; i < nirrep_; i++) ExEnv::out0() << " " << nsocc_[i]; ExEnv::out0() << " ]\n"; // check to see if this was done in SCF(keyval) if (!keyval->exists("maxiter")) maxiter_ = 100; if (!keyval->exists("level_shift")) level_shift_ = 0.25; // now take care of memory stuff init_mem(4);}HSOSSCF::~HSOSSCF(){ if (ndocc_) { delete[] ndocc_; ndocc_=0; } if (nsocc_) { delete[] nsocc_; nsocc_=0; } delete[] initial_ndocc_; delete[] initial_nsocc_;}voidHSOSSCF::save_data_state(StateOut& s){ SCF::save_data_state(s); cl_fock_.save_data_state(s); cl_fock_.result_noupdate().save(s); op_fock_.save_data_state(s); op_fock_.result_noupdate().save(s); s.put(user_occupations_); s.put(tndocc_); s.put(tnsocc_); s.put(nirrep_); s.put(ndocc_,nirrep_); s.put(nsocc_,nirrep_); s.put(initial_ndocc_,nirrep_); s.put(initial_nsocc_,nirrep_); SavableState::save_state(most_recent_pg_.pointer(),s);}doubleHSOSSCF::occupation(int ir, int i){ if (i < ndocc_[ir]) return 2.0; else if (i < ndocc_[ir] + nsocc_[ir]) return 1.0; return 0.0;}doubleHSOSSCF::alpha_occupation(int ir, int i){ if (i < ndocc_[ir] + nsocc_[ir]) return 1.0; return 0.0;}doubleHSOSSCF::beta_occupation(int ir, int i){ if (i < ndocc_[ir]) return 1.0; return 0.0;}intHSOSSCF::n_fock_matrices() const{ return 2;}RefSymmSCMatrixHSOSSCF::fock(int n){ if (n > 1) { ExEnv::err0() << indent << "HSOSSCF::fock: there are only two fock matrices, " << scprintf("but fock(%d) was requested\n",n); abort(); } if (n==0) return cl_fock_.result(); else return op_fock_.result();}intHSOSSCF::spin_polarized(){ return 1;}voidHSOSSCF::print(ostream&o) const{ int i; SCF::print(o); o << indent << "HSOSSCF Parameters:\n" << incindent << indent << "charge = " << molecule()->nuclear_charge() - 2*tndocc_ - tnsocc_ << endl << indent << "ndocc = " << tndocc_ << endl << indent << "nsocc = " << tnsocc_ << endl << indent << "docc = ["; for (i=0; i < nirrep_; i++) o << " " << ndocc_[i]; o << " ]" << endl; o << indent << "socc = ["; for (i=0; i < nirrep_; i++) o << " " << nsocc_[i]; o << " ]" << endl << decindent << endl;}//////////////////////////////////////////////////////////////////////////////voidHSOSSCF::set_occupations(const RefDiagSCMatrix& ev){ if (user_occupations_ || (initial_ndocc_ && initial_nsocc_ && ev.null())) { if (form_occupations(ndocc_, initial_ndocc_) &&form_occupations(nsocc_, initial_nsocc_)) { most_recent_pg_ = new PointGroup(molecule()->point_group()); return; } delete[] ndocc_; ndocc_ = 0; delete[] nsocc_; nsocc_ = 0; ExEnv::out0() << indent << "HSOSSCF: WARNING: reforming occupation vectors from scratch" << endl; } if (nirrep_==1) { delete[] ndocc_; ndocc_=new int[1]; ndocc_[0]=tndocc_; if (!initial_ndocc_) { initial_ndocc_=new int[1]; initial_ndocc_[0]=tndocc_; } delete[] nsocc_; nsocc_=new int[1]; nsocc_[0]=tnsocc_; if (!initial_nsocc_) { initial_nsocc_=new int[1]; initial_nsocc_[0]=tnsocc_; } return; } int i,j; RefDiagSCMatrix evals; if (ev.null()) { initial_vector(0); evals = eigenvalues_.result_noupdate(); } else evals = ev; // first convert evals to something we can deal with easily BlockedDiagSCMatrix *evalsb = require_dynamic_cast<BlockedDiagSCMatrix*>(evals, "HSOSSCF::set_occupations"); double **vals = new double*[nirrep_]; for (i=0; i < nirrep_; i++) { int nf=oso_dimension()->blocks()->size(i); if (nf) { vals[i] = new double[nf]; evalsb->block(i)->convert(vals[i]); } else { vals[i] = 0; } } // now loop to find the tndocc_ lowest eigenvalues and populate those // MO's int *newdocc = new int[nirrep_]; memset(newdocc,0,sizeof(int)*nirrep_); for (i=0; i < tndocc_; i++) { // find lowest eigenvalue int lir=0,ln=0; double lowest=999999999; for (int ir=0; ir < nirrep_; ir++) { int nf=oso_dimension()->blocks()->size(ir); if (!nf) continue; for (j=0; j < nf; j++) { if (vals[ir][j] < lowest) { lowest=vals[ir][j]; lir=ir; ln=j; } } } vals[lir][ln]=999999999; newdocc[lir]++; } int *newsocc = new int[nirrep_]; memset(newsocc,0,sizeof(int)*nirrep_); for (i=0; i < tnsocc_; i++) { // find lowest eigenvalue int lir=0,ln=0; double lowest=999999999; for (int ir=0; ir < nirrep_; ir++) { int nf=oso_dimension()->blocks()->size(ir); if (!nf) continue; for (j=0; j < nf; j++) { if (vals[ir][j] < lowest) { lowest=vals[ir][j]; lir=ir; ln=j; } } } vals[lir][ln]=999999999; newsocc[lir]++; } // get rid of vals for (i=0; i < nirrep_; i++) if (vals[i]) delete[] vals[i]; delete[] vals; if (!ndocc_) { ndocc_=newdocc; nsocc_=newsocc; } else if (most_recent_pg_.nonnull() && most_recent_pg_->equiv(molecule()->point_group())) { // test to see if newocc is different from ndocc_ for (i=0; i < nirrep_; i++) { if (ndocc_[i] != newdocc[i]) { ExEnv::err0() << indent << "HSOSSCF::set_occupations: WARNING!!!!\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -