source: ThirdParty/mpqc_open/src/lib/chemistry/molecule/symmcoor.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.1 KB
Line 
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
42using namespace std;
43using namespace sc;
44
45#define VERBOSE 0
46
47namespace sc {
48
49///////////////////////////////////////////////////////////////////////////
50// SymmCoorTransform
51
52class 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
72SymmCoorTransform::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
87void
88SymmCoorTransform::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
174void
175SymmCoorTransform::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
214void
215SymmCoorTransform::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
230static ClassDesc SymmMolecularCoor_cd(
231 typeid(SymmMolecularCoor),"SymmMolecularCoor",1,"public IntMolecularCoor",
232 0, create<SymmMolecularCoor>, create<SymmMolecularCoor>);
233
234SymmMolecularCoor::SymmMolecularCoor(Ref<Molecule>&mol):
235 IntMolecularCoor(mol)
236{
237 init();
238}
239
240SymmMolecularCoor::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
255SymmMolecularCoor::SymmMolecularCoor(StateIn& s):
256 IntMolecularCoor(s)
257{
258 s.get(change_coordinates_);
259 s.get(transform_hessian_);
260 s.get(max_kappa2_);
261}
262
263SymmMolecularCoor::~SymmMolecularCoor()
264{
265}
266
267void
268SymmMolecularCoor::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
276void
277SymmMolecularCoor::init()
278{
279 IntMolecularCoor::init();
280 change_coordinates_ = 0;
281 max_kappa2_ = 10.0;
282 transform_hessian_ = 1;
283}
284
285void
286SymmMolecularCoor::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
413void
414SymmMolecularCoor::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
449RefSymmSCMatrix
450SymmMolecularCoor::inverse_hessian(RefSymmSCMatrix& hessian)
451{
452 return hessian.gi();
453}
454
455// Possibly change to a new coordinate system
456Ref<NonlinearTransform>
457SymmMolecularCoor::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
520void
521SymmMolecularCoor::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:
Note: See TracBrowser for help on using the repository browser.