00001 #ifndef COLVARTYPES_H
00002 #define COLVARTYPES_H
00003
00004 #include <cmath>
00005
00006 #ifndef PI
00007 #define PI 3.14159265358979323846
00008 #endif
00009
00010
00013
00014
00015
00017 class colvarmodule::rvector {
00018
00019 public:
00020
00021 cvm::real x, y, z;
00022
00023 inline rvector()
00024 : x (0.0), y (0.0), z (0.0)
00025 {}
00026
00027 inline rvector (cvm::real const &x_i,
00028 cvm::real const &y_i,
00029 cvm::real const &z_i)
00030 : x (x_i), y (y_i), z (z_i)
00031 {}
00032
00033 inline rvector (cvm::real v)
00034 : x (v), y (v), z (v)
00035 {}
00036
00038 inline void set (cvm::real const value = 0.0) {
00039 x = y = z = value;
00040 }
00041
00043 inline void reset() {
00044 x = y = z = 0.0;
00045 }
00046
00048 inline cvm::real & operator [] (int const &i) {
00049 return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x;
00050 }
00051
00053 inline cvm::real const & operator [] (int const &i) const {
00054 return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x;
00055 }
00056
00057
00058 inline cvm::rvector & operator = (cvm::real const &v)
00059 {
00060 x = v;
00061 y = v;
00062 z = v;
00063 return *this;
00064 }
00065
00066 inline void operator += (cvm::rvector const &v)
00067 {
00068 x += v.x;
00069 y += v.y;
00070 z += v.z;
00071 }
00072
00073 inline void operator -= (cvm::rvector const &v)
00074 {
00075 x -= v.x;
00076 y -= v.y;
00077 z -= v.z;
00078 }
00079
00080 inline void operator *= (cvm::real const &v)
00081 {
00082 x *= v;
00083 y *= v;
00084 z *= v;
00085 }
00086
00087 inline void operator /= (cvm::real const& v)
00088 {
00089 x /= v;
00090 y /= v;
00091 z /= v;
00092 }
00093
00094 inline cvm::real norm2() const
00095 {
00096 return (x*x + y*y + z*z);
00097 }
00098
00099 inline cvm::real norm() const
00100 {
00101 return std::sqrt (this->norm2());
00102 }
00103
00104 inline cvm::rvector unit() const
00105 {
00106 return cvm::rvector (x, y, z)/this->norm();
00107 }
00108
00109 static inline size_t output_width (size_t const &real_width)
00110 {
00111 return 3*real_width + 10;
00112 }
00113
00114
00115 static inline cvm::rvector outer (cvm::rvector const &v1, cvm::rvector const &v2)
00116 {
00117 return cvm::rvector ( v1.y*v2.z - v2.y*v1.z,
00118 -v1.x*v2.z + v2.x*v1.z,
00119 v1.x*v2.y - v2.x*v1.y);
00120 }
00121
00122 friend inline cvm::rvector operator - (cvm::rvector const &v)
00123 {
00124 return cvm::rvector (-v.x, -v.y, -v.z);
00125 }
00126
00127 friend inline int operator == (cvm::rvector const &v1, cvm::rvector const &v2)
00128 {
00129 return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z);
00130 }
00131
00132 friend inline int operator != (cvm::rvector const &v1, cvm::rvector const &v2)
00133 {
00134 return (v1.x != v2.x) || (v1.y != v2.y) || (v1.z != v2.z);
00135 }
00136
00137 friend inline cvm::rvector operator + (cvm::rvector const &v1, cvm::rvector const &v2)
00138 {
00139 return cvm::rvector (v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
00140 }
00141 friend inline cvm::rvector operator - (cvm::rvector const &v1, cvm::rvector const &v2)
00142 {
00143 return cvm::rvector (v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
00144 }
00145
00146 friend inline cvm::real operator * (cvm::rvector const &v1, cvm::rvector const &v2)
00147 {
00148 return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
00149 }
00150
00151 friend inline cvm::rvector operator * (cvm::real const &a, cvm::rvector const &v)
00152 {
00153 return cvm::rvector (a*v.x, a*v.y, a*v.z);
00154 }
00155
00156 friend inline cvm::rvector operator * (cvm::rvector const &v, cvm::real const &a)
00157 {
00158 return cvm::rvector (a*v.x, a*v.y, a*v.z);
00159 }
00160
00161 friend inline cvm::rvector operator / (cvm::rvector const &v, cvm::real const &a)
00162 {
00163 return cvm::rvector (v.x/a, v.y/a, v.z/a);
00164 }
00165
00166
00167 };
00168
00169
00170
00174 template <class T, size_t const length> class colvarmodule::vector1d
00175 {
00176 protected:
00177
00179 T *array;
00180
00181 public:
00182
00184 inline size_t size()
00185 {
00186 return length;
00187 }
00188
00190 inline vector1d (T const &t = T())
00191 {
00192 array = new T[length];
00193 reset();
00194 }
00195
00197 inline void reset()
00198 {
00199 for (size_t i = 0; i < length; i++) {
00200 array[i] = T (0.0);
00201 }
00202 }
00203
00205 inline vector1d (T const *v)
00206 {
00207 array = new T[length];
00208 for (size_t i = 0; i < length; i++) {
00209 array[i] = v[i];
00210 }
00211 }
00212
00214 inline vector1d (vector1d<T, length> const &v)
00215 {
00216 array = new T[length];
00217 for (size_t i = 0; i < length; i++) {
00218 array[i] = v.array[i];
00219 }
00220 }
00221
00223 inline vector1d<T, length> & operator = (vector1d<T, length> const &v)
00224 {
00225 for (size_t i = 0; i < length; i++) {
00226 this->array[i] = v.array[i];
00227 }
00228 return *this;
00229 }
00230
00232 inline ~vector1d() {
00233 delete [] array;
00234 }
00235
00237 inline T *c_array() { return array; }
00238
00240 inline operator T *() { return array; }
00241
00243 inline friend T operator * (vector1d<T, length> const &v1,
00244 vector1d<T, length> const &v2)
00245 {
00246 T prod (0.0);
00247 for (size_t i = 0; i < length; i++) {
00248 prod += v1.array[i] * v2.array[i];
00249 }
00250 return prod;
00251 }
00252
00254 friend std::ostream & operator << (std::ostream &os,
00255 vector1d<T, length> const &v)
00256 {
00257 std::streamsize const w = os.width();
00258 std::streamsize const p = os.precision();
00259
00260 os << "( ";
00261 for (size_t i = 0; i < length-1; i++) {
00262 os.width (w); os.precision (p);
00263 os << v.array[i] << " , ";
00264 }
00265 os.width (w); os.precision (p);
00266 os << v.array[length-1] << " )";
00267 return os;
00268 }
00269
00270 };
00271
00272
00273
00277 template <class T,
00278 size_t const outer_length,
00279 size_t const inner_length> class colvarmodule::matrix2d
00280 {
00281 protected:
00282
00284 T **array;
00285
00286 public:
00287
00289 inline void alloc() {
00290 array = new T * [outer_length];
00291 for (size_t i = 0; i < outer_length; i++) {
00292 array[i] = new T [inner_length];
00293 }
00294 }
00295
00297 inline void reset()
00298 {
00299 for (size_t i = 0; i < outer_length; i++) {
00300 for (size_t j = 0; j < inner_length; j++) {
00301 array[i][j] = T (0.0);
00302 }
00303 }
00304 }
00305
00307 inline matrix2d()
00308 {
00309 this->alloc();
00310 reset();
00311 }
00312
00314 inline matrix2d (T const **m)
00315 {
00316 this->alloc();
00317 for (size_t i = 0; i < outer_length; i++) {
00318 for (size_t j = 0; j < inner_length; j++)
00319 array[i][j] = m[i][j];
00320 }
00321 }
00322
00324 inline matrix2d (matrix2d<T, outer_length, inner_length> const &m)
00325 {
00326 this->alloc();
00327 for (size_t i = 0; i < outer_length; i++) {
00328 for (size_t j = 0; j < inner_length; j++)
00329 this->array[i][j] = m.array[i][j];
00330 }
00331 }
00332
00334 inline matrix2d<T, outer_length, inner_length> &
00335 operator = (matrix2d<T, outer_length, inner_length> const &m)
00336 {
00337 for (size_t i = 0; i < outer_length; i++) {
00338 for (size_t j = 0; j < inner_length; j++)
00339 this->array[i][j] = m.array[i][j];
00340 }
00341 return *this;
00342 }
00343
00345 inline ~matrix2d() {
00346 for (size_t i = 0; i < outer_length; i++) {
00347 delete [] array[i];
00348 }
00349 delete [] array;
00350 }
00351
00353 inline T **c_array() { return array; }
00354
00356 inline operator T **() { return array; }
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00383 friend std::ostream & operator << (std::ostream &os,
00384 matrix2d<T, outer_length, inner_length> const &m)
00385 {
00386 std::streamsize const w = os.width();
00387 std::streamsize const p = os.precision();
00388
00389 os << "(";
00390 for (size_t i = 0; i < outer_length; i++) {
00391 os << " ( ";
00392 for (size_t j = 0; j < inner_length-1; j++) {
00393 os.width (w);
00394 os.precision (p);
00395 os << m.array[i][j] << " , ";
00396 }
00397 os.width (w);
00398 os.precision (p);
00399 os << m.array[i][inner_length-1] << " )";
00400 }
00401
00402 os << " )";
00403 return os;
00404 }
00405
00406 };
00407
00408
00411 class colvarmodule::rmatrix
00412 : public colvarmodule::matrix2d<colvarmodule::real, 3, 3> {
00413 private:
00414
00415 public:
00416
00418 inline cvm::real & xx() { return array[0][0]; }
00420 inline cvm::real & xy() { return array[0][1]; }
00422 inline cvm::real & xz() { return array[0][2]; }
00424 inline cvm::real & yx() { return array[1][0]; }
00426 inline cvm::real & yy() { return array[1][1]; }
00428 inline cvm::real & yz() { return array[1][2]; }
00430 inline cvm::real & zx() { return array[2][0]; }
00432 inline cvm::real & zy() { return array[2][1]; }
00434 inline cvm::real & zz() { return array[2][2]; }
00435
00437 inline cvm::real xx() const { return array[0][0]; }
00439 inline cvm::real xy() const { return array[0][1]; }
00441 inline cvm::real xz() const { return array[0][2]; }
00443 inline cvm::real yx() const { return array[1][0]; }
00445 inline cvm::real yy() const { return array[1][1]; }
00447 inline cvm::real yz() const { return array[1][2]; }
00449 inline cvm::real zx() const { return array[2][0]; }
00451 inline cvm::real zy() const { return array[2][1]; }
00453 inline cvm::real zz() const { return array[2][2]; }
00454
00456 inline rmatrix (cvm::real const **m)
00457 : cvm::matrix2d<cvm::real, 3, 3> (m)
00458 {}
00459
00461 inline rmatrix()
00462 : cvm::matrix2d<cvm::real, 3, 3>()
00463 {}
00464
00466 inline rmatrix (cvm::real const &xxi,
00467 cvm::real const &xyi,
00468 cvm::real const &xzi,
00469 cvm::real const &yxi,
00470 cvm::real const &yyi,
00471 cvm::real const &yzi,
00472 cvm::real const &zxi,
00473 cvm::real const &zyi,
00474 cvm::real const &zzi)
00475 : cvm::matrix2d<cvm::real, 3, 3>()
00476 {
00477 this->xx() = xxi;
00478 this->xy() = xyi;
00479 this->xz() = xzi;
00480 this->yx() = yxi;
00481 this->yy() = yyi;
00482 this->yz() = yzi;
00483 this->zx() = zxi;
00484 this->zy() = zyi;
00485 this->zz() = zzi;
00486 }
00487
00489 inline ~rmatrix()
00490 {}
00491
00493 inline cvm::real determinant() const
00494 {
00495 return
00496 ( xx() * (yy()*zz() - zy()*yz()))
00497 - (yx() * (xy()*zz() - zy()*xz()))
00498 + (zx() * (xy()*yz() - yy()*xz()));
00499 }
00500
00501 inline cvm::rmatrix transpose() const
00502 {
00503 return cvm::rmatrix (this->xx(),
00504 this->yx(),
00505 this->zx(),
00506 this->xy(),
00507 this->yy(),
00508 this->zy(),
00509 this->xz(),
00510 this->yz(),
00511 this->zz());
00512 }
00513
00514 friend cvm::rvector operator * (cvm::rmatrix const &m, cvm::rvector const &r);
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528 };
00529
00530
00531 inline cvm::rvector operator * (cvm::rmatrix const &m,
00532 cvm::rvector const &r)
00533 {
00534 return cvm::rvector (m.xx()*r.x + m.xy()*r.y + m.xz()*r.z,
00535 m.yx()*r.x + m.yy()*r.y + m.yz()*r.z,
00536 m.zx()*r.x + m.zy()*r.y + m.zz()*r.z);
00537 }
00538
00539
00541 void jacobi (cvm::real **a, int n, cvm::real d[], cvm::real **v, int *nrot);
00542
00544 void eigsrt (cvm::real d[], cvm::real **v, int n);
00545
00547 void transpose (cvm::real **v, int n);
00548
00549
00550
00551
00554 class colvarmodule::quaternion {
00555
00556 public:
00557
00558 cvm::real q0, q1, q2, q3;
00559
00561 inline quaternion (cvm::real const &x, cvm::real const &y, cvm::real const &z)
00562 : q0 (0.0), q1 (x), q2 (y), q3 (z)
00563 {}
00564
00566 inline quaternion (cvm::real const qv[4])
00567 : q0 (qv[0]), q1 (qv[1]), q2 (qv[2]), q3 (qv[3])
00568 {}
00569
00571 inline quaternion (cvm::real const &q0i,
00572 cvm::real const &q1i,
00573 cvm::real const &q2i,
00574 cvm::real const &q3i)
00575 : q0 (q0i), q1 (q1i), q2 (q2i), q3 (q3i)
00576 {}
00577
00581 inline void set_from_euler_angles (cvm::real const &phi_in,
00582 cvm::real const &theta_in,
00583 cvm::real const &psi_in)
00584 {
00585 q0 = ( (std::cos (phi_in/2.0)) * (std::cos (theta_in/2.0)) * (std::cos (psi_in/2.0)) +
00586 (std::sin (phi_in/2.0)) * (std::sin (theta_in/2.0)) * (std::sin (psi_in/2.0)) );
00587
00588 q1 = ( (std::sin (phi_in/2.0)) * (std::cos (theta_in/2.0)) * (std::cos (psi_in/2.0)) -
00589 (std::cos (phi_in/2.0)) * (std::sin (theta_in/2.0)) * (std::sin (psi_in/2.0)) );
00590
00591 q2 = ( (std::cos (phi_in/2.0)) * (std::sin (theta_in/2.0)) * (std::cos (psi_in/2.0)) +
00592 (std::sin (phi_in/2.0)) * (std::cos (theta_in/2.0)) * (std::sin (psi_in/2.0)) );
00593
00594 q3 = ( (std::cos (phi_in/2.0)) * (std::cos (theta_in/2.0)) * (std::sin (psi_in/2.0)) -
00595 (std::sin (phi_in/2.0)) * (std::sin (theta_in/2.0)) * (std::cos (psi_in/2.0)) );
00596 }
00597
00599 inline quaternion()
00600 {
00601 reset();
00602 }
00603
00605 inline void set (cvm::real const value = 0.0)
00606 {
00607 q0 = q1 = q2 = q3 = value;
00608 }
00609
00611 inline void reset()
00612 {
00613 q0 = q1 = q2 = q3 = 0.0;
00614 }
00615
00618 inline void reset_rotation()
00619 {
00620 q0 = 1.0;
00621 q1 = q2 = q3 = 0.0;
00622 }
00623
00625 static inline size_t output_width (size_t const &real_width)
00626 {
00627 return 4*real_width + 13;
00628 }
00629
00631 friend std::ostream & operator << (std::ostream &os, cvm::quaternion const &q);
00633 friend std::istream & operator >> (std::istream &is, cvm::quaternion &q);
00634
00636 inline cvm::real & operator [] (int const &i) {
00637 switch (i) {
00638 case 0:
00639 return this->q0;
00640 case 1:
00641 return this->q1;
00642 case 2:
00643 return this->q2;
00644 case 3:
00645 return this->q3;
00646 default:
00647 cvm::fatal_error ("Error: incorrect quaternion component.\n");
00648 return q0;
00649 }
00650 }
00651
00653 inline cvm::real operator [] (int const &i) const {
00654 switch (i) {
00655 case 0:
00656 return this->q0;
00657 case 1:
00658 return this->q1;
00659 case 2:
00660 return this->q2;
00661 case 3:
00662 return this->q3;
00663 default:
00664 cvm::fatal_error ("Error: trying to access a quaternion "
00665 "component which is not between 0 and 3.\n");
00666 return this->q0;
00667 }
00668 }
00669
00671 inline cvm::real norm2() const
00672 {
00673 return q0*q0 + q1*q1 + q2*q2 + q3*q3;
00674 }
00675
00677 inline cvm::real norm() const
00678 {
00679 return std::sqrt (this->norm2());
00680 }
00681
00683 inline cvm::quaternion conjugate() const
00684 {
00685 return cvm::quaternion (q0, -q1, -q2, -q3);
00686 }
00687
00688 inline void operator *= (cvm::real const &a)
00689 {
00690 q0 *= a; q1 *= a; q2 *= a; q3 *= a;
00691 }
00692
00693 inline void operator /= (cvm::real const &a)
00694 {
00695 q0 /= a; q1 /= a; q2 /= a; q3 /= a;
00696 }
00697
00698 inline void set_positive()
00699 {
00700 if (q0 > 0.0) return;
00701 q0 = -q0;
00702 q1 = -q1;
00703 q2 = -q2;
00704 q3 = -q3;
00705 }
00706
00707 inline void operator += (cvm::quaternion const &h)
00708 {
00709 q0+=h.q0; q1+=h.q1; q2+=h.q2; q3+=h.q3;
00710 }
00711 inline void operator -= (cvm::quaternion const &h)
00712 {
00713 q0-=h.q0; q1-=h.q1; q2-=h.q2; q3-=h.q3;
00714 }
00715
00717 static inline cvm::quaternion promote (cvm::rvector const &v)
00718 {
00719 return cvm::quaternion (0.0, v.x, v.y, v.z);
00720 }
00722 inline cvm::rvector get_vector() const
00723 {
00724 return cvm::rvector (q1, q2, q3);
00725 }
00726
00727
00728 friend inline cvm::quaternion operator + (cvm::quaternion const &h, cvm::quaternion const &q)
00729 {
00730 return cvm::quaternion (h.q0+q.q0, h.q1+q.q1, h.q2+q.q2, h.q3+q.q3);
00731 }
00732
00733 friend inline cvm::quaternion operator - (cvm::quaternion const &h, cvm::quaternion const &q)
00734 {
00735 return cvm::quaternion (h.q0-q.q0, h.q1-q.q1, h.q2-q.q2, h.q3-q.q3);
00736 }
00737
00740 friend inline cvm::quaternion operator * (cvm::quaternion const &h, cvm::quaternion const &q)
00741 {
00742 return cvm::quaternion (h.q0*q.q0 - h.q1*q.q1 - h.q2*q.q2 - h.q3*q.q3,
00743 h.q0*q.q1 + h.q1*q.q0 + h.q2*q.q3 - h.q3*q.q2,
00744 h.q0*q.q2 + h.q2*q.q0 + h.q3*q.q1 - h.q1*q.q3,
00745 h.q0*q.q3 + h.q3*q.q0 + h.q1*q.q2 - h.q2*q.q1);
00746 }
00747
00748 friend inline cvm::quaternion operator * (cvm::real const &c,
00749 cvm::quaternion const &q)
00750 {
00751 return cvm::quaternion (c*q.q0, c*q.q1, c*q.q2, c*q.q3);
00752 }
00753 friend inline cvm::quaternion operator * (cvm::quaternion const &q,
00754 cvm::real const &c)
00755 {
00756 return cvm::quaternion (q.q0*c, q.q1*c, q.q2*c, q.q3*c);
00757 }
00758 friend inline cvm::quaternion operator / (cvm::quaternion const &q,
00759 cvm::real const &c)
00760 {
00761 return cvm::quaternion (q.q0/c, q.q1/c, q.q2/c, q.q3/c);
00762 }
00763
00764
00767 inline cvm::rvector rotate (cvm::rvector const &v) const
00768 {
00769 return ((*this) * promote (v) * ((*this).conjugate())).get_vector();
00770 }
00771
00774 inline cvm::quaternion rotate (cvm::quaternion const &Q2) const
00775 {
00776 cvm::rvector const vq_rot = this->rotate (Q2.get_vector());
00777 return cvm::quaternion (Q2.q0, vq_rot.x, vq_rot.y, vq_rot.z);
00778 }
00779
00781 inline cvm::rmatrix rotation_matrix() const
00782 {
00783 cvm::rmatrix R;
00784
00785 R.xx() = q0*q0 + q1*q1 - q2*q2 - q3*q3;
00786 R.yy() = q0*q0 - q1*q1 + q2*q2 - q3*q3;
00787 R.zz() = q0*q0 - q1*q1 - q2*q2 + q3*q3;
00788
00789 R.xy() = 2.0 * (q1*q2 - q0*q3);
00790 R.xz() = 2.0 * (q0*q2 + q1*q3);
00791
00792 R.yx() = 2.0 * (q0*q3 + q1*q2);
00793 R.yz() = 2.0 * (q2*q3 - q0*q1);
00794
00795 R.zx() = 2.0 * (q1*q3 - q0*q2);
00796 R.zy() = 2.0 * (q0*q1 + q2*q3);
00797
00798 return R;
00799 }
00800
00801
00804 cvm::quaternion position_derivative_inner (cvm::rvector const &pos,
00805 cvm::rvector const &vec) const;
00806
00807
00810 inline cvm::real cosine (cvm::quaternion const &q) const
00811 {
00812 if (q0*q0 >= (1.0-1.0E-10)) {
00813
00814
00815 return (2.0*q.q0*q.q0 - 1.0);
00816 } else if (q.q0*q.q0 >= (1.0-1.0E-10)) {
00817 return (2.0*q0*q0 - 1.0);
00818 } else {
00819
00820 cvm::rvector const op = (cvm::rvector::outer (this->get_vector(), q.get_vector()));
00821 cvm::real const opl2 = op.norm2();
00822
00823 return ( (opl2 > 0.0) ?
00824 ((this->rotate (op)) * (q.rotate (op))) / opl2 :
00825 1.0 );
00826 }
00827 }
00828
00832 inline cvm::real dist2 (cvm::quaternion const &Q2) const
00833 {
00834 cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 +
00835 this->q2*Q2.q2 + this->q3*Q2.q3;
00836
00837 cvm::real const omega = std::acos ( (cos_omega > 1.0) ? 1.0 :
00838 ( (cos_omega < -1.0) ? -1.0 : cos_omega) );
00839
00840
00841 if (cos_omega > 0.0)
00842 return omega * omega;
00843 else
00844 return (PI-omega) * (PI-omega);
00845 }
00846
00849 inline cvm::quaternion dist2_grad (cvm::quaternion const &Q2) const
00850 {
00851 cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 + this->q2*Q2.q2 + this->q3*Q2.q3;
00852 cvm::real const omega = std::acos ( (cos_omega > 1.0) ? 1.0 :
00853 ( (cos_omega < -1.0) ? -1.0 : cos_omega) );
00854 cvm::real const sin_omega = std::sin (omega);
00855
00856 if (std::fabs (sin_omega) < 1.0E-14) {
00857
00858 return cvm::quaternion (0.0, 0.0, 0.0, 0.0);
00859 }
00860
00861 cvm::quaternion const
00862 grad1 ((-1.0)*sin_omega*Q2.q0 + cos_omega*(this->q0-cos_omega*Q2.q0)/sin_omega,
00863 (-1.0)*sin_omega*Q2.q1 + cos_omega*(this->q1-cos_omega*Q2.q1)/sin_omega,
00864 (-1.0)*sin_omega*Q2.q2 + cos_omega*(this->q2-cos_omega*Q2.q2)/sin_omega,
00865 (-1.0)*sin_omega*Q2.q3 + cos_omega*(this->q3-cos_omega*Q2.q3)/sin_omega);
00866
00867 if (cos_omega > 0.0) {
00868 return 2.0*omega*grad1;
00869 }
00870 else {
00871 return -2.0*(PI-omega)*grad1;
00872 }
00873 }
00874
00877 inline void match (cvm::quaternion &Q2) const
00878 {
00879 cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 +
00880 this->q2*Q2.q2 + this->q3*Q2.q3;
00881 if (cos_omega < 0.0) Q2 *= -1.0;
00882 }
00883
00886 inline cvm::real inner (cvm::quaternion const &Q2) const
00887 {
00888 cvm::real const prod = this->q0*Q2.q0 + this->q1*Q2.q1 +
00889 this->q2*Q2.q2 + this->q3*Q2.q3;
00890 return prod;
00891 }
00892
00893
00894 };
00895
00896
00899 class colvarmodule::rotation
00900 {
00901 public:
00902
00904 cvm::quaternion q;
00905
00907 cvm::real lambda;
00908
00910 bool b_debug_gradients;
00911
00914 std::vector< cvm::atom_pos > pos1, pos2;
00915
00917 std::vector< cvm::matrix2d<cvm::rvector, 4, 4> > dS_1, dS_2;
00919 std::vector< cvm::rvector > dL0_1, dL0_2;
00921 std::vector< cvm::vector1d<cvm::rvector, 4> > dQ0_1, dQ0_2;
00922
00924 inline void request_group1_gradients (size_t const &n)
00925 {
00926 dS_1.resize (n, cvm::matrix2d<cvm::rvector, 4, 4>());
00927 dL0_1.resize (n, cvm::rvector (0.0, 0.0, 0.0));
00928 dQ0_1.resize (n, cvm::vector1d<cvm::rvector, 4>());
00929 }
00930
00931 inline void request_group2_gradients (size_t const &n)
00932 {
00933 dS_2.resize (n, cvm::matrix2d<cvm::rvector, 4, 4>());
00934 dL0_2.resize (n, cvm::rvector (0.0, 0.0, 0.0));
00935 dQ0_2.resize (n, cvm::vector1d<cvm::rvector, 4>());
00936 }
00937
00948 void calc_optimal_rotation (std::vector<atom_pos> const &pos1,
00949 std::vector<atom_pos> const &pos2);
00950
00952 inline rotation()
00953 : b_debug_gradients (false)
00954 {}
00955
00957 inline rotation (cvm::quaternion const &qi)
00958 : b_debug_gradients (false)
00959 {
00960 q = qi;
00961 }
00962
00964 inline rotation (cvm::real const &angle, cvm::rvector const &axis)
00965 : b_debug_gradients (false)
00966 {
00967 cvm::rvector const axis_n = axis.unit();
00968 cvm::real const sina = std::sin (angle/2.0);
00969 q = cvm::quaternion (std::cos (angle/2.0),
00970 sina * axis_n.x, sina * axis_n.y, sina * axis_n.z);
00971 }
00972
00974 inline ~rotation()
00975 {}
00976
00978 inline cvm::rvector rotate (cvm::rvector const &v) const
00979 {
00980 return q.rotate (v);
00981 }
00982
00984 inline cvm::rotation inverse() const
00985 {
00986 return cvm::rotation (this->q.conjugate());
00987 }
00988
00990 inline cvm::rmatrix matrix() const
00991 {
00992 return q.rotation_matrix();
00993 }
00994
00995
00998 inline cvm::real spin_angle (cvm::rvector const &axis) const
00999 {
01000 cvm::rvector const q_vec = q.get_vector();
01001 cvm::real alpha = (180.0/PI) * 2.0 * std::atan2 (axis * q_vec, q.q0);
01002 while (alpha > 180.0) alpha -= 360;
01003 while (alpha < -180.0) alpha += 360;
01004 return alpha;
01005 }
01006
01009 inline cvm::quaternion dspin_angle_dq (cvm::rvector const &axis) const
01010 {
01011 cvm::rvector const q_vec = q.get_vector();
01012 cvm::real const iprod = axis * q_vec;
01013
01014 if (q.q0 != 0.0) {
01015
01016
01017
01018 cvm::real const dspindx = (180.0/PI) * 2.0 * (1.0 / (1.0 + (iprod*iprod)/(q.q0*q.q0)));
01019
01020 return
01021 cvm::quaternion ( dspindx * (iprod * (-1.0) / (q.q0*q.q0)),
01022 dspindx * ((1.0/q.q0) * axis.x),
01023 dspindx * ((1.0/q.q0) * axis.y),
01024 dspindx * ((1.0/q.q0) * axis.z));
01025 } else {
01026
01027 return
01028 cvm::quaternion ((180.0/PI) * 2.0 * ((-1.0)/iprod), 0.0, 0.0, 0.0);
01029
01030 }
01031 }
01032
01035 inline cvm::real cos_theta (cvm::rvector const &axis) const
01036 {
01037 cvm::rvector const q_vec = q.get_vector();
01038 cvm::real const alpha =
01039 (180.0/PI) * 2.0 * std::atan2 (axis * q_vec, q.q0);
01040
01041 cvm::real const cos_spin_2 = std::cos (alpha * (PI/180.0) * 0.5);
01042 cvm::real const cos_theta_2 = ( (cos_spin_2 != 0.0) ?
01043 (q.q0 / cos_spin_2) :
01044 (0.0) );
01045
01046 return 2.0 * (cos_theta_2*cos_theta_2) - 1.0;
01047 }
01048
01050 inline cvm::quaternion dcos_theta_dq (cvm::rvector const &axis) const
01051 {
01052 cvm::rvector const q_vec = q.get_vector();
01053 cvm::real const iprod = axis * q_vec;
01054
01055 cvm::real const cos_spin_2 = std::cos (std::atan2 (iprod, q.q0));
01056
01057 if (q.q0 != 0.0) {
01058
01059 cvm::real const d_cos_theta_dq0 =
01060 (4.0 * q.q0 / (cos_spin_2*cos_spin_2)) *
01061 (1.0 - (iprod*iprod)/(q.q0*q.q0) / (1.0 + (iprod*iprod)/(q.q0*q.q0)));
01062
01063 cvm::real const d_cos_theta_dqn =
01064 (4.0 * q.q0 / (cos_spin_2*cos_spin_2) *
01065 (iprod/q.q0) / (1.0 + (iprod*iprod)/(q.q0*q.q0)));
01066
01067 return cvm::quaternion (d_cos_theta_dq0,
01068 d_cos_theta_dqn * axis.x,
01069 d_cos_theta_dqn * axis.y,
01070 d_cos_theta_dqn * axis.z);
01071 } else {
01072
01073 cvm::real const d_cos_theta_dqn =
01074 (4.0 / (cos_spin_2*cos_spin_2 * iprod));
01075
01076 return cvm::quaternion (0.0,
01077 d_cos_theta_dqn * axis.x,
01078 d_cos_theta_dqn * axis.y,
01079 d_cos_theta_dqn * axis.z);
01080 }
01081 }
01082
01084 static cvm::real crossing_threshold;
01085
01086 protected:
01087
01091 cvm::quaternion q_old;
01092
01094 void build_matrix (std::vector<cvm::atom_pos> const &pos1,
01095 std::vector<cvm::atom_pos> const &pos2,
01096 cvm::matrix2d<real, 4, 4> &S);
01097
01099 void diagonalize_matrix (cvm::matrix2d<cvm::real, 4, 4> &S,
01100 cvm::real S_eigval[4],
01101 cvm::matrix2d<cvm::real, 4, 4> &S_eigvec);
01102 };
01103
01104
01105 #endif
01106
01107
01108
01109
01110