source: ThirdParty/mpqc_open/src/lib/chemistry/qc/mbpt/mbpt.cc@ 72461c

Action_Thermostats Add_AtomRandomPerturbation Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests AutomationFragmentation_failures Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_ChronosMutex Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids_IntegrationTest JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo StoppableMakroAction Subpackage_levmar Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since 72461c was 860145, checked in by Frederik Heber <heber@…>, 8 years ago

Merge commit '0b990dfaa8c6007a996d030163a25f7f5fc8a7e7' as 'ThirdParty/mpqc_open'

  • Property mode set to 100644
File size: 18.9 KB
Line 
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
40using namespace std;
41using 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/////////////////////////////////////////////////////////////////
48static void
49dqs(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}
75static void
76dquicksort(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
89static ClassDesc MBPT2_cd(
90 typeid(MBPT2),"MBPT2",9,"public Wavefunction",
91 0, create<MBPT2>, create<MBPT2>);
92
93MBPT2::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
176MBPT2::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
243MBPT2::~MBPT2()
244{
245 delete[] method_;
246 delete[] algorithm_;
247 delete[] symorb_irrep_;
248 delete[] symorb_num_;
249}
250
251void
252MBPT2::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
270void
271MBPT2::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
283int
284MBPT2::spin_polarized()
285{
286 return reference_->spin_polarized();
287}
288
289RefSymmSCMatrix
290MBPT2::density()
291{
292 return 0;
293}
294
295//////////////////////////////////////////////////////////////////////////////
296
297void
298MBPT2::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
354void
355MBPT2::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
366int
367MBPT2::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
382int
383MBPT2::value_implemented() const
384{
385 return 1;
386}
387
388//////////////////////////////////////////////////////////////////////////////
389
390void
391MBPT2::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
608void
609MBPT2::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
627void
628MBPT2::symmetry_changed()
629{
630 Wavefunction::symmetry_changed();
631 reference_->symmetry_changed();
632}
633
634/////////////////////////////////////////////////////////////////////////////
635
636int
637MBPT2::nelectron()
638{
639 return reference_->nelectron();
640}
641
642/////////////////////////////////////////////////////////////////////////////
643
644double
645MBPT2::ref_energy()
646{
647 return reference_->energy();
648}
649
650/////////////////////////////////////////////////////////////////////////////
651
652double
653MBPT2::corr_energy()
654{
655 return energy() - reference_->energy();
656}
657
658/////////////////////////////////////////////////////////////////////////////
659
660RefSCVector
661MBPT2::ref_energy_gradient()
662{
663 gradient();
664 return hf_gradient_;
665}
666
667/////////////////////////////////////////////////////////////////////////////
668
669RefSCVector
670MBPT2::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:
Note: See TracBrowser for help on using the repository browser.