source: ThirdParty/mpqc_open/src/lib/chemistry/qc/wfn/obwfn.cc@ 860145

Action_Thermostats Add_AtomRandomPerturbation Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests Automaking_mpqc_open 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_mpqc_open Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since 860145 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.7 KB
Line 
1//
2// obwfn.cc
3//
4// Copyright (C) 1996 Limit Point Systems, Inc.
5//
6// Author: Curtis Janssen <cljanss@limitpt.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 <util/state/stateio.h>
33#include <util/misc/formio.h>
34
35#include <math/symmetry/corrtab.h>
36#include <math/scmat/local.h>
37#include <math/scmat/blocked.h>
38
39#include <chemistry/qc/basis/integral.h>
40#include <chemistry/qc/basis/obint.h>
41#include <chemistry/qc/basis/petite.h>
42#include <chemistry/qc/wfn/obwfn.h>
43
44using namespace std;
45using namespace sc;
46
47#define DEBUG 0
48
49#ifndef DBL_EPSILON
50#define DBL_EPSILON 1.0e-15
51#endif
52
53static ClassDesc OneBodyWavefunction_cd(
54 typeid(OneBodyWavefunction),"OneBodyWavefunction",1,"public Wavefunction",
55 0, 0, 0);
56
57OneBodyWavefunction::OneBodyWavefunction(const Ref<KeyVal>&keyval):
58 Wavefunction(keyval),
59 density_(this),
60 oso_eigenvectors_(this),
61 eigenvalues_(this),
62 nirrep_(0),
63 nvecperirrep_(0),
64 occupations_(0),
65 alpha_occupations_(0),
66 beta_occupations_(0)
67{
68 double acc = keyval->doublevalue("eigenvector_accuracy");
69 if (keyval->error() != KeyVal::OK)
70 acc = value_.desired_accuracy();
71
72 oso_eigenvectors_.set_desired_accuracy(acc);
73 eigenvalues_.set_desired_accuracy(acc);
74
75 if (oso_eigenvectors_.desired_accuracy() < DBL_EPSILON) {
76 oso_eigenvectors_.set_desired_accuracy(DBL_EPSILON);
77 eigenvalues_.set_desired_accuracy(DBL_EPSILON);
78 }
79}
80
81OneBodyWavefunction::OneBodyWavefunction(StateIn&s):
82 SavableState(s),
83 Wavefunction(s),
84 density_(this),
85 oso_eigenvectors_(this),
86 eigenvalues_(this),
87 nirrep_(0),
88 nvecperirrep_(0),
89 occupations_(0),
90 alpha_occupations_(0),
91 beta_occupations_(0)
92{
93 oso_eigenvectors_.result_noupdate() =
94 basis_matrixkit()->matrix(oso_dimension(), oso_dimension());
95 oso_eigenvectors_.restore_state(s);
96 oso_eigenvectors_.result_noupdate().restore(s);
97
98 eigenvalues_.result_noupdate() =
99 basis_matrixkit()->diagmatrix(oso_dimension());
100 eigenvalues_.restore_state(s);
101 eigenvalues_.result_noupdate().restore(s);
102
103 density_.result_noupdate() =
104 basis_matrixkit()->symmmatrix(so_dimension());
105 density_.restore_state(s);
106 density_.result_noupdate().restore(s);
107}
108
109OneBodyWavefunction::~OneBodyWavefunction()
110{
111 if (nvecperirrep_) {
112 delete[] nvecperirrep_;
113 delete[] occupations_;
114 delete[] alpha_occupations_;
115 delete[] beta_occupations_;
116 }
117 nirrep_=0;
118 nvecperirrep_=0;
119 occupations_=0;
120 alpha_occupations_=0;
121 beta_occupations_=0;
122}
123
124void
125OneBodyWavefunction::save_data_state(StateOut&s)
126{
127 Wavefunction::save_data_state(s);
128
129 oso_eigenvectors_.save_data_state(s);
130 oso_eigenvectors_.result_noupdate().save(s);
131
132 eigenvalues_.save_data_state(s);
133 eigenvalues_.result_noupdate().save(s);
134
135 density_.save_data_state(s);
136 density_.result_noupdate().save(s);
137}
138
139RefSCMatrix
140OneBodyWavefunction::projected_eigenvectors(const Ref<OneBodyWavefunction>& owfn,
141 int alp)
142{
143 //............................................................
144 // first obtain the guess density matrix
145
146 // The old density in the old SO basis
147 RefSymmSCMatrix oldP_so;
148 if (owfn->spin_unrestricted()) {
149 if (alp) oldP_so = owfn->alpha_density();
150 else oldP_so = owfn->beta_density();
151 }
152 else oldP_so = owfn->density();
153
154 ExEnv::out0() << endl << indent
155 << "Projecting the guess density.\n"
156 << endl;
157 ExEnv::out0() << incindent;
158
159 // The old overlap
160 RefSymmSCMatrix oldS = owfn->overlap();
161 ExEnv::out0() << indent
162 << "The number of electrons in the guess density = "
163 << (oldP_so*oldS).trace() << endl;
164
165 // Transform the old SO overlap into the orthogonal SO basis, oSO
166 RefSCMatrix old_so_to_oso = owfn->so_to_orthog_so();
167 RefSymmSCMatrix oldP_oso(owfn->oso_dimension(), owfn->basis_matrixkit());
168 oldP_oso->assign(0.0);
169 oldP_oso->accumulate_transform(old_so_to_oso, oldP_so);
170
171 //............................................................
172 // transform the guess density into the current basis
173
174 // the transformation matrix is the new basis/old basis overlap
175 integral()->set_basis(owfn->basis(), basis());
176 RefSCMatrix old_to_new_ao(owfn->basis()->basisdim(), basis()->basisdim(),
177 basis()->matrixkit());
178 Ref<SCElementOp> op = new OneBodyIntOp(integral()->overlap());
179 old_to_new_ao.assign(0.0);
180 old_to_new_ao.element_op(op);
181 op = 0;
182 integral()->set_basis(basis());
183
184 // now must transform the transform into the SO basis
185 Ref<PetiteList> pl = integral()->petite_list();
186 Ref<PetiteList> oldpl = owfn->integral()->petite_list();
187 RefSCMatrix blocked_old_to_new_ao(oldpl->AO_basisdim(), pl->AO_basisdim(),
188 basis()->so_matrixkit());
189 blocked_old_to_new_ao->convert(old_to_new_ao);
190 RefSCMatrix old_to_new_so
191 = oldpl->sotoao() * blocked_old_to_new_ao * pl->aotoso();
192
193 // now must transform the transform into the orthogonal SO basis
194 RefSCMatrix so_to_oso = so_to_orthog_so();
195 RefSCMatrix old_to_new_oso = owfn->so_to_orthog_so_inverse().t()
196 * old_to_new_so
197 * so_to_oso.t();
198 old_so_to_oso = 0;
199 old_to_new_so = 0;
200
201 // The old density transformed to the new orthogonal SO basis
202 RefSymmSCMatrix newP_oso(oso_dimension(), basis_matrixkit());
203 newP_oso->assign(0.0);
204 newP_oso->accumulate_transform(old_to_new_oso.t(), oldP_oso);
205 old_to_new_oso = 0;
206 oldP_oso = 0;
207 //newP_oso.print("projected orthoSO density");
208
209 ExEnv::out0() << indent
210 << "The number of electrons in the projected density = "
211 << newP_oso.trace() << endl;
212
213 //............................................................
214
215 // reverse the sign of the density so the eigenvectors will
216 // be ordered in the right way
217 newP_oso.scale(-1.0);
218
219 // use the guess density in the new basis to find the orbitals
220 // (the density should be diagonal in the MO basis--this proceedure
221 // will not give canonical orbitals, but they should at least give
222 // a decent density)
223 RefDiagSCMatrix newP_oso_vals(newP_oso.dim(), basis_matrixkit());
224 RefSCMatrix newP_oso_vecs(newP_oso.dim(), newP_oso.dim(), basis_matrixkit());
225 newP_oso.diagonalize(newP_oso_vals, newP_oso_vecs);
226 //newP_oso_vals.print("eigenvalues of projected density");
227
228 // Reordering of the vectors isn't needed because of the way
229 // the density was scaled above.
230 RefSCMatrix newvec_oso = newP_oso_vecs;
231
232 if (debug_ >= 2) {
233 newvec_oso.print("projected ortho SO vector");
234 so_to_oso.print("SO to ortho SO transformation");
235 }
236
237 ExEnv::out0() << decindent;
238 return newvec_oso;
239}
240
241// this is a hack for big basis sets where the core hamiltonian eigenvalues
242// are total garbage. Use the old wavefunction's occupied eigenvalues, and
243// set all others to 99.
244
245RefDiagSCMatrix
246OneBodyWavefunction::projected_eigenvalues(const Ref<OneBodyWavefunction>& owfn,
247 int alp)
248{
249 // get the old eigenvalues and the new core hamiltonian evals
250 RefDiagSCMatrix oval;
251 if (owfn->spin_unrestricted()) {
252 if (alp)
253 oval = owfn->alpha_eigenvalues();
254 else
255 oval = owfn->beta_eigenvalues();
256 } else
257 oval = owfn->eigenvalues();
258
259 BlockedDiagSCMatrix *ovalp =
260 require_dynamic_cast<BlockedDiagSCMatrix*>(oval.pointer(),
261 "OneBodyWavefunction::projected_eigenvalues: oval"
262 );
263
264 // get the core hamiltonian eigenvalues
265 RefDiagSCMatrix val;
266 hcore_guess(val);
267 BlockedDiagSCMatrix *valp =
268 require_dynamic_cast<BlockedDiagSCMatrix*>(val.pointer(),
269 "OneBodyWavefunction::projected_eigenvalues: val"
270 );
271
272 RefSCDimension oso = oso_dimension();
273 RefSCDimension ooso = owfn->oso_dimension();
274
275 for (int irrep=0; irrep < valp->nblocks(); irrep++) {
276 // find out how many occupied orbitals there should be
277
278 int nf = oso->blocks()->size(irrep);
279 int nfo = ooso->blocks()->size(irrep);
280
281 int nocc = 0;
282 if (owfn->spin_unrestricted()) {
283 if (alp)
284 while (owfn->alpha_occupation(irrep,nocc) &&
285 nocc < nfo) nocc++;
286 else
287 while (owfn->beta_occupation(irrep,nocc) &&
288 nocc < nfo) nocc++;
289 } else
290 while (owfn->occupation(irrep,nocc) &&
291 nocc < nfo) nocc++;
292
293 if (!nf)
294 continue;
295
296 double *vals = new double[nf];
297 valp->block(irrep)->convert(vals);
298
299 int i;
300 if (nfo) {
301 double *ovals = new double[nfo];
302 ovalp->block(irrep)->convert(ovals);
303 for (i=0; i < nocc; i++) vals[i] = ovals[i];
304 delete[] ovals;
305 }
306
307 for (i=nocc; i < nf; i++)
308 vals[i] = 99.0;
309
310 valp->block(irrep)->assign(vals);
311
312 delete[] vals;
313 }
314
315#if DEBUG
316 val.print("projected values");
317#endif
318
319 return val;
320}
321
322RefSCMatrix
323OneBodyWavefunction::so_to_mo()
324{
325 // works for transforming H, S, etc (covariant)
326 return orthog_so_to_mo() * so_to_orthog_so();
327 // works for transforming the Density (contravariant)
328 //return orthog_so_to_mo() * so_to_orthog_so_inverse().t();
329}
330
331RefSCMatrix
332OneBodyWavefunction::orthog_so_to_mo()
333{
334 return oso_eigenvectors().t();
335}
336
337RefSCMatrix
338OneBodyWavefunction::mo_to_so()
339{
340 // works for transforming H, S, etc (covariant)
341 return so_to_orthog_so_inverse() * mo_to_orthog_so();
342 // works for transforming the Density (contravariant)
343 //return so_to_orthog_so().t() * mo_to_orthog_so();
344}
345
346RefSCMatrix
347OneBodyWavefunction::mo_to_orthog_so()
348{
349 return oso_eigenvectors();
350}
351
352RefSCMatrix
353OneBodyWavefunction::eigenvectors()
354{
355 return so_to_orthog_so().t() * oso_eigenvectors();
356}
357
358RefSCMatrix
359OneBodyWavefunction::hcore_guess()
360{
361 RefDiagSCMatrix val;
362 return hcore_guess(val);
363}
364
365RefSCMatrix
366OneBodyWavefunction::hcore_guess(RefDiagSCMatrix &val)
367{
368 RefSCMatrix vec(oso_dimension(), oso_dimension(), basis_matrixkit());
369 val = basis_matrixkit()->diagmatrix(oso_dimension());
370
371 // I'm about to do something strange, but it will only work
372 // if the SO and orthogonal SO dimensions are equivalent. This
373 // is not the case for canonical orthogonalization when there
374 // are linear dependencies.
375 if (so_dimension()->equiv(oso_dimension())) {
376 // Yes, this is diagonalizing Hcore in a nonorthogonal basis
377 // and does not really make any sense--except it seems to
378 // always give a better initial guess. I don't understand
379 // why it works better.
380 core_hamiltonian().diagonalize(val,vec);
381 }
382 else {
383 RefSymmSCMatrix hcore_oso(oso_dimension(), basis_matrixkit());
384 hcore_oso->assign(0.0);
385 hcore_oso->accumulate_transform(so_to_orthog_so(), core_hamiltonian());
386
387 if (debug_ > 1) {
388 hcore_oso.print("hcore in ortho SO basis");
389 }
390
391 hcore_oso.diagonalize(val,vec);
392
393 if (debug_ > 1) {
394 val.print("hcore eigenvalues in ortho SO basis");
395 vec.print("hcore eigenvectors in ortho SO basis");
396 }
397 }
398
399 return vec;
400}
401
402// Function for returning an orbital value at a point
403double
404OneBodyWavefunction::orbital(const SCVector3& r, int iorb)
405{
406 return Wavefunction::orbital(r,iorb,eigenvectors());
407}
408
409// Function for returning an orbital value at a point
410double
411OneBodyWavefunction::orbital_density(const SCVector3& r,
412 int iorb,
413 double* orbval)
414{
415 return Wavefunction::orbital_density(r,iorb,eigenvectors(),orbval);
416}
417
418void
419OneBodyWavefunction::print(ostream&o) const
420{
421 Wavefunction::print(o);
422}
423
424void
425OneBodyWavefunction::init_sym_info()
426{
427 RefSCDimension d = oso_dimension();
428 nirrep_ = d->blocks()->nblock();
429 nvecperirrep_ = new int[nirrep_];
430 occupations_ = new double[d->n()];
431 alpha_occupations_ = new double[d->n()];
432 beta_occupations_ = new double[d->n()];
433
434 int ij=0;
435 for (int i=0; i < nirrep_; i++) {
436 nvecperirrep_[i] = d->blocks()->size(i);
437
438 for (int j=0; j < nvecperirrep_[i]; j++, ij++) {
439 if (!spin_unrestricted()) occupations_[ij] = occupation(i,j);
440 else occupations_[ij] = 0.0;
441 alpha_occupations_[ij] = alpha_occupation(i,j);
442 beta_occupations_[ij] = beta_occupation(i,j);
443 }
444 }
445}
446
447double
448OneBodyWavefunction::occupation(int vectornum)
449{
450 if (spin_unrestricted()) {
451 ExEnv::errn() << "OneBodyWavefunction::occupation: called for USCF case"
452 << endl;
453 abort();
454 }
455 if (!nirrep_) init_sym_info();
456 return occupations_[vectornum];
457}
458
459double
460OneBodyWavefunction::alpha_occupation(int vectornum)
461{
462 if (!nirrep_) init_sym_info();
463 return alpha_occupations_[vectornum];
464}
465
466double
467OneBodyWavefunction::beta_occupation(int vectornum)
468{
469 if (!nirrep_) init_sym_info();
470 return beta_occupations_[vectornum];
471}
472
473double
474OneBodyWavefunction::alpha_occupation(int irrep, int vectornum)
475{
476 if (!spin_polarized())
477 return 0.5*occupation(irrep, vectornum);
478
479 ExEnv::errn() << class_name() << "::alpha_occupation not implemented" << endl;
480 abort();
481 return 0;
482}
483
484double
485OneBodyWavefunction::beta_occupation(int irrep, int vectornum)
486{
487 if (!spin_polarized())
488 return 0.5*occupation(irrep, vectornum);
489
490 ExEnv::errn() << class_name() << "::beta_occupation not implemented" << endl;
491 abort();
492 return 0;
493}
494
495RefSCMatrix
496OneBodyWavefunction::oso_alpha_eigenvectors()
497{
498 if (!spin_unrestricted())
499 return oso_eigenvectors().copy();
500
501 ExEnv::errn() << class_name() << "::oso_alpha_eigenvectors not implemented" << endl;
502 abort();
503 return 0;
504}
505
506RefSCMatrix
507OneBodyWavefunction::oso_beta_eigenvectors()
508{
509 if (!spin_unrestricted())
510 return oso_eigenvectors().copy();
511
512 ExEnv::errn() << class_name() << "::oso_beta_eigenvectors not implemented" << endl;
513 abort();
514 return 0;
515}
516
517RefSCMatrix
518OneBodyWavefunction::alpha_eigenvectors()
519{
520 if (!spin_unrestricted())
521 return eigenvectors().copy();
522
523 ExEnv::errn() << class_name() << "::alpha_eigenvectors not implemented" << endl;
524 abort();
525 return 0;
526}
527
528RefSCMatrix
529OneBodyWavefunction::beta_eigenvectors()
530{
531 if (!spin_unrestricted())
532 return eigenvectors().copy();
533
534 ExEnv::errn() << class_name() << "::beta_eigenvectors not implemented" << endl;
535 abort();
536 return 0;
537}
538
539RefDiagSCMatrix
540OneBodyWavefunction::alpha_eigenvalues()
541{
542 if (!spin_unrestricted())
543 return eigenvalues().copy();
544
545 ExEnv::errn() << class_name() << "::alpha_eigenvalues not implemented" << endl;
546 abort();
547 return 0;
548}
549
550RefDiagSCMatrix
551OneBodyWavefunction::beta_eigenvalues()
552{
553 if (!spin_unrestricted())
554 return eigenvalues().copy();
555
556 ExEnv::errn() << class_name() << "::beta_eigenvalues not implemented" << endl;
557 abort();
558 return 0;
559}
560
561int
562OneBodyWavefunction::nelectron()
563{
564 int noso = oso_dimension()->n();
565 double tocc = 0.0;
566 if (!spin_polarized()) {
567 for (int i=0; i<noso; i++) {
568 tocc += occupation(i);
569 }
570 }
571 else {
572 for (int i=0; i<noso; i++) {
573 tocc += alpha_occupation(i) + beta_occupation(i);
574 }
575 }
576 return int(tocc+0.5);
577}
578
579void
580OneBodyWavefunction::symmetry_changed()
581{
582 Wavefunction::symmetry_changed();
583
584 // junk the old occupation information
585 delete[] nvecperirrep_;
586 delete[] occupations_;
587 delete[] alpha_occupations_;
588 delete[] beta_occupations_;
589 nirrep_ = 0;
590 nvecperirrep_=0;
591 occupations_=0;
592 alpha_occupations_=0;
593 beta_occupations_=0;
594
595 // for now, delete old eigenvectors...later we'll transform to new
596 // pointgroup
597 oso_eigenvectors_.result_noupdate() = 0;
598}
599
600int
601OneBodyWavefunction::form_occupations(int *&newocc, const int *oldocc)
602{
603 delete[] newocc;
604 newocc = 0;
605
606 CorrelationTable corrtab;
607 if (corrtab.initialize_table(initial_pg_, molecule()->point_group()))
608 return 0;
609
610 newocc = new int[corrtab.subn()];
611 memset(newocc,0,sizeof(int)*corrtab.subn());
612
613 for (int i=0; i<corrtab.n(); i++) {
614 for (int j=0; j<corrtab.ngamma(i); j++) {
615 int gam = corrtab.gamma(i,j);
616 newocc[gam] += (corrtab.subdegen(gam)*oldocc[i])/corrtab.degen(i);
617 }
618 }
619
620 return 1;
621}
622
623void
624OneBodyWavefunction::set_desired_value_accuracy(double eps)
625{
626 Function::set_desired_value_accuracy(eps);
627 oso_eigenvectors_.set_desired_accuracy(eps);
628 eigenvalues_.set_desired_accuracy(eps);
629}
630
631/////////////////////////////////////////////////////////////////////////////
632
633// Local Variables:
634// mode: c++
635// c-file-style: "ETS"
636// End:
Note: See TracBrowser for help on using the repository browser.