| [0b990d] | 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 | 
 | 
|---|
 | 46 | using namespace std;
 | 
|---|
 | 47 | using namespace sc;
 | 
|---|
 | 48 | 
 | 
|---|
 | 49 | #define DEFAULT_CHECKPOINT  1
 | 
|---|
 | 50 | #define DEFAULT_RESTART     1
 | 
|---|
 | 51 | 
 | 
|---|
 | 52 | /////////////////////////////////////////////////////////////////
 | 
|---|
 | 53 | // FinDispMolecularHessian
 | 
|---|
 | 54 | 
 | 
|---|
 | 55 | static ClassDesc FinDispMolecularHessian_cd(
 | 
|---|
 | 56 |   typeid(FinDispMolecularHessian),"FinDispMolecularHessian",1,"public MolecularHessian",
 | 
|---|
 | 57 |   0, create<FinDispMolecularHessian>, create<FinDispMolecularHessian>);
 | 
|---|
 | 58 | 
 | 
|---|
 | 59 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 78 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 115 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 130 | FinDispMolecularHessian::~FinDispMolecularHessian()
 | 
|---|
 | 131 | {
 | 
|---|
 | 132 |   delete[] gradients_;
 | 
|---|
 | 133 |   delete[] checkpoint_file_;
 | 
|---|
 | 134 |   delete[] restart_file_;
 | 
|---|
 | 135 | }
 | 
|---|
 | 136 | 
 | 
|---|
 | 137 | void
 | 
|---|
 | 138 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 152 | void
 | 
|---|
 | 153 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 184 | void
 | 
|---|
 | 185 | FinDispMolecularHessian::set_energy(const Ref<MolecularEnergy> &energy)
 | 
|---|
 | 186 | {
 | 
|---|
 | 187 |   mole_ = energy;
 | 
|---|
 | 188 | }
 | 
|---|
 | 189 | 
 | 
|---|
 | 190 | MolecularEnergy*
 | 
|---|
 | 191 | FinDispMolecularHessian::energy() const
 | 
|---|
 | 192 | {
 | 
|---|
 | 193 |   return mole_.pointer();
 | 
|---|
 | 194 | }
 | 
|---|
 | 195 | 
 | 
|---|
 | 196 | void
 | 
|---|
 | 197 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 233 | void
 | 
|---|
 | 234 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 269 | void
 | 
|---|
 | 270 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 296 | RefSCMatrix
 | 
|---|
 | 297 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 309 | void
 | 
|---|
 | 310 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 353 | int
 | 
|---|
 | 354 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 367 | void
 | 
|---|
 | 368 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 426 | void
 | 
|---|
 | 427 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 443 | void
 | 
|---|
 | 444 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 460 | RefSymmSCMatrix
 | 
|---|
 | 461 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 522 | void
 | 
|---|
 | 523 | FinDispMolecularHessian::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 | 
 | 
|---|
 | 537 | RefSymmSCMatrix
 | 
|---|
 | 538 | FinDispMolecularHessian::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:
 | 
|---|