1 | //
|
---|
2 | // scf.cc --- implementation of the SCF abstract base 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 | #include <limits.h>
|
---|
34 | #include <sys/types.h>
|
---|
35 | #include <sys/stat.h>
|
---|
36 | #include <unistd.h>
|
---|
37 |
|
---|
38 | #include <util/misc/formio.h>
|
---|
39 | #include <util/state/stateio.h>
|
---|
40 | #include <util/group/mstate.h>
|
---|
41 |
|
---|
42 | #include <math/scmat/local.h>
|
---|
43 | #include <math/scmat/repl.h>
|
---|
44 | #include <math/scmat/offset.h>
|
---|
45 | #include <math/scmat/blocked.h>
|
---|
46 |
|
---|
47 | #include <math/optimize/diis.h>
|
---|
48 |
|
---|
49 | #include <chemistry/qc/basis/petite.h>
|
---|
50 | #include <chemistry/qc/scf/scf.h>
|
---|
51 |
|
---|
52 | using namespace std;
|
---|
53 | using namespace sc;
|
---|
54 |
|
---|
55 | ///////////////////////////////////////////////////////////////////////////
|
---|
56 | // SCF
|
---|
57 |
|
---|
58 | static ClassDesc SCF_cd(
|
---|
59 | typeid(SCF),"SCF",6,"public OneBodyWavefunction",
|
---|
60 | 0, 0, 0);
|
---|
61 |
|
---|
62 | SCF::SCF(StateIn& s) :
|
---|
63 | SavableState(s),
|
---|
64 | OneBodyWavefunction(s)
|
---|
65 | {
|
---|
66 | need_vec_ = 1;
|
---|
67 | compute_guess_ = 0;
|
---|
68 |
|
---|
69 | s.get(maxiter_,"maxiter");
|
---|
70 | s.get(dens_reset_freq_);
|
---|
71 | s.get(reset_occ_);
|
---|
72 | s.get(local_dens_);
|
---|
73 | if (s.version(::class_desc<SCF>()) >= 3) {
|
---|
74 | double dstorage;
|
---|
75 | s.get(dstorage);
|
---|
76 | storage_ = size_t(dstorage);
|
---|
77 | }
|
---|
78 | else {
|
---|
79 | unsigned int istorage;
|
---|
80 | s.get(istorage);
|
---|
81 | storage_ = istorage;
|
---|
82 | }
|
---|
83 | if (s.version(::class_desc<SCF>()) >= 2) {
|
---|
84 | s.get(print_all_evals_);
|
---|
85 | s.get(print_occ_evals_);
|
---|
86 | }
|
---|
87 | else {
|
---|
88 | print_all_evals_ = 0;
|
---|
89 | print_occ_evals_ = 0;
|
---|
90 | }
|
---|
91 | s.get(level_shift_);
|
---|
92 | if (s.version(::class_desc<SCF>()) >= 5) {
|
---|
93 | s.get(keep_guess_wfn_);
|
---|
94 | guess_wfn_ << SavableState::restore_state(s);
|
---|
95 | }
|
---|
96 | else keep_guess_wfn_ = 0;
|
---|
97 | if (s.version(::class_desc<SCF>()) >= 6) {
|
---|
98 | s.get(always_use_guess_wfn_);
|
---|
99 | }
|
---|
100 | else always_use_guess_wfn_ = 0;
|
---|
101 |
|
---|
102 | extrap_ << SavableState::restore_state(s);
|
---|
103 | accumdih_ << SavableState::restore_state(s);
|
---|
104 | accumddh_ << SavableState::restore_state(s);
|
---|
105 |
|
---|
106 | scf_grp_ = basis()->matrixkit()->messagegrp();
|
---|
107 | threadgrp_ = ThreadGrp::get_default_threadgrp();
|
---|
108 | }
|
---|
109 |
|
---|
110 | SCF::SCF(const Ref<KeyVal>& keyval) :
|
---|
111 | OneBodyWavefunction(keyval),
|
---|
112 | need_vec_(1),
|
---|
113 | compute_guess_(0),
|
---|
114 | maxiter_(100),
|
---|
115 | dens_reset_freq_(10),
|
---|
116 | reset_occ_(0),
|
---|
117 | local_dens_(1),
|
---|
118 | storage_(0),
|
---|
119 | level_shift_(0)
|
---|
120 | {
|
---|
121 | if (keyval->exists("maxiter"))
|
---|
122 | maxiter_ = keyval->intvalue("maxiter");
|
---|
123 |
|
---|
124 | if (keyval->exists("density_reset_frequency"))
|
---|
125 | dens_reset_freq_ = keyval->intvalue("density_reset_frequency");
|
---|
126 |
|
---|
127 | if (keyval->exists("reset_occupations"))
|
---|
128 | reset_occ_ = keyval->booleanvalue("reset_occupations");
|
---|
129 |
|
---|
130 | if (keyval->exists("level_shift"))
|
---|
131 | level_shift_ = keyval->doublevalue("level_shift");
|
---|
132 |
|
---|
133 | extrap_ << keyval->describedclassvalue("extrap");
|
---|
134 | if (extrap_.null())
|
---|
135 | extrap_ = new DIIS;
|
---|
136 |
|
---|
137 | accumdih_ << keyval->describedclassvalue("accumdih");
|
---|
138 | if (accumdih_.null())
|
---|
139 | accumdih_ = new AccumHNull;
|
---|
140 |
|
---|
141 | accumddh_ << keyval->describedclassvalue("accumddh");
|
---|
142 | if (accumddh_.null())
|
---|
143 | accumddh_ = new AccumHNull;
|
---|
144 |
|
---|
145 | KeyValValuesize defaultmem(DEFAULT_SC_MEMORY);
|
---|
146 | storage_ = keyval->sizevalue("memory",defaultmem);
|
---|
147 |
|
---|
148 | if (keyval->exists("local_density"))
|
---|
149 | local_dens_ = keyval->booleanvalue("local_density");
|
---|
150 |
|
---|
151 | print_all_evals_ = keyval->booleanvalue("print_evals");
|
---|
152 | print_occ_evals_ = keyval->booleanvalue("print_occupied_evals");
|
---|
153 |
|
---|
154 | scf_grp_ = basis()->matrixkit()->messagegrp();
|
---|
155 | threadgrp_ = ThreadGrp::get_default_threadgrp();
|
---|
156 |
|
---|
157 | keep_guess_wfn_ = keyval->booleanvalue("keep_guess_wavefunction");
|
---|
158 |
|
---|
159 | always_use_guess_wfn_
|
---|
160 | = keyval->booleanvalue("always_use_guess_wavefunction");
|
---|
161 |
|
---|
162 | // first see if guess_wavefunction is a wavefunction, then check to
|
---|
163 | // see if it's a string.
|
---|
164 | if (keyval->exists("guess_wavefunction")) {
|
---|
165 | ExEnv::out0() << incindent << incindent;
|
---|
166 | guess_wfn_ << keyval->describedclassvalue("guess_wavefunction");
|
---|
167 | compute_guess_=1;
|
---|
168 | if (guess_wfn_.null()) {
|
---|
169 | compute_guess_=0;
|
---|
170 | char *path = keyval->pcharvalue("guess_wavefunction");
|
---|
171 | struct stat sb;
|
---|
172 | if (path && stat(path, &sb)==0 && sb.st_size) {
|
---|
173 | BcastStateInBin s(scf_grp_, path);
|
---|
174 |
|
---|
175 | // reset the default matrixkit so that the matrices in the guess
|
---|
176 | // wavefunction will match those in this wavefunction
|
---|
177 | Ref<SCMatrixKit> oldkit = SCMatrixKit::default_matrixkit();
|
---|
178 | SCMatrixKit::set_default_matrixkit(basis()->matrixkit());
|
---|
179 |
|
---|
180 | guess_wfn_ << SavableState::restore_state(s);
|
---|
181 |
|
---|
182 | // go back to the original default matrixkit
|
---|
183 | SCMatrixKit::set_default_matrixkit(oldkit);
|
---|
184 | delete[] path;
|
---|
185 | }
|
---|
186 | }
|
---|
187 | ExEnv::out0() << decindent << decindent;
|
---|
188 | }
|
---|
189 | }
|
---|
190 |
|
---|
191 | SCF::~SCF()
|
---|
192 | {
|
---|
193 | }
|
---|
194 |
|
---|
195 | void
|
---|
196 | SCF::save_data_state(StateOut& s)
|
---|
197 | {
|
---|
198 | OneBodyWavefunction::save_data_state(s);
|
---|
199 | s.put(maxiter_);
|
---|
200 | s.put(dens_reset_freq_);
|
---|
201 | s.put(reset_occ_);
|
---|
202 | s.put(local_dens_);
|
---|
203 | double dstorage = storage_;
|
---|
204 | s.put(dstorage);
|
---|
205 | s.put(print_all_evals_);
|
---|
206 | s.put(print_occ_evals_);
|
---|
207 | s.put(level_shift_);
|
---|
208 | s.put(keep_guess_wfn_);
|
---|
209 | SavableState::save_state(guess_wfn_.pointer(),s);
|
---|
210 | s.put(always_use_guess_wfn_);
|
---|
211 | SavableState::save_state(extrap_.pointer(),s);
|
---|
212 | SavableState::save_state(accumdih_.pointer(),s);
|
---|
213 | SavableState::save_state(accumddh_.pointer(),s);
|
---|
214 | }
|
---|
215 |
|
---|
216 | RefSCMatrix
|
---|
217 | SCF::oso_eigenvectors()
|
---|
218 | {
|
---|
219 | return oso_eigenvectors_.result();
|
---|
220 | }
|
---|
221 |
|
---|
222 | RefDiagSCMatrix
|
---|
223 | SCF::eigenvalues()
|
---|
224 | {
|
---|
225 | return eigenvalues_.result();
|
---|
226 | }
|
---|
227 |
|
---|
228 | int
|
---|
229 | SCF::spin_unrestricted()
|
---|
230 | {
|
---|
231 | return 0;
|
---|
232 | }
|
---|
233 |
|
---|
234 | void
|
---|
235 | SCF::symmetry_changed()
|
---|
236 | {
|
---|
237 | OneBodyWavefunction::symmetry_changed();
|
---|
238 | if (guess_wfn_.nonnull()) {
|
---|
239 | guess_wfn_->symmetry_changed();
|
---|
240 | }
|
---|
241 | }
|
---|
242 |
|
---|
243 | void
|
---|
244 | SCF::print(ostream&o) const
|
---|
245 | {
|
---|
246 | OneBodyWavefunction::print(o);
|
---|
247 | o << indent << "SCF Parameters:\n" << incindent
|
---|
248 | << indent << "maxiter = " << maxiter_ << endl
|
---|
249 | << indent << "density_reset_frequency = " << dens_reset_freq_ << endl
|
---|
250 | << indent << scprintf("level_shift = %f\n",level_shift_)
|
---|
251 | << decindent << endl;
|
---|
252 | }
|
---|
253 |
|
---|
254 | //////////////////////////////////////////////////////////////////////////////
|
---|
255 |
|
---|
256 | void
|
---|
257 | SCF::compute()
|
---|
258 | {
|
---|
259 | local_ = (dynamic_cast<LocalSCMatrixKit*>(basis()->matrixkit().pointer()) ||
|
---|
260 | dynamic_cast<ReplSCMatrixKit*>(basis()->matrixkit().pointer())) ? 1:0;
|
---|
261 |
|
---|
262 | const double hess_to_grad_acc = 1.0/100.0;
|
---|
263 | if (hessian_needed())
|
---|
264 | set_desired_gradient_accuracy(desired_hessian_accuracy()*hess_to_grad_acc);
|
---|
265 |
|
---|
266 | const double grad_to_val_acc = 1.0/100.0;
|
---|
267 | if (gradient_needed())
|
---|
268 | set_desired_value_accuracy(desired_gradient_accuracy()*grad_to_val_acc);
|
---|
269 |
|
---|
270 | double delta;
|
---|
271 | if (value_needed()) {
|
---|
272 | ExEnv::out0() << endl << indent
|
---|
273 | << scprintf("SCF::compute: energy accuracy = %10.7e\n",
|
---|
274 | desired_value_accuracy())
|
---|
275 | << endl;
|
---|
276 |
|
---|
277 | // calculate the nuclear repulsion energy
|
---|
278 | double nucrep = nuclear_repulsion_energy();
|
---|
279 | ExEnv::out0() << indent
|
---|
280 | << scprintf("nuclear repulsion energy = %15.10f", nucrep)
|
---|
281 | << endl << endl;
|
---|
282 |
|
---|
283 | double eelec;
|
---|
284 | delta = compute_vector(eelec,nucrep);
|
---|
285 |
|
---|
286 | double eother = 0.0;
|
---|
287 | if (accumddh_.nonnull()) eother = accumddh_->e();
|
---|
288 | ExEnv::out0() << endl << indent
|
---|
289 | << scprintf("total scf energy = %15.10f", eelec+eother+nucrep)
|
---|
290 | << endl;
|
---|
291 |
|
---|
292 | set_energy(eelec+eother+nucrep);
|
---|
293 | set_actual_value_accuracy(delta);
|
---|
294 | }
|
---|
295 | else {
|
---|
296 | delta = actual_value_accuracy();
|
---|
297 | }
|
---|
298 |
|
---|
299 | if (gradient_needed()) {
|
---|
300 | RefSCVector gradient = matrixkit()->vector(moldim());
|
---|
301 |
|
---|
302 | ExEnv::out0() << endl << indent
|
---|
303 | << scprintf("SCF::compute: gradient accuracy = %10.7e\n",
|
---|
304 | desired_gradient_accuracy())
|
---|
305 | << endl;
|
---|
306 |
|
---|
307 | compute_gradient(gradient);
|
---|
308 | print_natom_3(gradient,"Total Gradient:");
|
---|
309 | set_gradient(gradient);
|
---|
310 |
|
---|
311 | set_actual_gradient_accuracy(delta/grad_to_val_acc);
|
---|
312 | }
|
---|
313 |
|
---|
314 | if (hessian_needed()) {
|
---|
315 | RefSymmSCMatrix hessian = matrixkit()->symmmatrix(moldim());
|
---|
316 |
|
---|
317 | ExEnv::out0() << endl << indent
|
---|
318 | << scprintf("SCF::compute: hessian accuracy = %10.7e\n",
|
---|
319 | desired_hessian_accuracy())
|
---|
320 | << endl;
|
---|
321 |
|
---|
322 | compute_hessian(hessian);
|
---|
323 | set_hessian(hessian);
|
---|
324 |
|
---|
325 | set_actual_hessian_accuracy(delta/grad_to_val_acc/hess_to_grad_acc);
|
---|
326 | }
|
---|
327 | }
|
---|
328 |
|
---|
329 | //////////////////////////////////////////////////////////////////////////////
|
---|
330 |
|
---|
331 | signed char *
|
---|
332 | SCF::init_pmax(double *pmat_data)
|
---|
333 | {
|
---|
334 | double l2inv = 1.0/log(2.0);
|
---|
335 | double tol = pow(2.0,-126.0);
|
---|
336 |
|
---|
337 | GaussianBasisSet& gbs = *basis().pointer();
|
---|
338 |
|
---|
339 | signed char * pmax = new signed char[i_offset(gbs.nshell())];
|
---|
340 |
|
---|
341 | int ish, jsh, ij;
|
---|
342 | for (ish=ij=0; ish < gbs.nshell(); ish++) {
|
---|
343 | int istart = gbs.shell_to_function(ish);
|
---|
344 | int iend = istart + gbs(ish).nfunction();
|
---|
345 |
|
---|
346 | for (jsh=0; jsh <= ish; jsh++,ij++) {
|
---|
347 | int jstart = gbs.shell_to_function(jsh);
|
---|
348 | int jend = jstart + gbs(jsh).nfunction();
|
---|
349 |
|
---|
350 | double maxp=0, tmp;
|
---|
351 |
|
---|
352 | for (int i=istart; i < iend; i++) {
|
---|
353 | int ijoff = i_offset(i) + jstart;
|
---|
354 | for (int j=jstart; j < ((ish==jsh) ? i+1 : jend); j++,ijoff++)
|
---|
355 | if ((tmp=fabs(pmat_data[ijoff])) > maxp)
|
---|
356 | maxp=tmp;
|
---|
357 | }
|
---|
358 |
|
---|
359 | if (maxp <= tol)
|
---|
360 | maxp=tol;
|
---|
361 |
|
---|
362 | long power = long(ceil(log(maxp)*l2inv));
|
---|
363 | if (power < SCHAR_MIN) pmax[ij] = SCHAR_MIN;
|
---|
364 | else if (power > SCHAR_MAX) pmax[ij] = SCHAR_MAX;
|
---|
365 | else pmax[ij] = (signed char) power;
|
---|
366 | }
|
---|
367 | }
|
---|
368 |
|
---|
369 | return pmax;
|
---|
370 | }
|
---|
371 |
|
---|
372 | //////////////////////////////////////////////////////////////////////////////
|
---|
373 |
|
---|
374 | RefSymmSCMatrix
|
---|
375 | SCF::get_local_data(const RefSymmSCMatrix& m, double*& p, Access access)
|
---|
376 | {
|
---|
377 | RefSymmSCMatrix l = m;
|
---|
378 |
|
---|
379 | if (!dynamic_cast<LocalSymmSCMatrix*>(l.pointer())
|
---|
380 | && !dynamic_cast<ReplSymmSCMatrix*>(l.pointer())) {
|
---|
381 | Ref<SCMatrixKit> k = new ReplSCMatrixKit;
|
---|
382 | l = k->symmmatrix(m.dim());
|
---|
383 | l->convert(m);
|
---|
384 |
|
---|
385 | if (access == Accum)
|
---|
386 | l->assign(0.0);
|
---|
387 | } else if (scf_grp_->n() > 1 && access==Accum) {
|
---|
388 | l = m.clone();
|
---|
389 | l.assign(0.0);
|
---|
390 | }
|
---|
391 |
|
---|
392 | if (dynamic_cast<ReplSymmSCMatrix*>(l.pointer()))
|
---|
393 | p = dynamic_cast<ReplSymmSCMatrix*>(l.pointer())->get_data();
|
---|
394 | else
|
---|
395 | p = dynamic_cast<LocalSymmSCMatrix*>(l.pointer())->get_data();
|
---|
396 |
|
---|
397 | return l;
|
---|
398 | }
|
---|
399 |
|
---|
400 | //////////////////////////////////////////////////////////////////////////////
|
---|
401 |
|
---|
402 | void
|
---|
403 | SCF::initial_vector(int needv)
|
---|
404 | {
|
---|
405 | if (need_vec_) {
|
---|
406 | if (always_use_guess_wfn_ || oso_eigenvectors_.result_noupdate().null()) {
|
---|
407 | // if guess_wfn_ is non-null then try to get a guess vector from it.
|
---|
408 | // First check that the same basis is used...if not, then project the
|
---|
409 | // guess vector into the present basis.
|
---|
410 | if (guess_wfn_.nonnull()) {
|
---|
411 | if (basis()->equiv(guess_wfn_->basis())
|
---|
412 | &&orthog_method() == guess_wfn_->orthog_method()
|
---|
413 | &&oso_dimension()->equiv(guess_wfn_->oso_dimension().pointer())) {
|
---|
414 | ExEnv::out0() << indent
|
---|
415 | << "Using guess wavefunction as starting vector" << endl;
|
---|
416 |
|
---|
417 | // indent output of eigenvectors() call if there is any
|
---|
418 | ExEnv::out0() << incindent << incindent;
|
---|
419 | SCF *g = dynamic_cast<SCF*>(guess_wfn_.pointer());
|
---|
420 | if (!g || compute_guess_) {
|
---|
421 | oso_eigenvectors_ = guess_wfn_->oso_eigenvectors().copy();
|
---|
422 | eigenvalues_ = guess_wfn_->eigenvalues().copy();
|
---|
423 | } else {
|
---|
424 | oso_eigenvectors_ = g->oso_eigenvectors_.result_noupdate().copy();
|
---|
425 | eigenvalues_ = g->eigenvalues_.result_noupdate().copy();
|
---|
426 | }
|
---|
427 | ExEnv::out0() << decindent << decindent;
|
---|
428 | } else {
|
---|
429 | ExEnv::out0() << indent
|
---|
430 | << "Projecting guess wavefunction into the present basis set"
|
---|
431 | << endl;
|
---|
432 |
|
---|
433 | // indent output of projected_eigenvectors() call if there is any
|
---|
434 | ExEnv::out0() << incindent << incindent;
|
---|
435 | oso_eigenvectors_ = projected_eigenvectors(guess_wfn_);
|
---|
436 | eigenvalues_ = projected_eigenvalues(guess_wfn_);
|
---|
437 | ExEnv::out0() << decindent << decindent;
|
---|
438 | }
|
---|
439 |
|
---|
440 | // we should only have to do this once, so free up memory used
|
---|
441 | // for the old wavefunction, unless told otherwise
|
---|
442 | if (!keep_guess_wfn_) guess_wfn_=0;
|
---|
443 |
|
---|
444 | ExEnv::out0() << endl;
|
---|
445 |
|
---|
446 | } else {
|
---|
447 | ExEnv::out0() << indent << "Starting from core Hamiltonian guess\n"
|
---|
448 | << endl;
|
---|
449 | oso_eigenvectors_ = hcore_guess(eigenvalues_.result_noupdate());
|
---|
450 | }
|
---|
451 | } else {
|
---|
452 | // this is just an old vector
|
---|
453 | }
|
---|
454 | }
|
---|
455 |
|
---|
456 | need_vec_=needv;
|
---|
457 | }
|
---|
458 |
|
---|
459 | //////////////////////////////////////////////////////////////////////////////
|
---|
460 |
|
---|
461 | void
|
---|
462 | SCF::init_mem(int nm)
|
---|
463 | {
|
---|
464 | // if local_den_ is already 0, then that means it was set to zero by
|
---|
465 | // the user.
|
---|
466 | if (!local_dens_) {
|
---|
467 | integral()->set_storage(storage_);
|
---|
468 | return;
|
---|
469 | }
|
---|
470 |
|
---|
471 | size_t nmem = i_offset(basis()->nbasis())*nm*sizeof(double);
|
---|
472 |
|
---|
473 | // if we're actually using local matrices, then there's no choice
|
---|
474 | if (dynamic_cast<LocalSCMatrixKit*>(basis()->matrixkit().pointer())
|
---|
475 | ||dynamic_cast<ReplSCMatrixKit*>(basis()->matrixkit().pointer())) {
|
---|
476 | if (nmem > storage_)
|
---|
477 | return;
|
---|
478 | } else {
|
---|
479 | if (nmem > storage_) {
|
---|
480 | local_dens_=0;
|
---|
481 | integral()->set_storage(storage_);
|
---|
482 | return;
|
---|
483 | }
|
---|
484 | }
|
---|
485 |
|
---|
486 | integral()->set_storage(storage_-nmem);
|
---|
487 | }
|
---|
488 |
|
---|
489 | /////////////////////////////////////////////////////////////////////////////
|
---|
490 |
|
---|
491 | void
|
---|
492 | SCF::so_density(const RefSymmSCMatrix& d, double occ, int alp)
|
---|
493 | {
|
---|
494 | int i,j,k;
|
---|
495 | int me=scf_grp_->me();
|
---|
496 | int nproc=scf_grp_->n();
|
---|
497 | int uhf = spin_unrestricted();
|
---|
498 |
|
---|
499 | d->assign(0.0);
|
---|
500 |
|
---|
501 | RefSCMatrix oso_vector;
|
---|
502 | if (alp || !uhf) {
|
---|
503 | if (oso_scf_vector_.nonnull())
|
---|
504 | oso_vector = oso_scf_vector_;
|
---|
505 | }
|
---|
506 | else {
|
---|
507 | if (oso_scf_vector_beta_.nonnull())
|
---|
508 | oso_vector = oso_scf_vector_beta_;
|
---|
509 | }
|
---|
510 |
|
---|
511 | if (oso_vector.null()) {
|
---|
512 | if (uhf) {
|
---|
513 | if (alp)
|
---|
514 | oso_vector = oso_alpha_eigenvectors();
|
---|
515 | else
|
---|
516 | oso_vector = oso_beta_eigenvectors();
|
---|
517 | } else
|
---|
518 | oso_vector = oso_eigenvectors();
|
---|
519 | }
|
---|
520 |
|
---|
521 | if (debug_ > 1) oso_vector.print("ortho SO vector");
|
---|
522 |
|
---|
523 | RefSCMatrix vector = so_to_orthog_so().t() * oso_vector;
|
---|
524 | oso_vector = 0;
|
---|
525 |
|
---|
526 | if (debug_ > 1) vector.print("SO vector");
|
---|
527 |
|
---|
528 | BlockedSCMatrix *bvec = require_dynamic_cast<BlockedSCMatrix*>(
|
---|
529 | vector, "SCF::so_density: blocked vector");
|
---|
530 |
|
---|
531 | BlockedSymmSCMatrix *bd = require_dynamic_cast<BlockedSymmSCMatrix*>(
|
---|
532 | d, "SCF::so_density: blocked density");
|
---|
533 |
|
---|
534 | for (int ir=0; ir < oso_dimension()->blocks()->nblock(); ir++) {
|
---|
535 | RefSCMatrix vir = bvec->block(ir);
|
---|
536 | RefSymmSCMatrix dir = bd->block(ir);
|
---|
537 |
|
---|
538 | if (vir.null() || vir.ncol()==0)
|
---|
539 | continue;
|
---|
540 |
|
---|
541 | int n_orthoSO = oso_dimension()->blocks()->size(ir);
|
---|
542 | int n_SO = so_dimension()->blocks()->size(ir);
|
---|
543 |
|
---|
544 | // figure out which columns of the scf vector we'll need
|
---|
545 | int col0 = -1, coln = -1;
|
---|
546 | for (i=0; i < n_orthoSO; i++) {
|
---|
547 | double occi;
|
---|
548 | if (!uhf)
|
---|
549 | occi = occupation(ir, i);
|
---|
550 | else if (alp)
|
---|
551 | occi = alpha_occupation(ir, i);
|
---|
552 | else
|
---|
553 | occi = beta_occupation(ir, i);
|
---|
554 |
|
---|
555 | if (fabs(occi-occ) < 1.0e-8) {
|
---|
556 | if (col0 == -1)
|
---|
557 | col0 = i;
|
---|
558 | continue;
|
---|
559 | } else if (col0 != -1) {
|
---|
560 | coln = i-1;
|
---|
561 | break;
|
---|
562 | }
|
---|
563 | }
|
---|
564 |
|
---|
565 | if (col0 == -1)
|
---|
566 | continue;
|
---|
567 |
|
---|
568 | if (coln == -1)
|
---|
569 | coln = n_orthoSO-1;
|
---|
570 |
|
---|
571 | if (local_ || local_dens_) {
|
---|
572 | RefSymmSCMatrix ldir = dir;
|
---|
573 |
|
---|
574 | RefSCMatrix occbits; // holds the occupied bits of the scf vector
|
---|
575 |
|
---|
576 | // get local copies of vector and density matrix
|
---|
577 | if (!local_) {
|
---|
578 | Ref<SCMatrixKit> rk = new ReplSCMatrixKit;
|
---|
579 | RefSCMatrix lvir = rk->matrix(vir.rowdim(), vir.coldim());
|
---|
580 | lvir->convert(vir);
|
---|
581 | occbits = lvir->get_subblock(0, n_SO-1, col0, coln);
|
---|
582 | lvir = 0;
|
---|
583 |
|
---|
584 | ldir = rk->symmmatrix(dir.dim());
|
---|
585 | ldir->convert(dir);
|
---|
586 |
|
---|
587 | } else {
|
---|
588 | occbits = vir->get_subblock(0, n_SO-1, col0, coln);
|
---|
589 | }
|
---|
590 |
|
---|
591 | double **c;
|
---|
592 | double *dens;
|
---|
593 |
|
---|
594 | if (dynamic_cast<LocalSCMatrix*>(occbits.pointer()))
|
---|
595 | c = dynamic_cast<LocalSCMatrix*>(occbits.pointer())->get_rows();
|
---|
596 | else if (dynamic_cast<ReplSCMatrix*>(occbits.pointer()))
|
---|
597 | c = dynamic_cast<ReplSCMatrix*>(occbits.pointer())->get_rows();
|
---|
598 | else
|
---|
599 | abort();
|
---|
600 |
|
---|
601 | if (dynamic_cast<LocalSymmSCMatrix*>(ldir.pointer()))
|
---|
602 | dens = dynamic_cast<LocalSymmSCMatrix*>(ldir.pointer())->get_data();
|
---|
603 | else if (dynamic_cast<ReplSymmSCMatrix*>(ldir.pointer()))
|
---|
604 | dens = dynamic_cast<ReplSymmSCMatrix*>(ldir.pointer())->get_data();
|
---|
605 | else
|
---|
606 | abort();
|
---|
607 |
|
---|
608 | int ij=0;
|
---|
609 | for (i=0; i < n_SO; i++) {
|
---|
610 | for (j=0; j <= i; j++, ij++) {
|
---|
611 | if (ij%nproc != me)
|
---|
612 | continue;
|
---|
613 |
|
---|
614 | double dv = 0;
|
---|
615 |
|
---|
616 | int kk=0;
|
---|
617 | for (k=col0; k <= coln; k++, kk++)
|
---|
618 | dv += c[i][kk]*c[j][kk];
|
---|
619 |
|
---|
620 | dens[ij] = dv;
|
---|
621 | }
|
---|
622 | }
|
---|
623 |
|
---|
624 | if (nproc > 1)
|
---|
625 | scf_grp_->sum(dens, i_offset(n_SO));
|
---|
626 |
|
---|
627 | if (!local_) {
|
---|
628 | dir->convert(ldir);
|
---|
629 | }
|
---|
630 | }
|
---|
631 |
|
---|
632 | // for now quit
|
---|
633 | else {
|
---|
634 | ExEnv::err0() << indent
|
---|
635 | << "Cannot yet use anything but Local matrices"
|
---|
636 | << endl;
|
---|
637 | abort();
|
---|
638 | }
|
---|
639 | }
|
---|
640 |
|
---|
641 | if (debug_ > 0) {
|
---|
642 | ExEnv::out0() << indent
|
---|
643 | << "Nelectron = " << 2.0 * (d * overlap()).trace() << endl;
|
---|
644 | }
|
---|
645 |
|
---|
646 | int use_alternate_density = 0;
|
---|
647 | if (use_alternate_density || debug_ > 2) {
|
---|
648 | // double check the density with this simpler, slower way to compute
|
---|
649 | // the density matrix
|
---|
650 | RefSymmSCMatrix occ(oso_dimension(), basis_matrixkit());
|
---|
651 | occ.assign(0.0);
|
---|
652 | for (i=0; i<oso_dimension()->n(); i++) {
|
---|
653 | occ(i,i) = occupation(i);
|
---|
654 | }
|
---|
655 | occ.scale(0.5);
|
---|
656 | RefSymmSCMatrix d2(so_dimension(), basis_matrixkit());
|
---|
657 | d2.assign(0.0);
|
---|
658 | d2.accumulate_transform(vector, occ);
|
---|
659 | if (debug_ > 2) {
|
---|
660 | d2.print("d2 density");
|
---|
661 | ExEnv::out0() << indent << "d2 Nelectron = "
|
---|
662 | << 2.0 * (d2 * overlap()).trace() << endl;
|
---|
663 | }
|
---|
664 | if (use_alternate_density) {
|
---|
665 | d.assign(d2);
|
---|
666 | ExEnv::out0() << indent
|
---|
667 | << "using alternate density algorithm" << endl;
|
---|
668 | }
|
---|
669 | }
|
---|
670 |
|
---|
671 | if (debug_ > 1) {
|
---|
672 | d.print("SO Density");
|
---|
673 | RefSCMatrix rd(d.dim(), d.dim(), basis_matrixkit());
|
---|
674 | rd.assign(0.0);
|
---|
675 | rd.accumulate(d);
|
---|
676 | (d*overlap()*d-rd).print("SO Density idempotency error");
|
---|
677 | }
|
---|
678 | }
|
---|
679 |
|
---|
680 | double
|
---|
681 | SCF::one_body_energy()
|
---|
682 | {
|
---|
683 | RefSymmSCMatrix dens = ao_density().copy();
|
---|
684 | RefSymmSCMatrix hcore = dens->clone();
|
---|
685 | hcore.assign(0.0);
|
---|
686 | Ref<SCElementOp> hcore_op = new OneBodyIntOp(integral()->hcore());
|
---|
687 | hcore.element_op(hcore_op);
|
---|
688 |
|
---|
689 | dens->scale_diagonal(0.5);
|
---|
690 | SCElementScalarProduct *prod = new SCElementScalarProduct;
|
---|
691 | prod->reference();
|
---|
692 | Ref<SCElementOp2> op = prod;
|
---|
693 | hcore->element_op(prod, dens);
|
---|
694 | double e = prod->result();
|
---|
695 | op = 0;
|
---|
696 | prod->dereference();
|
---|
697 | delete prod;
|
---|
698 | return 2.0 * e;
|
---|
699 | }
|
---|
700 |
|
---|
701 | void
|
---|
702 | SCF::two_body_energy(double &ec, double &ex)
|
---|
703 | {
|
---|
704 | ExEnv::errn() << class_name() << ": two_body_energy not implemented" << endl;
|
---|
705 | }
|
---|
706 |
|
---|
707 | /////////////////////////////////////////////////////////////////////////////
|
---|
708 |
|
---|
709 | void
|
---|
710 | SCF::init_threads()
|
---|
711 | {
|
---|
712 | int nthread = threadgrp_->nthread();
|
---|
713 | size_t int_store = integral()->storage_unused()/nthread;
|
---|
714 |
|
---|
715 | // initialize the two electron integral classes
|
---|
716 | tbis_ = new Ref<TwoBodyInt>[nthread];
|
---|
717 | for (int i=0; i < nthread; i++) {
|
---|
718 | tbis_[i] = integral()->electron_repulsion();
|
---|
719 | tbis_[i]->set_integral_storage(int_store);
|
---|
720 | }
|
---|
721 |
|
---|
722 | }
|
---|
723 |
|
---|
724 | void
|
---|
725 | SCF::done_threads()
|
---|
726 | {
|
---|
727 | for (int i=0; i < threadgrp_->nthread(); i++) tbis_[i] = 0;
|
---|
728 | delete[] tbis_;
|
---|
729 | tbis_ = 0;
|
---|
730 | }
|
---|
731 |
|
---|
732 | int *
|
---|
733 | SCF::read_occ(const Ref<KeyVal> &keyval, const char *name, int nirrep)
|
---|
734 | {
|
---|
735 | int *occ = 0;
|
---|
736 | if (keyval->exists(name)) {
|
---|
737 | if (keyval->count(name) != nirrep) {
|
---|
738 | ExEnv::err0() << indent
|
---|
739 | << "ERROR: SCF: have " << nirrep << " irreps but "
|
---|
740 | << name << " vector is length " << keyval->count(name)
|
---|
741 | << endl;
|
---|
742 | abort();
|
---|
743 | }
|
---|
744 | occ = new int[nirrep];
|
---|
745 | for (int i=0; i<nirrep; i++) {
|
---|
746 | occ[i] = keyval->intvalue(name,i);
|
---|
747 | }
|
---|
748 | }
|
---|
749 | return occ;
|
---|
750 | }
|
---|
751 |
|
---|
752 | void
|
---|
753 | SCF::obsolete()
|
---|
754 | {
|
---|
755 | OneBodyWavefunction::obsolete();
|
---|
756 | if (guess_wfn_.nonnull()) guess_wfn_->obsolete();
|
---|
757 | }
|
---|
758 |
|
---|
759 | /////////////////////////////////////////////////////////////////////////////
|
---|
760 |
|
---|
761 | // Local Variables:
|
---|
762 | // mode: c++
|
---|
763 | // c-file-style: "ETS"
|
---|
764 | // End:
|
---|