source: ThirdParty/mpqc_open/src/lib/chemistry/qc/scf/uscf.cc@ bbc982

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 bbc982 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: 33.8 KB
Line 
1//
2// uscf.cc --- implementation of the UnrestrictedSCF abstract base class
3//
4// Copyright (C) 1997 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/state/stateio.h>
39
40#include <util/misc/timer.h>
41#include <util/misc/formio.h>
42
43#include <math/scmat/local.h>
44#include <math/scmat/repl.h>
45#include <math/scmat/offset.h>
46#include <math/scmat/block.h>
47#include <math/scmat/blocked.h>
48#include <math/scmat/blkiter.h>
49#include <math/scmat/local.h>
50
51#include <math/optimize/scextrapmat.h>
52#include <math/optimize/diis.h>
53
54#include <chemistry/qc/basis/petite.h>
55#include <chemistry/qc/scf/scfops.h>
56#include <chemistry/qc/scf/scflocal.h>
57#include <chemistry/qc/scf/uscf.h>
58#include <chemistry/qc/scf/ltbgrad.h>
59#include <chemistry/qc/scf/uhftmpl.h>
60
61using namespace std;
62using namespace sc;
63
64namespace sc {
65
66///////////////////////////////////////////////////////////////////////////
67// UnrestrictedSCF
68
69static ClassDesc UnrestrictedSCF_cd(
70 typeid(UnrestrictedSCF),"UnrestrictedSCF",2,"public SCF",
71 0, 0, 0);
72
73UnrestrictedSCF::UnrestrictedSCF(StateIn& s) :
74 SavableState(s),
75 SCF(s),
76 oso_eigenvectors_beta_(this),
77 eigenvalues_beta_(this),
78 focka_(this),
79 fockb_(this)
80{
81 need_vec_ = 1;
82 compute_guess_ = 0;
83
84 oso_eigenvectors_beta_.result_noupdate() =
85 basis_matrixkit()->matrix(so_dimension(), oso_dimension());
86 oso_eigenvectors_beta_.restore_state(s);
87 oso_eigenvectors_beta_.result_noupdate().restore(s);
88
89 eigenvalues_beta_.result_noupdate() =
90 basis_matrixkit()->diagmatrix(oso_dimension());
91 eigenvalues_beta_.restore_state(s);
92 eigenvalues_beta_.result_noupdate().restore(s);
93
94 focka_.result_noupdate() =
95 basis_matrixkit()->symmmatrix(so_dimension());
96 focka_.restore_state(s);
97 focka_.result_noupdate().restore(s);
98
99 fockb_.result_noupdate() =
100 basis_matrixkit()->symmmatrix(so_dimension());
101 fockb_.restore_state(s);
102 fockb_.result_noupdate().restore(s);
103
104 s.get(user_occupations_);
105 s.get(tnalpha_);
106 s.get(tnbeta_);
107 s.get(nirrep_);
108 s.get(nalpha_);
109 s.get(nbeta_);
110
111 if (s.version(::class_desc<UnrestrictedSCF>()) >= 2) {
112 s.get(initial_nalpha_);
113 s.get(initial_nbeta_);
114 most_recent_pg_ << SavableState::restore_state(s);
115 } else {
116 initial_nalpha_ = new int[nirrep_];
117 memcpy(initial_nalpha_, nalpha_, sizeof(int)*nirrep_);
118 initial_nbeta_ = new int[nirrep_];
119 memcpy(initial_nbeta_, nbeta_, sizeof(int)*nirrep_);
120 }
121
122 init_mem(4);
123}
124
125UnrestrictedSCF::UnrestrictedSCF(const Ref<KeyVal>& keyval) :
126 SCF(keyval),
127 oso_eigenvectors_beta_(this),
128 eigenvalues_beta_(this),
129 focka_(this),
130 fockb_(this)
131{
132 int i;
133
134 double acc = oso_eigenvectors_.desired_accuracy();
135 oso_eigenvectors_beta_.set_desired_accuracy(acc);
136 eigenvalues_beta_.set_desired_accuracy(acc);
137
138 if (oso_eigenvectors_beta_.desired_accuracy() < DBL_EPSILON) {
139 oso_eigenvectors_beta_.set_desired_accuracy(DBL_EPSILON);
140 eigenvalues_beta_.set_desired_accuracy(DBL_EPSILON);
141 }
142
143 focka_.compute()=0;
144 focka_.computed()=0;
145 fockb_.compute()=0;
146 fockb_.computed()=0;
147
148 // calculate the total nuclear charge
149 double Znuc=molecule()->nuclear_charge();
150
151 // check to see if this is to be a charged molecule
152 double charge = keyval->doublevalue("total_charge");
153 int nelectrons = (int)(Znuc-charge+1.0e-4);
154
155 // first let's try to figure out how many open shells there are
156 if (keyval->exists("multiplicity")) {
157 int mult = keyval->intvalue("multiplicity");
158 if (mult < 1) {
159 ExEnv::err0() << endl << indent
160 << "USCF::init: bad value for multiplicity: " << mult << endl
161 << indent << "assuming singlet" << endl;
162 mult=1;
163 }
164
165 // for singlet, triplet, etc. we need an even number of electrons
166 // for doublet, quartet, etc. we need an odd number of electrons
167 if ((mult%2 && nelectrons%2) || (!(mult%2) && !(nelectrons%2))) {
168 ExEnv::err0() << endl << indent
169 << "USCF::init: Warning, there's a leftover electron..."
170 << " I'm going to get rid of it" << endl
171 << incindent << indent << "total_charge = " << charge << endl
172 << indent << "total nuclear charge = " << Znuc << endl
173 << indent << "multiplicity = " << mult << endl << decindent;
174 nelectrons--;
175 }
176 if (mult%2)
177 tnalpha_ = nelectrons/2 + (mult-1)/2;
178 else
179 tnalpha_ = nelectrons/2 + mult/2;
180
181 } else {
182 // if there's an odd number of electrons, then do a doublet, otherwise
183 // do a triplet
184 tnalpha_=nelectrons/2+1;
185 }
186
187 tnbeta_ = nelectrons-tnalpha_;
188
189 ExEnv::out0() << endl << indent
190 << "USCF::init: total charge = " << Znuc-tnalpha_-tnbeta_
191 << endl << endl;
192
193 nirrep_ = molecule()->point_group()->char_table().ncomp();
194
195 nalpha_ = read_occ(keyval, "alpha", nirrep_);
196 nbeta_ = read_occ(keyval, "beta", nirrep_);
197 if (nalpha_ && nbeta_) {
198 tnalpha_ = 0;
199 tnbeta_ = 0;
200 user_occupations_=1;
201 for (i=0; i < nirrep_; i++) {
202 tnalpha_ += nalpha_[i];
203 tnbeta_ += nbeta_[i];
204 }
205 initial_nalpha_ = new int[nirrep_];
206 memcpy(initial_nalpha_, nalpha_, sizeof(int)*nirrep_);
207 initial_nbeta_ = new int[nirrep_];
208 memcpy(initial_nbeta_, nbeta_, sizeof(int)*nirrep_);
209 }
210 else if (nalpha_ && !nbeta_ || !nalpha_ && nbeta_) {
211 ExEnv::out0() << "ERROR: USCF: only one of alpha and beta specified: "
212 << "give both or none" << endl;
213 abort();
214 }
215 else {
216 initial_nalpha_=0;
217 initial_nbeta_=0;
218 nalpha_=0;
219 nbeta_=0;
220 user_occupations_=0;
221 set_occupations(0,0);
222 }
223
224 ExEnv::out0() << indent << "alpha = [";
225 for (i=0; i < nirrep_; i++)
226 ExEnv::out0() << " " << nalpha_[i];
227 ExEnv::out0() << " ]\n";
228
229 ExEnv::out0() << indent << "beta = [";
230 for (i=0; i < nirrep_; i++)
231 ExEnv::out0() << " " << nbeta_[i];
232 ExEnv::out0() << " ]\n";
233
234 // check to see if this was done in SCF(keyval)
235 if (!keyval->exists("maxiter"))
236 maxiter_ = 100;
237
238 if (!keyval->exists("level_shift"))
239 level_shift_ = 0.25;
240
241 // now take care of memory stuff
242 init_mem(4);
243}
244
245UnrestrictedSCF::~UnrestrictedSCF()
246{
247 if (nalpha_) {
248 delete[] nalpha_;
249 nalpha_=0;
250 }
251 if (nbeta_) {
252 delete[] nbeta_;
253 nbeta_=0;
254 }
255 delete[] initial_nalpha_;
256 delete[] initial_nbeta_;
257}
258
259void
260UnrestrictedSCF::save_data_state(StateOut& s)
261{
262 SCF::save_data_state(s);
263 oso_eigenvectors_beta_.save_data_state(s);
264 oso_eigenvectors_beta_.result_noupdate().save(s);
265 eigenvalues_beta_.save_data_state(s);
266 eigenvalues_beta_.result_noupdate().save(s);
267 focka_.save_data_state(s);
268 focka_.result_noupdate().save(s);
269 fockb_.save_data_state(s);
270 fockb_.result_noupdate().save(s);
271
272 s.put(user_occupations_);
273 s.put(tnalpha_);
274 s.put(tnbeta_);
275 s.put(nirrep_);
276 s.put(nalpha_, nirrep_);
277 s.put(nbeta_, nirrep_);
278
279 s.put(initial_nalpha_,initial_pg_->char_table().ncomp());
280 s.put(initial_nbeta_,initial_pg_->char_table().ncomp());
281 SavableState::save_state(most_recent_pg_.pointer(),s);
282}
283
284double
285UnrestrictedSCF::occupation(int ir, int i)
286{
287 abort();
288 return 0;
289}
290
291double
292UnrestrictedSCF::alpha_occupation(int ir, int i)
293{
294 if (i < nalpha_[ir]) return 1.0;
295 return 0.0;
296}
297
298double
299UnrestrictedSCF::beta_occupation(int ir, int i)
300{
301 if (i < nbeta_[ir]) return 1.0;
302 return 0.0;
303}
304
305RefSCMatrix
306UnrestrictedSCF::eigenvectors()
307{
308 abort();
309 return 0;
310}
311
312RefDiagSCMatrix
313UnrestrictedSCF::eigenvalues()
314{
315 abort();
316 return 0;
317}
318
319RefSCMatrix
320UnrestrictedSCF::oso_alpha_eigenvectors()
321{
322 return oso_eigenvectors_.result();
323}
324
325RefSCMatrix
326UnrestrictedSCF::alpha_eigenvectors()
327{
328 return so_to_orthog_so().t() * oso_eigenvectors_.result();
329}
330
331RefDiagSCMatrix
332UnrestrictedSCF::alpha_eigenvalues()
333{
334 return eigenvalues_.result();
335}
336
337RefSCMatrix
338UnrestrictedSCF::oso_beta_eigenvectors()
339{
340 return oso_eigenvectors_beta_.result();
341}
342
343RefSCMatrix
344UnrestrictedSCF::beta_eigenvectors()
345{
346 return so_to_orthog_so().t() * oso_eigenvectors_beta_.result();
347}
348
349RefDiagSCMatrix
350UnrestrictedSCF::beta_eigenvalues()
351{
352 return eigenvalues_beta_.result();
353}
354
355int
356UnrestrictedSCF::spin_polarized()
357{
358 return 1;
359}
360
361int
362UnrestrictedSCF::spin_unrestricted()
363{
364 return 1;
365}
366
367int
368UnrestrictedSCF::n_fock_matrices() const
369{
370 return 2;
371}
372
373RefSymmSCMatrix
374UnrestrictedSCF::fock(int n)
375{
376 if (n > 1) {
377 ExEnv::err0() << indent
378 << "USCF::fock: there are only two fock matrices, "
379 << scprintf("but fock(%d) was requested\n",n);
380 abort();
381 }
382
383 if (n==0)
384 return focka_.result();
385 else
386 return fockb_.result();
387}
388
389void
390UnrestrictedSCF::print(ostream&o) const
391{
392 int i;
393
394 SCF::print(o);
395 o << indent << "UnrestrictedSCF Parameters:\n" << incindent
396 << indent << "charge = " << molecule()->nuclear_charge()
397 - tnalpha_ - tnbeta_ << endl
398 << indent << "nalpha = " << tnalpha_ << endl
399 << indent << "nbeta = " << tnbeta_ << endl
400 << indent << "alpha = [";
401
402 for (i=0; i < nirrep_; i++)
403 o << " " << nalpha_[i];
404 o << " ]" << endl;
405
406 o << indent << "beta = [";
407 for (i=0; i < nirrep_; i++)
408 o << " " << nbeta_[i];
409 o << " ]" << endl << decindent << endl;
410}
411
412//////////////////////////////////////////////////////////////////////////////
413
414void
415UnrestrictedSCF::initial_vector(int needv)
416{
417 if (need_vec_) {
418 if (always_use_guess_wfn_ || oso_eigenvectors_.result_noupdate().null()) {
419 // if guess_wfn_ is non-null then try to get a guess vector from it.
420 // First check that the same basis is used...if not, then project the
421 // guess vector into the present basis.
422 // right now the check is crude...there should be an equiv member in
423 // GaussianBasisSet
424 if (guess_wfn_.nonnull()) {
425 if (guess_wfn_->basis()->nbasis() == basis()->nbasis()) {
426 ExEnv::out0() << indent
427 << "Using guess wavefunction as starting vector" << endl;
428
429 // indent output of eigenvectors() call if there is any
430 ExEnv::out0() << incindent << incindent;
431 UnrestrictedSCF *ug =
432 dynamic_cast<UnrestrictedSCF*>(guess_wfn_.pointer());
433 if (!ug || compute_guess_) {
434 oso_eigenvectors_ = guess_wfn_->oso_alpha_eigenvectors().copy();
435 eigenvalues_ = guess_wfn_->alpha_eigenvalues().copy();
436 oso_eigenvectors_beta_ = guess_wfn_->oso_beta_eigenvectors().copy();
437 eigenvalues_beta_ = guess_wfn_->beta_eigenvalues().copy();
438 } else if (ug) {
439 oso_eigenvectors_ = ug->oso_eigenvectors_.result_noupdate().copy();
440 eigenvalues_ = ug->eigenvalues_.result_noupdate().copy();
441 oso_eigenvectors_beta_
442 = ug->oso_eigenvectors_beta_.result_noupdate().copy();
443 eigenvalues_beta_ = ug->eigenvalues_beta_.result_noupdate().copy();
444 }
445 ExEnv::out0() << decindent << decindent;
446 } else {
447 ExEnv::out0() << indent
448 << "Projecting guess wavefunction into the present basis set"
449 << endl;
450
451 // indent output of projected_eigenvectors() call if there is any
452 ExEnv::out0() << incindent << incindent;
453 oso_eigenvectors_ = projected_eigenvectors(guess_wfn_, 1);
454 eigenvalues_ = projected_eigenvalues(guess_wfn_, 1);
455 oso_eigenvectors_beta_ = projected_eigenvectors(guess_wfn_, 0);
456 eigenvalues_beta_ = projected_eigenvalues(guess_wfn_, 0);
457 ExEnv::out0() << decindent << decindent;
458 }
459
460 // we should only have to do this once, so free up memory used
461 // for the old wavefunction, unless told otherwise
462 if (!keep_guess_wfn_) guess_wfn_=0;
463
464 ExEnv::out0() << endl;
465
466 } else {
467 ExEnv::out0() << indent << "Starting from core Hamiltonian guess\n"
468 << endl;
469 oso_eigenvectors_ = hcore_guess(eigenvalues_.result_noupdate());
470 oso_eigenvectors_beta_ = oso_eigenvectors_.result_noupdate().copy();
471 eigenvalues_beta_ = eigenvalues_.result_noupdate().copy();
472 }
473 } else {
474 // this is just an old vector
475 }
476 }
477
478 need_vec_=needv;
479}
480
481//////////////////////////////////////////////////////////////////////////////
482
483void
484UnrestrictedSCF::set_occupations(const RefDiagSCMatrix& ev)
485{
486 abort();
487}
488
489void
490UnrestrictedSCF::set_occupations(const RefDiagSCMatrix& eva,
491 const RefDiagSCMatrix& evb)
492{
493 if (user_occupations_ || (initial_nalpha_ && eva.null())) {
494 if (form_occupations(nalpha_, initial_nalpha_)) {
495 form_occupations(nbeta_, initial_nbeta_);
496 most_recent_pg_ = new PointGroup(molecule()->point_group());
497 return;
498 }
499 ExEnv::out0() << indent
500 << "UnrestrictedSCF: WARNING: reforming occupation vector from scratch" << endl;
501 }
502
503 if (nirrep_==1) {
504 delete[] nalpha_;
505 nalpha_=new int[1];
506 nalpha_[0] = tnalpha_;
507 delete[] nbeta_;
508 nbeta_=new int[1];
509 nbeta_[0] = tnbeta_;
510 if (!initial_nalpha_ && initial_pg_->equiv(molecule()->point_group())) {
511 initial_nalpha_=new int[1];
512 initial_nalpha_[0] = tnalpha_;
513 }
514 if (!initial_nbeta_ && initial_pg_->equiv(molecule()->point_group())) {
515 initial_nbeta_=new int[1];
516 initial_nbeta_[0] = tnbeta_;
517 }
518 return;
519 }
520
521 int i,j;
522
523 RefDiagSCMatrix evalsa, evalsb;
524
525 if (eva.null()) {
526 initial_vector(0);
527 evalsa = eigenvalues_.result_noupdate();
528 evalsb = eigenvalues_beta_.result_noupdate();
529 }
530 else {
531 evalsa = eva;
532 evalsb = evb;
533 }
534
535 // first convert evals to something we can deal with easily
536 BlockedDiagSCMatrix *bevalsa = require_dynamic_cast<BlockedDiagSCMatrix*>(evalsa,
537 "UnrestrictedSCF::set_occupations");
538 BlockedDiagSCMatrix *bevalsb = require_dynamic_cast<BlockedDiagSCMatrix*>(evalsb,
539 "UnrestrictedSCF::set_occupations");
540
541 double **valsa = new double*[nirrep_];
542 double **valsb = new double*[nirrep_];
543 for (i=0; i < nirrep_; i++) {
544 int nf=oso_dimension()->blocks()->size(i);
545 if (nf) {
546 valsa[i] = new double[nf];
547 valsb[i] = new double[nf];
548 bevalsa->block(i)->convert(valsa[i]);
549 bevalsb->block(i)->convert(valsb[i]);
550 } else {
551 valsa[i] = 0;
552 valsb[i] = 0;
553 }
554 }
555
556 // now loop to find the tnalpha_ lowest eigenvalues and populate those
557 // MO's
558 int *newalpha = new int[nirrep_];
559 memset(newalpha,0,sizeof(int)*nirrep_);
560
561 for (i=0; i < tnalpha_; i++) {
562 // find lowest eigenvalue
563 int lir=0,ln=0;
564 double lowest=999999999;
565
566 for (int ir=0; ir < nirrep_; ir++) {
567 int nf=oso_dimension()->blocks()->size(ir);
568 if (!nf)
569 continue;
570 for (j=0; j < nf; j++) {
571 if (valsa[ir][j] < lowest) {
572 lowest=valsa[ir][j];
573 lir=ir;
574 ln=j;
575 }
576 }
577 }
578 valsa[lir][ln]=999999999;
579 newalpha[lir]++;
580 }
581
582 int *newbeta = new int[nirrep_];
583 memset(newbeta,0,sizeof(int)*nirrep_);
584
585 for (i=0; i < tnbeta_; i++) {
586 // find lowest eigenvalue
587 int lir=0,ln=0;
588 double lowest=999999999;
589
590 for (int ir=0; ir < nirrep_; ir++) {
591 int nf=oso_dimension()->blocks()->size(ir);
592 if (!nf)
593 continue;
594 for (j=0; j < nf; j++) {
595 if (valsb[ir][j] < lowest) {
596 lowest=valsb[ir][j];
597 lir=ir;
598 ln=j;
599 }
600 }
601 }
602 valsb[lir][ln]=999999999;
603 newbeta[lir]++;
604 }
605
606 // get rid of vals
607 for (i=0; i < nirrep_; i++) {
608 if (valsa[i])
609 delete[] valsa[i];
610 if (valsb[i])
611 delete[] valsb[i];
612 }
613 delete[] valsa;
614 delete[] valsb;
615
616 if (!nalpha_) {
617 nalpha_=newalpha;
618 nbeta_=newbeta;
619 } else if (most_recent_pg_.nonnull()
620 && most_recent_pg_->equiv(molecule()->point_group())) {
621 // test to see if newocc is different from nalpha_
622 for (i=0; i < nirrep_; i++) {
623 if (nalpha_[i] != newalpha[i]) {
624 ExEnv::err0() << indent << "UnrestrictedSCF::set_occupations: WARNING!!!!\n"
625 << incindent << indent
626 << scprintf("occupations for irrep %d have changed\n",i+1)
627 << indent
628 << scprintf("nalpha was %d, changed to %d", nalpha_[i], newalpha[i])
629 << endl << decindent;
630 }
631 if (nbeta_[i] != newbeta[i]) {
632 ExEnv::err0() << indent << "UnrestrictedSCF::set_occupations: WARNING!!!!\n"
633 << incindent << indent
634 << scprintf("occupations for irrep %d have changed\n",i+1)
635 << indent
636 << scprintf("nbeta was %d, changed to %d", nbeta_[i], newbeta[i])
637 << endl << decindent;
638 }
639 }
640
641 memcpy(nalpha_,newalpha,sizeof(int)*nirrep_);
642 memcpy(nbeta_,newbeta,sizeof(int)*nirrep_);
643 delete[] newalpha;
644 delete[] newbeta;
645 }
646
647 if (initial_pg_->equiv(molecule()->point_group())) {
648 delete[] initial_nalpha_;
649 initial_nalpha_ = new int[nirrep_];
650 memcpy(initial_nalpha_,nalpha_,sizeof(int)*nirrep_);
651 }
652
653 if (initial_pg_->equiv(molecule()->point_group())) {
654 delete[] initial_nbeta_;
655 initial_nbeta_ = new int[nirrep_];
656 memcpy(initial_nbeta_,nbeta_,sizeof(int)*nirrep_);
657 }
658
659 most_recent_pg_ = new PointGroup(molecule()->point_group());
660}
661
662void
663UnrestrictedSCF::symmetry_changed()
664{
665 SCF::symmetry_changed();
666 nirrep_ = molecule()->point_group()->char_table().ncomp();
667 oso_eigenvectors_beta_.result_noupdate() = 0;
668 eigenvalues_beta_.result_noupdate() = 0;
669 focka_.result_noupdate() = 0;
670 fockb_.result_noupdate() = 0;
671 set_occupations(0,0);
672}
673
674//////////////////////////////////////////////////////////////////////////////
675//
676// scf things
677//
678
679void
680UnrestrictedSCF::init_vector()
681{
682 init_threads();
683
684 // allocate storage for other temp matrices
685 densa_ = hcore_.clone();
686 densa_.assign(0.0);
687
688 diff_densa_ = hcore_.clone();
689 diff_densa_.assign(0.0);
690
691 densb_ = hcore_.clone();
692 densb_.assign(0.0);
693
694 diff_densb_ = hcore_.clone();
695 diff_densb_.assign(0.0);
696
697 // gmat is in AO basis
698 gmata_ = basis()->matrixkit()->symmmatrix(basis()->basisdim());
699 gmata_.assign(0.0);
700
701 gmatb_ = gmata_.clone();
702 gmatb_.assign(0.0);
703
704 if (focka_.result_noupdate().null()) {
705 focka_ = hcore_.clone();
706 focka_.result_noupdate().assign(0.0);
707 fockb_ = hcore_.clone();
708 fockb_.result_noupdate().assign(0.0);
709 }
710
711 // set up trial vector
712 initial_vector(1);
713
714 oso_scf_vector_ = oso_eigenvectors_.result_noupdate();
715 oso_scf_vector_beta_ = oso_eigenvectors_beta_.result_noupdate();
716}
717
718void
719UnrestrictedSCF::done_vector()
720{
721 done_threads();
722
723 hcore_ = 0;
724 gmata_ = 0;
725 densa_ = 0;
726 diff_densa_ = 0;
727 gmatb_ = 0;
728 densb_ = 0;
729 diff_densb_ = 0;
730
731 oso_scf_vector_ = 0;
732 oso_scf_vector_beta_ = 0;
733}
734
735RefSymmSCMatrix
736UnrestrictedSCF::alpha_density()
737{
738 RefSymmSCMatrix dens(so_dimension(), basis_matrixkit());
739 so_density(dens, 1.0, 1);
740 return dens;
741}
742
743RefSymmSCMatrix
744UnrestrictedSCF::beta_density()
745{
746 RefSymmSCMatrix dens(so_dimension(), basis_matrixkit());
747 so_density(dens, 1.0, 0);
748 return dens;
749}
750
751void
752UnrestrictedSCF::reset_density()
753{
754 gmata_.assign(0.0);
755 diff_densa_.assign(densa_);
756
757 gmatb_.assign(0.0);
758 diff_densb_.assign(densb_);
759}
760
761double
762UnrestrictedSCF::new_density()
763{
764 // copy current density into density diff and scale by -1. later we'll
765 // add the new density to this to get the density difference.
766 diff_densa_.assign(densa_);
767 diff_densa_.scale(-1.0);
768
769 diff_densb_.assign(densb_);
770 diff_densb_.scale(-1.0);
771
772 so_density(densa_, 1.0, 1);
773 so_density(densb_, 1.0, 0);
774
775 diff_densa_.accumulate(densa_);
776 diff_densb_.accumulate(densb_);
777
778 RefSymmSCMatrix d = diff_densa_ + diff_densb_;
779
780 Ref<SCElementScalarProduct> sp(new SCElementScalarProduct);
781 d.element_op(sp.pointer(), d);
782 d=0;
783
784 double delta = sp->result();
785 delta = sqrt(delta/i_offset(diff_densa_.n()));
786
787 return delta;
788}
789
790RefSymmSCMatrix
791UnrestrictedSCF::density()
792{
793 if (!density_.computed()) {
794 RefSymmSCMatrix densa(so_dimension(), basis_matrixkit());
795 RefSymmSCMatrix densb(so_dimension(), basis_matrixkit());
796 so_density(densa, 1.0, 1);
797 so_density(densb, 1.0, 0);
798 densa.accumulate(densb);
799 densb=0;
800
801 density_ = densa;
802 // only flag the density as computed if the calc is converged
803 if (!value_needed()) density_.computed() = 1;
804 }
805
806 return density_.result_noupdate();
807}
808
809double
810UnrestrictedSCF::scf_energy()
811{
812 SCFEnergy *eop = new SCFEnergy;
813 eop->reference();
814 Ref<SCElementOp2> op = eop;
815 focka_.result_noupdate().element_op(op, densa_);
816 double ea = eop->result();
817
818 eop->reset();
819 fockb_.result_noupdate().element_op(op, densb_);
820 double eb = eop->result();
821
822 RefSymmSCMatrix denst = densa_+densb_;
823 eop->reset();
824 hcore_.element_op(op, denst);
825 double ec = eop->result();
826 denst=0;
827
828 op=0;
829 eop->dereference();
830 delete eop;
831
832 return ec+ea+eb;
833}
834
835RefSymmSCMatrix
836UnrestrictedSCF::effective_fock()
837{
838 abort();
839 return 0;
840}
841
842////////////////////////////////////////////////////////////////////////////
843
844class UAExtrapErrorOp : public BlockedSCElementOp {
845 private:
846 UnrestrictedSCF *scf_;
847
848 public:
849 UAExtrapErrorOp(UnrestrictedSCF *s) : scf_(s) {}
850 ~UAExtrapErrorOp() {}
851
852 int has_side_effects() { return 1; }
853
854 void process(SCMatrixBlockIter& bi) {
855 int ir=current_block();
856
857 for (bi.reset(); bi; bi++) {
858 int i=bi.i();
859 int j=bi.j();
860 if (scf_->alpha_occupation(ir,i) == scf_->alpha_occupation(ir,j))
861 bi.set(0.0);
862 }
863 }
864};
865
866class UBExtrapErrorOp : public BlockedSCElementOp {
867 private:
868 UnrestrictedSCF *scf_;
869
870 public:
871 UBExtrapErrorOp(UnrestrictedSCF *s) : scf_(s) {}
872 ~UBExtrapErrorOp() {}
873
874 int has_side_effects() { return 1; }
875
876 void process(SCMatrixBlockIter& bi) {
877 int ir=current_block();
878
879 for (bi.reset(); bi; bi++) {
880 int i=bi.i();
881 int j=bi.j();
882 if (scf_->beta_occupation(ir,i) == scf_->beta_occupation(ir,j))
883 bi.set(0.0);
884 }
885 }
886};
887
888Ref<SCExtrapData>
889UnrestrictedSCF::extrap_data()
890{
891 Ref<SCExtrapData> data =
892 new SymmSCMatrix2SCExtrapData(focka_.result_noupdate(),
893 fockb_.result_noupdate());
894 return data;
895}
896
897Ref<SCExtrapError>
898UnrestrictedSCF::extrap_error()
899{
900 RefSCMatrix so_to_ortho_so_tr = so_to_orthog_so().t();
901
902 // form Error_a
903 RefSymmSCMatrix moa(oso_dimension(), basis_matrixkit());
904 moa.assign(0.0);
905 moa.accumulate_transform(so_to_ortho_so_tr * oso_scf_vector_,
906 focka_.result_noupdate(),
907 SCMatrix::TransposeTransform);
908
909 Ref<SCElementOp> op = new UAExtrapErrorOp(this);
910 moa.element_op(op.pointer());
911
912 // form Error_b
913 RefSymmSCMatrix mob(oso_dimension(), basis_matrixkit());
914 mob.assign(0.0);
915 mob.accumulate_transform(so_to_ortho_so_tr * oso_scf_vector_beta_,
916 fockb_.result_noupdate(),
917 SCMatrix::TransposeTransform);
918
919 op = new UBExtrapErrorOp(this);
920 mob.element_op(op);
921
922 RefSymmSCMatrix aoa(so_dimension(), basis_matrixkit());
923 aoa.assign(0.0);
924 aoa.accumulate_transform(so_to_ortho_so_tr * oso_scf_vector_, moa);
925 moa = 0;
926
927 RefSymmSCMatrix aob(so_dimension(), basis_matrixkit());
928 aob.assign(0.0);
929 aob.accumulate_transform(so_to_ortho_so_tr * oso_scf_vector_beta_,mob);
930 mob=0;
931
932 aoa.accumulate(aob);
933 aob=0;
934
935 Ref<SCExtrapError> error = new SymmSCMatrixSCExtrapError(aoa);
936 aoa=0;
937
938 return error;
939}
940
941///////////////////////////////////////////////////////////////////////////
942
943double
944UnrestrictedSCF::compute_vector(double& eelec, double nucrep)
945{
946 tim_enter("vector");
947 int i;
948
949 // reinitialize the extrapolation object
950 extrap_->reinitialize();
951
952 // create level shifter
953 ALevelShift *alevel_shift = new ALevelShift(this);
954 alevel_shift->reference();
955 BLevelShift *blevel_shift = new BLevelShift(this);
956 blevel_shift->reference();
957
958 // calculate the core Hamiltonian
959 hcore_ = core_hamiltonian();
960
961 // add density independant contributions to Hcore
962 accumdih_->accum(hcore_);
963
964 // set up subclass for vector calculation
965 init_vector();
966
967 RefDiagSCMatrix evalsa(oso_dimension(), basis_matrixkit());
968 RefDiagSCMatrix evalsb(oso_dimension(), basis_matrixkit());
969
970 double delta = 1.0;
971 int iter;
972
973 ExEnv::out0() << indent
974 << "Beginning iterations. Basis is "
975 << basis()->label() << '.' << std::endl;
976 for (iter=0; iter < maxiter_; iter++) {
977 // form the density from the current vector
978 tim_enter("density");
979 delta = new_density();
980 tim_exit("density");
981
982 // check convergence
983 if (delta < desired_value_accuracy())
984 break;
985
986 // reset the density from time to time
987 if (iter && !(iter%dens_reset_freq_))
988 reset_density();
989
990 // form the AO basis fock matrix
991 tim_enter("fock");
992 double accuracy = 0.01 * delta;
993 if (accuracy > 0.0001) accuracy = 0.0001;
994 ao_fock(accuracy);
995 tim_exit("fock");
996
997 // calculate the electronic energy
998 eelec = scf_energy();
999 ExEnv::out0() << indent
1000 << scprintf("iter %5d energy = %15.10f delta = %10.5e",
1001 iter+1, eelec+nucrep, delta)
1002 << endl;
1003
1004 // now extrapolate the fock matrix
1005 tim_enter("extrap");
1006 Ref<SCExtrapData> data = extrap_data();
1007 Ref<SCExtrapError> error = extrap_error();
1008 extrap_->extrapolate(data,error);
1009 data=0;
1010 error=0;
1011 tim_exit("extrap");
1012
1013 // diagonalize effective MO fock to get MO vector
1014 tim_enter("evals");
1015
1016 RefSCMatrix so_to_oso_tr = so_to_orthog_so().t();
1017
1018 RefSymmSCMatrix moa(oso_dimension(), basis_matrixkit());
1019 moa.assign(0.0);
1020 moa.accumulate_transform(so_to_oso_tr * oso_scf_vector_,
1021 focka_.result_noupdate(),
1022 SCMatrix::TransposeTransform);
1023
1024 RefSymmSCMatrix mob(oso_dimension(), basis_matrixkit());
1025 mob.assign(0.0);
1026 mob.accumulate_transform(so_to_oso_tr * oso_scf_vector_beta_,
1027 fockb_.result_noupdate(),
1028 SCMatrix::TransposeTransform);
1029
1030 RefSCMatrix nvectora(oso_dimension(), oso_dimension(), basis_matrixkit());
1031 RefSCMatrix nvectorb(oso_dimension(), oso_dimension(), basis_matrixkit());
1032
1033 // level shift effective fock in the mo basis
1034 alevel_shift->set_shift(level_shift_);
1035 moa.element_op(alevel_shift);
1036 blevel_shift->set_shift(level_shift_);
1037 mob.element_op(blevel_shift);
1038
1039 // transform back to the oso basis to do the diagonalization
1040 RefSymmSCMatrix osoa(oso_dimension(), basis_matrixkit());
1041 osoa.assign(0.0);
1042 osoa.accumulate_transform(oso_scf_vector_,moa);
1043 moa = 0;
1044 osoa.diagonalize(evalsa,oso_scf_vector_);
1045 osoa = 0;
1046
1047 RefSymmSCMatrix osob(oso_dimension(), basis_matrixkit());
1048 osob.assign(0.0);
1049 osob.accumulate_transform(oso_scf_vector_beta_,mob);
1050 mob = 0;
1051 osob.diagonalize(evalsb,oso_scf_vector_beta_);
1052 osob = 0;
1053
1054 tim_exit("evals");
1055
1056 // now un-level shift eigenvalues
1057 alevel_shift->set_shift(-level_shift_);
1058 evalsa.element_op(alevel_shift);
1059 blevel_shift->set_shift(-level_shift_);
1060 evalsb.element_op(blevel_shift);
1061
1062 if (reset_occ_)
1063 set_occupations(evalsa, evalsb);
1064
1065 savestate_iter(iter);
1066 }
1067
1068 eigenvalues_ = evalsa;
1069 eigenvalues_.computed() = 1;
1070 eigenvalues_.set_actual_accuracy(delta);
1071 evalsa = 0;
1072
1073 oso_eigenvectors_ = oso_scf_vector_;
1074 oso_eigenvectors_.computed() = 1;
1075 oso_eigenvectors_.set_actual_accuracy(delta);
1076
1077 oso_eigenvectors_beta_ = oso_scf_vector_beta_;
1078 oso_eigenvectors_beta_.computed() = 1;
1079 oso_eigenvectors_beta_.set_actual_accuracy(delta);
1080
1081 eigenvalues_beta_ = evalsb;
1082 eigenvalues_beta_.computed() = 1;
1083 eigenvalues_beta_.set_actual_accuracy(delta);
1084 evalsb = 0;
1085
1086 {
1087 // compute spin contamination
1088 RefSCMatrix so_to_oso_tr = so_to_orthog_so().t();
1089 RefSCMatrix Sab
1090 = (so_to_oso_tr * oso_scf_vector_).t()
1091 * overlap()
1092 * (so_to_oso_tr * oso_scf_vector_beta_);
1093 //Sab.print("Sab");
1094 BlockedSCMatrix *pSab = dynamic_cast<BlockedSCMatrix*>(Sab.pointer());
1095 double s2=0;
1096 for (int ir=0; ir < nirrep_; ir++) {
1097 RefSCMatrix Sab_ir=pSab->block(0);
1098 if (Sab_ir.nonnull()) {
1099 for (i=0; i < nalpha_[ir]; i++)
1100 for (int j=0; j < nbeta_[ir]; j++)
1101 s2 += Sab_ir.get_element(i,j)*Sab_ir.get_element(i,j);
1102 }
1103 }
1104
1105 double S2real = (double)(tnalpha_-tnbeta_)/2.;
1106 S2real = S2real*(S2real+1);
1107 double S2 = S2real + tnbeta_ - s2;
1108
1109 ExEnv::out0() << endl
1110 << indent << scprintf("<S^2>exact = %f", S2real) << endl
1111 << indent << scprintf("<S^2> = %f", S2) << endl;
1112 }
1113
1114 // now clean up
1115 done_vector();
1116
1117 alevel_shift->dereference();
1118 delete alevel_shift;
1119 blevel_shift->dereference();
1120 delete blevel_shift;
1121
1122 tim_exit("vector");
1123 //tim_print(0);
1124
1125 return delta;
1126}
1127
1128////////////////////////////////////////////////////////////////////////////
1129
1130void
1131UnrestrictedSCF::init_gradient()
1132{
1133 // presumably the eigenvectors have already been computed by the time
1134 // we get here
1135 oso_scf_vector_ = oso_eigenvectors_.result_noupdate();
1136 oso_scf_vector_beta_ = oso_eigenvectors_beta_.result_noupdate();
1137}
1138
1139void
1140UnrestrictedSCF::done_gradient()
1141{
1142 densa_=0;
1143 densb_=0;
1144 oso_scf_vector_ = 0;
1145 oso_scf_vector_beta_ = 0;
1146}
1147
1148/////////////////////////////////////////////////////////////////////////////
1149
1150RefSymmSCMatrix
1151UnrestrictedSCF::lagrangian()
1152{
1153 RefSCMatrix so_to_oso_tr = so_to_orthog_so().t();
1154
1155 RefDiagSCMatrix ea = eigenvalues_.result_noupdate().copy();
1156 RefDiagSCMatrix eb = eigenvalues_beta_.result_noupdate().copy();
1157
1158 BlockedDiagSCMatrix *eab = dynamic_cast<BlockedDiagSCMatrix*>(ea.pointer());
1159 BlockedDiagSCMatrix *ebb = dynamic_cast<BlockedDiagSCMatrix*>(eb.pointer());
1160
1161 Ref<PetiteList> pl = integral()->petite_list(basis());
1162
1163 for (int ir=0; ir < nirrep_; ir++) {
1164 RefDiagSCMatrix eair = eab->block(ir);
1165 RefDiagSCMatrix ebir = ebb->block(ir);
1166
1167 if (eair.null())
1168 continue;
1169
1170 int i;
1171 for (i=nalpha_[ir]; i < eair.dim().n(); i++)
1172 eair.set_element(i,0.0);
1173 for (i=nbeta_[ir]; i < ebir.dim().n(); i++)
1174 ebir.set_element(i,0.0);
1175 }
1176
1177 RefSymmSCMatrix la = basis_matrixkit()->symmmatrix(so_dimension());
1178 la.assign(0.0);
1179 la.accumulate_transform(so_to_oso_tr * oso_scf_vector_, ea);
1180
1181 RefSymmSCMatrix lb = la.clone();
1182 lb.assign(0.0);
1183 lb.accumulate_transform(so_to_oso_tr * oso_scf_vector_beta_, eb);
1184
1185 la.accumulate(lb);
1186
1187 la = pl->to_AO_basis(la);
1188 la->scale(-1.0);
1189
1190 return la;
1191}
1192
1193RefSymmSCMatrix
1194UnrestrictedSCF::gradient_density()
1195{
1196 densa_ = basis_matrixkit()->symmmatrix(so_dimension());
1197 densb_ = densa_.clone();
1198
1199 so_density(densa_, 1.0, 1);
1200 so_density(densb_, 1.0, 0);
1201
1202 Ref<PetiteList> pl = integral()->petite_list(basis());
1203
1204 densa_ = pl->to_AO_basis(densa_);
1205 densb_ = pl->to_AO_basis(densb_);
1206
1207 RefSymmSCMatrix tdens = densa_.copy();
1208 tdens.accumulate(densb_);
1209 return tdens;
1210}
1211
1212//////////////////////////////////////////////////////////////////////////////
1213
1214void
1215UnrestrictedSCF::init_hessian()
1216{
1217}
1218
1219void
1220UnrestrictedSCF::done_hessian()
1221{
1222}
1223
1224//////////////////////////////////////////////////////////////////////////////
1225
1226void
1227UnrestrictedSCF::two_body_deriv_hf(double * tbgrad, double exchange_fraction)
1228{
1229 Ref<SCElementMaxAbs> m = new SCElementMaxAbs;
1230 densa_.element_op(m.pointer());
1231 double pmax = m->result();
1232 m=0;
1233
1234 // now try to figure out the matrix specialization we're dealing with.
1235 // if we're using Local matrices, then there's just one subblock, or
1236 // see if we can convert P to local matrices
1237
1238 if (local_ || local_dens_) {
1239 // grab the data pointers from the P matrices
1240 double *pmata, *pmatb;
1241 RefSymmSCMatrix ptmpa = get_local_data(densa_, pmata, SCF::Read);
1242 RefSymmSCMatrix ptmpb = get_local_data(densb_, pmatb, SCF::Read);
1243
1244 Ref<PetiteList> pl = integral()->petite_list();
1245 LocalUHFGradContribution l(pmata,pmatb);
1246
1247 int i;
1248 int na3 = molecule()->natom()*3;
1249 int nthread = threadgrp_->nthread();
1250 double **grads = new double*[nthread];
1251 Ref<TwoBodyDerivInt> *tbis = new Ref<TwoBodyDerivInt>[nthread];
1252 for (i=0; i < nthread; i++) {
1253 tbis[i] = integral()->electron_repulsion_deriv();
1254 grads[i] = new double[na3];
1255 memset(grads[i], 0, sizeof(double)*na3);
1256 }
1257
1258 LocalTBGrad<LocalUHFGradContribution> **tblds =
1259 new LocalTBGrad<LocalUHFGradContribution>*[nthread];
1260
1261 for (i=0; i < nthread; i++) {
1262 tblds[i] = new LocalTBGrad<LocalUHFGradContribution>(
1263 l, tbis[i], pl, basis(), scf_grp_, grads[i], pmax,
1264 desired_gradient_accuracy(), nthread, i, exchange_fraction);
1265 threadgrp_->add_thread(i, tblds[i]);
1266 }
1267
1268 if (threadgrp_->start_threads() < 0
1269 ||threadgrp_->wait_threads() < 0) {
1270 ExEnv::err0() << indent
1271 << "USCF: error running threads" << endl;
1272 abort();
1273 }
1274
1275 for (i=0; i < nthread; i++) {
1276 for (int j=0; j < na3; j++)
1277 tbgrad[j] += grads[i][j];
1278
1279 delete[] grads[i];
1280 delete tblds[i];
1281 }
1282
1283 scf_grp_->sum(tbgrad,3 * basis()->molecule()->natom());
1284 }
1285
1286 // for now quit
1287 else {
1288 ExEnv::err0() << indent
1289 << "USCF::two_body_deriv_hf: can't do gradient yet\n";
1290 abort();
1291 }
1292}
1293
1294void
1295UnrestrictedSCF::set_desired_value_accuracy(double eps)
1296{
1297 OneBodyWavefunction::set_desired_value_accuracy(eps);
1298 oso_eigenvectors_beta_.set_desired_accuracy(eps);
1299 eigenvalues_beta_.set_desired_accuracy(eps);
1300}
1301
1302
1303//////////////////////////////////////////////////////////////////////////////
1304
1305}
1306
1307// Local Variables:
1308// mode: c++
1309// c-file-style: "ETS"
1310// End:
Note: See TracBrowser for help on using the repository browser.