source: ThirdParty/mpqc_open/src/lib/chemistry/qc/scf/scfvector.cc@ a844d8

Candidate_v1.6.1
Last change on this file since a844d8 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: 13.2 KB
Line 
1//
2// scfvector.cc --- implementation of SCF::compute_vector
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#include <unistd.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include <sstream>
33
34#include <util/misc/timer.h>
35#include <util/misc/formio.h>
36
37#include <util/state/state_bin.h>
38#include <util/group/mstate.h>
39
40#include <math/scmat/offset.h>
41#include <math/scmat/blocked.h>
42#include <math/scmat/blkiter.h>
43
44#include <math/optimize/diis.h>
45#include <math/optimize/scextrapmat.h>
46
47#include <chemistry/qc/basis/symmint.h>
48
49#include <chemistry/qc/scf/scf.h>
50#include <chemistry/qc/scf/scfops.h>
51#include <chemistry/qc/scf/scflocal.h>
52
53#include <errno.h>
54
55using namespace std;
56using namespace sc;
57
58#undef GENERALIZED_EIGENSOLVER
59
60namespace sc {
61
62///////////////////////////////////////////////////////////////////////////
63
64extern "C" {
65 void
66 dsygv_(int *ITYPE, const char *JOBZ, const char *UPLO,
67 int *N, double *A, int *LDA, double *B, int *LDB,
68 double *W, double *WORK, int *LWORK, int *INFO);
69}
70
71void
72SCF::savestate_to_file(const std::string &filename)
73{
74 std::string filename_to_delete = previous_savestate_file_;
75 std::string filename_to_use;
76 if (scf_grp_->me() == 0) {
77 filename_to_use = filename;
78 previous_savestate_file_ = filename;
79 }
80 else {
81 filename_to_use = "/dev/null";
82 }
83 StateOutBin so(filename_to_use.c_str());
84 save_state(this,so);
85 so.close();
86 if (filename_to_delete.size() > 0) {
87 if (unlink(filename_to_delete.c_str())) {
88 int unlink_errno = errno;
89 ExEnv::out0() << indent
90 << "WARNING: SCF::compute_vector(): "
91 << "unlink of temporary checkpoint file"
92 << endl
93 << indent
94 << " \"" << filename_to_delete << "\" "
95 << "failed with error: "
96 << strerror(unlink_errno)
97 << endl;
98 }
99 }
100}
101
102void
103SCF::savestate_iter(int iter)
104{
105 char *ckptfile=0, *oldckptfile=0;
106 const char *devnull=0;
107 const char *filename=0;
108
109 bool savestate = if_to_checkpoint();
110 int savestate_freq = checkpoint_freq();
111
112 if (savestate && ( (iter+1)%savestate_freq==0) ) {
113 ostringstream sstr;
114 const char *filename = checkpoint_file();
115 sstr << filename << "." << iter+1 << ".tmp";
116 savestate_to_file(sstr.str());
117 free((void*)filename);
118 }
119}
120
121double
122SCF::compute_vector(double& eelec, double nucrep)
123{
124 tim_enter("vector");
125 int i;
126
127 // reinitialize the extrapolation object
128 extrap_->reinitialize();
129
130 // create level shifter
131 LevelShift *level_shift = new LevelShift(this);
132 level_shift->reference();
133
134 // calculate the core Hamiltonian
135 hcore_ = core_hamiltonian();
136
137 // add density independant contributions to Hcore
138 accumdih_->accum(hcore_);
139
140 // set up subclass for vector calculation
141 init_vector();
142
143 RefDiagSCMatrix evals(oso_dimension(), basis_matrixkit());
144
145 double delta = 1.0;
146 int iter, iter_since_reset = 0;
147 double accuracy = 1.0;
148
149 ExEnv::out0() << indent
150 << "Beginning iterations. Basis is "
151 << basis()->label() << '.' << std::endl;
152 for (iter=0; iter < maxiter_; iter++, iter_since_reset++) {
153 // form the density from the current vector
154 tim_enter("density");
155 delta = new_density();
156 tim_exit("density");
157
158 // check convergence
159 if (delta < desired_value_accuracy()
160 && accuracy < desired_value_accuracy()) break;
161
162 // reset the density from time to time
163 if (iter_since_reset && !(iter_since_reset%dens_reset_freq_)) {
164 reset_density();
165 iter_since_reset = 0;
166 }
167
168 // form the AO basis fock matrix & add density dependant H
169 tim_enter("fock");
170 double base_accuracy = delta;
171 if (base_accuracy < desired_value_accuracy())
172 base_accuracy = desired_value_accuracy();
173 double new_accuracy = 0.01 * base_accuracy;
174 if (new_accuracy > 0.001) new_accuracy = 0.001;
175 if (iter == 0) accuracy = new_accuracy;
176 else if (new_accuracy < accuracy) {
177 accuracy = new_accuracy/10.0;
178 if (iter_since_reset > 0) {
179 reset_density();
180 iter_since_reset = 0;
181 }
182 }
183 ao_fock(accuracy);
184 tim_exit("fock");
185
186 // calculate the electronic energy
187 eelec = scf_energy();
188 double eother = 0.0;
189 if (accumddh_.nonnull()) eother = accumddh_->e();
190 ExEnv::out0() << indent
191 << scprintf("iter %5d energy = %15.10f delta = %10.5e",
192 iter+1, eelec+eother+nucrep, delta)
193 << endl;
194
195 // now extrapolate the fock matrix
196 tim_enter("extrap");
197 Ref<SCExtrapData> data = extrap_data();
198 Ref<SCExtrapError> error = extrap_error();
199 extrap_->extrapolate(data,error);
200 data=0;
201 error=0;
202 tim_exit("extrap");
203
204#ifdef GENERALIZED_EIGENSOLVER
205 // Get the fock matrix and overlap in the SO basis. The fock matrix
206 // used here works for CLOSED SHELL ONLY.
207 RefSymmSCMatrix bfmatref = fock(0);
208 RefSymmSCMatrix bsmatref = overlap();
209 BlockedSymmSCMatrix *bfmat
210 = dynamic_cast<BlockedSymmSCMatrix*>(bfmatref.pointer());
211 BlockedSymmSCMatrix *bsmat
212 = dynamic_cast<BlockedSymmSCMatrix*>(bsmatref.pointer());
213 BlockedDiagSCMatrix *bevals
214 = dynamic_cast<BlockedDiagSCMatrix*>(evals.pointer());
215 BlockedSCMatrix *bvec
216 = dynamic_cast<BlockedSCMatrix*>(oso_scf_vector_.pointer());
217
218 ExEnv::out0() << indent
219 << "solving generalized eigenvalue problem" << endl;
220
221 for (int iblock=0; iblock<bfmat->nblocks(); iblock++) {
222 RefSymmSCMatrix fmat = bfmat->block(iblock);
223 RefSymmSCMatrix smat = bsmat->block(iblock);
224 RefDiagSCMatrix evalblock = bevals->block(iblock);
225 RefSCMatrix oso_scf_vector_block = bvec->block(iblock);
226 int nbasis = fmat.dim().n();
227 int nbasis2 = nbasis*nbasis;
228
229 if (!nbasis) continue;
230
231 // Convert to the lapack storage format.
232 double *fso = new double[nbasis2];
233 double *sso = new double[nbasis2];
234 int ij=0;
235 for (int i=0; i<nbasis; i++) {
236 for (int j=0; j<nbasis; j++,ij++) {
237 fso[ij] = fmat(i,j);
238 sso[ij] = smat(i,j);
239 }
240 }
241
242 // solve generalized eigenvalue problem with DSYGV
243 int itype = 1;
244 double *epsilon = new double[nbasis];
245 int lwork = -1;
246 int info;
247 double optlwork;
248 dsygv_(&itype,"V","U",&nbasis,fso,&nbasis,sso,&nbasis,
249 epsilon,&optlwork,&lwork,&info);
250 if (info) {
251 ExEnv::outn() << "dsygv could not determine work size: info = "
252 << info << endl;
253 abort();
254 }
255 lwork = (int)optlwork;
256 double *work = new double[lwork];
257 dsygv_(&itype,"V","U",&nbasis,fso,&nbasis,sso,&nbasis,
258 epsilon,work,&lwork,&info);
259 if (info) {
260 ExEnv::outn() << "dsygv could not diagonalize matrix: info = "
261 << info << endl;
262 abort();
263 }
264 double *z = fso; // the vector is placed in fso
265
266 // make sure everyone agrees on the new arrays
267 scf_grp_->bcast(z, nbasis2);
268 scf_grp_->bcast(epsilon, nbasis);
269
270 evalblock->assign(epsilon);
271 oso_scf_vector_block->assign(z);
272
273 // cleanup
274 delete[] fso;
275 delete[] work;
276 delete[] sso;
277 delete[] epsilon;
278 }
279
280 oso_scf_vector_ = (oso_scf_vector_ * so_to_orthog_so_inverse()).t();
281#else
282 // diagonalize effective MO fock to get MO vector
283 tim_enter("evals");
284 RefSCMatrix nvector(oso_dimension(),oso_dimension(),basis_matrixkit());
285
286 RefSymmSCMatrix eff = effective_fock();
287
288 // level shift effective fock
289 level_shift->set_shift(level_shift_);
290 eff.element_op(level_shift);
291
292 if (debug_>1) {
293 eff.print("effective 1 body hamiltonian in current mo basis");
294 }
295
296 // transform eff to the oso basis to diagonalize it
297 RefSymmSCMatrix oso_eff(oso_dimension(), basis_matrixkit());
298 oso_eff.assign(0.0);
299 oso_eff.accumulate_transform(oso_scf_vector_,eff);
300 eff = 0;
301 oso_eff.diagonalize(evals, oso_scf_vector_);
302
303 tim_exit("evals");
304
305 if (debug_>0 && level_shift_ != 0.0) {
306 evals.print("level shifted scf eigenvalues");
307 }
308
309 // now un-level shift eigenvalues
310 level_shift->set_shift(-level_shift_);
311 evals.element_op(level_shift);
312#endif
313
314 if (debug_>0) {
315 evals.print("scf eigenvalues");
316 }
317
318 if (reset_occ_)
319 set_occupations(evals);
320
321 if (debug_>1) {
322 oso_scf_vector_.print("OSO basis scf vector");
323 (oso_scf_vector_.t()*oso_scf_vector_).print(
324 "vOSO.t()*vOSO",ExEnv::out0(),14);
325 }
326
327 savestate_iter(iter);
328 }
329
330 eigenvalues_ = evals;
331 eigenvalues_.computed() = 1;
332 eigenvalues_.set_actual_accuracy(accuracy<delta?delta:accuracy);
333
334 // search for HOMO and LUMO
335 // first convert evals to something we can deal with easily
336 BlockedDiagSCMatrix *evalsb = require_dynamic_cast<BlockedDiagSCMatrix*>(evals,
337 "SCF::compute_vector");
338
339 CharacterTable ct = molecule()->point_group()->char_table();
340
341 int homo_ir=0, lumo_ir=0;
342 int homo_mo = -1, lumo_mo = -1;
343 double homo=-1e99, lumo=1e99;
344 for (i=0; i < oso_dimension()->blocks()->nblock(); i++) {
345 int nf=oso_dimension()->blocks()->size(i);
346 if (nf) {
347 double *vals = new double[nf];
348 evalsb->block(i)->convert(vals);
349
350 for (int mo=0; mo < nf; mo++) {
351 if (occupation(i, mo) > 0.0) {
352 if (vals[mo] > homo) {
353 homo = vals[mo];
354 homo_ir = i;
355 homo_mo = mo;
356 }
357 } else {
358 if (vals[mo] < lumo) {
359 lumo = vals[mo];
360 lumo_ir = i;
361 lumo_mo = mo;
362 }
363 }
364 }
365
366 if (print_all_evals_ || print_occ_evals_) {
367 ExEnv::out0() << endl
368 << indent << ct.gamma(i).symbol() << endl << incindent;
369 for (int m=0; m < nf; m++) {
370 if (occupation(i,m) < 1e-8 && !print_all_evals_)
371 break;
372 ExEnv::out0() << indent
373 << scprintf("%5d %10.5f %10.5f", m+1, vals[m], occupation(i,m))
374 << endl;
375 }
376 ExEnv::out0() << decindent;
377 }
378
379 delete[] vals;
380 }
381 }
382
383 if (homo_mo >= 0) {
384 ExEnv::out0() << endl << indent
385 << scprintf("HOMO is %5d %3s = %10.6f",
386 homo_mo+1,
387 ct.gamma(homo_ir).symbol(),
388 homo)
389 << endl;
390 }
391 if (lumo_mo >= 0) {
392 ExEnv::out0() << indent
393 << scprintf("LUMO is %5d %3s = %10.6f",
394 lumo_mo+1,
395 ct.gamma(lumo_ir).symbol(),
396 lumo)
397 << endl;
398 }
399
400 // free up evals
401 evals = 0;
402
403 oso_eigenvectors_ = oso_scf_vector_;
404 oso_eigenvectors_.computed() = 1;
405 oso_eigenvectors_.set_actual_accuracy(delta);
406 // Checkpoint wavefunction, if needed, so that if converged
407 // on the last iteration then the wavefunction is marked as computed
408 if (if_to_checkpoint()) {
409 const char *checkpoint_filename = checkpoint_file();
410 std::string state_filename = checkpoint_filename;
411 free((void*)checkpoint_filename);
412 state_filename += ".tmp";
413 savestate_to_file(state_filename);
414 }
415
416 // now clean up
417 done_vector();
418 hcore_ = 0;
419
420 level_shift->dereference();
421 delete level_shift;
422
423 tim_exit("vector");
424 //tim_print(0);
425
426 return delta;
427}
428
429////////////////////////////////////////////////////////////////////////////
430
431class ExtrapErrorOp : public BlockedSCElementOp {
432 private:
433 SCF *scf_;
434
435 public:
436 ExtrapErrorOp(SCF *s) : scf_(s) {}
437 ~ExtrapErrorOp() {}
438
439 int has_side_effects() { return 1; }
440
441 void process(SCMatrixBlockIter& bi) {
442 int ir=current_block();
443
444 for (bi.reset(); bi; bi++) {
445 int i=bi.i();
446 int j=bi.j();
447 if (scf_->occupation(ir,i) == scf_->occupation(ir,j))
448 bi.set(0.0);
449 }
450 }
451};
452
453Ref<SCExtrapError>
454SCF::extrap_error()
455{
456 RefSymmSCMatrix mofock = effective_fock();
457
458 Ref<SCElementOp> op = new ExtrapErrorOp(this);
459 mofock.element_op(op);
460
461 RefSymmSCMatrix aoerror(so_dimension(), basis_matrixkit());
462 aoerror.assign(0.0);
463 aoerror.accumulate_transform(so_to_orthog_so().t()*oso_scf_vector_, mofock);
464 mofock=0;
465
466 Ref<SCExtrapError> error = new SymmSCMatrixSCExtrapError(aoerror);
467 aoerror=0;
468
469 return error;
470}
471
472/////////////////////////////////////////////////////////////////////////////
473
474}
475
476// Local Variables:
477// mode: c++
478// c-file-style: "ETS"
479// End:
Note: See TracBrowser for help on using the repository browser.