[0b990d] | 1 | //
|
---|
| 2 | // mbpt.cc
|
---|
| 3 | //
|
---|
| 4 | // Copyright (C) 1996 Limit Point Systems, Inc.
|
---|
| 5 | //
|
---|
| 6 | // Author: Ida Nielsen <ida@kemi.aau.dk>
|
---|
| 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 <util/class/scexception.h>
|
---|
| 33 | #include <util/misc/formio.h>
|
---|
| 34 | #include <util/misc/exenv.h>
|
---|
| 35 | #include <util/state/stateio.h>
|
---|
| 36 | #include <math/scmat/blocked.h>
|
---|
| 37 | #include <chemistry/qc/basis/petite.h>
|
---|
| 38 | #include <chemistry/qc/mbpt/mbpt.h>
|
---|
| 39 |
|
---|
| 40 | using namespace std;
|
---|
| 41 | using namespace sc;
|
---|
| 42 |
|
---|
| 43 | /////////////////////////////////////////////////////////////////
|
---|
| 44 | // Function dquicksort performs a quick sort (smaller -> larger)
|
---|
| 45 | // of the double data in item by the integer indices in index;
|
---|
| 46 | // data in item remain unchanged
|
---|
| 47 | /////////////////////////////////////////////////////////////////
|
---|
| 48 | static void
|
---|
| 49 | dqs(double *item,int *index,int left,int right)
|
---|
| 50 | {
|
---|
| 51 | register int i,j;
|
---|
| 52 | double x;
|
---|
| 53 | int y;
|
---|
| 54 |
|
---|
| 55 | i=left; j=right;
|
---|
| 56 | x=item[index[(left+right)/2]];
|
---|
| 57 |
|
---|
| 58 | do {
|
---|
| 59 | while(item[index[i]]<x && i<right) i++;
|
---|
| 60 | while(x<item[index[j]] && j>left) j--;
|
---|
| 61 |
|
---|
| 62 | if (i<=j) {
|
---|
| 63 | if (item[index[i]] != item[index[j]]) {
|
---|
| 64 | y=index[i];
|
---|
| 65 | index[i]=index[j];
|
---|
| 66 | index[j]=y;
|
---|
| 67 | }
|
---|
| 68 | i++; j--;
|
---|
| 69 | }
|
---|
| 70 | } while(i<=j);
|
---|
| 71 |
|
---|
| 72 | if (left<j) dqs(item,index,left,j);
|
---|
| 73 | if (i<right) dqs(item,index,i,right);
|
---|
| 74 | }
|
---|
| 75 | static void
|
---|
| 76 | dquicksort(double *item,int *index,int n)
|
---|
| 77 | {
|
---|
| 78 | int i;
|
---|
| 79 | if (n<=0) return;
|
---|
| 80 | for (i=0; i<n; i++) {
|
---|
| 81 | index[i] = i;
|
---|
| 82 | }
|
---|
| 83 | dqs(item,index,0,n-1);
|
---|
| 84 | }
|
---|
| 85 |
|
---|
| 86 | ///////////////////////////////////////////////////////////////////////////
|
---|
| 87 | // MBPT2
|
---|
| 88 |
|
---|
| 89 | static ClassDesc MBPT2_cd(
|
---|
| 90 | typeid(MBPT2),"MBPT2",9,"public Wavefunction",
|
---|
| 91 | 0, create<MBPT2>, create<MBPT2>);
|
---|
| 92 |
|
---|
| 93 | MBPT2::MBPT2(StateIn& s):
|
---|
| 94 | SavableState(s),
|
---|
| 95 | Wavefunction(s)
|
---|
| 96 | {
|
---|
| 97 | reference_ << SavableState::restore_state(s);
|
---|
| 98 | s.get(nfzc);
|
---|
| 99 | s.get(nfzv);
|
---|
| 100 | if (s.version(::class_desc<MBPT2>()) >= 8) {
|
---|
| 101 | double dmem_alloc;
|
---|
| 102 | s.get(dmem_alloc);
|
---|
| 103 | mem_alloc = size_t(dmem_alloc);
|
---|
| 104 | }
|
---|
| 105 | else {
|
---|
| 106 | unsigned int imem_alloc;
|
---|
| 107 | s.get(imem_alloc);
|
---|
| 108 | mem_alloc = imem_alloc;
|
---|
| 109 | }
|
---|
| 110 | s.getstring(method_);
|
---|
| 111 | s.getstring(algorithm_);
|
---|
| 112 |
|
---|
| 113 | if (s.version(::class_desc<MBPT2>()) <= 6) {
|
---|
| 114 | int debug_old;
|
---|
| 115 | s.get(debug_old);
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | if (s.version(::class_desc<MBPT2>()) >= 2) {
|
---|
| 119 | s.get(do_d1_);
|
---|
| 120 | }
|
---|
| 121 | else {
|
---|
| 122 | do_d1_ = 0;
|
---|
| 123 | }
|
---|
| 124 |
|
---|
| 125 | if (s.version(::class_desc<MBPT2>()) >= 3) {
|
---|
| 126 | s.get(dynamic_);
|
---|
| 127 | }
|
---|
| 128 | else {
|
---|
| 129 | dynamic_ = 0;
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | if (s.version(::class_desc<MBPT2>()) >= 9) {
|
---|
| 133 | s.get(print_percent_);
|
---|
| 134 | }
|
---|
| 135 | else {
|
---|
| 136 | print_percent_ = 10.0;
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 | if (s.version(::class_desc<MBPT2>()) >= 4) {
|
---|
| 140 | s.get(cphf_epsilon_);
|
---|
| 141 | }
|
---|
| 142 | else {
|
---|
| 143 | cphf_epsilon_ = 1.0e-8;
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | if (s.version(::class_desc<MBPT2>()) >= 5) {
|
---|
| 147 | s.get(max_norb_);
|
---|
| 148 | }
|
---|
| 149 | else {
|
---|
| 150 | max_norb_ = 0;
|
---|
| 151 | }
|
---|
| 152 |
|
---|
| 153 | if (s.version(::class_desc<MBPT2>()) >= 6) {
|
---|
| 154 | s.get(do_d2_);
|
---|
| 155 | }
|
---|
| 156 | else {
|
---|
| 157 | do_d2_ = 1;
|
---|
| 158 | }
|
---|
| 159 |
|
---|
| 160 | hf_energy_ = 0.0;
|
---|
| 161 |
|
---|
| 162 | symorb_irrep_ = 0;
|
---|
| 163 | symorb_num_ = 0;
|
---|
| 164 |
|
---|
| 165 | eliminate_in_gmat_ = 1;
|
---|
| 166 |
|
---|
| 167 | mem = MemoryGrp::get_default_memorygrp();
|
---|
| 168 | msg_ = MessageGrp::get_default_messagegrp();
|
---|
| 169 | thr_ = ThreadGrp::get_default_threadgrp();
|
---|
| 170 |
|
---|
| 171 | restart_ecorr_ = 0.0;
|
---|
| 172 | restart_orbital_v1_ = 0;
|
---|
| 173 | restart_orbital_memgrp_ = 0;
|
---|
| 174 | }
|
---|
| 175 |
|
---|
| 176 | MBPT2::MBPT2(const Ref<KeyVal>& keyval):
|
---|
| 177 | Wavefunction(keyval)
|
---|
| 178 | {
|
---|
| 179 | reference_ << keyval->describedclassvalue("reference");
|
---|
| 180 | if (reference_.null()) {
|
---|
| 181 | ExEnv::err0() << "MBPT2::MBPT2: no reference wavefunction" << endl;
|
---|
| 182 | abort();
|
---|
| 183 | }
|
---|
| 184 | copy_orthog_info(reference_);
|
---|
| 185 | nfzc = keyval->intvalue("nfzc");
|
---|
| 186 | char *nfzc_charval = keyval->pcharvalue("nfzc");
|
---|
| 187 | if (nfzc_charval && !strcmp(nfzc_charval, "auto")) {
|
---|
| 188 | if (molecule()->max_z() > 30) {
|
---|
| 189 | ExEnv::err0()
|
---|
| 190 | << "MBPT2: cannot use \"nfzc = auto\" for Z > 30" << endl;
|
---|
| 191 | abort();
|
---|
| 192 | }
|
---|
| 193 | nfzc = molecule()->n_core_electrons()/2;
|
---|
| 194 | ExEnv::out0() << indent
|
---|
| 195 | << "MBPT2: auto-freezing " << nfzc << " core orbitals" << endl;
|
---|
| 196 | }
|
---|
| 197 | delete[] nfzc_charval;
|
---|
| 198 | nfzv = keyval->intvalue("nfzv");
|
---|
| 199 | mem_alloc = keyval->sizevalue("memory");
|
---|
| 200 | if (keyval->error() != KeyVal::OK) {
|
---|
| 201 | // by default, take half of the memory
|
---|
| 202 | mem_alloc = ExEnv::memory()/2;
|
---|
| 203 | if (mem_alloc == 0) {
|
---|
| 204 | mem_alloc = DEFAULT_SC_MEMORY;
|
---|
| 205 | }
|
---|
| 206 | }
|
---|
| 207 | mem << keyval->describedclassvalue("memorygrp");
|
---|
| 208 | if (mem.null()) {
|
---|
| 209 | mem = MemoryGrp::get_default_memorygrp();
|
---|
| 210 | }
|
---|
| 211 | msg_ = MessageGrp::get_default_messagegrp();
|
---|
| 212 | thr_ = ThreadGrp::get_default_threadgrp();
|
---|
| 213 |
|
---|
| 214 | method_ = keyval->pcharvalue("method");
|
---|
| 215 |
|
---|
| 216 | algorithm_ = keyval->pcharvalue("algorithm");
|
---|
| 217 |
|
---|
| 218 | do_d1_ = keyval->booleanvalue("compute_d1");
|
---|
| 219 | do_d2_ = keyval->booleanvalue("compute_d2",KeyValValueboolean(1));
|
---|
| 220 |
|
---|
| 221 | restart_ecorr_ = keyval->doublevalue("restart_ecorr");
|
---|
| 222 | restart_orbital_v1_ = keyval->intvalue("restart_orbital_v1");
|
---|
| 223 | restart_orbital_memgrp_ = keyval->intvalue("restart_orbital_memgrp");
|
---|
| 224 |
|
---|
| 225 | KeyValValueint default_dynamic(0);
|
---|
| 226 | dynamic_ = keyval->booleanvalue("dynamic", default_dynamic);
|
---|
| 227 |
|
---|
| 228 | KeyValValuedouble default_print_percent(10.0);
|
---|
| 229 | print_percent_ = keyval->doublevalue("print_percent", default_print_percent);
|
---|
| 230 |
|
---|
| 231 | cphf_epsilon_ = keyval->doublevalue("cphf_epsilon",KeyValValuedouble(1.e-8));
|
---|
| 232 |
|
---|
| 233 | max_norb_ = keyval->intvalue("max_norb",KeyValValueint(-1));
|
---|
| 234 |
|
---|
| 235 | hf_energy_ = 0.0;
|
---|
| 236 |
|
---|
| 237 | symorb_irrep_ = 0;
|
---|
| 238 | symorb_num_ = 0;
|
---|
| 239 |
|
---|
| 240 | eliminate_in_gmat_ = 1;
|
---|
| 241 | }
|
---|
| 242 |
|
---|
| 243 | MBPT2::~MBPT2()
|
---|
| 244 | {
|
---|
| 245 | delete[] method_;
|
---|
| 246 | delete[] algorithm_;
|
---|
| 247 | delete[] symorb_irrep_;
|
---|
| 248 | delete[] symorb_num_;
|
---|
| 249 | }
|
---|
| 250 |
|
---|
| 251 | void
|
---|
| 252 | MBPT2::save_data_state(StateOut& s)
|
---|
| 253 | {
|
---|
| 254 | Wavefunction::save_data_state(s);
|
---|
| 255 | SavableState::save_state(reference_.pointer(),s);
|
---|
| 256 | s.put(nfzc);
|
---|
| 257 | s.put(nfzv);
|
---|
| 258 | double dmem_alloc = mem_alloc;
|
---|
| 259 | s.put(dmem_alloc);
|
---|
| 260 | s.putstring(method_);
|
---|
| 261 | s.putstring(algorithm_);
|
---|
| 262 | s.put(do_d1_);
|
---|
| 263 | s.put(dynamic_);
|
---|
| 264 | s.put(print_percent_);
|
---|
| 265 | s.put(cphf_epsilon_);
|
---|
| 266 | s.put(max_norb_);
|
---|
| 267 | s.put(do_d2_);
|
---|
| 268 | }
|
---|
| 269 |
|
---|
| 270 | void
|
---|
| 271 | MBPT2::print(ostream&o) const
|
---|
| 272 | {
|
---|
| 273 | o << indent << "MBPT2:" << endl;
|
---|
| 274 | o << incindent;
|
---|
| 275 | Wavefunction::print(o);
|
---|
| 276 | o << indent << "Reference Wavefunction:" << endl;
|
---|
| 277 | o << incindent; reference_->print(o); o << decindent << endl;
|
---|
| 278 | o << decindent;
|
---|
| 279 | }
|
---|
| 280 |
|
---|
| 281 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 282 |
|
---|
| 283 | int
|
---|
| 284 | MBPT2::spin_polarized()
|
---|
| 285 | {
|
---|
| 286 | return reference_->spin_polarized();
|
---|
| 287 | }
|
---|
| 288 |
|
---|
| 289 | RefSymmSCMatrix
|
---|
| 290 | MBPT2::density()
|
---|
| 291 | {
|
---|
| 292 | return 0;
|
---|
| 293 | }
|
---|
| 294 |
|
---|
| 295 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 296 |
|
---|
| 297 | void
|
---|
| 298 | MBPT2::compute()
|
---|
| 299 | {
|
---|
| 300 | if (std::string(reference_->integral()->class_name())
|
---|
| 301 | !=integral()->class_name()) {
|
---|
| 302 | FeatureNotImplemented ex(
|
---|
| 303 | "cannot use a reference with a different Integral specialization",
|
---|
| 304 | __FILE__, __LINE__, class_desc());
|
---|
| 305 | try {
|
---|
| 306 | ex.elaborate()
|
---|
| 307 | << "reference uses " << reference_->integral()->class_name()
|
---|
| 308 | << " but this object uses " << integral()->class_name()
|
---|
| 309 | << std::endl;
|
---|
| 310 | }
|
---|
| 311 | catch (...) {}
|
---|
| 312 | throw ex;
|
---|
| 313 | }
|
---|
| 314 |
|
---|
| 315 | init_variables();
|
---|
| 316 |
|
---|
| 317 | reference_->set_desired_value_accuracy(desired_value_accuracy()
|
---|
| 318 | / ref_to_mp2_acc);
|
---|
| 319 | if (gradient_needed()) {
|
---|
| 320 | if (nsocc) {
|
---|
| 321 | ExEnv::errn() << "MBPT2: cannot compute open shell gradients" << endl;
|
---|
| 322 | abort();
|
---|
| 323 | }
|
---|
| 324 | compute_cs_grad();
|
---|
| 325 | }
|
---|
| 326 | else {
|
---|
| 327 | if (nsocc && algorithm_ && !strcmp(algorithm_,"memgrp")) {
|
---|
| 328 | ExEnv::errn() << "MBPT2: memgrp algorithm cannot compute open shell energy"
|
---|
| 329 | << endl;
|
---|
| 330 | abort();
|
---|
| 331 | }
|
---|
| 332 | if (!nsocc && (!algorithm_ || !strcmp(algorithm_,"memgrp"))) {
|
---|
| 333 | compute_cs_grad();
|
---|
| 334 | }
|
---|
| 335 | else if ((!algorithm_ && msg_->n() <= 32)
|
---|
| 336 | || (algorithm_ && !strcmp(algorithm_,"v1"))) {
|
---|
| 337 | compute_hsos_v1();
|
---|
| 338 | }
|
---|
| 339 | else if (!algorithm_ || !strcmp(algorithm_,"v2")) {
|
---|
| 340 | compute_hsos_v2();
|
---|
| 341 | }
|
---|
| 342 | else if (!strcmp(algorithm_,"v2lb")) {
|
---|
| 343 | compute_hsos_v2_lb();
|
---|
| 344 | }
|
---|
| 345 | else {
|
---|
| 346 | ExEnv::errn() << "MBPT2: unknown algorithm: " << algorithm_ << endl;
|
---|
| 347 | abort();
|
---|
| 348 | }
|
---|
| 349 | }
|
---|
| 350 | }
|
---|
| 351 |
|
---|
| 352 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 353 |
|
---|
| 354 | void
|
---|
| 355 | MBPT2::obsolete()
|
---|
| 356 | {
|
---|
| 357 | // Solaris 2.7 workshop 5.0 is causing this routine to
|
---|
| 358 | // be incorrectly called in a base class CTOR. Thus
|
---|
| 359 | // reference_ might be null and it must be tested.
|
---|
| 360 | if (reference_.nonnull()) reference_->obsolete();
|
---|
| 361 | Wavefunction::obsolete();
|
---|
| 362 | }
|
---|
| 363 |
|
---|
| 364 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 365 |
|
---|
| 366 | int
|
---|
| 367 | MBPT2::gradient_implemented() const
|
---|
| 368 | {
|
---|
| 369 | int nb = reference_->oso_dimension()->n();
|
---|
| 370 | int n = 0;
|
---|
| 371 |
|
---|
| 372 | for (int i=0; i<nb; i++) {
|
---|
| 373 | if (reference_->occupation(i) == 1.0) n++;
|
---|
| 374 | }
|
---|
| 375 |
|
---|
| 376 | if (n) return 0;
|
---|
| 377 | return 1;
|
---|
| 378 | }
|
---|
| 379 |
|
---|
| 380 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 381 |
|
---|
| 382 | int
|
---|
| 383 | MBPT2::value_implemented() const
|
---|
| 384 | {
|
---|
| 385 | return 1;
|
---|
| 386 | }
|
---|
| 387 |
|
---|
| 388 | //////////////////////////////////////////////////////////////////////////////
|
---|
| 389 |
|
---|
| 390 | void
|
---|
| 391 | MBPT2::eigen(RefDiagSCMatrix &vals, RefSCMatrix &vecs, RefDiagSCMatrix &occs)
|
---|
| 392 | {
|
---|
| 393 | int i, j;
|
---|
| 394 | if (nsocc) {
|
---|
| 395 | if (reference_->n_fock_matrices() != 2) {
|
---|
| 396 | ExEnv::errn() << "MBPT2: given open reference with"
|
---|
| 397 | << " wrong number of Fock matrices" << endl;
|
---|
| 398 | abort();
|
---|
| 399 | }
|
---|
| 400 |
|
---|
| 401 | // Notation: oo = orthonormal symmetry orbital basis
|
---|
| 402 | // ao = atomic orbital basis
|
---|
| 403 | // so = symmetrized atomic orbital basis
|
---|
| 404 | // mo1 = SCF molecular orbital basis
|
---|
| 405 | // mo2 = MBPT molecular orbital basis
|
---|
| 406 |
|
---|
| 407 | // get the closed shell and open shell AO fock matrices
|
---|
| 408 | RefSymmSCMatrix fock_c_so = reference_->fock(0);
|
---|
| 409 | RefSymmSCMatrix fock_o_so = reference_->fock(1);
|
---|
| 410 |
|
---|
| 411 | // transform the AO fock matrices to the MO basis
|
---|
| 412 | RefSymmSCMatrix fock_c_mo1
|
---|
| 413 | = basis_matrixkit()->symmmatrix(oso_dimension());
|
---|
| 414 | RefSymmSCMatrix fock_o_mo1
|
---|
| 415 | = basis_matrixkit()->symmmatrix(oso_dimension());
|
---|
| 416 | RefSCMatrix vecs_so_mo1 = reference_->eigenvectors();
|
---|
| 417 |
|
---|
| 418 | fock_c_mo1.assign(0.0);
|
---|
| 419 | fock_o_mo1.assign(0.0);
|
---|
| 420 | fock_c_mo1.accumulate_transform(vecs_so_mo1.t(), fock_c_so);
|
---|
| 421 | fock_o_mo1.accumulate_transform(vecs_so_mo1.t(), fock_o_so);
|
---|
| 422 | fock_c_so = 0;
|
---|
| 423 | fock_o_so = 0;
|
---|
| 424 |
|
---|
| 425 | /* Convert to the Guest & Saunders general form.
|
---|
| 426 | This is the form used for an OPT2 calculation.
|
---|
| 427 |
|
---|
| 428 | C O V
|
---|
| 429 | ----------
|
---|
| 430 | | |
|
---|
| 431 | C | fc |
|
---|
| 432 | | |
|
---|
| 433 | -------------------
|
---|
| 434 | | | |
|
---|
| 435 | O | 2fc-fo | fc |
|
---|
| 436 | | | |
|
---|
| 437 | ----------------------------
|
---|
| 438 | | | | |
|
---|
| 439 | V | fc | fo | fc |
|
---|
| 440 | | | | |
|
---|
| 441 | ----------------------------
|
---|
| 442 | */
|
---|
| 443 | RefSymmSCMatrix fock_eff_mo1 = fock_c_mo1.clone();
|
---|
| 444 | fock_eff_mo1.assign(fock_c_mo1);
|
---|
| 445 | for (i=0; i<oso_dimension()->n(); i++) {
|
---|
| 446 | double occi = reference_->occupation(i);
|
---|
| 447 | for (j=0; j<=i; j++) {
|
---|
| 448 | double occj = reference_->occupation(j);
|
---|
| 449 | if (occi == 2.0 && occj == 1.0
|
---|
| 450 | || occi == 1.0 && occj == 2.0) {
|
---|
| 451 | fock_eff_mo1.accumulate_element(i,j,
|
---|
| 452 | fock_c_mo1(i,j)-fock_o_mo1(i,j));
|
---|
| 453 | }
|
---|
| 454 | else if (occi == 0.0 && occj == 1.0
|
---|
| 455 | || occi == 1.0 && occj == 0.0) {
|
---|
| 456 | fock_eff_mo1.accumulate_element(i,j,
|
---|
| 457 | fock_o_mo1(i,j)-fock_c_mo1(i,j));
|
---|
| 458 | }
|
---|
| 459 | }
|
---|
| 460 | }
|
---|
| 461 |
|
---|
| 462 | // diagonalize the new fock matrix
|
---|
| 463 | RefDiagSCMatrix vals_mo2(fock_eff_mo1.dim(), fock_eff_mo1.kit());
|
---|
| 464 | RefSCMatrix vecs_mo1_mo2(fock_eff_mo1.dim(), fock_eff_mo1.dim(),
|
---|
| 465 | fock_eff_mo1.kit());
|
---|
| 466 | fock_eff_mo1.diagonalize(vals_mo2, vecs_mo1_mo2);
|
---|
| 467 | vals = vals_mo2;
|
---|
| 468 |
|
---|
| 469 | // compute the AO to new MO scf vector
|
---|
| 470 | RefSCMatrix so_ao = reference_->integral()->petite_list()->sotoao();
|
---|
| 471 |
|
---|
| 472 | if (debug_ > 1) {
|
---|
| 473 | vecs_mo1_mo2.t().print("vecs_mo1_mo2.t()");
|
---|
| 474 | vecs_so_mo1.t().print("vecs_so_mo1.t()");
|
---|
| 475 | so_ao.print("so_ao");
|
---|
| 476 | }
|
---|
| 477 |
|
---|
| 478 | vecs = vecs_mo1_mo2.t() * vecs_so_mo1.t() * so_ao;
|
---|
| 479 | }
|
---|
| 480 | else {
|
---|
| 481 | if (debug_) ExEnv::out0() << indent << "getting fock matrix" << endl;
|
---|
| 482 | // get the closed shell AO fock matrices
|
---|
| 483 | RefSymmSCMatrix fock_c_so = reference_->fock(0);
|
---|
| 484 |
|
---|
| 485 | // transform the AO fock matrices to the MO basis
|
---|
| 486 | RefSymmSCMatrix fock_c_mo1
|
---|
| 487 | = basis_matrixkit()->symmmatrix(oso_dimension());
|
---|
| 488 | RefSCMatrix vecs_so_mo1 = reference_->eigenvectors();
|
---|
| 489 |
|
---|
| 490 | fock_c_mo1.assign(0.0);
|
---|
| 491 | fock_c_mo1.accumulate_transform(vecs_so_mo1.t(), fock_c_so);
|
---|
| 492 | fock_c_so = 0;
|
---|
| 493 |
|
---|
| 494 | if (debug_) ExEnv::out0() << indent << "diagonalizing" << endl;
|
---|
| 495 | // diagonalize the fock matrix
|
---|
| 496 | vals = fock_c_mo1.eigvals();
|
---|
| 497 |
|
---|
| 498 | // compute the AO to new MO scf vector
|
---|
| 499 | if (debug_) ExEnv::out0() << indent << "AO to MO" << endl;
|
---|
| 500 | RefSCMatrix so_ao = reference_->integral()->petite_list()->sotoao();
|
---|
| 501 | vecs = vecs_so_mo1.t() * so_ao;
|
---|
| 502 | }
|
---|
| 503 | // fill in the occupations
|
---|
| 504 | occs = matrixkit()->diagmatrix(vals.dim());
|
---|
| 505 | for (i=0; i<oso_dimension()->n(); i++) {
|
---|
| 506 | occs(i) = reference_->occupation(i);
|
---|
| 507 | }
|
---|
| 508 | // allocate storage for symmetry information
|
---|
| 509 | if (!symorb_irrep_) symorb_irrep_ = new int[nbasis];
|
---|
| 510 | if (!symorb_num_) symorb_num_ = new int[nbasis];
|
---|
| 511 | // Check for degenerate eigenvalues. Use unsorted eigenvalues since it
|
---|
| 512 | // only matters if the degeneracies occur within a given irrep.
|
---|
| 513 | BlockedDiagSCMatrix *bvals = dynamic_cast<BlockedDiagSCMatrix*>(vals.pointer());
|
---|
| 514 | for (i=0; i<bvals->nblocks(); i++) {
|
---|
| 515 | int done = 0;
|
---|
| 516 | RefDiagSCMatrix valsi = bvals->block(i);
|
---|
| 517 | for (j=1; j<valsi.n(); j++) {
|
---|
| 518 | if (fabs(valsi(j)-valsi(j-1)) < 1.0e-7) {
|
---|
| 519 | ExEnv::out0() << indent
|
---|
| 520 | << "NOTE: There are degenerate orbitals within an irrep."
|
---|
| 521 | << " This will make"
|
---|
| 522 | << endl
|
---|
| 523 | << indent
|
---|
| 524 | << " some diagnostics, such as the largest amplitude,"
|
---|
| 525 | << " nonunique."
|
---|
| 526 | << endl;
|
---|
| 527 | done = 1;
|
---|
| 528 | break;
|
---|
| 529 | }
|
---|
| 530 | if (done) break;
|
---|
| 531 | }
|
---|
| 532 | }
|
---|
| 533 | // sort the eigenvectors and values if symmetry is not c1
|
---|
| 534 | if (molecule()->point_group()->char_table().order() != 1) {
|
---|
| 535 | if (debug_) ExEnv::out0() << indent << "sorting eigenvectors" << endl;
|
---|
| 536 | double *evals = new double[noso];
|
---|
| 537 | vals->convert(evals);
|
---|
| 538 | int *indices = new int[noso];
|
---|
| 539 | dquicksort(evals,indices,noso);
|
---|
| 540 | delete[] evals;
|
---|
| 541 | // make sure all nodes see the same indices and evals
|
---|
| 542 | msg_->bcast(indices,noso);
|
---|
| 543 | RefSCMatrix newvecs(vecs.rowdim(), vecs.coldim(), matrixkit());
|
---|
| 544 | RefDiagSCMatrix newvals(vals.dim(), matrixkit());
|
---|
| 545 | RefDiagSCMatrix newoccs(vals.dim(), matrixkit());
|
---|
| 546 | for (i=0; i<noso; i++) {
|
---|
| 547 | newvals(i) = vals(indices[i]);
|
---|
| 548 | newoccs(i) = occs(indices[i]);
|
---|
| 549 | for (j=0; j<nbasis; j++) {
|
---|
| 550 | newvecs(i,j) = vecs(indices[i],j);
|
---|
| 551 | }
|
---|
| 552 | }
|
---|
| 553 | occs = newoccs;
|
---|
| 554 | vecs = newvecs;
|
---|
| 555 | vals = newvals;
|
---|
| 556 |
|
---|
| 557 | // compute orbital symmetry information
|
---|
| 558 | CharacterTable ct = molecule()->point_group()->char_table();
|
---|
| 559 | int orbnum = 0;
|
---|
| 560 | int *tmp_irrep = new int[noso];
|
---|
| 561 | int *tmp_num = new int[noso];
|
---|
| 562 | for (i=0; i<oso_dimension()->blocks()->nblock(); i++) {
|
---|
| 563 | for (j=0; j<oso_dimension()->blocks()->size(i); j++, orbnum++) {
|
---|
| 564 | tmp_irrep[orbnum] = i;
|
---|
| 565 | tmp_num[orbnum] = j;
|
---|
| 566 | }
|
---|
| 567 | }
|
---|
| 568 | for (i=0; i<noso; i++) {
|
---|
| 569 | symorb_irrep_[i] = tmp_irrep[indices[i]];
|
---|
| 570 | symorb_num_[i] = tmp_num[indices[i]];
|
---|
| 571 | }
|
---|
| 572 | delete[] tmp_irrep;
|
---|
| 573 | delete[] tmp_num;
|
---|
| 574 |
|
---|
| 575 | delete[] indices;
|
---|
| 576 | }
|
---|
| 577 | else {
|
---|
| 578 | // compute orbital symmetry information for c1
|
---|
| 579 | for (i=0; i<noso; i++) {
|
---|
| 580 | symorb_irrep_[i] = 0;
|
---|
| 581 | symorb_num_[i] = i;
|
---|
| 582 | }
|
---|
| 583 | }
|
---|
| 584 | // check the splitting between frozen and nonfrozen orbitals
|
---|
| 585 | if (nfzc && nfzc < noso) {
|
---|
| 586 | double split = vals(nfzc) - vals(nfzc-1);
|
---|
| 587 | if (split < 0.2) {
|
---|
| 588 | ExEnv::out0() << endl
|
---|
| 589 | << indent << "WARNING: "
|
---|
| 590 | << "MBPT2: gap between frozen and active occupied orbitals is "
|
---|
| 591 | << split << " au" << endl << endl;
|
---|
| 592 | }
|
---|
| 593 | }
|
---|
| 594 | if (nfzv && noso-nfzv-1 >= 0) {
|
---|
| 595 | double split = vals(nbasis-nfzv) - vals(nbasis-nfzv-1);
|
---|
| 596 | if (split < 0.2) {
|
---|
| 597 | ExEnv::out0() << endl
|
---|
| 598 | << indent << "WARNING: "
|
---|
| 599 | << "MBPT2: gap between frozen and active virtual orbitals is "
|
---|
| 600 | << split << " au" << endl << endl;
|
---|
| 601 | }
|
---|
| 602 | }
|
---|
| 603 | if (debug_) ExEnv::out0() << indent << "eigen done" << endl;
|
---|
| 604 | }
|
---|
| 605 |
|
---|
| 606 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 607 |
|
---|
| 608 | void
|
---|
| 609 | MBPT2::init_variables()
|
---|
| 610 | {
|
---|
| 611 | nbasis = so_dimension()->n();
|
---|
| 612 | noso = oso_dimension()->n();
|
---|
| 613 | // if (nbasis != noso) {
|
---|
| 614 | // ExEnv::outn() << "MBPT2: Noso != Nbasis: MBPT2 not checked for this case" << endl;
|
---|
| 615 | // abort();
|
---|
| 616 | // }
|
---|
| 617 | nocc = nvir = nsocc = 0;
|
---|
| 618 | for (int i=0; i<noso; i++) {
|
---|
| 619 | if (reference_->occupation(i) == 2.0) nocc++;
|
---|
| 620 | else if (reference_->occupation(i) == 1.0) nsocc++;
|
---|
| 621 | else nvir++;
|
---|
| 622 | }
|
---|
| 623 | }
|
---|
| 624 |
|
---|
| 625 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 626 |
|
---|
| 627 | void
|
---|
| 628 | MBPT2::symmetry_changed()
|
---|
| 629 | {
|
---|
| 630 | Wavefunction::symmetry_changed();
|
---|
| 631 | reference_->symmetry_changed();
|
---|
| 632 | }
|
---|
| 633 |
|
---|
| 634 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 635 |
|
---|
| 636 | int
|
---|
| 637 | MBPT2::nelectron()
|
---|
| 638 | {
|
---|
| 639 | return reference_->nelectron();
|
---|
| 640 | }
|
---|
| 641 |
|
---|
| 642 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 643 |
|
---|
| 644 | double
|
---|
| 645 | MBPT2::ref_energy()
|
---|
| 646 | {
|
---|
| 647 | return reference_->energy();
|
---|
| 648 | }
|
---|
| 649 |
|
---|
| 650 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 651 |
|
---|
| 652 | double
|
---|
| 653 | MBPT2::corr_energy()
|
---|
| 654 | {
|
---|
| 655 | return energy() - reference_->energy();
|
---|
| 656 | }
|
---|
| 657 |
|
---|
| 658 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 659 |
|
---|
| 660 | RefSCVector
|
---|
| 661 | MBPT2::ref_energy_gradient()
|
---|
| 662 | {
|
---|
| 663 | gradient();
|
---|
| 664 | return hf_gradient_;
|
---|
| 665 | }
|
---|
| 666 |
|
---|
| 667 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 668 |
|
---|
| 669 | RefSCVector
|
---|
| 670 | MBPT2::corr_energy_gradient()
|
---|
| 671 | {
|
---|
| 672 | gradient();
|
---|
| 673 | return get_cartesian_gradient() - hf_gradient_;
|
---|
| 674 | }
|
---|
| 675 |
|
---|
| 676 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 677 |
|
---|
| 678 | // Local Variables:
|
---|
| 679 | // mode: c++
|
---|
| 680 | // c-file-style: "CLJ"
|
---|
| 681 | // End:
|
---|