📄 tcscf.cc
字号:
//// tcscf.cc --- implementation of the two-configuration 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/tcscf.h>using namespace std;using namespace sc;///////////////////////////////////////////////////////////////////////////// TCSCFstatic ClassDesc TCSCF_cd( typeid(TCSCF),"TCSCF",1,"public SCF", 0, 0, 0);TCSCF::TCSCF(StateIn& s) : SavableState(s), SCF(s), focka_(this), fockb_(this), ka_(this), kb_(this){ focka_.result_noupdate() = basis_matrixkit()->symmmatrix(so_dimension()); focka_.restore_state(s); focka_.result_noupdate().restore(s); fockb_.result_noupdate() = basis_matrixkit()->symmmatrix(so_dimension()); fockb_.restore_state(s); fockb_.result_noupdate().restore(s); ka_.result_noupdate() = basis_matrixkit()->symmmatrix(so_dimension()); ka_.restore_state(s); ka_.result_noupdate().restore(s); kb_.result_noupdate() = basis_matrixkit()->symmmatrix(so_dimension()); kb_.restore_state(s); kb_.result_noupdate().restore(s); s.get(user_occupations_); s.get(tndocc_); s.get(nirrep_); s.get(ndocc_); s.get(osa_); s.get(osb_); s.get(occa_); s.get(occb_); s.get(ci1_); s.get(ci2_); // now take care of memory stuff init_mem(8);}TCSCF::TCSCF(const Ref<KeyVal>& keyval) : SCF(keyval), focka_(this), fockb_(this), ka_(this), kb_(this){ focka_.compute()=0; focka_.computed()=0; fockb_.compute()=0; fockb_.computed()=0; ka_.compute()=0; ka_.computed()=0; kb_.compute()=0; kb_.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); // figure out how many doubly occupied shells there are if (keyval->exists("ndocc")) { tndocc_ = keyval->intvalue("ndocc"); } else { tndocc_ = (nelectrons-2)/2; if ((nelectrons-2)%2) { ExEnv::err0() << endl << indent << "TCSCF::init: Warning, there's a leftover electron.\n" << incindent << indent << "total_charge = " << charge << endl << indent << "total nuclear charge = " << Znuc << endl << indent << "ndocc_ = " << tndocc_ << endl << decindent; } } ExEnv::out0() << endl << indent << "TCSCF::init: total charge = " << Znuc-2*tndocc_-2 << endl << endl; nirrep_ = molecule()->point_group()->char_table().ncomp(); if (nirrep_==1) { ExEnv::err0() << indent << "TCSCF::init: cannot do C1 symmetry\n"; abort(); } occa_=occb_=1.0; ci1_=ci2_ = 0.5*sqrt(2.0); if (keyval->exists("ci1")) { ci1_ = keyval->doublevalue("ci1"); ci2_ = sqrt(1.0 - ci1_*ci1_); occa_ = 2.0*ci1_*ci1_; occb_ = 2.0*ci2_*ci2_; } if (keyval->exists("occa")) { occa_ = keyval->doublevalue("occa"); ci1_ = sqrt(occa_/2.0); ci2_ = sqrt(1.0 - ci1_*ci1_); occb_ = 2.0*ci2_*ci2_; } osa_=-1; osb_=-1; ndocc_ = read_occ(keyval, "docc", nirrep_); int *nsocc = read_occ(keyval, "socc", nirrep_); if (ndocc_ && nsocc) { user_occupations_=1; for (int i=0; i < nirrep_; i++) { int nsi = nsocc[i]; if (nsi && osa_<0) osa_=i; else if (nsi && osb_<0) osb_=i; else if (nsi) { ExEnv::err0() << indent << "TCSCF::init: too many open shells\n"; abort(); } } delete[] nsocc; } else if (ndocc_ && !nsocc || !ndocc_ && nsocc) { ExEnv::outn() << "ERROR: TCSCF: only one of docc and socc specified: " << "give both or none" << endl; abort(); } else { ndocc_=0; user_occupations_=0; set_occupations(0); } int i; 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() << " " << (i==osa_ || i==osb_) ? 1 : 0; ExEnv::out0() << " ]\n"; // check to see if this was done in SCF(keyval) if (!keyval->exists("maxiter")) maxiter_ = 200; if (!keyval->exists("level_shift")) level_shift_ = 0.25; // now take care of memory stuff init_mem(8);}TCSCF::~TCSCF(){ if (ndocc_) { delete[] ndocc_; ndocc_=0; }}voidTCSCF::save_data_state(StateOut& s){ SCF::save_data_state(s); focka_.save_data_state(s); focka_.result_noupdate().save(s); fockb_.save_data_state(s); fockb_.result_noupdate().save(s); ka_.save_data_state(s); ka_.result_noupdate().save(s); kb_.save_data_state(s); kb_.result_noupdate().save(s); s.put(user_occupations_); s.put(tndocc_); s.put(nirrep_); s.put(ndocc_,nirrep_); s.put(osa_); s.put(osb_); s.put(occa_); s.put(occb_); s.put(ci1_); s.put(ci2_);}doubleTCSCF::occupation(int ir, int i){ if (i < ndocc_[ir]) return 2.0; else if (ir==osa_ && i==ndocc_[ir]) return occa_; else if (ir==osb_ && i==ndocc_[ir]) return occb_; else return 0.0;}doubleTCSCF::alpha_occupation(int ir, int i){ if (i < ndocc_[ir]) return 1.0; else if (ir==osa_ && i==ndocc_[ir]) return 0.5*occa_; return 0.0;}doubleTCSCF::beta_occupation(int ir, int i){ if (i < ndocc_[ir]) return 1.0; else if (ir==osb_ && i==ndocc_[ir]) return 0.5*occb_; return 0.0;}intTCSCF::n_fock_matrices() const{ return 4;}RefSymmSCMatrixTCSCF::fock(int n){ if (n > 3) { ExEnv::err0() << indent << "TCSCF::fock: there are only four fock matrices, " << scprintf("but fock(%d) was requested\n", n); abort(); } if (n==0) return focka_.result(); else if (n==1) return fockb_.result(); else if (n==2) return ka_.result(); else return kb_.result();}intTCSCF::spin_polarized(){ return 1;}voidTCSCF::print(ostream&o) const{ int i; SCF::print(o); o << indent << "TCSCF Parameters:\n" << incindent << indent << "ndocc = " << tndocc_ << endl << indent << scprintf("occa = %f", occa_) << endl << indent << scprintf("occb = %f", occb_) << endl << indent << scprintf("ci1 = %9.6f", ci1_) << endl << indent << scprintf("ci2 = %9.6f", ci2_) << endl << indent << "docc = ["; for (i=0; i < nirrep_; i++) o << " " << ndocc_[i]; o << " ]" << endl << indent << "socc = ["; for (i=0; i < nirrep_; i++) o << " " << (i==osa_ || i==osb_) ? 1 : 0; o << " ]" << endl << decindent << endl;}//////////////////////////////////////////////////////////////////////////////voidTCSCF::set_occupations(const RefDiagSCMatrix& ev){ if (user_occupations_) 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, "TCSCF::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 osa=-1, osb=-1; for (i=0; i < 2; 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; if (!i) { osa=lir; } else { if (lir==osa) { i--; continue; } osb=lir; } } if (osa > osb) { int tmp=osa; osa=osb; osb=tmp; } // get rid of vals for (i=0; i < nirrep_; i++) if (vals[i]) delete[] vals[i]; delete[] vals; if (!ndocc_) { ndocc_=newdocc; osa_=osa; osb_=osb; } else { // test to see if newocc is different from ndocc_ for (i=0; i < nirrep_; i++) { if (ndocc_[i] != newdocc[i]) { ExEnv::err0() << indent << "TCSCF::set_occupations: WARNING!!!!\n" << incindent << indent << scprintf("occupations for irrep %d have changed\n", i+1) << indent << scprintf("ndocc was %d, changed to %d", ndocc_[i], newdocc[i]) << endl << decindent; } if (((osa != osa_ && osa != osb_) || (osb != osb_ && osb != osa_))) { ExEnv::err0() << indent << "TCSCF::set_occupations: WARNING!!!!\n" << incindent << indent << "open shell occupations have changed" << endl << decindent; osa_=osa; osb_=osb; reset_density(); } } memcpy(ndocc_,newdocc,sizeof(int)*nirrep_); delete[] newdocc; }}voidTCSCF::symmetry_changed(){ SCF::symmetry_changed(); focka_.result_noupdate()=0; fockb_.result_noupdate()=0; ka_.result_noupdate()=0; kb_.result_noupdate()=0; nirrep_ = molecule()->point_group()->char_table().ncomp(); set_occupations(0);}////////////////////////////////////////////////////////////////////////////////// scf things//voidTCSCF::init_vector(){ init_threads(); // allocate storage for other temp matrices
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -