source: ThirdParty/mpqc_open/src/lib/chemistry/molecule/fdhess.cc@ 7516f6

Action_Thermostats Adding_MD_integration_tests Adding_StructOpt_integration_tests AutomationFragmentation_failures Candidate_v1.6.1 ChemicalSpaceEvaluator Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Exclude_Hydrogens_annealWithBondGraph Fix_Verbose_Codepatterns ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion Gui_displays_atomic_force_velocity JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool PythonUI_with_named_parameters Recreated_GuiChecks StoppableMakroAction TremoloParser_IncreasedPrecision
Last change on this file since 7516f6 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.2 KB
Line 
1//
2// fdhess.cc
3//
4// Copyright (C) 1997 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 <stdlib.h>
33#include <sys/stat.h>
34
35#include <util/class/scexception.h>
36#include <util/misc/formio.h>
37#include <util/misc/timer.h>
38#include <util/state/stateio.h>
39#include <util/state/state_bin.h>
40#include <util/group/mstate.h>
41#include <util/keyval/keyval.h>
42#include <math/scmat/blocked.h>
43#include <math/symmetry/corrtab.h>
44#include <chemistry/molecule/fdhess.h>
45
46using namespace std;
47using namespace sc;
48
49#define DEFAULT_CHECKPOINT 1
50#define DEFAULT_RESTART 1
51
52/////////////////////////////////////////////////////////////////
53// FinDispMolecularHessian
54
55static ClassDesc FinDispMolecularHessian_cd(
56 typeid(FinDispMolecularHessian),"FinDispMolecularHessian",1,"public MolecularHessian",
57 0, create<FinDispMolecularHessian>, create<FinDispMolecularHessian>);
58
59FinDispMolecularHessian::FinDispMolecularHessian(const Ref<MolecularEnergy> &e):
60 mole_(e)
61{
62 only_totally_symmetric_ = 0;
63 eliminate_cubic_terms_ = 1;
64 do_null_displacement_ = 1;
65 disp_ = 1.0e-2;
66 ndisp_ = 0;
67 debug_ = 0;
68 gradients_ = 0;
69 accuracy_ = disp_/1000;
70 restart_ = DEFAULT_RESTART;
71 checkpoint_ = DEFAULT_CHECKPOINT;
72 checkpoint_file_ = 0;
73 restart_file_ = 0;
74 checkpoint_file_ = SCFormIO::fileext_to_filename(".ckpt.hess");
75 restart_file_ = SCFormIO::fileext_to_filename(".ckpt.hess");
76}
77
78FinDispMolecularHessian::FinDispMolecularHessian(const Ref<KeyVal>&keyval):
79 MolecularHessian(keyval)
80{
81 mole_ << keyval->describedclassvalue("energy");
82
83 debug_ = keyval->booleanvalue("debug");
84
85 displacement_point_group_ << keyval->describedclassvalue("point_group");
86
87 disp_ = keyval->doublevalue("displacement",KeyValValuedouble(1.0e-2));
88
89 KeyValValueboolean def_restart(DEFAULT_RESTART);
90 KeyValValueboolean def_checkpoint(DEFAULT_CHECKPOINT);
91 KeyValValueboolean truevalue(1);
92 KeyValValueboolean falsevalue(0);
93
94 restart_ = keyval->booleanvalue("restart", def_restart);
95 char *def_file = SCFormIO::fileext_to_filename(".ckpt.hess");
96 KeyValValueString def_restart_file(def_file,KeyValValueString::Steal);
97 restart_file_ = keyval->pcharvalue("restart_file", def_restart_file);
98 checkpoint_ = keyval->booleanvalue("checkpoint", def_checkpoint);
99 checkpoint_file_ = keyval->pcharvalue("checkpoint_file", def_restart_file);
100 only_totally_symmetric_ = keyval->booleanvalue("only_totally_symmetric",
101 falsevalue);
102 eliminate_cubic_terms_ = keyval->booleanvalue("eliminate_cubic_terms",
103 truevalue);
104
105 do_null_displacement_ = keyval->booleanvalue("do_null_displacement",
106 truevalue);
107
108 accuracy_ = keyval->doublevalue("gradient_accuracy",
109 KeyValValuedouble(disp_/1000));
110
111 gradients_ = 0;
112 ndisp_ = 0;
113}
114
115FinDispMolecularHessian::FinDispMolecularHessian(StateIn&s):
116 SavableState(s),
117 MolecularHessian(s)
118{
119 mole_ << SavableState::restore_state(s);
120 s.get(checkpoint_);
121 s.get(debug_);
122 s.get(accuracy_);
123 s.getstring(checkpoint_file_);
124 s.getstring(restart_file_);
125
126 gradients_ = 0;
127 restore_displacements(s);
128}
129
130FinDispMolecularHessian::~FinDispMolecularHessian()
131{
132 delete[] gradients_;
133 delete[] checkpoint_file_;
134 delete[] restart_file_;
135}
136
137void
138FinDispMolecularHessian::save_data_state(StateOut&s)
139{
140 MolecularHessian::save_data_state(s);
141
142 SavableState::save_state(mole_.pointer(),s);
143 s.put(checkpoint_);
144 s.put(debug_);
145 s.put(accuracy_);
146 s.putstring(checkpoint_file_);
147 s.putstring(restart_file_);
148
149 checkpoint_displacements(s);
150}
151
152void
153FinDispMolecularHessian::init()
154{
155 if (mole_.null()) return;
156
157 mol_ = mole_->molecule();
158
159 if (displacement_point_group_.null()) {
160 displacement_point_group_
161 = new PointGroup(*mol_->point_group().pointer());
162 }
163
164 nirrep_ = displacement_point_group_->char_table().nirrep();
165
166 original_point_group_ = mol_->point_group();
167 original_geometry_ = matrixkit()->vector(d3natom());
168
169 int i, coor;
170 for (i=0, coor=0; i<mol_->natom(); i++) {
171 for (int j=0; j<3; j++, coor++) {
172 original_geometry_(coor) = mol_->r(i,j);
173 }
174 }
175
176 ndisp_ = 0;
177 symbasis_ = cartesian_to_symmetry(mol_,
178 displacement_point_group_,
179 matrixkit());
180 delete[] gradients_;
181 gradients_ = new RefSCVector[ndisplace()];
182}
183
184void
185FinDispMolecularHessian::set_energy(const Ref<MolecularEnergy> &energy)
186{
187 mole_ = energy;
188}
189
190MolecularEnergy*
191FinDispMolecularHessian::energy() const
192{
193 return mole_.pointer();
194}
195
196void
197FinDispMolecularHessian::restart()
198{
199 int statresult, statsize;
200 Ref<MessageGrp> grp = MessageGrp::get_default_messagegrp();
201 if (grp->me() == 0) {
202 struct stat sb;
203 statresult = stat(restart_file_,&sb);
204 statsize = (statresult==0) ? sb.st_size : 0;
205 }
206 grp->bcast(statsize);
207 if (statsize) {
208 BcastStateInBin si(grp,restart_file_);
209 restore_displacements(si);
210 mol_ = mole_->molecule();
211
212 if (ndisplacements_done() >= ndisplace()) {
213 restart_=0;
214 return;
215 }
216 }
217
218 if (ndisp_) {
219 int irrep, index;
220 double coef;
221 get_disp(ndisplacements_done(), irrep, index, coef);
222 if (irrep != 0 && index != 0) {
223 displace(ndisplacements_done());
224 mole_->symmetry_changed();
225 }
226 }
227 else {
228 init();
229 }
230 restart_ = 0;
231}
232
233void
234FinDispMolecularHessian::restore_displacements(StateIn& s)
235{
236 int i;
237 displacement_point_group_ << SavableState::restore_state(s);
238 original_point_group_ << SavableState::restore_state(s);
239 original_geometry_ = matrixkit()->vector(d3natom());
240 original_geometry_.restore(s);
241
242 s.get(disp_);
243 s.get(ndisp_);
244 s.get(nirrep_);
245 s.get(only_totally_symmetric_);
246 s.get(eliminate_cubic_terms_);
247 s.get(do_null_displacement_);
248
249 if (ndisp_) {
250 RefSCDimension symrow, symcol;
251 symrow << SavableState::restore_state(s);
252 symcol << SavableState::restore_state(s);
253 Ref<SCMatrixKit> symkit = new BlockedSCMatrixKit(matrixkit());
254 symbasis_ = symkit->matrix(symrow,symcol);
255 symbasis_.restore(s);
256
257 delete[] gradients_;
258 gradients_ = new RefSCVector[ndisplace()];
259 for (i=0; i < ndisp_; i++) {
260 int ndisp;
261 s.get(ndisp);
262 RefSCDimension ddisp = new SCDimension(ndisp);
263 gradients_[i] = matrixkit()->vector(ddisp);
264 gradients_[i].restore(s);
265 }
266 }
267}
268
269void
270FinDispMolecularHessian::checkpoint_displacements(StateOut& s)
271{
272 int i;
273 SavableState::save_state(displacement_point_group_.pointer(),s);
274 SavableState::save_state(original_point_group_.pointer(),s);
275 original_geometry_.save(s);
276
277 s.put(disp_);
278 s.put(ndisp_);
279 s.put(nirrep_);
280 s.put(only_totally_symmetric_);
281 s.put(eliminate_cubic_terms_);
282 s.put(do_null_displacement_);
283
284 if (ndisp_) {
285 SavableState::save_state(symbasis_.rowdim().pointer(),s);
286 SavableState::save_state(symbasis_.coldim().pointer(),s);
287 symbasis_.save(s);
288
289 for (i=0; i < ndisp_; i++) {
290 s.put(gradients_[i].n());
291 gradients_[i].save(s);
292 }
293 }
294}
295
296RefSCMatrix
297FinDispMolecularHessian::displacements(int irrep) const
298{
299 BlockedSCMatrix *bsymbasis = dynamic_cast<BlockedSCMatrix*>(symbasis_.pointer());
300 RefSCMatrix block = bsymbasis->block(irrep);
301 if (block.null() || (only_totally_symmetric_ && irrep > 0)) {
302 RefSCDimension zero = new SCDimension(0);
303 block = matrixkit()->matrix(zero,zero);
304 return block;
305 }
306 return block.t();
307}
308
309void
310FinDispMolecularHessian::get_disp(int disp, int &irrep,
311 int &index, double &coef)
312{
313 int disp_offset = 0;
314
315 if (do_null_displacement_ && disp == 0) {
316 irrep = 0;
317 coef = 0.0;
318 index = -1;
319 return;
320 }
321 disp_offset++;
322 // check for +ve totally symmetric displacements
323 if (disp < disp_offset + displacements(0).ncol()) {
324 irrep = 0;
325 coef = 1.0;
326 index = disp - disp_offset;
327 return;
328 }
329 disp_offset += displacements(0).ncol();
330 // check for -ve totally symmetric displacements
331 if (eliminate_cubic_terms_) {
332 if (disp < disp_offset + displacements(0).ncol()) {
333 irrep = 0;
334 coef = -1.0;
335 index = disp - disp_offset;
336 return;
337 }
338 disp_offset += displacements(0).ncol();
339 }
340 for (int i=1; i<nirrep_; i++) {
341 if (disp < disp_offset + displacements(i).ncol()) {
342 irrep = i;
343 coef = 1.0;
344 index = disp - disp_offset;
345 return;
346 }
347 disp_offset += displacements(i).ncol();
348 }
349 throw ProgrammingError("bad displacement number",
350 __FILE__, __LINE__, class_desc());
351}
352
353int
354FinDispMolecularHessian::ndisplace() const
355{
356 int ndisp = displacements(0).ncol();
357 if (eliminate_cubic_terms_) {
358 ndisp *= 2;
359 }
360 for (int i=1; i<nirrep_; i++) {
361 ndisp += displacements(i).ncol();
362 }
363 if (do_null_displacement_) ndisp++;
364 return ndisp;
365}
366
367void
368FinDispMolecularHessian::displace(int disp)
369{
370 int irrep, index;
371 double coef;
372 get_disp(disp, irrep, index, coef);
373
374 if (mole_.nonnull()) mole_->obsolete();
375
376 for (int i=0, coor=0; i<mol_->natom(); i++) {
377 for (int j=0; j<3; j++, coor++) {
378 if (index >= 0) {
379 mol_->r(i,j) = original_geometry_(coor)
380 + coef * disp_
381 * displacements(irrep)->get_element(coor,index);
382
383 }
384 else {
385 mol_->r(i,j) = original_geometry_(coor);
386 }
387 }
388 }
389
390 if (irrep == 0) {
391 mol_->set_point_group(original_point_group_);
392 }
393 else {
394 Ref<PointGroup> oldpg = mol_->point_group();
395 Ref<PointGroup> newpg = mol_->highest_point_group();
396 CorrelationTable corrtab;
397 if (corrtab.initialize_table(original_point_group_, newpg)) {
398 // something went wrong so use c1 symmetry
399 newpg = new PointGroup("c1");
400 }
401 if (!oldpg->equiv(newpg)) {
402 mol_->set_point_group(newpg);
403 mole_->symmetry_changed();
404 }
405 }
406
407#ifdef DEBUG
408 ExEnv::out0() << indent
409 << "Displacement point group: " << endl
410 << incindent << displacement_point_group_ << decindent;
411 ExEnv::out0() << indent
412 << "Displaced molecule: " << endl
413 << incindent << mol_ << decindent;
414#endif
415
416 ExEnv::out0() << indent
417 << "Displacement is "
418 << displacement_point_group_->char_table().gamma(irrep).symbol()
419 << " in " << displacement_point_group_->symbol()
420 << ". Using point group "
421 << mol_->point_group()->symbol()
422 << " for displaced molecule."
423 << endl;
424}
425
426void
427FinDispMolecularHessian::original_geometry()
428{
429 if (mole_.nonnull()) mole_->obsolete();
430
431 for (int i=0, coor=0; i<mol_->natom(); i++) {
432 for (int j=0; j<3; j++, coor++) {
433 mol_->r(i,j) = original_geometry_(coor);
434 }
435 }
436
437 if (!mol_->point_group()->equiv(original_point_group_)) {
438 mol_->set_point_group(original_point_group_);
439 mole_->symmetry_changed();
440 }
441}
442
443void
444FinDispMolecularHessian::set_gradient(int disp, const RefSCVector &grad)
445{
446 int irrep, index;
447 double coef;
448 get_disp(disp, irrep, index, coef);
449
450 // transform the gradient into symmetrized coordinates
451 gradients_[disp] = displacements(irrep).t() * grad;
452 if (debug_) {
453 grad.print("cartesian gradient");
454 gradients_[disp].print("internal gradient");
455 }
456
457 ndisp_++;
458}
459
460RefSymmSCMatrix
461FinDispMolecularHessian::compute_hessian_from_gradients()
462{
463 int i;
464
465 RefSymmSCMatrix dhessian;
466
467 RefSymmSCMatrix xhessian = matrixkit()->symmmatrix(d3natom());
468 xhessian.assign(0.0);
469
470 // start with the totally symmetric displacments
471 int offset = 0;
472 if (do_null_displacement_) offset++;
473 RefSCMatrix dtrans = displacements(0);
474 RefSCDimension ddim = dtrans.coldim();
475 dhessian = matrixkit()->symmmatrix(ddim);
476 for (i=0; i<ddim.n(); i++) {
477 for (int j=0; j<=i; j++) {
478 double hij = gradients_[i+offset](j) + gradients_[j+offset](i);
479 double ncontrib = 2.0;
480 if (do_null_displacement_) {
481 hij -= gradients_[0](j) + gradients_[0](i);
482 }
483 if (eliminate_cubic_terms_) {
484 hij -= gradients_[i+ddim.n()+offset](j)
485 + gradients_[j+ddim.n()+offset](i);
486 ncontrib += 2.0;
487 if (do_null_displacement_) {
488 hij += gradients_[0](j) + gradients_[0](i);
489 }
490 }
491 hij /= ncontrib*disp_;
492 dhessian(i,j) = hij;
493 }
494 }
495 do_hess_for_irrep(0, dhessian, xhessian);
496
497 offset += ddim.n();
498 if (eliminate_cubic_terms_) offset += ddim.n();
499 for (int irrep=1; irrep<nirrep_; irrep++) {
500 dtrans = displacements(irrep);
501 ddim = dtrans.coldim();
502 if (ddim.n() == 0) continue;
503 dhessian = matrixkit()->symmmatrix(ddim);
504 for (i=0; i<ddim.n(); i++) {
505 for (int j=0; j<=i; j++) {
506 dhessian(i,j) = (gradients_[i+offset](j)
507 + gradients_[j+offset](i))
508 /(2.0*disp_);
509 }
510 }
511 do_hess_for_irrep(irrep, dhessian, xhessian);
512 offset += ddim.n();
513 }
514
515 if (debug_) {
516 xhessian.print("xhessian");
517 }
518
519 return xhessian;
520}
521
522void
523FinDispMolecularHessian::do_hess_for_irrep(int irrep,
524 const RefSymmSCMatrix &dhessian,
525 const RefSymmSCMatrix &xhessian)
526{
527 RefSCMatrix dtrans = displacements(irrep);
528 RefSCDimension ddim = dtrans.coldim();
529 if (ddim.n() == 0) return;
530 if (debug_) {
531 dhessian.print("dhessian");
532 dtrans.print("dtrans");
533 }
534 xhessian.accumulate_transform(dtrans, dhessian);
535}
536
537RefSymmSCMatrix
538FinDispMolecularHessian::cartesian_hessian()
539{
540 tim_enter("hessian");
541
542 if (restart_) restart();
543 else init();
544
545 ExEnv::out0() << indent
546 << "Computing molecular hessian from "
547 << ndisplace() << " displacements:" << endl
548 << indent << "Starting at displacement: "
549 << ndisplacements_done() << endl;
550 ExEnv::out0() << indent << "Hessian options: " << endl;
551 ExEnv::out0() << indent << " displacement: " << disp_
552 << " bohr" << endl;
553 ExEnv::out0() << indent << " gradient_accuracy: "
554 << accuracy_ << " au" << endl;
555 ExEnv::out0() << indent << " eliminate_cubic_terms: "
556 << (eliminate_cubic_terms_==0?"no":"yes") << endl;
557 ExEnv::out0() << indent << " only_totally_symmetric: "
558 << (only_totally_symmetric_==0?"no":"yes") << endl;
559
560 for (int i=ndisplacements_done(); i<ndisplace(); i++) {
561 // This produces side-effects in mol and may even change
562 // its symmetry.
563 ExEnv::out0() << endl << indent
564 << "Beginning displacement " << i << ":" << endl;
565 displace(i);
566
567 mole_->obsolete();
568 double original_accuracy;
569 original_accuracy = mole_->desired_gradient_accuracy();
570 if (accuracy_ > 0.0)
571 mole_->set_desired_gradient_accuracy(accuracy_);
572 else
573 mole_->set_desired_gradient_accuracy(disp_/1000.0);
574 RefSCVector gradv = mole_->get_cartesian_gradient();
575 mole_->set_desired_gradient_accuracy(original_accuracy);
576 set_gradient(i, gradv);
577
578 if (checkpoint_) {
579 const char *hessckptfile;
580 if (MessageGrp::get_default_messagegrp()->me() == 0) {
581 hessckptfile = checkpoint_file_;
582 }
583 else {
584 hessckptfile = "/dev/null";
585 }
586 StateOutBin so(hessckptfile);
587 checkpoint_displacements(so);
588 }
589 }
590 original_geometry();
591 RefSymmSCMatrix xhessian = compute_hessian_from_gradients();
592 tim_exit("hessian");
593
594 symbasis_ = 0;
595 delete[] gradients_;
596 gradients_ = 0;
597 ndisp_ = 0;
598
599 return xhessian;
600}
601
602/////////////////////////////////////////////////////////////////////////////
603
604// Local Variables:
605// mode: c++
606// c-file-style: "CLJ-CONDENSED"
607// End:
Note: See TracBrowser for help on using the repository browser.