Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

colvartypes.C

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 
00003 // This file is part of the Collective Variables module (Colvars).
00004 // The original version of Colvars and its updates are located at:
00005 // https://github.com/Colvars/colvars
00006 // Please update all Colvars source files before making any changes.
00007 // If you wish to distribute your changes, please submit them to the
00008 // Colvars repository at GitHub.
00009 
00010 #include <cstdlib>
00011 #include <cstring>
00012 
00013 #include "colvarmodule.h"
00014 #include "colvartypes.h"
00015 #include "colvarparse.h"
00016 
00017 #ifdef COLVARS_LAMMPS
00018 // Use open-source Jacobi implementation
00019 #include "math_eigen_impl.h"
00020 #else
00021 // Fall back to NR routine
00022 #include "nr_jacobi.h"
00023 #endif
00024 
00025 
00026 bool      colvarmodule::rotation::monitor_crossings = false;
00027 cvm::real colvarmodule::rotation::crossing_threshold = 1.0E-02;
00028 
00029 
00030 std::string cvm::rvector::to_simple_string() const
00031 {
00032   std::ostringstream os;
00033   os.setf(std::ios::scientific, std::ios::floatfield);
00034   os.precision(cvm::cv_prec);
00035   os << x << " " << y << " " << z;
00036   return os.str();
00037 }
00038 
00039 
00040 int cvm::rvector::from_simple_string(std::string const &s)
00041 {
00042   std::stringstream stream(s);
00043   if ( !(stream >> x) ||
00044        !(stream >> y) ||
00045        !(stream >> z) ) {
00046     return COLVARS_ERROR;
00047   }
00048   return COLVARS_OK;
00049 }
00050 
00051 
00052 std::ostream & operator << (std::ostream &os, colvarmodule::rvector const &v)
00053 {
00054   std::streamsize const w = os.width();
00055   std::streamsize const p = os.precision();
00056 
00057   os.width(2);
00058   os << "( ";
00059   os.width(w); os.precision(p);
00060   os << v.x << " , ";
00061   os.width(w); os.precision(p);
00062   os << v.y << " , ";
00063   os.width(w); os.precision(p);
00064   os << v.z << " )";
00065   return os;
00066 }
00067 
00068 
00069 std::istream & operator >> (std::istream &is, colvarmodule::rvector &v)
00070 {
00071   std::streampos const start_pos = is.tellg();
00072   char sep;
00073   if ( !(is >> sep) || !(sep == '(') ||
00074        !(is >> v.x) || !(is >> sep)  || !(sep == ',') ||
00075        !(is >> v.y) || !(is >> sep)  || !(sep == ',') ||
00076        !(is >> v.z) || !(is >> sep)  || !(sep == ')') ) {
00077     is.clear();
00078     is.seekg(start_pos, std::ios::beg);
00079     is.setstate(std::ios::failbit);
00080     return is;
00081   }
00082   return is;
00083 }
00084 
00085 std::string cvm::quaternion::to_simple_string() const
00086 {
00087   std::ostringstream os;
00088   os.setf(std::ios::scientific, std::ios::floatfield);
00089   os.precision(cvm::cv_prec);
00090   os << q0 << " " << q1 << " " << q2 << " " << q3;
00091   return os.str();
00092 }
00093 
00094 int cvm::quaternion::from_simple_string(std::string const &s)
00095 {
00096   std::stringstream stream(s);
00097   if ( !(stream >> q0) ||
00098        !(stream >> q1) ||
00099        !(stream >> q2) ||
00100        !(stream >> q3) ) {
00101     return COLVARS_ERROR;
00102   }
00103   return COLVARS_OK;
00104 }
00105 
00106 std::ostream & operator << (std::ostream &os, colvarmodule::quaternion const &q)
00107 {
00108   std::streamsize const w = os.width();
00109   std::streamsize const p = os.precision();
00110 
00111   os.width(2);
00112   os << "( ";
00113   os.width(w); os.precision(p);
00114   os << q.q0 << " , ";
00115   os.width(w); os.precision(p);
00116   os << q.q1 << " , ";
00117   os.width(w); os.precision(p);
00118   os << q.q2 << " , ";
00119   os.width(w); os.precision(p);
00120   os << q.q3 << " )";
00121   return os;
00122 }
00123 
00124 
00125 std::istream & operator >> (std::istream &is, colvarmodule::quaternion &q)
00126 {
00127   std::streampos const start_pos = is.tellg();
00128   char sep;
00129   if ( !(is >> sep)  || !(sep == '(') ||
00130        !(is >> q.q0) || !(is >> sep)  || !(sep == ',') ||
00131        !(is >> q.q1) || !(is >> sep)  || !(sep == ',') ||
00132        !(is >> q.q2) || !(is >> sep)  || !(sep == ',') ||
00133        !(is >> q.q3) || !(is >> sep)  || !(sep == ')') ) {
00134     is.clear();
00135     is.seekg(start_pos, std::ios::beg);
00136     is.setstate(std::ios::failbit);
00137   }
00138   return is;
00139 }
00140 
00141 
00142 cvm::quaternion
00143 cvm::quaternion::position_derivative_inner(cvm::rvector const &pos,
00144                                             cvm::rvector const &vec) const
00145 {
00146   cvm::quaternion result(0.0, 0.0, 0.0, 0.0);
00147 
00148 
00149   result.q0 =   2.0 * pos.x * q0 * vec.x
00150                +2.0 * pos.y * q0 * vec.y
00151                +2.0 * pos.z * q0 * vec.z
00152 
00153                -2.0 * pos.y * q3 * vec.x
00154                +2.0 * pos.z * q2 * vec.x
00155 
00156                +2.0 * pos.x * q3 * vec.y
00157                -2.0 * pos.z * q1 * vec.y
00158 
00159                -2.0 * pos.x * q2 * vec.z
00160                +2.0 * pos.y * q1 * vec.z;
00161 
00162 
00163   result.q1 =  +2.0 * pos.x * q1 * vec.x
00164                -2.0 * pos.y * q1 * vec.y
00165                -2.0 * pos.z * q1 * vec.z
00166 
00167                +2.0 * pos.y * q2 * vec.x
00168                +2.0 * pos.z * q3 * vec.x
00169 
00170                +2.0 * pos.x * q2 * vec.y
00171                -2.0 * pos.z * q0 * vec.y
00172 
00173                +2.0 * pos.x * q3 * vec.z
00174                +2.0 * pos.y * q0 * vec.z;
00175 
00176 
00177   result.q2 =  -2.0 * pos.x * q2 * vec.x
00178                +2.0 * pos.y * q2 * vec.y
00179                -2.0 * pos.z * q2 * vec.z
00180 
00181                +2.0 * pos.y * q1 * vec.x
00182                +2.0 * pos.z * q0 * vec.x
00183 
00184                +2.0 * pos.x * q1 * vec.y
00185                +2.0 * pos.z * q3 * vec.y
00186 
00187                -2.0 * pos.x * q0 * vec.z
00188                +2.0 * pos.y * q3 * vec.z;
00189 
00190 
00191   result.q3 =  -2.0 * pos.x * q3 * vec.x
00192                -2.0 * pos.y * q3 * vec.y
00193                +2.0 * pos.z * q3 * vec.z
00194 
00195                -2.0 * pos.y * q0 * vec.x
00196                +2.0 * pos.z * q1 * vec.x
00197 
00198                +2.0 * pos.x * q0 * vec.y
00199                +2.0 * pos.z * q2 * vec.y
00200 
00201                +2.0 * pos.x * q1 * vec.z
00202                +2.0 * pos.y * q2 * vec.z;
00203 
00204   return result;
00205 }
00206 
00207 
00208 
00209 
00210 // Calculate the optimal rotation between two groups, and implement it
00211 // as a quaternion.  Uses the method documented in: Coutsias EA,
00212 // Seok C, Dill KA.  Using quaternions to calculate RMSD.  J Comput
00213 // Chem. 25(15):1849-57 (2004) DOI: 10.1002/jcc.20110 PubMed: 15376254
00214 
00215 #ifdef COLVARS_LAMMPS
00216 namespace {
00217   inline void *new_Jacobi_solver(int size) {
00218     return reinterpret_cast<void *>(new MathEigen::Jacobi<cvm::real,
00219                                     cvm::vector1d<cvm::real> &,
00220                                     cvm::matrix2d<cvm::real> &>(4));
00221   }
00222 }
00223 #endif
00224 
00225 
00226 int colvarmodule::rotation::init()
00227 {
00228   b_debug_gradients = false;
00229   lambda = 0.0;
00230   cvm::main()->cite_feature("Optimal rotation via flexible fitting");
00231   return COLVARS_OK;
00232 }
00233 
00234 
00235 colvarmodule::rotation::rotation()
00236 {
00237   init();
00238 #ifdef COLVARS_LAMMPS
00239   jacobi = new_Jacobi_solver(4);
00240 #else
00241   jacobi = NULL;
00242 #endif
00243 }
00244 
00245 
00246 colvarmodule::rotation::rotation(cvm::quaternion const &qi)
00247   : q(qi)
00248 {
00249   init();
00250 #ifdef COLVARS_LAMMPS
00251   jacobi = new_Jacobi_solver(4);
00252 #else
00253   jacobi = NULL;
00254 #endif
00255 }
00256 
00257 
00258 colvarmodule::rotation::rotation(cvm::real angle, cvm::rvector const &axis)
00259 {
00260   init();
00261   cvm::rvector const axis_n = axis.unit();
00262   cvm::real const sina = cvm::sin(angle/2.0);
00263   q = cvm::quaternion(cvm::cos(angle/2.0),
00264                       sina * axis_n.x, sina * axis_n.y, sina * axis_n.z);
00265 #ifdef COLVARS_LAMMPS
00266   jacobi = new_Jacobi_solver(4);
00267 #else
00268   jacobi = NULL;
00269 #endif
00270 }
00271 
00272 
00273 colvarmodule::rotation::~rotation()
00274 {
00275 #ifdef COLVARS_LAMMPS
00276   delete reinterpret_cast<
00277     MathEigen::Jacobi<cvm::real,
00278                       cvm::vector1d<cvm::real> &,
00279                       cvm::matrix2d<cvm::real> &> *>(jacobi);
00280 #endif
00281 }
00282 
00283 
00284 void colvarmodule::rotation::build_correlation_matrix(
00285                                         std::vector<cvm::atom_pos> const &pos1,
00286                                         std::vector<cvm::atom_pos> const &pos2)
00287 {
00288   // build the correlation matrix
00289   size_t i;
00290   for (i = 0; i < pos1.size(); i++) {
00291     C.xx += pos1[i].x * pos2[i].x;
00292     C.xy += pos1[i].x * pos2[i].y;
00293     C.xz += pos1[i].x * pos2[i].z;
00294     C.yx += pos1[i].y * pos2[i].x;
00295     C.yy += pos1[i].y * pos2[i].y;
00296     C.yz += pos1[i].y * pos2[i].z;
00297     C.zx += pos1[i].z * pos2[i].x;
00298     C.zy += pos1[i].z * pos2[i].y;
00299     C.zz += pos1[i].z * pos2[i].z;
00300   }
00301 }
00302 
00303 
00304 void colvarmodule::rotation::compute_overlap_matrix()
00305 {
00306   // build the "overlap" matrix, whose eigenvectors are stationary
00307   // points of the RMSD in the space of rotations
00308   S[0][0] =    C.xx + C.yy + C.zz;
00309   S[1][0] =    C.yz - C.zy;
00310   S[0][1] = S[1][0];
00311   S[2][0] =  - C.xz + C.zx ;
00312   S[0][2] = S[2][0];
00313   S[3][0] =    C.xy - C.yx;
00314   S[0][3] = S[3][0];
00315   S[1][1] =    C.xx - C.yy - C.zz;
00316   S[2][1] =    C.xy + C.yx;
00317   S[1][2] = S[2][1];
00318   S[3][1] =    C.xz + C.zx;
00319   S[1][3] = S[3][1];
00320   S[2][2] = - C.xx + C.yy - C.zz;
00321   S[3][2] =   C.yz + C.zy;
00322   S[2][3] = S[3][2];
00323   S[3][3] = - C.xx - C.yy + C.zz;
00324 }
00325 
00326 
00327 #ifndef COLVARS_LAMMPS
00328 namespace {
00329 
00330 void diagonalize_matrix(cvm::matrix2d<cvm::real> &m,
00331                         cvm::vector1d<cvm::real> &eigval,
00332                         cvm::matrix2d<cvm::real> &eigvec)
00333 {
00334   eigval.resize(4);
00335   eigval.reset();
00336   eigvec.resize(4, 4);
00337   eigvec.reset();
00338 
00339   // diagonalize
00340   int jac_nrot = 0;
00341   if (NR_Jacobi::jacobi(m.c_array(), eigval.c_array(), eigvec.c_array(), &jac_nrot) !=
00342       COLVARS_OK) {
00343     cvm::error("Too many iterations in jacobi diagonalization.\n"
00344                "This is usually the result of an ill-defined set of atoms for "
00345                "rotational alignment (RMSD, rotateReference, etc).\n");
00346   }
00347   NR_Jacobi::eigsrt(eigval.c_array(), eigvec.c_array());
00348   // jacobi saves eigenvectors by columns
00349   NR_Jacobi::transpose(eigvec.c_array());
00350 
00351   // normalize eigenvectors
00352   for (size_t ie = 0; ie < 4; ie++) {
00353     cvm::real norm2 = 0.0;
00354     size_t i;
00355     for (i = 0; i < 4; i++) {
00356       norm2 += eigvec[ie][i] * eigvec[ie][i];
00357     }
00358     cvm::real const norm = cvm::sqrt(norm2);
00359     for (i = 0; i < 4; i++) {
00360       eigvec[ie][i] /= norm;
00361     }
00362   }
00363 }
00364 
00365 }
00366 #endif
00367 
00368 
00369 // Calculate the rotation, plus its derivatives
00370 
00371 void colvarmodule::rotation::calc_optimal_rotation(
00372                                         std::vector<cvm::atom_pos> const &pos1,
00373                                         std::vector<cvm::atom_pos> const &pos2)
00374 {
00375   C.reset();
00376   build_correlation_matrix(pos1, pos2);
00377 
00378   S.resize(4, 4);
00379   S.reset();
00380   compute_overlap_matrix();
00381 
00382   S_backup.resize(4, 4);
00383   S_backup = S;
00384 
00385   if (b_debug_gradients) {
00386     cvm::log("S     = "+cvm::to_str(S_backup, cvm::cv_width, cvm::cv_prec)+"\n");
00387   }
00388 
00389   S_eigval.resize(4);
00390   S_eigvec.resize(4, 4);
00391 
00392 #ifdef COLVARS_LAMMPS
00393   MathEigen::Jacobi<cvm::real,
00394                     cvm::vector1d<cvm::real> &,
00395                     cvm::matrix2d<cvm::real> &> *ecalc =
00396     reinterpret_cast<MathEigen::Jacobi<cvm::real,
00397                                        cvm::vector1d<cvm::real> &,
00398                                        cvm::matrix2d<cvm::real> &> *>(jacobi);
00399 
00400   int ierror = ecalc->Diagonalize(S, S_eigval, S_eigvec);
00401   if (ierror) {
00402     cvm::error("Too many iterations in jacobi diagonalization.\n"
00403                "This is usually the result of an ill-defined set of atoms for "
00404                "rotational alignment (RMSD, rotateReference, etc).\n");
00405   }
00406 #else
00407   diagonalize_matrix(S, S_eigval, S_eigvec);
00408 #endif
00409 
00410 
00411   // eigenvalues and eigenvectors
00412   cvm::real const L0 = S_eigval[0];
00413   cvm::real const L1 = S_eigval[1];
00414   cvm::real const L2 = S_eigval[2];
00415   cvm::real const L3 = S_eigval[3];
00416   cvm::quaternion const Q0(S_eigvec[0]);
00417   cvm::quaternion const Q1(S_eigvec[1]);
00418   cvm::quaternion const Q2(S_eigvec[2]);
00419   cvm::quaternion const Q3(S_eigvec[3]);
00420 
00421   lambda = L0;
00422   q = Q0;
00423 
00424   if (cvm::rotation::monitor_crossings) {
00425     if (q_old.norm2() > 0.0) {
00426       q.match(q_old);
00427       if (q_old.inner(q) < (1.0 - crossing_threshold)) {
00428         cvm::log("Warning: one molecular orientation has changed by more than "+
00429                  cvm::to_str(crossing_threshold)+": discontinuous rotation ?\n");
00430       }
00431     }
00432     q_old = q;
00433   }
00434 
00435   if (b_debug_gradients) {
00436     cvm::log("L0 = "+cvm::to_str(L0, cvm::cv_width, cvm::cv_prec)+
00437              ", Q0 = "+cvm::to_str(Q0, cvm::cv_width, cvm::cv_prec)+
00438              ", Q0*Q0 = "+cvm::to_str(Q0.inner(Q0), cvm::cv_width, cvm::cv_prec)+
00439              "\n");
00440     cvm::log("L1 = "+cvm::to_str(L1, cvm::cv_width, cvm::cv_prec)+
00441              ", Q1 = "+cvm::to_str(Q1, cvm::cv_width, cvm::cv_prec)+
00442              ", Q0*Q1 = "+cvm::to_str(Q0.inner(Q1), cvm::cv_width, cvm::cv_prec)+
00443              "\n");
00444     cvm::log("L2 = "+cvm::to_str(L2, cvm::cv_width, cvm::cv_prec)+
00445              ", Q2 = "+cvm::to_str(Q2, cvm::cv_width, cvm::cv_prec)+
00446              ", Q0*Q2 = "+cvm::to_str(Q0.inner(Q2), cvm::cv_width, cvm::cv_prec)+
00447              "\n");
00448     cvm::log("L3 = "+cvm::to_str(L3, cvm::cv_width, cvm::cv_prec)+
00449              ", Q3 = "+cvm::to_str(Q3, cvm::cv_width, cvm::cv_prec)+
00450              ", Q0*Q3 = "+cvm::to_str(Q0.inner(Q3), cvm::cv_width, cvm::cv_prec)+
00451              "\n");
00452   }
00453 
00454   // calculate derivatives of L0 and Q0 with respect to each atom in
00455   // either group; note: if dS_1 is a null vector, nothing will be
00456   // calculated
00457   size_t ia;
00458   for (ia = 0; ia < dS_1.size(); ia++) {
00459 
00460     cvm::real const &a2x = pos2[ia].x;
00461     cvm::real const &a2y = pos2[ia].y;
00462     cvm::real const &a2z = pos2[ia].z;
00463 
00464     cvm::matrix2d<cvm::rvector> &ds_1 = dS_1[ia];
00465 
00466     // derivative of the S matrix
00467     ds_1.reset();
00468     ds_1[0][0].set( a2x,  a2y,  a2z);
00469     ds_1[1][0].set( 0.0,  a2z, -a2y);
00470     ds_1[0][1] = ds_1[1][0];
00471     ds_1[2][0].set(-a2z,  0.0,  a2x);
00472     ds_1[0][2] = ds_1[2][0];
00473     ds_1[3][0].set( a2y, -a2x,  0.0);
00474     ds_1[0][3] = ds_1[3][0];
00475     ds_1[1][1].set( a2x, -a2y, -a2z);
00476     ds_1[2][1].set( a2y,  a2x,  0.0);
00477     ds_1[1][2] = ds_1[2][1];
00478     ds_1[3][1].set( a2z,  0.0,  a2x);
00479     ds_1[1][3] = ds_1[3][1];
00480     ds_1[2][2].set(-a2x,  a2y, -a2z);
00481     ds_1[3][2].set( 0.0,  a2z,  a2y);
00482     ds_1[2][3] = ds_1[3][2];
00483     ds_1[3][3].set(-a2x, -a2y,  a2z);
00484 
00485     cvm::rvector                &dl0_1 = dL0_1[ia];
00486     cvm::vector1d<cvm::rvector> &dq0_1 = dQ0_1[ia];
00487 
00488     // matrix multiplications; derivatives of L_0 and Q_0 are
00489     // calculated using Hellmann-Feynman theorem (i.e. exploiting the
00490     // fact that the eigenvectors Q_i form an orthonormal basis)
00491 
00492     dl0_1.reset();
00493     for (size_t i = 0; i < 4; i++) {
00494       for (size_t j = 0; j < 4; j++) {
00495         dl0_1 += Q0[i] * ds_1[i][j] * Q0[j];
00496       }
00497     }
00498 
00499     dq0_1.reset();
00500     for (size_t p = 0; p < 4; p++) {
00501       for (size_t i = 0; i < 4; i++) {
00502         for (size_t j = 0; j < 4; j++) {
00503           dq0_1[p] +=
00504             (Q1[i] * ds_1[i][j] * Q0[j]) / (L0-L1) * Q1[p] +
00505             (Q2[i] * ds_1[i][j] * Q0[j]) / (L0-L2) * Q2[p] +
00506             (Q3[i] * ds_1[i][j] * Q0[j]) / (L0-L3) * Q3[p];
00507         }
00508       }
00509     }
00510   }
00511 
00512   // do the same for the second group
00513   for (ia = 0; ia < dS_2.size(); ia++) {
00514 
00515     cvm::real const &a1x = pos1[ia].x;
00516     cvm::real const &a1y = pos1[ia].y;
00517     cvm::real const &a1z = pos1[ia].z;
00518 
00519     cvm::matrix2d<cvm::rvector> &ds_2 = dS_2[ia];
00520 
00521     ds_2.reset();
00522     ds_2[0][0].set( a1x,  a1y,  a1z);
00523     ds_2[1][0].set( 0.0, -a1z,  a1y);
00524     ds_2[0][1] = ds_2[1][0];
00525     ds_2[2][0].set( a1z,  0.0, -a1x);
00526     ds_2[0][2] = ds_2[2][0];
00527     ds_2[3][0].set(-a1y,  a1x,  0.0);
00528     ds_2[0][3] = ds_2[3][0];
00529     ds_2[1][1].set( a1x, -a1y, -a1z);
00530     ds_2[2][1].set( a1y,  a1x,  0.0);
00531     ds_2[1][2] = ds_2[2][1];
00532     ds_2[3][1].set( a1z,  0.0,  a1x);
00533     ds_2[1][3] = ds_2[3][1];
00534     ds_2[2][2].set(-a1x,  a1y, -a1z);
00535     ds_2[3][2].set( 0.0,  a1z,  a1y);
00536     ds_2[2][3] = ds_2[3][2];
00537     ds_2[3][3].set(-a1x, -a1y,  a1z);
00538 
00539     cvm::rvector                &dl0_2 = dL0_2[ia];
00540     cvm::vector1d<cvm::rvector> &dq0_2 = dQ0_2[ia];
00541 
00542     dl0_2.reset();
00543     for (size_t i = 0; i < 4; i++) {
00544       for (size_t j = 0; j < 4; j++) {
00545         dl0_2 += Q0[i] * ds_2[i][j] * Q0[j];
00546       }
00547     }
00548 
00549     dq0_2.reset();
00550     for (size_t p = 0; p < 4; p++) {
00551       for (size_t i = 0; i < 4; i++) {
00552         for (size_t j = 0; j < 4; j++) {
00553           dq0_2[p] +=
00554             (Q1[i] * ds_2[i][j] * Q0[j]) / (L0-L1) * Q1[p] +
00555             (Q2[i] * ds_2[i][j] * Q0[j]) / (L0-L2) * Q2[p] +
00556             (Q3[i] * ds_2[i][j] * Q0[j]) / (L0-L3) * Q3[p];
00557         }
00558       }
00559     }
00560 
00561     if (b_debug_gradients) {
00562 
00563       cvm::matrix2d<cvm::real> S_new(4, 4);
00564       cvm::vector1d<cvm::real> S_new_eigval(4);
00565       cvm::matrix2d<cvm::real> S_new_eigvec(4, 4);
00566 
00567       // make an infitesimal move along each cartesian coordinate of
00568       // this atom, and solve again the eigenvector problem
00569       for (size_t comp = 0; comp < 3; comp++) {
00570 
00571         S_new = S_backup;
00572         // diagonalize the new overlap matrix
00573         for (size_t i = 0; i < 4; i++) {
00574           for (size_t j = 0; j < 4; j++) {
00575             S_new[i][j] +=
00576               colvarmodule::debug_gradients_step_size * ds_2[i][j][comp];
00577           }
00578         }
00579 
00580         //           cvm::log("S_new = "+cvm::to_str(cvm::to_str (S_new), cvm::cv_width, cvm::cv_prec)+"\n");
00581 
00582 #ifdef COLVARS_LAMMPS
00583         ecalc->Diagonalize(S_new, S_new_eigval, S_new_eigvec);
00584 #else
00585         diagonalize_matrix(S_new, S_new_eigval, S_new_eigvec);
00586 #endif
00587 
00588         cvm::real const &L0_new = S_new_eigval[0];
00589         cvm::quaternion const Q0_new(S_new_eigvec[0]);
00590 
00591         cvm::real const DL0 = (dl0_2[comp]) * colvarmodule::debug_gradients_step_size;
00592         cvm::quaternion const DQ0(dq0_2[0][comp] * colvarmodule::debug_gradients_step_size,
00593                                   dq0_2[1][comp] * colvarmodule::debug_gradients_step_size,
00594                                   dq0_2[2][comp] * colvarmodule::debug_gradients_step_size,
00595                                   dq0_2[3][comp] * colvarmodule::debug_gradients_step_size);
00596 
00597         cvm::log(  "|(l_0+dl_0) - l_0^new|/l_0 = "+
00598                    cvm::to_str(cvm::fabs(L0+DL0 - L0_new)/L0, cvm::cv_width, cvm::cv_prec)+
00599                    ", |(q_0+dq_0) - q_0^new| = "+
00600                    cvm::to_str((Q0+DQ0 - Q0_new).norm(), cvm::cv_width, cvm::cv_prec)+
00601                    "\n");
00602       }
00603     }
00604   }
00605 }
00606 
00607 
00608 

Generated on Fri Apr 19 02:44:09 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002