[0b990d] | 1 | //
|
---|
| 2 | // scf.cc --- implementation of the SCF abstract base class
|
---|
| 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 | #ifdef __GNUC__
|
---|
| 29 | #pragma implementation
|
---|
| 30 | #endif
|
---|
| 31 |
|
---|
| 32 | #include <math.h>
|
---|
| 33 | #include <limits.h>
|
---|
| 34 | #include <sys/types.h>
|
---|
| 35 | #include <sys/stat.h>
|
---|
| 36 | #include <unistd.h>
|
---|
| 37 |
|
---|
| 38 | #include <util/misc/formio.h>
|
---|
| 39 | #include <util/state/stateio.h>
|
---|
| 40 | #include <util/group/mstate.h>
|
---|
| 41 |
|
---|
| 42 | #include <math/scmat/local.h>
|
---|
| 43 | #include <math/scmat/repl.h>
|
---|
| 44 | #include <math/scmat/offset.h>
|
---|
| 45 | #include <math/scmat/blocked.h>
|
---|
| 46 |
|
---|
| 47 | #include <math/optimize/diis.h>
|
---|
| 48 |
|
---|
| 49 | #include <chemistry/qc/basis/petite.h>
|
---|
| 50 | #include <chemistry/qc/scf/scf.h>
|
---|
| 51 |
|
---|
| 52 | using namespace std;
|
---|
| 53 | using namespace sc;
|
---|
| 54 |
|
---|
| 55 | ///////////////////////////////////////////////////////////////////////////
|
---|
| 56 | // SCF
|
---|
| 57 |
|
---|
| 58 | static ClassDesc SCF_cd(
|
---|
| 59 | typeid(SCF),"SCF",6,"public OneBodyWavefunction",
|
---|
| 60 | 0, 0, 0);
|
---|
| 61 |
|
---|
| 62 | SCF::SCF(StateIn& s) :
|
---|
| 63 | SavableState(s),
|
---|
| 64 | OneBodyWavefunction(s)
|
---|
| 65 | {
|
---|
| 66 | need_vec_ = 1;
|
---|
| 67 | compute_guess_ = 0;
|
---|
| 68 |
|
---|
| 69 | s.get(maxiter_,"maxiter");
|
---|
| 70 | s.get(dens_reset_freq_);
|
---|
| 71 | s.get(reset_occ_);
|
---|
| 72 | s.get(local_dens_);
|
---|
| 73 | if (s.version(::class_desc<SCF>()) >= 3) {
|
---|
| 74 | double dstorage;
|
---|
| 75 | s.get(dstorage);
|
---|
| 76 | storage_ = size_t(dstorage);
|
---|
| 77 | }
|
---|
| 78 | else {
|
---|
| 79 | unsigned int istorage;
|
---|
| 80 | s.get(istorage);
|
---|
| 81 | storage_ = istorage;
|
---|
| 82 | }
|
---|
| 83 | if (s.version(::class_desc<SCF>()) >= 2) {
|
---|
| 84 | s.get(print_all_evals_);
|
---|
| 85 | s.get(print_occ_evals_);
|
---|
| 86 | }
|
---|
| 87 | else {
|
---|
| 88 | print_all_evals_ = 0;
|
---|
| 89 | print_occ_evals_ = 0;
|
---|
| 90 | }
|
---|
| 91 | s.get(level_shift_);
|
---|
| 92 | if (s.version(::class_desc<SCF>()) >= 5) {
|
---|
| 93 | s.get(keep_guess_wfn_);
|
---|
| 94 | guess_wfn_ << SavableState::restore_state(s);
|
---|
| 95 | }
|
---|
| 96 | else keep_guess_wfn_ = 0;
|
---|
| 97 | if (s.version(::class_desc<SCF>()) >= 6) {
|
---|
| 98 | s.get(always_use_guess_wfn_);
|
---|
| 99 | }
|
---|
| 100 | else always_use_guess_wfn_ = 0;
|
---|
| 101 |
|
---|
| 102 | extrap_ << SavableState::restore_state(s);
|
---|
| 103 | accumdih_ << SavableState::restore_state(s);
|
---|
| 104 | accumddh_ << SavableState::restore_state(s);
|
---|
| 105 |
|
---|
| 106 | scf_grp_ = basis()->matrixkit()->messagegrp();
|
---|
| 107 | threadgrp_ = ThreadGrp::get_default_threadgrp();
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | SCF::SCF(const Ref<KeyVal>& keyval) :
|
---|
| 111 | OneBodyWavefunction(keyval),
|
---|
| 112 | need_vec_(1),
|
---|
| 113 | compute_guess_(0),
|
---|
| 114 | maxiter_(100),
|
---|
| 115 | dens_reset_freq_(10),
|
---|
| 116 | reset_occ_(0),
|
---|
| 117 | local_dens_(1),
|
---|
| 118 | storage_(0),
|
---|
| 119 | level_shift_(0)
|
---|
| 120 | {
|
---|
| 121 | if (keyval->exists("maxiter"))
|
---|
| 122 | maxiter_ = keyval->intvalue("maxiter");
|
---|
| 123 |
|
---|
| 124 | if (keyval->exists("density_reset_frequency"))
|
---|
| 125 | dens_reset_freq_ = keyval->intvalue("density_reset_frequency");
|
---|
| 126 |
|
---|
| 127 | if (keyval->exists("reset_occupations"))
|
---|
| 128 | reset_occ_ = keyval->booleanvalue("reset_occupations");
|
---|
| 129 |
|
---|
| 130 | if (keyval->exists("level_shift"))
|
---|
| 131 | level_shift_ = keyval->doublevalue("level_shift");
|
---|
| 132 |
|
---|
| 133 | extrap_ << keyval->describedclassvalue("extrap");
|
---|
| 134 | if (extrap_.null())
|
---|
| 135 | extrap_ = new DIIS;
|
---|
| 136 |
|
---|
| 137 | accumdih_ << keyval->describedclassvalue("accumdih");
|
---|
| 138 | if (accumdih_.null())
|
---|
| 139 | accumdih_ = new AccumHNull;
|
---|
| 140 |
|
---|
| 141 | accumddh_ << keyval->describedclassvalue("accumddh");
|
---|
| 142 | if (accumddh_.null())
|
---|
| 143 | accumddh_ = new AccumHNull;
|
---|
| 144 |
|
---|
| 145 | KeyValValuesize defaultmem(DEFAULT_SC_MEMORY);
|
---|
| 146 | storage_ = keyval->sizevalue("memory",defaultmem);
|
---|
| 147 |
|
---|
| 148 | if (keyval->exists("local_density"))
|
---|
| 149 | local_dens_ = keyval->booleanvalue("local_density");
|
---|
| 150 |
|
---|
| 151 | print_all_evals_ = keyval->booleanvalue("print_evals");
|
---|
| 152 | print_occ_evals_ = keyval->booleanvalue("print_occupied_evals");
|
---|
| 153 |
|
---|
| 154 | scf_grp_ = basis()->matrixkit()->messagegrp();
|
---|
| 155 | threadgrp_ = ThreadGrp::get_default_threadgrp();
|
---|
| 156 |
|
---|
| 157 | keep_guess_wfn_ = keyval->booleanvalue("keep_guess_wavefunction");
|
---|
| 158 |
|
---|
| 159 | always_use_guess_wfn_
|
---|
| 160 | = keyval->booleanvalue("always_use_guess_wavefunction");
|
---|
| 161 |
|
---|
| 162 | // first see if guess_wavefunction is a wavefunction, then check to
|
---|
| 163 | // see if it's a string.
|
---|
| 164 | if (keyval->exists("guess_wavefunction")) {
|
---|
| 165 | ExEnv::out0() << incindent << incindent;
|
---|
| 166 | guess_wfn_ << keyval->describedclassvalue("guess_wavefunction");
|
---|
| 167 | compute_guess_=1;
|
---|
| 168 | if (guess_wfn_.null()) {
|
---|
| 169 | compute_guess_=0;
|
---|
| 170 | char *path = keyval->pcharvalue("guess_wavefunction");
|
---|
| 171 | struct stat sb;
|
---|
| 172 | if (path && stat(path, &sb)==0 && sb.st_size) {
|
---|
| 173 | BcastStateInBin s(scf_grp_, path);
|
---|
| 174 |
|
---|
| 175 | // reset the default matrixkit so that the matrices in the guess
|
---|
| 176 | // wavefunction will match those in this wavefunction
|
---|
| 177 | Ref<SCMatrixKit> oldkit = SCMatrixKit::default_matrixkit();
|
---|
| 178 | SCMatrixKit::set_default_matrixkit(basis()->matrixkit());
|
---|
| 179 |
|
---|
| 180 | guess_wfn_ << SavableState::restore_state(s);
|
---|
| 181 |
|
---|
| 182 | // go back to the original default matrixkit
|
---|
| 183 | SCMatrixKit::set_default_matrixkit(oldkit);
|
---|
| 184 | delete[] path;
|
---|
| 185 | }
|
---|
| 186 | }
|
---|
| 187 | ExEnv::out0() << decindent << decindent;
|
---|
| 188 | }
|
---|
| 189 | }
|
---|
| 190 |
|
---|
| 191 | SCF::~SCF()
|
---|
| 192 | {
|
---|
| 193 | }
|
---|
| 194 |
|
---|
| 195 | void
|
---|
| 196 | SCF::save_data_state(StateOut& s)
|
---|
| 197 | {
|
---|
| 198 | OneBodyWavefunction::save_data_state(s);
|
---|
| 199 | s.put(maxiter_);
|
---|
| 200 | s.put(dens_reset_freq_);
|
---|
| 201 | s.put(reset_occ_);
|
---|
| 202 | s.put(local_dens_);
|
---|
| 203 | double dstorage = storage_;
|
---|
| 204 | s.put(dstorage);
|
---|
| 205 | s.put(print_all_evals_);
|
---|
| 206 | s.put(print_occ_evals_);
|
---|
| 207 | s.put(level_shift_);
|
---|
| 208 | s.put(keep_guess_wfn_);
|
---|
| 209 | SavableState::save_state(guess_wfn_.pointer(),s);
|
---|
| 210 | s.put(always_use_guess_wfn_);
|
---|
| 211 | SavableState::save_state(extrap_.pointer(),s);
|
---|
| 212 | SavableState::save_state(accumdih_.pointer(),s);
|
---|
| 213 | SavableState::save_state(accumddh_.pointer(),s);
|
---|
| 214 | }
|
---|
| 215 |
|
---|
| 216 | RefSCMatrix
|
---|
| 217 | SCF::oso_eigenvectors()
|
---|
| 218 | {
|
---|
| 219 | return oso_eigenvectors_.result();
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | RefDiagSCMatrix
|
---|
| 223 | SCF::eigenvalues()
|
---|
| 224 | {
|
---|
| 225 | return eigenvalues_.result();
|
---|
| 226 | }
|
---|
| 227 |
|
---|
| 228 | int
|
---|
| 229 | SCF::spin_unrestricted()
|
---|
| 230 | {
|
---|
| 231 | return 0;
|
---|
| 232 | }
|
---|
| 233 |
|
---|
| 234 | void
|
---|
| 235 | SCF::symmetry_changed()
|
---|
| 236 | {
|
---|
| 237 | OneBodyWavefunction::symmetry_changed();
|
---|
| 238 | if (guess_wfn_.nonnull()) {
|
---|
| 239 | guess_wfn_->symmetry_changed();
|
---|
| 240 | }
|
---|
| 241 | }
|
---|
| 242 |
|
---|
| 243 | void
|
---|
| 244 | SCF::print(ostream&o) const
|
---|
| 245 | {
|
---|
| 246 | OneBodyWavefunction::print(o);
|
---|
| 247 | o << indent << "SCF Parameters:\n" << incindent
|
---|
| 248 | << indent << "maxiter = " << maxiter_ << endl
|
---|
| 249 | << indent << "density_reset_frequency = " << dens_reset_freq_ << endl
|
---|
| 250 | << indent << scprintf("level_shift = %f\n",level_shift_)
|
---|
| 251 | << decindent << endl;
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 255 |
|
---|
| 256 | void
|
---|
| 257 | SCF::compute()
|
---|
| 258 | {
|
---|
| 259 | local_ = (dynamic_cast<LocalSCMatrixKit*>(basis()->matrixkit().pointer()) ||
|
---|
| 260 | dynamic_cast<ReplSCMatrixKit*>(basis()->matrixkit().pointer())) ? 1:0;
|
---|
| 261 |
|
---|
| 262 | const double hess_to_grad_acc = 1.0/100.0;
|
---|
| 263 | if (hessian_needed())
|
---|
| 264 | set_desired_gradient_accuracy(desired_hessian_accuracy()*hess_to_grad_acc);
|
---|
| 265 |
|
---|
| 266 | const double grad_to_val_acc = 1.0/100.0;
|
---|
| 267 | if (gradient_needed())
|
---|
| 268 | set_desired_value_accuracy(desired_gradient_accuracy()*grad_to_val_acc);
|
---|
| 269 |
|
---|
| 270 | double delta;
|
---|
| 271 | if (value_needed()) {
|
---|
| 272 | ExEnv::out0() << endl << indent
|
---|
| 273 | << scprintf("SCF::compute: energy accuracy = %10.7e\n",
|
---|
| 274 | desired_value_accuracy())
|
---|
| 275 | << endl;
|
---|
| 276 |
|
---|
| 277 | // calculate the nuclear repulsion energy
|
---|
| 278 | double nucrep = nuclear_repulsion_energy();
|
---|
| 279 | ExEnv::out0() << indent
|
---|
| 280 | << scprintf("nuclear repulsion energy = %15.10f", nucrep)
|
---|
| 281 | << endl << endl;
|
---|
| 282 |
|
---|
| 283 | double eelec;
|
---|
| 284 | delta = compute_vector(eelec,nucrep);
|
---|
| 285 |
|
---|
| 286 | double eother = 0.0;
|
---|
| 287 | if (accumddh_.nonnull()) eother = accumddh_->e();
|
---|
| 288 | ExEnv::out0() << endl << indent
|
---|
| 289 | << scprintf("total scf energy = %15.10f", eelec+eother+nucrep)
|
---|
| 290 | << endl;
|
---|
| 291 |
|
---|
| 292 | set_energy(eelec+eother+nucrep);
|
---|
| 293 | set_actual_value_accuracy(delta);
|
---|
| 294 | }
|
---|
| 295 | else {
|
---|
| 296 | delta = actual_value_accuracy();
|
---|
| 297 | }
|
---|
| 298 |
|
---|
| 299 | if (gradient_needed()) {
|
---|
| 300 | RefSCVector gradient = matrixkit()->vector(moldim());
|
---|
| 301 |
|
---|
| 302 | ExEnv::out0() << endl << indent
|
---|
| 303 | << scprintf("SCF::compute: gradient accuracy = %10.7e\n",
|
---|
| 304 | desired_gradient_accuracy())
|
---|
| 305 | << endl;
|
---|
| 306 |
|
---|
| 307 | compute_gradient(gradient);
|
---|
| 308 | print_natom_3(gradient,"Total Gradient:");
|
---|
| 309 | set_gradient(gradient);
|
---|
| 310 |
|
---|
| 311 | set_actual_gradient_accuracy(delta/grad_to_val_acc);
|
---|
| 312 | }
|
---|
| 313 |
|
---|
| 314 | if (hessian_needed()) {
|
---|
| 315 | RefSymmSCMatrix hessian = matrixkit()->symmmatrix(moldim());
|
---|
| 316 |
|
---|
| 317 | ExEnv::out0() << endl << indent
|
---|
| 318 | << scprintf("SCF::compute: hessian accuracy = %10.7e\n",
|
---|
| 319 | desired_hessian_accuracy())
|
---|
| 320 | << endl;
|
---|
| 321 |
|
---|
| 322 | compute_hessian(hessian);
|
---|
| 323 | set_hessian(hessian);
|
---|
| 324 |
|
---|
| 325 | set_actual_hessian_accuracy(delta/grad_to_val_acc/hess_to_grad_acc);
|
---|
| 326 | }
|
---|
| 327 | }
|
---|
| 328 |
|
---|
| 329 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 330 |
|
---|
| 331 | signed char *
|
---|
| 332 | SCF::init_pmax(double *pmat_data)
|
---|
| 333 | {
|
---|
| 334 | double l2inv = 1.0/log(2.0);
|
---|
| 335 | double tol = pow(2.0,-126.0);
|
---|
| 336 |
|
---|
| 337 | GaussianBasisSet& gbs = *basis().pointer();
|
---|
| 338 |
|
---|
| 339 | signed char * pmax = new signed char[i_offset(gbs.nshell())];
|
---|
| 340 |
|
---|
| 341 | int ish, jsh, ij;
|
---|
| 342 | for (ish=ij=0; ish < gbs.nshell(); ish++) {
|
---|
| 343 | int istart = gbs.shell_to_function(ish);
|
---|
| 344 | int iend = istart + gbs(ish).nfunction();
|
---|
| 345 |
|
---|
| 346 | for (jsh=0; jsh <= ish; jsh++,ij++) {
|
---|
| 347 | int jstart = gbs.shell_to_function(jsh);
|
---|
| 348 | int jend = jstart + gbs(jsh).nfunction();
|
---|
| 349 |
|
---|
| 350 | double maxp=0, tmp;
|
---|
| 351 |
|
---|
| 352 | for (int i=istart; i < iend; i++) {
|
---|
| 353 | int ijoff = i_offset(i) + jstart;
|
---|
| 354 | for (int j=jstart; j < ((ish==jsh) ? i+1 : jend); j++,ijoff++)
|
---|
| 355 | if ((tmp=fabs(pmat_data[ijoff])) > maxp)
|
---|
| 356 | maxp=tmp;
|
---|
| 357 | }
|
---|
| 358 |
|
---|
| 359 | if (maxp <= tol)
|
---|
| 360 | maxp=tol;
|
---|
| 361 |
|
---|
| 362 | long power = long(ceil(log(maxp)*l2inv));
|
---|
| 363 | if (power < SCHAR_MIN) pmax[ij] = SCHAR_MIN;
|
---|
| 364 | else if (power > SCHAR_MAX) pmax[ij] = SCHAR_MAX;
|
---|
| 365 | else pmax[ij] = (signed char) power;
|
---|
| 366 | }
|
---|
| 367 | }
|
---|
| 368 |
|
---|
| 369 | return pmax;
|
---|
| 370 | }
|
---|
| 371 |
|
---|
| 372 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 373 |
|
---|
| 374 | RefSymmSCMatrix
|
---|
| 375 | SCF::get_local_data(const RefSymmSCMatrix& m, double*& p, Access access)
|
---|
| 376 | {
|
---|
| 377 | RefSymmSCMatrix l = m;
|
---|
| 378 |
|
---|
| 379 | if (!dynamic_cast<LocalSymmSCMatrix*>(l.pointer())
|
---|
| 380 | && !dynamic_cast<ReplSymmSCMatrix*>(l.pointer())) {
|
---|
| 381 | Ref<SCMatrixKit> k = new ReplSCMatrixKit;
|
---|
| 382 | l = k->symmmatrix(m.dim());
|
---|
| 383 | l->convert(m);
|
---|
| 384 |
|
---|
| 385 | if (access == Accum)
|
---|
| 386 | l->assign(0.0);
|
---|
| 387 | } else if (scf_grp_->n() > 1 && access==Accum) {
|
---|
| 388 | l = m.clone();
|
---|
| 389 | l.assign(0.0);
|
---|
| 390 | }
|
---|
| 391 |
|
---|
| 392 | if (dynamic_cast<ReplSymmSCMatrix*>(l.pointer()))
|
---|
| 393 | p = dynamic_cast<ReplSymmSCMatrix*>(l.pointer())->get_data();
|
---|
| 394 | else
|
---|
| 395 | p = dynamic_cast<LocalSymmSCMatrix*>(l.pointer())->get_data();
|
---|
| 396 |
|
---|
| 397 | return l;
|
---|
| 398 | }
|
---|
| 399 |
|
---|
| 400 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 401 |
|
---|
| 402 | void
|
---|
| 403 | SCF::initial_vector(int needv)
|
---|
| 404 | {
|
---|
| 405 | if (need_vec_) {
|
---|
| 406 | if (always_use_guess_wfn_ || oso_eigenvectors_.result_noupdate().null()) {
|
---|
| 407 | // if guess_wfn_ is non-null then try to get a guess vector from it.
|
---|
| 408 | // First check that the same basis is used...if not, then project the
|
---|
| 409 | // guess vector into the present basis.
|
---|
| 410 | if (guess_wfn_.nonnull()) {
|
---|
| 411 | if (basis()->equiv(guess_wfn_->basis())
|
---|
| 412 | &&orthog_method() == guess_wfn_->orthog_method()
|
---|
| 413 | &&oso_dimension()->equiv(guess_wfn_->oso_dimension().pointer())) {
|
---|
| 414 | ExEnv::out0() << indent
|
---|
| 415 | << "Using guess wavefunction as starting vector" << endl;
|
---|
| 416 |
|
---|
| 417 | // indent output of eigenvectors() call if there is any
|
---|
| 418 | ExEnv::out0() << incindent << incindent;
|
---|
| 419 | SCF *g = dynamic_cast<SCF*>(guess_wfn_.pointer());
|
---|
| 420 | if (!g || compute_guess_) {
|
---|
| 421 | oso_eigenvectors_ = guess_wfn_->oso_eigenvectors().copy();
|
---|
| 422 | eigenvalues_ = guess_wfn_->eigenvalues().copy();
|
---|
| 423 | } else {
|
---|
| 424 | oso_eigenvectors_ = g->oso_eigenvectors_.result_noupdate().copy();
|
---|
| 425 | eigenvalues_ = g->eigenvalues_.result_noupdate().copy();
|
---|
| 426 | }
|
---|
| 427 | ExEnv::out0() << decindent << decindent;
|
---|
| 428 | } else {
|
---|
| 429 | ExEnv::out0() << indent
|
---|
| 430 | << "Projecting guess wavefunction into the present basis set"
|
---|
| 431 | << endl;
|
---|
| 432 |
|
---|
| 433 | // indent output of projected_eigenvectors() call if there is any
|
---|
| 434 | ExEnv::out0() << incindent << incindent;
|
---|
| 435 | oso_eigenvectors_ = projected_eigenvectors(guess_wfn_);
|
---|
| 436 | eigenvalues_ = projected_eigenvalues(guess_wfn_);
|
---|
| 437 | ExEnv::out0() << decindent << decindent;
|
---|
| 438 | }
|
---|
| 439 |
|
---|
| 440 | // we should only have to do this once, so free up memory used
|
---|
| 441 | // for the old wavefunction, unless told otherwise
|
---|
| 442 | if (!keep_guess_wfn_) guess_wfn_=0;
|
---|
| 443 |
|
---|
| 444 | ExEnv::out0() << endl;
|
---|
| 445 |
|
---|
| 446 | } else {
|
---|
| 447 | ExEnv::out0() << indent << "Starting from core Hamiltonian guess\n"
|
---|
| 448 | << endl;
|
---|
| 449 | oso_eigenvectors_ = hcore_guess(eigenvalues_.result_noupdate());
|
---|
| 450 | }
|
---|
| 451 | } else {
|
---|
| 452 | // this is just an old vector
|
---|
| 453 | }
|
---|
| 454 | }
|
---|
| 455 |
|
---|
| 456 | need_vec_=needv;
|
---|
| 457 | }
|
---|
| 458 |
|
---|
| 459 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 460 |
|
---|
| 461 | void
|
---|
| 462 | SCF::init_mem(int nm)
|
---|
| 463 | {
|
---|
| 464 | // if local_den_ is already 0, then that means it was set to zero by
|
---|
| 465 | // the user.
|
---|
| 466 | if (!local_dens_) {
|
---|
| 467 | integral()->set_storage(storage_);
|
---|
| 468 | return;
|
---|
| 469 | }
|
---|
| 470 |
|
---|
| 471 | size_t nmem = i_offset(basis()->nbasis())*nm*sizeof(double);
|
---|
| 472 |
|
---|
| 473 | // if we're actually using local matrices, then there's no choice
|
---|
| 474 | if (dynamic_cast<LocalSCMatrixKit*>(basis()->matrixkit().pointer())
|
---|
| 475 | ||dynamic_cast<ReplSCMatrixKit*>(basis()->matrixkit().pointer())) {
|
---|
| 476 | if (nmem > storage_)
|
---|
| 477 | return;
|
---|
| 478 | } else {
|
---|
| 479 | if (nmem > storage_) {
|
---|
| 480 | local_dens_=0;
|
---|
| 481 | integral()->set_storage(storage_);
|
---|
| 482 | return;
|
---|
| 483 | }
|
---|
| 484 | }
|
---|
| 485 |
|
---|
| 486 | integral()->set_storage(storage_-nmem);
|
---|
| 487 | }
|
---|
| 488 |
|
---|
| 489 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 490 |
|
---|
| 491 | void
|
---|
| 492 | SCF::so_density(const RefSymmSCMatrix& d, double occ, int alp)
|
---|
| 493 | {
|
---|
| 494 | int i,j,k;
|
---|
| 495 | int me=scf_grp_->me();
|
---|
| 496 | int nproc=scf_grp_->n();
|
---|
| 497 | int uhf = spin_unrestricted();
|
---|
| 498 |
|
---|
| 499 | d->assign(0.0);
|
---|
| 500 |
|
---|
| 501 | RefSCMatrix oso_vector;
|
---|
| 502 | if (alp || !uhf) {
|
---|
| 503 | if (oso_scf_vector_.nonnull())
|
---|
| 504 | oso_vector = oso_scf_vector_;
|
---|
| 505 | }
|
---|
| 506 | else {
|
---|
| 507 | if (oso_scf_vector_beta_.nonnull())
|
---|
| 508 | oso_vector = oso_scf_vector_beta_;
|
---|
| 509 | }
|
---|
| 510 |
|
---|
| 511 | if (oso_vector.null()) {
|
---|
| 512 | if (uhf) {
|
---|
| 513 | if (alp)
|
---|
| 514 | oso_vector = oso_alpha_eigenvectors();
|
---|
| 515 | else
|
---|
| 516 | oso_vector = oso_beta_eigenvectors();
|
---|
| 517 | } else
|
---|
| 518 | oso_vector = oso_eigenvectors();
|
---|
| 519 | }
|
---|
| 520 |
|
---|
| 521 | if (debug_ > 1) oso_vector.print("ortho SO vector");
|
---|
| 522 |
|
---|
| 523 | RefSCMatrix vector = so_to_orthog_so().t() * oso_vector;
|
---|
| 524 | oso_vector = 0;
|
---|
| 525 |
|
---|
| 526 | if (debug_ > 1) vector.print("SO vector");
|
---|
| 527 |
|
---|
| 528 | BlockedSCMatrix *bvec = require_dynamic_cast<BlockedSCMatrix*>(
|
---|
| 529 | vector, "SCF::so_density: blocked vector");
|
---|
| 530 |
|
---|
| 531 | BlockedSymmSCMatrix *bd = require_dynamic_cast<BlockedSymmSCMatrix*>(
|
---|
| 532 | d, "SCF::so_density: blocked density");
|
---|
| 533 |
|
---|
| 534 | for (int ir=0; ir < oso_dimension()->blocks()->nblock(); ir++) {
|
---|
| 535 | RefSCMatrix vir = bvec->block(ir);
|
---|
| 536 | RefSymmSCMatrix dir = bd->block(ir);
|
---|
| 537 |
|
---|
| 538 | if (vir.null() || vir.ncol()==0)
|
---|
| 539 | continue;
|
---|
| 540 |
|
---|
| 541 | int n_orthoSO = oso_dimension()->blocks()->size(ir);
|
---|
| 542 | int n_SO = so_dimension()->blocks()->size(ir);
|
---|
| 543 |
|
---|
| 544 | // figure out which columns of the scf vector we'll need
|
---|
| 545 | int col0 = -1, coln = -1;
|
---|
| 546 | for (i=0; i < n_orthoSO; i++) {
|
---|
| 547 | double occi;
|
---|
| 548 | if (!uhf)
|
---|
| 549 | occi = occupation(ir, i);
|
---|
| 550 | else if (alp)
|
---|
| 551 | occi = alpha_occupation(ir, i);
|
---|
| 552 | else
|
---|
| 553 | occi = beta_occupation(ir, i);
|
---|
| 554 |
|
---|
| 555 | if (fabs(occi-occ) < 1.0e-8) {
|
---|
| 556 | if (col0 == -1)
|
---|
| 557 | col0 = i;
|
---|
| 558 | continue;
|
---|
| 559 | } else if (col0 != -1) {
|
---|
| 560 | coln = i-1;
|
---|
| 561 | break;
|
---|
| 562 | }
|
---|
| 563 | }
|
---|
| 564 |
|
---|
| 565 | if (col0 == -1)
|
---|
| 566 | continue;
|
---|
| 567 |
|
---|
| 568 | if (coln == -1)
|
---|
| 569 | coln = n_orthoSO-1;
|
---|
| 570 |
|
---|
| 571 | if (local_ || local_dens_) {
|
---|
| 572 | RefSymmSCMatrix ldir = dir;
|
---|
| 573 |
|
---|
| 574 | RefSCMatrix occbits; // holds the occupied bits of the scf vector
|
---|
| 575 |
|
---|
| 576 | // get local copies of vector and density matrix
|
---|
| 577 | if (!local_) {
|
---|
| 578 | Ref<SCMatrixKit> rk = new ReplSCMatrixKit;
|
---|
| 579 | RefSCMatrix lvir = rk->matrix(vir.rowdim(), vir.coldim());
|
---|
| 580 | lvir->convert(vir);
|
---|
| 581 | occbits = lvir->get_subblock(0, n_SO-1, col0, coln);
|
---|
| 582 | lvir = 0;
|
---|
| 583 |
|
---|
| 584 | ldir = rk->symmmatrix(dir.dim());
|
---|
| 585 | ldir->convert(dir);
|
---|
| 586 |
|
---|
| 587 | } else {
|
---|
| 588 | occbits = vir->get_subblock(0, n_SO-1, col0, coln);
|
---|
| 589 | }
|
---|
| 590 |
|
---|
| 591 | double **c;
|
---|
| 592 | double *dens;
|
---|
| 593 |
|
---|
| 594 | if (dynamic_cast<LocalSCMatrix*>(occbits.pointer()))
|
---|
| 595 | c = dynamic_cast<LocalSCMatrix*>(occbits.pointer())->get_rows();
|
---|
| 596 | else if (dynamic_cast<ReplSCMatrix*>(occbits.pointer()))
|
---|
| 597 | c = dynamic_cast<ReplSCMatrix*>(occbits.pointer())->get_rows();
|
---|
| 598 | else
|
---|
| 599 | abort();
|
---|
| 600 |
|
---|
| 601 | if (dynamic_cast<LocalSymmSCMatrix*>(ldir.pointer()))
|
---|
| 602 | dens = dynamic_cast<LocalSymmSCMatrix*>(ldir.pointer())->get_data();
|
---|
| 603 | else if (dynamic_cast<ReplSymmSCMatrix*>(ldir.pointer()))
|
---|
| 604 | dens = dynamic_cast<ReplSymmSCMatrix*>(ldir.pointer())->get_data();
|
---|
| 605 | else
|
---|
| 606 | abort();
|
---|
| 607 |
|
---|
| 608 | int ij=0;
|
---|
| 609 | for (i=0; i < n_SO; i++) {
|
---|
| 610 | for (j=0; j <= i; j++, ij++) {
|
---|
| 611 | if (ij%nproc != me)
|
---|
| 612 | continue;
|
---|
| 613 |
|
---|
| 614 | double dv = 0;
|
---|
| 615 |
|
---|
| 616 | int kk=0;
|
---|
| 617 | for (k=col0; k <= coln; k++, kk++)
|
---|
| 618 | dv += c[i][kk]*c[j][kk];
|
---|
| 619 |
|
---|
| 620 | dens[ij] = dv;
|
---|
| 621 | }
|
---|
| 622 | }
|
---|
| 623 |
|
---|
| 624 | if (nproc > 1)
|
---|
| 625 | scf_grp_->sum(dens, i_offset(n_SO));
|
---|
| 626 |
|
---|
| 627 | if (!local_) {
|
---|
| 628 | dir->convert(ldir);
|
---|
| 629 | }
|
---|
| 630 | }
|
---|
| 631 |
|
---|
| 632 | // for now quit
|
---|
| 633 | else {
|
---|
| 634 | ExEnv::err0() << indent
|
---|
| 635 | << "Cannot yet use anything but Local matrices"
|
---|
| 636 | << endl;
|
---|
| 637 | abort();
|
---|
| 638 | }
|
---|
| 639 | }
|
---|
| 640 |
|
---|
| 641 | if (debug_ > 0) {
|
---|
| 642 | ExEnv::out0() << indent
|
---|
| 643 | << "Nelectron = " << 2.0 * (d * overlap()).trace() << endl;
|
---|
| 644 | }
|
---|
| 645 |
|
---|
| 646 | int use_alternate_density = 0;
|
---|
| 647 | if (use_alternate_density || debug_ > 2) {
|
---|
| 648 | // double check the density with this simpler, slower way to compute
|
---|
| 649 | // the density matrix
|
---|
| 650 | RefSymmSCMatrix occ(oso_dimension(), basis_matrixkit());
|
---|
| 651 | occ.assign(0.0);
|
---|
| 652 | for (i=0; i<oso_dimension()->n(); i++) {
|
---|
| 653 | occ(i,i) = occupation(i);
|
---|
| 654 | }
|
---|
| 655 | occ.scale(0.5);
|
---|
| 656 | RefSymmSCMatrix d2(so_dimension(), basis_matrixkit());
|
---|
| 657 | d2.assign(0.0);
|
---|
| 658 | d2.accumulate_transform(vector, occ);
|
---|
| 659 | if (debug_ > 2) {
|
---|
| 660 | d2.print("d2 density");
|
---|
| 661 | ExEnv::out0() << indent << "d2 Nelectron = "
|
---|
| 662 | << 2.0 * (d2 * overlap()).trace() << endl;
|
---|
| 663 | }
|
---|
| 664 | if (use_alternate_density) {
|
---|
| 665 | d.assign(d2);
|
---|
| 666 | ExEnv::out0() << indent
|
---|
| 667 | << "using alternate density algorithm" << endl;
|
---|
| 668 | }
|
---|
| 669 | }
|
---|
| 670 |
|
---|
| 671 | if (debug_ > 1) {
|
---|
| 672 | d.print("SO Density");
|
---|
| 673 | RefSCMatrix rd(d.dim(), d.dim(), basis_matrixkit());
|
---|
| 674 | rd.assign(0.0);
|
---|
| 675 | rd.accumulate(d);
|
---|
| 676 | (d*overlap()*d-rd).print("SO Density idempotency error");
|
---|
| 677 | }
|
---|
| 678 | }
|
---|
| 679 |
|
---|
| 680 | double
|
---|
| 681 | SCF::one_body_energy()
|
---|
| 682 | {
|
---|
| 683 | RefSymmSCMatrix dens = ao_density().copy();
|
---|
| 684 | RefSymmSCMatrix hcore = dens->clone();
|
---|
| 685 | hcore.assign(0.0);
|
---|
| 686 | Ref<SCElementOp> hcore_op = new OneBodyIntOp(integral()->hcore());
|
---|
| 687 | hcore.element_op(hcore_op);
|
---|
| 688 |
|
---|
| 689 | dens->scale_diagonal(0.5);
|
---|
| 690 | SCElementScalarProduct *prod = new SCElementScalarProduct;
|
---|
| 691 | prod->reference();
|
---|
| 692 | Ref<SCElementOp2> op = prod;
|
---|
| 693 | hcore->element_op(prod, dens);
|
---|
| 694 | double e = prod->result();
|
---|
| 695 | op = 0;
|
---|
| 696 | prod->dereference();
|
---|
| 697 | delete prod;
|
---|
| 698 | return 2.0 * e;
|
---|
| 699 | }
|
---|
| 700 |
|
---|
| 701 | void
|
---|
| 702 | SCF::two_body_energy(double &ec, double &ex)
|
---|
| 703 | {
|
---|
| 704 | ExEnv::errn() << class_name() << ": two_body_energy not implemented" << endl;
|
---|
| 705 | }
|
---|
| 706 |
|
---|
| 707 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 708 |
|
---|
| 709 | void
|
---|
| 710 | SCF::init_threads()
|
---|
| 711 | {
|
---|
| 712 | int nthread = threadgrp_->nthread();
|
---|
| 713 | size_t int_store = integral()->storage_unused()/nthread;
|
---|
| 714 |
|
---|
| 715 | // initialize the two electron integral classes
|
---|
| 716 | tbis_ = new Ref<TwoBodyInt>[nthread];
|
---|
| 717 | for (int i=0; i < nthread; i++) {
|
---|
| 718 | tbis_[i] = integral()->electron_repulsion();
|
---|
| 719 | tbis_[i]->set_integral_storage(int_store);
|
---|
| 720 | }
|
---|
| 721 |
|
---|
| 722 | }
|
---|
| 723 |
|
---|
| 724 | void
|
---|
| 725 | SCF::done_threads()
|
---|
| 726 | {
|
---|
| 727 | for (int i=0; i < threadgrp_->nthread(); i++) tbis_[i] = 0;
|
---|
| 728 | delete[] tbis_;
|
---|
| 729 | tbis_ = 0;
|
---|
| 730 | }
|
---|
| 731 |
|
---|
| 732 | int *
|
---|
| 733 | SCF::read_occ(const Ref<KeyVal> &keyval, const char *name, int nirrep)
|
---|
| 734 | {
|
---|
| 735 | int *occ = 0;
|
---|
| 736 | if (keyval->exists(name)) {
|
---|
| 737 | if (keyval->count(name) != nirrep) {
|
---|
| 738 | ExEnv::err0() << indent
|
---|
| 739 | << "ERROR: SCF: have " << nirrep << " irreps but "
|
---|
| 740 | << name << " vector is length " << keyval->count(name)
|
---|
| 741 | << endl;
|
---|
| 742 | abort();
|
---|
| 743 | }
|
---|
| 744 | occ = new int[nirrep];
|
---|
| 745 | for (int i=0; i<nirrep; i++) {
|
---|
| 746 | occ[i] = keyval->intvalue(name,i);
|
---|
| 747 | }
|
---|
| 748 | }
|
---|
| 749 | return occ;
|
---|
| 750 | }
|
---|
| 751 |
|
---|
| 752 | void
|
---|
| 753 | SCF::obsolete()
|
---|
| 754 | {
|
---|
| 755 | OneBodyWavefunction::obsolete();
|
---|
| 756 | if (guess_wfn_.nonnull()) guess_wfn_->obsolete();
|
---|
| 757 | }
|
---|
| 758 |
|
---|
| 759 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 760 |
|
---|
| 761 | // Local Variables:
|
---|
| 762 | // mode: c++
|
---|
| 763 | // c-file-style: "ETS"
|
---|
| 764 | // End:
|
---|