source: ThirdParty/mpqc_open/src/lib/chemistry/qc/scf/clscf.cc@ 1513599

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 1513599 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: 16.1 KB
Line 
1//
2// clscf.cc --- implementation of the closed shell SCF 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
34#include <util/misc/timer.h>
35#include <util/misc/formio.h>
36#include <util/state/stateio.h>
37
38#include <math/scmat/block.h>
39#include <math/scmat/blocked.h>
40#include <math/scmat/blkiter.h>
41#include <math/scmat/local.h>
42
43#include <math/optimize/scextrapmat.h>
44
45#include <chemistry/qc/basis/petite.h>
46
47#include <chemistry/qc/scf/scflocal.h>
48#include <chemistry/qc/scf/scfops.h>
49#include <chemistry/qc/scf/clscf.h>
50#include <chemistry/qc/scf/ltbgrad.h>
51#include <chemistry/qc/scf/clhftmpl.h>
52
53using namespace std;
54using namespace sc;
55
56namespace sc {
57
58///////////////////////////////////////////////////////////////////////////
59// CLSCF
60
61static ClassDesc CLSCF_cd(
62 typeid(CLSCF),"CLSCF",2,"public SCF",
63 0, 0, 0);
64
65CLSCF::CLSCF(StateIn& s) :
66 SavableState(s),
67 SCF(s),
68 cl_fock_(this)
69{
70 cl_fock_.result_noupdate() =
71 basis_matrixkit()->symmmatrix(so_dimension());
72 cl_fock_.restore_state(s);
73 cl_fock_.result_noupdate().restore(s);
74
75 s.get(user_occupations_);
76 s.get(tndocc_);
77 s.get(nirrep_);
78 s.get(ndocc_);
79 if (s.version(::class_desc<CLSCF>()) >= 2) {
80 s.get(initial_ndocc_);
81 most_recent_pg_ << SavableState::restore_state(s);
82 } else {
83 initial_ndocc_ = new int[nirrep_];
84 memcpy(initial_ndocc_, ndocc_, sizeof(int)*nirrep_);
85 }
86
87 // now take care of memory stuff
88 init_mem(2);
89}
90
91CLSCF::CLSCF(const Ref<KeyVal>& keyval) :
92 SCF(keyval),
93 cl_fock_(this)
94{
95 int i;
96 int me = scf_grp_->me();
97
98 cl_fock_.compute()=0;
99 cl_fock_.computed()=0;
100
101 // calculate the total nuclear charge
102 double Znuc=molecule()->nuclear_charge();
103
104 // check to see if this is to be a charged molecule
105 double charge = keyval->doublevalue("total_charge");
106
107 int nelectron = (int)((Znuc-charge+1.0e-4));
108
109 // now see if ndocc was specified
110 if (keyval->exists("ndocc")) {
111 tndocc_ = keyval->intvalue("ndocc");
112 } else {
113 tndocc_ = nelectron/2;
114 if (nelectron%2 && me==0) {
115 ExEnv::err0() << endl
116 << indent << "CLSCF::init: Warning, there's a leftover electron.\n"
117 << incindent << indent << "total_charge = " << charge << endl
118 << indent << "total nuclear charge = " << Znuc << endl
119 << indent << "ndocc_ = " << tndocc_ << endl << decindent;
120 }
121 }
122
123 ExEnv::out0() << endl << indent
124 << "CLSCF::init: total charge = " << Znuc-2*tndocc_ << endl << endl;
125
126 nirrep_ = molecule()->point_group()->char_table().ncomp();
127
128 ndocc_ = read_occ(keyval, "docc", nirrep_);
129 if (ndocc_) {
130 user_occupations_=1;
131 initial_ndocc_ = new int[nirrep_];
132 memcpy(initial_ndocc_, ndocc_, sizeof(int)*nirrep_);
133 } else {
134 initial_ndocc_=0;
135 ndocc_=0;
136 user_occupations_=0;
137 set_occupations(0);
138 }
139
140 ExEnv::out0() << indent << "docc = [";
141 for (i=0; i < nirrep_; i++)
142 ExEnv::out0() << " " << ndocc_[i];
143 ExEnv::out0() << " ]\n";
144
145 ExEnv::out0() << indent << "nbasis = " << basis()->nbasis() << endl;
146
147 // check to see if this was done in SCF(keyval)
148 if (!keyval->exists("maxiter"))
149 maxiter_ = 100;
150
151 // now take care of memory stuff
152 init_mem(2);
153}
154
155CLSCF::~CLSCF()
156{
157 if (ndocc_) {
158 delete[] ndocc_;
159 ndocc_=0;
160 }
161 delete[] initial_ndocc_;
162}
163
164void
165CLSCF::save_data_state(StateOut& s)
166{
167 SCF::save_data_state(s);
168
169 cl_fock_.save_data_state(s);
170 cl_fock_.result_noupdate().save(s);
171
172 s.put(user_occupations_);
173 s.put(tndocc_);
174 s.put(nirrep_);
175 s.put(ndocc_,nirrep_);
176 s.put(initial_ndocc_,nirrep_);
177 SavableState::save_state(most_recent_pg_.pointer(),s);
178}
179
180double
181CLSCF::occupation(int ir, int i)
182{
183 if (i < ndocc_[ir]) return 2.0;
184 return 0.0;
185}
186
187int
188CLSCF::n_fock_matrices() const
189{
190 return 1;
191}
192
193RefSymmSCMatrix
194CLSCF::fock(int n)
195{
196 if (n > 0) {
197 ExEnv::err0() << indent
198 << "CLSCF::fock: there is only one fock matrix, "
199 << scprintf("but fock(%d) was requested\n",n);
200 abort();
201 }
202
203 return cl_fock_.result();
204}
205
206int
207CLSCF::spin_polarized()
208{
209 return 0;
210}
211
212void
213CLSCF::print(ostream&o) const
214{
215 SCF::print(o);
216 o << indent << "CLSCF Parameters:\n" << incindent
217 << indent << "charge = " << molecule()->nuclear_charge()-2*tndocc_ << endl
218 << indent << "ndocc = " << tndocc_ << endl
219 << indent << "docc = [";
220 for (int i=0; i < nirrep_; i++)
221 o << " " << ndocc_[i];
222 o << " ]" << endl << decindent << endl;
223}
224
225//////////////////////////////////////////////////////////////////////////////
226
227void
228CLSCF::set_occupations(const RefDiagSCMatrix& ev)
229{
230 if (user_occupations_ || (initial_ndocc_ && ev.null())) {
231 if (form_occupations(ndocc_, initial_ndocc_)) {
232 most_recent_pg_ = new PointGroup(molecule()->point_group());
233 return;
234 }
235 ExEnv::out0() << indent
236 << "CLSCF: WARNING: reforming occupation vector from scratch" << endl;
237 }
238
239 if (nirrep_==1) {
240 delete[] ndocc_;
241 ndocc_=new int[1];
242 ndocc_[0]=tndocc_;
243 if (!initial_ndocc_) {
244 initial_ndocc_=new int[1];
245 initial_ndocc_[0]=tndocc_;
246 }
247 return;
248 }
249
250 int i,j;
251
252 RefDiagSCMatrix evals;
253
254 if (ev.null()) {
255 initial_vector(0);
256 evals = eigenvalues_.result_noupdate();
257 }
258 else
259 evals = ev;
260
261 // first convert evals to something we can deal with easily
262 BlockedDiagSCMatrix *evalsb = require_dynamic_cast<BlockedDiagSCMatrix*>(evals,
263 "CLSCF::set_occupations");
264
265 double **vals = new double*[nirrep_];
266 for (i=0; i < nirrep_; i++) {
267 int nf=oso_dimension()->blocks()->size(i);
268 if (nf) {
269 vals[i] = new double[nf];
270 evalsb->block(i)->convert(vals[i]);
271 } else {
272 vals[i] = 0;
273 }
274 }
275
276 // now loop to find the tndocc_ lowest eigenvalues and populate those
277 // MO's
278 int *newocc = new int[nirrep_];
279 memset(newocc,0,sizeof(int)*nirrep_);
280
281 for (i=0; i < tndocc_; i++) {
282 // find lowest eigenvalue
283 int lir=0,ln=0;
284 double lowest=999999999;
285
286 for (int ir=0; ir < nirrep_; ir++) {
287 int nf=oso_dimension()->blocks()->size(ir);
288 if (!nf)
289 continue;
290 for (j=0; j < nf; j++) {
291 if (vals[ir][j] < lowest) {
292 lowest=vals[ir][j];
293 lir=ir;
294 ln=j;
295 }
296 }
297 }
298 vals[lir][ln]=999999999;
299 newocc[lir]++;
300 }
301
302 // get rid of vals
303 for (i=0; i < nirrep_; i++)
304 if (vals[i])
305 delete[] vals[i];
306 delete[] vals;
307
308 if (!ndocc_) {
309 ndocc_=newocc;
310 } else if (most_recent_pg_.nonnull()
311 && most_recent_pg_->equiv(molecule()->point_group())) {
312 // test to see if newocc is different from ndocc_
313 for (i=0; i < nirrep_; i++) {
314 if (ndocc_[i] != newocc[i]) {
315 ExEnv::err0() << indent << "CLSCF::set_occupations: WARNING!!!!\n"
316 << incindent << indent
317 << scprintf("occupations for irrep %d have changed\n",i+1)
318 << indent
319 << scprintf("ndocc was %d, changed to %d", ndocc_[i],newocc[i])
320 << endl << decindent;
321 }
322 }
323
324 memcpy(ndocc_,newocc,sizeof(int)*nirrep_);
325 delete[] newocc;
326 }
327
328 if (!initial_ndocc_
329 || initial_pg_->equiv(molecule()->point_group())) {
330 delete[] initial_ndocc_;
331 initial_ndocc_ = new int[nirrep_];
332 memcpy(initial_ndocc_,ndocc_,sizeof(int)*nirrep_);
333 }
334
335 most_recent_pg_ = new PointGroup(molecule()->point_group());
336}
337
338void
339CLSCF::symmetry_changed()
340{
341 SCF::symmetry_changed();
342 cl_fock_.result_noupdate()=0;
343 nirrep_ = molecule()->point_group()->char_table().ncomp();
344 set_occupations(0);
345}
346
347//////////////////////////////////////////////////////////////////////////////
348//
349// scf things
350//
351
352void
353CLSCF::init_vector()
354{
355 init_threads();
356
357 // initialize the two electron integral classes
358 ExEnv::out0() << indent
359 << "integral intermediate storage = " << integral()->storage_used()
360 << " bytes" << endl;
361 ExEnv::out0() << indent
362 << "integral cache = " << integral()->storage_unused()
363 << " bytes" << endl;
364
365 // allocate storage for other temp matrices
366 cl_dens_ = hcore_.clone();
367 cl_dens_.assign(0.0);
368
369 cl_dens_diff_ = hcore_.clone();
370 cl_dens_diff_.assign(0.0);
371
372 // gmat is in AO basis
373 cl_gmat_ = basis()->matrixkit()->symmmatrix(basis()->basisdim());
374 cl_gmat_.assign(0.0);
375
376 if (cl_fock_.result_noupdate().null()) {
377 cl_fock_ = hcore_.clone();
378 cl_fock_.result_noupdate().assign(0.0);
379 }
380
381 // set up trial vector
382 initial_vector(1);
383
384 oso_scf_vector_ = oso_eigenvectors_.result_noupdate();
385
386 if (accumddh_.nonnull()) accumddh_->init(this);
387}
388
389void
390CLSCF::done_vector()
391{
392 done_threads();
393
394 if (accumddh_.nonnull()) {
395 accumddh_->print_summary();
396 accumddh_->done();
397 }
398
399 cl_gmat_ = 0;
400 cl_dens_ = 0;
401 cl_dens_diff_ = 0;
402
403 oso_scf_vector_ = 0;
404}
405
406void
407CLSCF::reset_density()
408{
409 cl_gmat_.assign(0.0);
410 cl_dens_diff_.assign(cl_dens_);
411}
412
413RefSymmSCMatrix
414CLSCF::density()
415{
416 if (!density_.computed()) {
417 RefSymmSCMatrix dens(so_dimension(), basis_matrixkit());
418 so_density(dens, 2.0);
419 dens.scale(2.0);
420
421 density_ = dens;
422 // only flag the density as computed if the calc is converged
423 if (!value_needed()) density_.computed() = 1;
424 }
425
426 return density_.result_noupdate();
427}
428
429double
430CLSCF::new_density()
431{
432 // copy current density into density diff and scale by -1. later we'll
433 // add the new density to this to get the density difference.
434 cl_dens_diff_.assign(cl_dens_);
435 cl_dens_diff_.scale(-1.0);
436
437 so_density(cl_dens_, 2.0);
438 cl_dens_.scale(2.0);
439
440 cl_dens_diff_.accumulate(cl_dens_);
441
442 Ref<SCElementScalarProduct> sp(new SCElementScalarProduct);
443 cl_dens_diff_.element_op(sp.pointer(), cl_dens_diff_);
444
445 double delta = sp->result();
446 delta = sqrt(delta/i_offset(cl_dens_diff_.n()));
447
448 return delta;
449}
450
451double
452CLSCF::scf_energy()
453{
454 RefSymmSCMatrix t = cl_fock_.result_noupdate().copy();
455 t.accumulate(hcore_);
456
457 SCFEnergy *eop = new SCFEnergy;
458 eop->reference();
459 Ref<SCElementOp2> op = eop;
460 t.element_op(op,cl_dens_);
461 op=0;
462 eop->dereference();
463
464 double eelec = eop->result();
465
466 delete eop;
467
468 return eelec;
469}
470
471Ref<SCExtrapData>
472CLSCF::extrap_data()
473{
474 Ref<SCExtrapData> data =
475 new SymmSCMatrixSCExtrapData(cl_fock_.result_noupdate());
476 return data;
477}
478
479RefSymmSCMatrix
480CLSCF::effective_fock()
481{
482 // just return MO fock matrix. use fock() instead of cl_fock_ just in
483 // case this is called from someplace outside SCF::compute_vector()
484 RefSymmSCMatrix mofock(oso_dimension(), basis_matrixkit());
485 mofock.assign(0.0);
486
487 if (debug_ > 1) {
488 fock(0).print("CL Fock matrix in SO basis");
489 }
490
491 // use eigenvectors if scf_vector_ is null
492 if (oso_scf_vector_.null())
493 mofock.accumulate_transform(eigenvectors(), fock(0),
494 SCMatrix::TransposeTransform);
495 else
496 mofock.accumulate_transform(so_to_orthog_so().t() * oso_scf_vector_,
497 fock(0),
498 SCMatrix::TransposeTransform);
499
500 return mofock;
501}
502
503//////////////////////////////////////////////////////////////////////////////
504
505void
506CLSCF::init_gradient()
507{
508 // presumably the eigenvectors have already been computed by the time
509 // we get here
510 oso_scf_vector_ = oso_eigenvectors_.result_noupdate();
511}
512
513void
514CLSCF::done_gradient()
515{
516 cl_dens_=0;
517 oso_scf_vector_ = 0;
518}
519
520/////////////////////////////////////////////////////////////////////////////
521
522class CLLag : public BlockedSCElementOp {
523 private:
524 CLSCF *scf_;
525
526 public:
527 CLLag(CLSCF* s) : scf_(s) {}
528 ~CLLag() {}
529
530 int has_side_effects() { return 1; }
531
532 void process(SCMatrixBlockIter& bi) {
533 int ir=current_block();
534
535 for (bi.reset(); bi; bi++) {
536 double occi = scf_->occupation(ir,bi.i());
537
538 if (occi==0.0)
539 bi.set(0.0);
540 }
541 }
542};
543
544RefSymmSCMatrix
545CLSCF::lagrangian()
546{
547 // the MO lagrangian is just the eigenvalues of the occupied MO's
548 RefSymmSCMatrix mofock = effective_fock();
549
550 Ref<SCElementOp> op = new CLLag(this);
551 mofock.element_op(op);
552
553 // transform MO lagrangian to SO basis
554 RefSymmSCMatrix so_lag(so_dimension(), basis_matrixkit());
555 so_lag.assign(0.0);
556 so_lag.accumulate_transform(so_to_orthog_so().t() * oso_scf_vector_, mofock);
557
558 // and then from SO to AO
559 Ref<PetiteList> pl = integral()->petite_list();
560 RefSymmSCMatrix ao_lag = pl->to_AO_basis(so_lag);
561 ao_lag->scale(-2.0);
562
563 return ao_lag;
564}
565
566RefSymmSCMatrix
567CLSCF::gradient_density()
568{
569 cl_dens_ = basis_matrixkit()->symmmatrix(so_dimension());
570 cl_dens_.assign(0.0);
571
572 so_density(cl_dens_, 2.0);
573 cl_dens_.scale(2.0);
574
575 Ref<PetiteList> pl = integral()->petite_list(basis());
576
577 cl_dens_ = pl->to_AO_basis(cl_dens_);
578
579 return cl_dens_;
580}
581
582/////////////////////////////////////////////////////////////////////////////
583
584void
585CLSCF::init_hessian()
586{
587}
588
589void
590CLSCF::done_hessian()
591{
592}
593
594/////////////////////////////////////////////////////////////////////////////
595
596void
597CLSCF::two_body_deriv_hf(double * tbgrad, double exchange_fraction)
598{
599 int i;
600 int na3 = molecule()->natom()*3;
601 int nthread = threadgrp_->nthread();
602
603 tim_enter("setup");
604 Ref<SCElementMaxAbs> m = new SCElementMaxAbs;
605 cl_dens_.element_op(m.pointer());
606 double pmax = m->result();
607 m=0;
608
609 double **grads = new double*[nthread];
610 Ref<TwoBodyDerivInt> *tbis = new Ref<TwoBodyDerivInt>[nthread];
611 for (i=0; i < nthread; i++) {
612 tbis[i] = integral()->electron_repulsion_deriv();
613 grads[i] = new double[na3];
614 memset(grads[i], 0, sizeof(double)*na3);
615 }
616
617 Ref<PetiteList> pl = integral()->petite_list();
618
619 tim_change("contribution");
620
621 // now try to figure out the matrix specialization we're dealing with.
622 // if we're using Local matrices, then there's just one subblock, or
623 // see if we can convert P to a local matrix
624 if (local_ || local_dens_) {
625 double *pmat;
626 RefSymmSCMatrix ptmp = get_local_data(cl_dens_, pmat, SCF::Read);
627
628 LocalCLHFGradContribution l(pmat);
629 LocalTBGrad<LocalCLHFGradContribution> **tblds =
630 new LocalTBGrad<LocalCLHFGradContribution>*[nthread];
631
632 for (i=0; i < nthread; i++) {
633 tblds[i] = new LocalTBGrad<LocalCLHFGradContribution>(
634 l, tbis[i], pl, basis(), scf_grp_, grads[i], pmax,
635 desired_gradient_accuracy(), nthread, i, exchange_fraction);
636 threadgrp_->add_thread(i, tblds[i]);
637 }
638
639 tim_enter("start thread");
640 if (threadgrp_->start_threads() < 0) {
641 ExEnv::err0() << indent
642 << "CLSCF: error starting threads" << endl;
643 abort();
644 }
645 tim_exit("start thread");
646
647 tim_enter("stop thread");
648 if (threadgrp_->wait_threads() < 0) {
649 ExEnv::err0() << indent
650 << "CLSCF: error waiting for threads" << endl;
651 abort();
652 }
653 tim_exit("stop thread");
654
655 for (i=0; i < nthread; i++) {
656 if (i) {
657 for (int j=0; j < na3; j++)
658 grads[0][j] += grads[i][j];
659
660 delete[] grads[i];
661 }
662
663 delete tblds[i];
664 }
665
666 if (scf_grp_->n() > 1)
667 scf_grp_->sum(grads[0], na3);
668
669 for (i=0; i < na3; i++)
670 tbgrad[i] += grads[0][i];
671
672 delete[] grads[0];
673 delete[] tblds;
674 delete[] grads;
675 }
676
677 // for now quit
678 else {
679 ExEnv::err0() << indent
680 << "CLHF::two_body_deriv: can't do gradient yet\n";
681 abort();
682 }
683
684 for (i=0; i < nthread; i++)
685 tbis[i] = 0;
686 delete[] tbis;
687
688 tim_exit("contribution");
689}
690
691/////////////////////////////////////////////////////////////////////////////
692
693}
694
695// Local Variables:
696// mode: c++
697// c-file-style: "ETS"
698// End:
Note: See TracBrowser for help on using the repository browser.