| [0b990d] | 1 | //
 | 
|---|
 | 2 | // symmcoor.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 | #include <math.h>
 | 
|---|
 | 29 | 
 | 
|---|
 | 30 | #include <util/class/scexception.h>
 | 
|---|
 | 31 | #include <util/misc/formio.h>
 | 
|---|
 | 32 | #include <util/state/stateio.h>
 | 
|---|
 | 33 | #include <math/scmat/matrix.h>
 | 
|---|
 | 34 | #include <math/scmat/elemop.h>
 | 
|---|
 | 35 | #include <chemistry/molecule/localdef.h>
 | 
|---|
 | 36 | #include <chemistry/molecule/molecule.h>
 | 
|---|
 | 37 | #include <chemistry/molecule/coor.h>
 | 
|---|
 | 38 | #include <chemistry/molecule/simple.h>
 | 
|---|
 | 39 | 
 | 
|---|
 | 40 | #include <util/container/bitarray.h>
 | 
|---|
 | 41 | 
 | 
|---|
 | 42 | using namespace std;
 | 
|---|
 | 43 | using namespace sc;
 | 
|---|
 | 44 | 
 | 
|---|
 | 45 | #define VERBOSE 0
 | 
|---|
 | 46 | 
 | 
|---|
 | 47 | namespace sc {
 | 
|---|
 | 48 | 
 | 
|---|
 | 49 | ///////////////////////////////////////////////////////////////////////////
 | 
|---|
 | 50 | // SymmCoorTransform
 | 
|---|
 | 51 | 
 | 
|---|
 | 52 | class SymmCoorTransform: public NonlinearTransform {
 | 
|---|
 | 53 |   private:
 | 
|---|
 | 54 |     Ref<Molecule> molecule_;
 | 
|---|
 | 55 |     RefSCDimension dnatom3_;
 | 
|---|
 | 56 |     Ref<SetIntCoor> oldintcoor_;
 | 
|---|
 | 57 |     Ref<SetIntCoor> newintcoor_;
 | 
|---|
 | 58 |     Ref<SCMatrixKit> matrixkit_;
 | 
|---|
 | 59 |     int transform_hessian_;
 | 
|---|
 | 60 |   public:
 | 
|---|
 | 61 |     SymmCoorTransform(const Ref<Molecule>& molecule,
 | 
|---|
 | 62 |                       const RefSCDimension& dnatom3,
 | 
|---|
 | 63 |                       const Ref<SCMatrixKit>& kit,
 | 
|---|
 | 64 |                       const Ref<SetIntCoor>& oldintcoor,
 | 
|---|
 | 65 |                       const Ref<SetIntCoor>& newintcoor,
 | 
|---|
 | 66 |                       int transform_hessian);
 | 
|---|
 | 67 |     void to_cartesian(const RefSCVector& new_internal);
 | 
|---|
 | 68 |     void transform_coordinates(const RefSCVector& x);
 | 
|---|
 | 69 |     void transform_hessian(const RefSymmSCMatrix& h);
 | 
|---|
 | 70 | };
 | 
|---|
 | 71 | 
 | 
|---|
 | 72 | SymmCoorTransform::SymmCoorTransform(const Ref<Molecule>& molecule,
 | 
|---|
 | 73 |                                      const RefSCDimension& dnatom3,
 | 
|---|
 | 74 |                                      const Ref<SCMatrixKit>& kit,
 | 
|---|
 | 75 |                                      const Ref<SetIntCoor>& oldintcoor,
 | 
|---|
 | 76 |                                      const Ref<SetIntCoor>& newintcoor,
 | 
|---|
 | 77 |                                      int transform_hessian)
 | 
|---|
 | 78 | {
 | 
|---|
 | 79 |   molecule_ = new Molecule(*molecule.pointer());
 | 
|---|
 | 80 |   dnatom3_ = dnatom3;
 | 
|---|
 | 81 |   matrixkit_ = kit;
 | 
|---|
 | 82 |   oldintcoor_ = oldintcoor;
 | 
|---|
 | 83 |   newintcoor_ = newintcoor;
 | 
|---|
 | 84 |   transform_hessian_ = transform_hessian;
 | 
|---|
 | 85 | }
 | 
|---|
 | 86 | 
 | 
|---|
 | 87 | void
 | 
|---|
 | 88 | SymmCoorTransform::to_cartesian(const RefSCVector& new_internal)
 | 
|---|
 | 89 | {
 | 
|---|
 | 90 |   Ref<SCMatrixKit> kit = new_internal.kit();
 | 
|---|
 | 91 | 
 | 
|---|
 | 92 |   // get a reference to Molecule for convenience
 | 
|---|
 | 93 |   Molecule& molecule = *(molecule_.pointer());
 | 
|---|
 | 94 | 
 | 
|---|
 | 95 |   RefSCDimension dim = new_internal.dim();
 | 
|---|
 | 96 | 
 | 
|---|
 | 97 |   // don't bother updating the bmatrix when the error is less than this
 | 
|---|
 | 98 |   const double update_tolerance = 1.0e-3;
 | 
|---|
 | 99 |   const double cartesian_tolerance = 1.0e-8;
 | 
|---|
 | 100 | 
 | 
|---|
 | 101 |   // compute the internal coordinate displacements
 | 
|---|
 | 102 |   RefSCVector old_internal(new_internal.dim(),kit);
 | 
|---|
 | 103 | 
 | 
|---|
 | 104 |   RefSCMatrix internal_to_cart_disp;
 | 
|---|
 | 105 |   double maxabs_cart_diff = 0.0;
 | 
|---|
 | 106 |   const int maxiter = 100;
 | 
|---|
 | 107 |   for (int step = 0; step < maxiter; step++) {
 | 
|---|
 | 108 |       // compute the old internal coordinates
 | 
|---|
 | 109 |       oldintcoor_->update_values(molecule_);
 | 
|---|
 | 110 |       oldintcoor_->values_to_vector(old_internal);
 | 
|---|
 | 111 | 
 | 
|---|
 | 112 |       // the displacements
 | 
|---|
 | 113 |       RefSCVector displacement = new_internal - old_internal;
 | 
|---|
 | 114 | 
 | 
|---|
 | 115 |       if (maxabs_cart_diff>update_tolerance
 | 
|---|
 | 116 |           || internal_to_cart_disp.null()) {
 | 
|---|
 | 117 | 
 | 
|---|
 | 118 |           int i;
 | 
|---|
 | 119 |           RefSCMatrix bmat(dim,dnatom3_,kit);
 | 
|---|
 | 120 | 
 | 
|---|
 | 121 |           // form the bmatrix
 | 
|---|
 | 122 |           oldintcoor_->bmat(molecule_,bmat);
 | 
|---|
 | 123 | 
 | 
|---|
 | 124 |           // Compute the singular value decomposition of B
 | 
|---|
 | 125 |           RefSCMatrix U(dim,dim,kit);
 | 
|---|
 | 126 |           RefSCMatrix V(dnatom3_,dnatom3_,kit);
 | 
|---|
 | 127 |           RefSCDimension min;
 | 
|---|
 | 128 |           if (dnatom3_.n()<dim.n()) min = dnatom3_;
 | 
|---|
 | 129 |           else min = dim;
 | 
|---|
 | 130 |           int nmin = min.n();
 | 
|---|
 | 131 |           RefDiagSCMatrix sigma(min,kit);
 | 
|---|
 | 132 |           bmat.svd(U,sigma,V);
 | 
|---|
 | 133 | 
 | 
|---|
 | 134 |           // compute the epsilon rank of B
 | 
|---|
 | 135 |           int rank = 0;
 | 
|---|
 | 136 |           for (i=0; i<nmin; i++) {
 | 
|---|
 | 137 |               if (fabs(sigma(i)) > 0.0001) rank++;
 | 
|---|
 | 138 |             }
 | 
|---|
 | 139 | 
 | 
|---|
 | 140 |           RefSCDimension drank = new SCDimension(rank);
 | 
|---|
 | 141 |           RefDiagSCMatrix sigma_i(drank,kit);
 | 
|---|
 | 142 |           for (i=0; i<rank; i++) {
 | 
|---|
 | 143 |               sigma_i(i) = 1.0/sigma(i);
 | 
|---|
 | 144 |             }
 | 
|---|
 | 145 |           RefSCMatrix Ur(dim, drank, kit);
 | 
|---|
 | 146 |           RefSCMatrix Vr(dnatom3_, drank, kit);
 | 
|---|
 | 147 |           Ur.assign_subblock(U,0, dim.n()-1, 0, drank.n()-1, 0, 0);
 | 
|---|
 | 148 |           Vr.assign_subblock(V,0, dnatom3_.n()-1, 0, drank.n()-1, 0, 0);
 | 
|---|
 | 149 |           internal_to_cart_disp = Vr * sigma_i * Ur.t();
 | 
|---|
 | 150 |         }
 | 
|---|
 | 151 | 
 | 
|---|
 | 152 |       // compute the cartesian displacements
 | 
|---|
 | 153 |       RefSCVector cartesian_displacement = internal_to_cart_disp*displacement;
 | 
|---|
 | 154 |       // update the geometry
 | 
|---|
 | 155 |       for (int i=0; i < dnatom3_.n(); i++) {
 | 
|---|
 | 156 |           molecule.r(i/3,i%3) += cartesian_displacement(i);
 | 
|---|
 | 157 |         }
 | 
|---|
 | 158 | 
 | 
|---|
 | 159 |       // check for convergence
 | 
|---|
 | 160 |       Ref<SCElementMaxAbs> maxabs = new SCElementMaxAbs();
 | 
|---|
 | 161 |       Ref<SCElementOp> op = maxabs.pointer();
 | 
|---|
 | 162 |       cartesian_displacement.element_op(op);
 | 
|---|
 | 163 |       maxabs_cart_diff = maxabs->result();
 | 
|---|
 | 164 |       if (maxabs_cart_diff < cartesian_tolerance) {
 | 
|---|
 | 165 |           oldintcoor_->update_values(molecule_);
 | 
|---|
 | 166 |           return;
 | 
|---|
 | 167 |         }
 | 
|---|
 | 168 |     }
 | 
|---|
 | 169 | 
 | 
|---|
 | 170 |   throw MaxIterExceeded("too many iterations in geometry update",
 | 
|---|
 | 171 |                         __FILE__, __LINE__, maxiter);
 | 
|---|
 | 172 | }
 | 
|---|
 | 173 | 
 | 
|---|
 | 174 | void
 | 
|---|
 | 175 | SymmCoorTransform::transform_coordinates(const RefSCVector& x)
 | 
|---|
 | 176 | {
 | 
|---|
 | 177 |   if (x.null()) return;
 | 
|---|
 | 178 | 
 | 
|---|
 | 179 |   Ref<SCMatrixKit> kit = x.kit();
 | 
|---|
 | 180 |   RefSCDimension dim = x.dim();
 | 
|---|
 | 181 | 
 | 
|---|
 | 182 |   // using the old coordinates update molecule
 | 
|---|
 | 183 |   to_cartesian(x);
 | 
|---|
 | 184 | 
 | 
|---|
 | 185 |   // compute the new coordinates
 | 
|---|
 | 186 |   newintcoor_->update_values(molecule_);
 | 
|---|
 | 187 |   newintcoor_->values_to_vector(x);
 | 
|---|
 | 188 | 
 | 
|---|
 | 189 |   // compute the linear transformation information
 | 
|---|
 | 190 | 
 | 
|---|
 | 191 |   // the old B matrix
 | 
|---|
 | 192 |   RefSCMatrix B(dim, dnatom3_, kit);
 | 
|---|
 | 193 |   oldintcoor_->bmat(molecule_, B);
 | 
|---|
 | 194 | 
 | 
|---|
 | 195 |   // get the B matrix for the new coordinates
 | 
|---|
 | 196 |   RefSCMatrix Bnew(dim, dnatom3_, kit);
 | 
|---|
 | 197 |   newintcoor_->update_values(molecule_);
 | 
|---|
 | 198 |   newintcoor_->bmat(molecule_, Bnew);
 | 
|---|
 | 199 | 
 | 
|---|
 | 200 |   // the transform from cartesian to new internal coordinates
 | 
|---|
 | 201 |   RefSymmSCMatrix bmbt(dim,kit);
 | 
|---|
 | 202 |   bmbt.assign(0.0);
 | 
|---|
 | 203 |   bmbt.accumulate_symmetric_product(Bnew);
 | 
|---|
 | 204 |   RefSCMatrix cart_to_new_internal = bmbt.gi() * Bnew;
 | 
|---|
 | 205 |   Bnew = 0;
 | 
|---|
 | 206 |   bmbt = 0;
 | 
|---|
 | 207 | 
 | 
|---|
 | 208 |   linear_transform_ = cart_to_new_internal * B.t();
 | 
|---|
 | 209 | #if VERBOSE
 | 
|---|
 | 210 |   linear_transform_.print("old internal to new");
 | 
|---|
 | 211 | #endif
 | 
|---|
 | 212 | }
 | 
|---|
 | 213 | 
 | 
|---|
 | 214 | void
 | 
|---|
 | 215 | SymmCoorTransform::transform_hessian(const RefSymmSCMatrix& h)
 | 
|---|
 | 216 | {
 | 
|---|
 | 217 |   if (transform_hessian_) {
 | 
|---|
 | 218 |       NonlinearTransform::transform_hessian(h);
 | 
|---|
 | 219 |     }
 | 
|---|
 | 220 |   else {
 | 
|---|
 | 221 |       ExEnv::err0() << indent
 | 
|---|
 | 222 |            << "WARNING: SymmCoorTransform::transform_hessian: "
 | 
|---|
 | 223 |            << "skipping hessian transform";
 | 
|---|
 | 224 |     }
 | 
|---|
 | 225 | }
 | 
|---|
 | 226 | 
 | 
|---|
 | 227 | ///////////////////////////////////////////////////////////////////////////
 | 
|---|
 | 228 | // members of SymmMolecularCoor
 | 
|---|
 | 229 | 
 | 
|---|
 | 230 | static ClassDesc SymmMolecularCoor_cd(
 | 
|---|
 | 231 |   typeid(SymmMolecularCoor),"SymmMolecularCoor",1,"public IntMolecularCoor",
 | 
|---|
 | 232 |   0, create<SymmMolecularCoor>, create<SymmMolecularCoor>);
 | 
|---|
 | 233 | 
 | 
|---|
 | 234 | SymmMolecularCoor::SymmMolecularCoor(Ref<Molecule>&mol):
 | 
|---|
 | 235 |   IntMolecularCoor(mol)
 | 
|---|
 | 236 | {
 | 
|---|
 | 237 |   init();
 | 
|---|
 | 238 | }
 | 
|---|
 | 239 | 
 | 
|---|
 | 240 | SymmMolecularCoor::SymmMolecularCoor(const Ref<KeyVal>& keyval):
 | 
|---|
 | 241 |   IntMolecularCoor(keyval)
 | 
|---|
 | 242 | {
 | 
|---|
 | 243 |   init();
 | 
|---|
 | 244 | 
 | 
|---|
 | 245 |   int itmp;
 | 
|---|
 | 246 |   double dtmp;
 | 
|---|
 | 247 |   itmp = keyval->booleanvalue("change_coordinates");
 | 
|---|
 | 248 |   if (keyval->error() == KeyVal::OK) change_coordinates_ = itmp;
 | 
|---|
 | 249 |   itmp = keyval->booleanvalue("transform_hessian");
 | 
|---|
 | 250 |   if (keyval->error() == KeyVal::OK) transform_hessian_ = itmp;
 | 
|---|
 | 251 |   dtmp = keyval->doublevalue("max_kappa2");
 | 
|---|
 | 252 |   if (keyval->error() == KeyVal::OK) max_kappa2_ = dtmp;
 | 
|---|
 | 253 | }
 | 
|---|
 | 254 | 
 | 
|---|
 | 255 | SymmMolecularCoor::SymmMolecularCoor(StateIn& s):
 | 
|---|
 | 256 |   IntMolecularCoor(s)
 | 
|---|
 | 257 | {
 | 
|---|
 | 258 |   s.get(change_coordinates_);
 | 
|---|
 | 259 |   s.get(transform_hessian_);
 | 
|---|
 | 260 |   s.get(max_kappa2_);
 | 
|---|
 | 261 | }
 | 
|---|
 | 262 | 
 | 
|---|
 | 263 | SymmMolecularCoor::~SymmMolecularCoor()
 | 
|---|
 | 264 | {
 | 
|---|
 | 265 | }
 | 
|---|
 | 266 | 
 | 
|---|
 | 267 | void
 | 
|---|
 | 268 | SymmMolecularCoor::save_data_state(StateOut&s)
 | 
|---|
 | 269 | {
 | 
|---|
 | 270 |   IntMolecularCoor::save_data_state(s);
 | 
|---|
 | 271 |   s.put(change_coordinates_);
 | 
|---|
 | 272 |   s.put(transform_hessian_);
 | 
|---|
 | 273 |   s.put(max_kappa2_);
 | 
|---|
 | 274 | }
 | 
|---|
 | 275 | 
 | 
|---|
 | 276 | void
 | 
|---|
 | 277 | SymmMolecularCoor::init()
 | 
|---|
 | 278 | {
 | 
|---|
 | 279 |   IntMolecularCoor::init();
 | 
|---|
 | 280 |   change_coordinates_ = 0;
 | 
|---|
 | 281 |   max_kappa2_ = 10.0;
 | 
|---|
 | 282 |   transform_hessian_ = 1;
 | 
|---|
 | 283 | }
 | 
|---|
 | 284 | 
 | 
|---|
 | 285 | void
 | 
|---|
 | 286 | SymmMolecularCoor::form_coordinates(int keep_variable)
 | 
|---|
 | 287 | {
 | 
|---|
 | 288 |   int i;
 | 
|---|
 | 289 |   int nbonds = bonds_->n();
 | 
|---|
 | 290 |   int nbends = bends_->n();
 | 
|---|
 | 291 |   int ntors = tors_->n();
 | 
|---|
 | 292 |   int nouts = outs_->n();
 | 
|---|
 | 293 |   int nextras = extras_->n();
 | 
|---|
 | 294 | 
 | 
|---|
 | 295 |   Ref<SetIntCoor> saved_fixed_ = fixed_;
 | 
|---|
 | 296 |   fixed_ = new SetIntCoor;
 | 
|---|
 | 297 |   fixed_->add(saved_fixed_);
 | 
|---|
 | 298 |   // if we're following coordinates, add them to the fixed list
 | 
|---|
 | 299 |   if (followed_.nonnull())
 | 
|---|
 | 300 |     fixed_->add(followed_);
 | 
|---|
 | 301 |   
 | 
|---|
 | 302 |   int nredundant = nbonds + nbends + ntors + nouts + nextras;
 | 
|---|
 | 303 |   int nfixed = fixed_->n();
 | 
|---|
 | 304 | 
 | 
|---|
 | 305 |   // see how many coords we expect
 | 
|---|
 | 306 |   int n3 = molecule_->natom()*3;
 | 
|---|
 | 307 |   int nunique = n3 - 6; // need to detect linear
 | 
|---|
 | 308 | 
 | 
|---|
 | 309 |   if (nredundant < nunique) {
 | 
|---|
 | 310 |       AlgorithmException ex("found too few redundant coordinates",
 | 
|---|
 | 311 |                             __FILE__, __LINE__, class_desc());
 | 
|---|
 | 312 |       try {
 | 
|---|
 | 313 |           ex.elaborate()
 | 
|---|
 | 314 |               << scprintf("nredundant = %d, 3n-6 = %d",
 | 
|---|
 | 315 |                           nredundant, nunique)
 | 
|---|
 | 316 |               << std::endl
 | 
|---|
 | 317 |               << "(the geometry is probably bad)"
 | 
|---|
 | 318 |               << std::endl;
 | 
|---|
 | 319 |         }
 | 
|---|
 | 320 |       catch (...) {}
 | 
|---|
 | 321 |       throw ex;
 | 
|---|
 | 322 |     }
 | 
|---|
 | 323 | 
 | 
|---|
 | 324 |   RefSCDimension dredundant = new SCDimension(nredundant, "Nredund");
 | 
|---|
 | 325 |   RefSCDimension dfixed = new SCDimension(nfixed, "Nfixed");
 | 
|---|
 | 326 |   RefSCMatrix K; // nredundant x nnonzero
 | 
|---|
 | 327 |   int* is_totally_symmetric; // nnonzero; if 1 coor has tot. symm. component
 | 
|---|
 | 328 | 
 | 
|---|
 | 329 |   form_K_matrix(dredundant, dfixed, K, is_totally_symmetric);
 | 
|---|
 | 330 | 
 | 
|---|
 | 331 |   RefSCDimension dnonzero = K.coldim();
 | 
|---|
 | 332 |   int nnonzero = dnonzero.n();
 | 
|---|
 | 333 | 
 | 
|---|
 | 334 |   if (!keep_variable) variable_->clear();
 | 
|---|
 | 335 |   constant_->clear();
 | 
|---|
 | 336 | 
 | 
|---|
 | 337 |   // now remove followed coords from the fixed list, and add to the
 | 
|---|
 | 338 |   // variable list
 | 
|---|
 | 339 |   if (followed_.nonnull()) {
 | 
|---|
 | 340 |     fixed_->pop();
 | 
|---|
 | 341 |     variable_->add(followed_);
 | 
|---|
 | 342 |   }
 | 
|---|
 | 343 |   
 | 
|---|
 | 344 |   // put the fixed coordinates into the constant list
 | 
|---|
 | 345 |   nfixed = fixed_->n();
 | 
|---|
 | 346 |   for (i=0; i<nfixed; i++) {
 | 
|---|
 | 347 |       constant_->add(fixed_->coor(i));
 | 
|---|
 | 348 |     }
 | 
|---|
 | 349 | 
 | 
|---|
 | 350 |   // ok, now we have the K matrix, the columns of which give us the
 | 
|---|
 | 351 |   // contribution from each red. coord to the ith non-red. coord.
 | 
|---|
 | 352 |   // this gets a little hairy since the red coords can themselves be
 | 
|---|
 | 353 |   // linear combinations of simple coords
 | 
|---|
 | 354 |   for(i=0; i < nnonzero; i++) {
 | 
|---|
 | 355 |       // construct the new linear combination coordinate
 | 
|---|
 | 356 |       char label[80];
 | 
|---|
 | 357 |       if (is_totally_symmetric[i]) {
 | 
|---|
 | 358 |           sprintf(label,"symm_coord_%03d",i+1);
 | 
|---|
 | 359 |         }
 | 
|---|
 | 360 |       else {
 | 
|---|
 | 361 |           sprintf(label,"asymm_coord_%03d",i+1);
 | 
|---|
 | 362 |         }
 | 
|---|
 | 363 |       SumIntCoor* coordinate = new SumIntCoor(label);
 | 
|---|
 | 364 | 
 | 
|---|
 | 365 |       int j;
 | 
|---|
 | 366 |       for(j=0; j < nredundant; j++) {
 | 
|---|
 | 367 |           if(pow(K(j,i),2.0) > simple_tolerance_) {
 | 
|---|
 | 368 |               Ref<IntCoor> c = all_->coor(j);
 | 
|---|
 | 369 |               coordinate->add(c,K(j,i));
 | 
|---|
 | 370 |               if (debug_) {
 | 
|---|
 | 371 |                   ExEnv::out0() << "added redund coor "
 | 
|---|
 | 372 |                        << j << " to coor " << i << ":" << endl;
 | 
|---|
 | 373 |                   c->print();
 | 
|---|
 | 374 |                 }
 | 
|---|
 | 375 |             }
 | 
|---|
 | 376 |         }
 | 
|---|
 | 377 | 
 | 
|---|
 | 378 |       // normalize the coordinate
 | 
|---|
 | 379 |       coordinate->normalize();
 | 
|---|
 | 380 | 
 | 
|---|
 | 381 |       if (only_totally_symmetric_ && !is_totally_symmetric[i]) {
 | 
|---|
 | 382 |           // Don't put nonsymmetric coordinates into the
 | 
|---|
 | 383 |           // constant_ coordinate set.  This causes problems
 | 
|---|
 | 384 |           // when coordinates with small coefficients are eliminated
 | 
|---|
 | 385 |           // since they can then acquire symmetric components.
 | 
|---|
 | 386 |           // constant_->add(coordinate);
 | 
|---|
 | 387 |           delete coordinate;
 | 
|---|
 | 388 |         }
 | 
|---|
 | 389 |       else {
 | 
|---|
 | 390 |           if (!keep_variable) variable_->add(coordinate);
 | 
|---|
 | 391 |         }
 | 
|---|
 | 392 |     }
 | 
|---|
 | 393 | 
 | 
|---|
 | 394 |   constant_->update_values(molecule_);
 | 
|---|
 | 395 |   variable_->update_values(molecule_);
 | 
|---|
 | 396 | 
 | 
|---|
 | 397 |   ExEnv::out0() << incindent << indent
 | 
|---|
 | 398 |        << "SymmMolecularCoor::form_variable_coordinates()\n" << incindent
 | 
|---|
 | 399 |        << indent << "expected " << nunique << " coordinates\n"
 | 
|---|
 | 400 |        << indent << "found " << variable_->n() << " variable coordinates\n"
 | 
|---|
 | 401 |        << indent << "found " << constant_->n() << " constant coordinates\n"
 | 
|---|
 | 402 |        << decindent << decindent << flush;
 | 
|---|
 | 403 | 
 | 
|---|
 | 404 |   delete[] is_totally_symmetric;
 | 
|---|
 | 405 |   fixed_ = saved_fixed_;
 | 
|---|
 | 406 | 
 | 
|---|
 | 407 |   if (form_print_molecule_) molecule_->print();
 | 
|---|
 | 408 |   if (form_print_simples_) print_simples(ExEnv::out0());
 | 
|---|
 | 409 |   if (form_print_variable_) print_variable(ExEnv::out0());
 | 
|---|
 | 410 |   if (form_print_constant_) print_constant(ExEnv::out0());
 | 
|---|
 | 411 | }
 | 
|---|
 | 412 | 
 | 
|---|
 | 413 | void
 | 
|---|
 | 414 | SymmMolecularCoor::guess_hessian(RefSymmSCMatrix&hessian)
 | 
|---|
 | 415 | {
 | 
|---|
 | 416 |   // first form diagonal hessian in redundant internal coordinates
 | 
|---|
 | 417 |   RefSCDimension rdim = new SCDimension(all_->n(), "Nall");
 | 
|---|
 | 418 |   RefSymmSCMatrix rhessian(rdim,matrixkit_);
 | 
|---|
 | 419 |   rhessian.assign(0.0);
 | 
|---|
 | 420 |   all_->guess_hessian(molecule_,rhessian);
 | 
|---|
 | 421 | 
 | 
|---|
 | 422 |   // create redundant coordinate bmat
 | 
|---|
 | 423 |   RefSCDimension dn3 = dnatom3_;
 | 
|---|
 | 424 |   RefSCMatrix bmatr(rdim,dn3,matrixkit_);
 | 
|---|
 | 425 |   all_->bmat(molecule_,bmatr);
 | 
|---|
 | 426 | 
 | 
|---|
 | 427 |   // then form the variable coordinate bmat
 | 
|---|
 | 428 |   RefSCDimension dredundant = new SCDimension(variable_->n(), "Nvar");
 | 
|---|
 | 429 |   RefSCMatrix bmat(dredundant,dn3,matrixkit_);
 | 
|---|
 | 430 |   variable_->bmat(molecule_,bmat);
 | 
|---|
 | 431 | 
 | 
|---|
 | 432 |   // and (B*B+)^-1
 | 
|---|
 | 433 |   RefSymmSCMatrix bmbt(dredundant,matrixkit_);
 | 
|---|
 | 434 |   bmbt.assign(0.0);
 | 
|---|
 | 435 |   bmbt.accumulate_symmetric_product(bmat);
 | 
|---|
 | 436 |   bmbt = bmbt.gi();
 | 
|---|
 | 437 | 
 | 
|---|
 | 438 |   // now transform redundant hessian to internal coordinates
 | 
|---|
 | 439 |   // Hc = Br+ * Hr * Br
 | 
|---|
 | 440 |   // Hi = (B*B+)^-1 * B * Hc * B+ * (B*B+)^-1+
 | 
|---|
 | 441 |   //    = bmbt_inv*B*Br+ * Hr * Br*B+*bmbt_inv+
 | 
|---|
 | 442 |   //    = b * Hr * b+  (b = (B*B+)^-1 * B * Br+)
 | 
|---|
 | 443 |   RefSCMatrix b = bmbt * bmat * bmatr.t();
 | 
|---|
 | 444 |   
 | 
|---|
 | 445 |   hessian.assign(0.0);
 | 
|---|
 | 446 |   hessian.accumulate_transform(b,rhessian);
 | 
|---|
 | 447 | }
 | 
|---|
 | 448 | 
 | 
|---|
 | 449 | RefSymmSCMatrix
 | 
|---|
 | 450 | SymmMolecularCoor::inverse_hessian(RefSymmSCMatrix& hessian)
 | 
|---|
 | 451 | {
 | 
|---|
 | 452 |   return hessian.gi();
 | 
|---|
 | 453 | }
 | 
|---|
 | 454 | 
 | 
|---|
 | 455 | // Possibly change to a new coordinate system
 | 
|---|
 | 456 | Ref<NonlinearTransform>
 | 
|---|
 | 457 | SymmMolecularCoor::change_coordinates()
 | 
|---|
 | 458 | {
 | 
|---|
 | 459 |   if (dim_.n() == 0 || !change_coordinates_) return 0;
 | 
|---|
 | 460 | 
 | 
|---|
 | 461 |   const double epsilon = 0.001;
 | 
|---|
 | 462 | 
 | 
|---|
 | 463 |   // compute the condition number of the old coordinate system at the
 | 
|---|
 | 464 |   // current point
 | 
|---|
 | 465 |   RefSCMatrix B(dim_, dnatom3_, matrixkit_);
 | 
|---|
 | 466 |   variable_->bmat(molecule_, B);
 | 
|---|
 | 467 | 
 | 
|---|
 | 468 |   // Compute the singular value decomposition of B
 | 
|---|
 | 469 |   RefSCMatrix U(dim_,dim_,matrixkit_);
 | 
|---|
 | 470 |   RefSCMatrix V(dnatom3_,dnatom3_,matrixkit_);
 | 
|---|
 | 471 |   RefSCDimension min;
 | 
|---|
 | 472 |   if (dnatom3_.n()<dim_.n()) min = dnatom3_;
 | 
|---|
 | 473 |   else min = dim_;
 | 
|---|
 | 474 |   int nmin = min.n();
 | 
|---|
 | 475 |   RefDiagSCMatrix sigma(min,matrixkit_);
 | 
|---|
 | 476 |   B.svd(U,sigma,V);
 | 
|---|
 | 477 | 
 | 
|---|
 | 478 |   // Compute the epsilon rank of B
 | 
|---|
 | 479 |   int i, rank = 0;
 | 
|---|
 | 480 |   for (i=0; i<nmin; i++) {
 | 
|---|
 | 481 |       if (sigma(i) > epsilon) rank++;
 | 
|---|
 | 482 |     }
 | 
|---|
 | 483 |   // the rank could get bigger if there is a fixed coordinate
 | 
|---|
 | 484 |   if (rank < dim_.n() || ((fixed_.null()
 | 
|---|
 | 485 |                            || fixed_->n() == 0) && rank != dim_.n())) {
 | 
|---|
 | 486 |       throw AlgorithmException("disallowed rank change",
 | 
|---|
 | 487 |                                __FILE__, __LINE__, class_desc());
 | 
|---|
 | 488 |     }
 | 
|---|
 | 489 |   if (rank != dim_.n()) {
 | 
|---|
 | 490 |       ExEnv::out0() << indent
 | 
|---|
 | 491 |            << "SymmMolecularCoor::change_coordinates: rank changed\n";
 | 
|---|
 | 492 |     }
 | 
|---|
 | 493 | 
 | 
|---|
 | 494 |   double kappa2 = sigma(0)/sigma(dim_.n()-1);
 | 
|---|
 | 495 | 
 | 
|---|
 | 496 |   ExEnv::out0() << indent
 | 
|---|
 | 497 |        << scprintf(
 | 
|---|
 | 498 |            "SymmMolecularCoor: condition number = %14.8f (max = %14.8f)\n",
 | 
|---|
 | 499 |            kappa2, max_kappa2_);
 | 
|---|
 | 500 | 
 | 
|---|
 | 501 |   if (kappa2 > max_kappa2_) {
 | 
|---|
 | 502 |       Ref<SetIntCoor> oldvariable = new SetIntCoor;
 | 
|---|
 | 503 |       oldvariable->add(variable_);
 | 
|---|
 | 504 | 
 | 
|---|
 | 505 |       // form the new variable coordinates
 | 
|---|
 | 506 |       form_coordinates();
 | 
|---|
 | 507 | 
 | 
|---|
 | 508 |       SymmCoorTransform *trans = new SymmCoorTransform(molecule_,
 | 
|---|
 | 509 |                                                        dnatom3_,
 | 
|---|
 | 510 |                                                        matrixkit_,
 | 
|---|
 | 511 |                                                        oldvariable,
 | 
|---|
 | 512 |                                                        variable_,
 | 
|---|
 | 513 |                                                        transform_hessian_);
 | 
|---|
 | 514 |       return trans;
 | 
|---|
 | 515 |     }
 | 
|---|
 | 516 | 
 | 
|---|
 | 517 |   return 0;
 | 
|---|
 | 518 | }
 | 
|---|
 | 519 | 
 | 
|---|
 | 520 | void
 | 
|---|
 | 521 | SymmMolecularCoor::print(ostream& os) const
 | 
|---|
 | 522 | {
 | 
|---|
 | 523 |   IntMolecularCoor::print(os);
 | 
|---|
 | 524 |   
 | 
|---|
 | 525 |   os << indent << "SymmMolecularCoor Parameters:\n" << incindent
 | 
|---|
 | 526 |      << indent << "change_coordinates = "
 | 
|---|
 | 527 |      << (change_coordinates_?"yes":"no") << endl
 | 
|---|
 | 528 |      << indent << "transform_hessian = "
 | 
|---|
 | 529 |      << (transform_hessian_?"yes":"no") << endl
 | 
|---|
 | 530 |      << indent << scprintf("max_kappa2 = %f",max_kappa2_) << endl
 | 
|---|
 | 531 |      << decindent << endl;
 | 
|---|
 | 532 | }
 | 
|---|
 | 533 | 
 | 
|---|
 | 534 | /////////////////////////////////////////////////////////////////////////////
 | 
|---|
 | 535 | 
 | 
|---|
 | 536 | }
 | 
|---|
 | 537 | 
 | 
|---|
 | 538 | // Local Variables:
 | 
|---|
 | 539 | // mode: c++
 | 
|---|
 | 540 | // c-file-style: "CLJ"
 | 
|---|
 | 541 | // End:
 | 
|---|