| 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: | 
|---|