00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef COLVARTYPES_H
00011 #define COLVARTYPES_H
00012
00013 #include <vector>
00014
00015 #include "colvarmodule.h"
00016
00017 #ifndef PI
00018 #define PI 3.14159265358979323846
00019 #endif
00020
00021
00024
00025
00026
00030 template <class T> class colvarmodule::vector1d
00031 {
00032 protected:
00033
00034 std::vector<T> data;
00035
00036 public:
00037
00039 inline vector1d(size_t const n = 0)
00040 {
00041 data.resize(n);
00042 reset();
00043 }
00044
00046 inline vector1d(size_t const n, T const *t)
00047 {
00048 data.resize(n);
00049 reset();
00050 size_t i;
00051 for (i = 0; i < size(); i++) {
00052 data[i] = t[i];
00053 }
00054 }
00055
00057 inline T * c_array()
00058 {
00059 if (data.size() > 0) {
00060 return &(data[0]);
00061 } else {
00062 return NULL;
00063 }
00064 }
00065
00067 inline std::vector<T> &data_array()
00068 {
00069 return data;
00070 }
00071
00072 inline ~vector1d()
00073 {
00074 data.clear();
00075 }
00076
00078 inline void reset()
00079 {
00080 data.assign(data.size(), T(0.0));
00081 }
00082
00083 inline size_t size() const
00084 {
00085 return data.size();
00086 }
00087
00088 inline void resize(size_t const n)
00089 {
00090 data.resize(n);
00091 }
00092
00093 inline void clear()
00094 {
00095 data.clear();
00096 }
00097
00098 inline T & operator [] (size_t const i) {
00099 return data[i];
00100 }
00101
00102 inline T const & operator [] (size_t const i) const {
00103 return data[i];
00104 }
00105
00106 inline static void check_sizes(vector1d<T> const &v1, vector1d<T> const &v2)
00107 {
00108 if (v1.size() != v2.size()) {
00109 cvm::error("Error: trying to perform an operation between vectors of different sizes, "+
00110 cvm::to_str(v1.size())+" and "+cvm::to_str(v2.size())+".\n");
00111 }
00112 }
00113
00114 inline void operator += (vector1d<T> const &v)
00115 {
00116 check_sizes(*this, v);
00117 size_t i;
00118 for (i = 0; i < this->size(); i++) {
00119 (*this)[i] += v[i];
00120 }
00121 }
00122
00123 inline void operator -= (vector1d<T> const &v)
00124 {
00125 check_sizes(*this, v);
00126 size_t i;
00127 for (i = 0; i < this->size(); i++) {
00128 (*this)[i] -= v[i];
00129 }
00130 }
00131
00132 inline void operator *= (cvm::real a)
00133 {
00134 size_t i;
00135 for (i = 0; i < this->size(); i++) {
00136 (*this)[i] *= a;
00137 }
00138 }
00139
00140 inline void operator /= (cvm::real a)
00141 {
00142 size_t i;
00143 for (i = 0; i < this->size(); i++) {
00144 (*this)[i] /= a;
00145 }
00146 }
00147
00148 inline friend vector1d<T> operator + (vector1d<T> const &v1,
00149 vector1d<T> const &v2)
00150 {
00151 check_sizes(v1.size(), v2.size());
00152 vector1d<T> result(v1.size());
00153 size_t i;
00154 for (i = 0; i < v1.size(); i++) {
00155 result[i] = v1[i] + v2[i];
00156 }
00157 return result;
00158 }
00159
00160 inline friend vector1d<T> operator - (vector1d<T> const &v1,
00161 vector1d<T> const &v2)
00162 {
00163 check_sizes(v1.size(), v2.size());
00164 vector1d<T> result(v1.size());
00165 size_t i;
00166 for (i = 0; i < v1.size(); i++) {
00167 result[i] = v1[i] - v2[i];
00168 }
00169 return result;
00170 }
00171
00172 inline friend vector1d<T> operator * (vector1d<T> const &v, cvm::real a)
00173 {
00174 vector1d<T> result(v.size());
00175 size_t i;
00176 for (i = 0; i < v.size(); i++) {
00177 result[i] = v[i] * a;
00178 }
00179 return result;
00180 }
00181
00182 inline friend vector1d<T> operator * (cvm::real a, vector1d<T> const &v)
00183 {
00184 return v * a;
00185 }
00186
00187 inline friend vector1d<T> operator / (vector1d<T> const &v, cvm::real a)
00188 {
00189 vector1d<T> result(v.size());
00190 size_t i;
00191 for (i = 0; i < v.size(); i++) {
00192 result[i] = v[i] / a;
00193 }
00194 return result;
00195 }
00196
00198 inline friend T operator * (vector1d<T> const &v1, vector1d<T> const &v2)
00199 {
00200 check_sizes(v1.size(), v2.size());
00201 T prod(0.0);
00202 size_t i;
00203 for (i = 0; i < v1.size(); i++) {
00204 prod += v1[i] * v2[i];
00205 }
00206 return prod;
00207 }
00208
00210 inline cvm::real norm2() const
00211 {
00212 cvm::real result = 0.0;
00213 size_t i;
00214 for (i = 0; i < this->size(); i++) {
00215 result += (*this)[i] * (*this)[i];
00216 }
00217 return result;
00218 }
00219
00220 inline cvm::real norm() const
00221 {
00222 return cvm::sqrt(this->norm2());
00223 }
00224
00225 inline cvm::real sum() const
00226 {
00227 cvm::real result = 0.0;
00228 size_t i;
00229 for (i = 0; i < this->size(); i++) {
00230 result += (*this)[i];
00231 }
00232 return result;
00233 }
00234
00236 inline vector1d<T> const slice(size_t const i1, size_t const i2) const
00237 {
00238 if ((i2 < i1) || (i2 >= this->size())) {
00239 cvm::error("Error: trying to slice a vector using incorrect boundaries.\n");
00240 }
00241 vector1d<T> result(i2 - i1);
00242 size_t i;
00243 for (i = 0; i < (i2 - i1); i++) {
00244 result[i] = (*this)[i1+i];
00245 }
00246 return result;
00247 }
00248
00250 inline void sliceassign(size_t const i1, size_t const i2,
00251 vector1d<T> const &v)
00252 {
00253 if ((i2 < i1) || (i2 >= this->size())) {
00254 cvm::error("Error: trying to slice a vector using incorrect boundaries.\n");
00255 }
00256 size_t i;
00257 for (i = 0; i < (i2 - i1); i++) {
00258 (*this)[i1+i] = v[i];
00259 }
00260 }
00261
00263
00264 inline size_t output_width(size_t real_width) const
00265 {
00266 return real_width*(this->size()) + 3*(this->size()-1) + 4;
00267 }
00268
00269 inline friend std::istream & operator >> (std::istream &is,
00270 cvm::vector1d<T> &v)
00271 {
00272 if (v.size() == 0) return is;
00273 std::streampos const start_pos = is.tellg();
00274 char sep;
00275 if ( !(is >> sep) || !(sep == '(') ) {
00276 is.clear();
00277 is.seekg(start_pos, std::ios::beg);
00278 is.setstate(std::ios::failbit);
00279 return is;
00280 }
00281 size_t count = 0;
00282 while ( (is >> v[count]) &&
00283 (count < (v.size()-1) ? ((is >> sep) && (sep == ',')) : true) ) {
00284 if (++count == v.size()) break;
00285 }
00286 if (count < v.size()) {
00287 is.clear();
00288 is.seekg(start_pos, std::ios::beg);
00289 is.setstate(std::ios::failbit);
00290 }
00291 return is;
00292 }
00293
00294 inline friend std::ostream & operator << (std::ostream &os,
00295 cvm::vector1d<T> const &v)
00296 {
00297 std::streamsize const w = os.width();
00298 std::streamsize const p = os.precision();
00299
00300 os.width(2);
00301 os << "( ";
00302 size_t i;
00303 for (i = 0; i < v.size()-1; i++) {
00304 os.width(w); os.precision(p);
00305 os << v[i] << " , ";
00306 }
00307 os.width(w); os.precision(p);
00308 os << v[v.size()-1] << " )";
00309 return os;
00310 }
00311
00312 inline std::string to_simple_string() const
00313 {
00314 if (this->size() == 0) return std::string("");
00315 std::ostringstream os;
00316 os.setf(std::ios::scientific, std::ios::floatfield);
00317 os.precision(cvm::cv_prec);
00318 os << (*this)[0];
00319 size_t i;
00320 for (i = 1; i < this->size(); i++) {
00321 os << " " << (*this)[i];
00322 }
00323 return os.str();
00324 }
00325
00326 inline int from_simple_string(std::string const &s)
00327 {
00328 std::stringstream stream(s);
00329 size_t i = 0;
00330 if (this->size()) {
00331 while ((stream >> (*this)[i]) && (i < this->size())) {
00332 i++;
00333 }
00334 if (i < this->size()) {
00335 return COLVARS_ERROR;
00336 }
00337 } else {
00338 T input;
00339 while (stream >> input) {
00340 if ((i % 100) == 0) {
00341 data.reserve(data.size()+100);
00342 }
00343 data.resize(data.size()+1);
00344 data[i] = input;
00345 i++;
00346 }
00347 }
00348 return COLVARS_OK;
00349 }
00350
00351 };
00352
00353
00357 template <class T> class colvarmodule::matrix2d
00358 {
00359 public:
00360
00361 friend class row;
00362 size_t outer_length;
00363 size_t inner_length;
00364
00365 protected:
00366
00367 class row {
00368 public:
00369 T * data;
00370 size_t length;
00371 inline row(T * const row_data, size_t const inner_length)
00372 : data(row_data), length(inner_length)
00373 {}
00374 inline T & operator [] (size_t const j) {
00375 return *(data+j);
00376 }
00377 inline T const & operator [] (size_t const j) const {
00378 return *(data+j);
00379 }
00380 inline operator vector1d<T>() const
00381 {
00382 return vector1d<T>(length, data);
00383 }
00384 inline int set(cvm::vector1d<T> const &v) const
00385 {
00386 if (v.size() != length) {
00387 return cvm::error("Error: setting a matrix row from a vector of "
00388 "incompatible size.\n", COLVARS_BUG_ERROR);
00389 }
00390 for (size_t i = 0; i < length; i++) data[i] = v[i];
00391 return COLVARS_OK;
00392 }
00393 };
00394
00395 std::vector<T> data;
00396 std::vector<row> rows;
00397 std::vector<T *> pointers;
00398
00399 public:
00400
00402 inline void resize(size_t const ol, size_t const il)
00403 {
00404 if ((ol > 0) && (il > 0)) {
00405
00406 if (data.size() > 0) {
00407
00408 size_t i, j;
00409 std::vector<T> new_data(ol * il);
00410 for (i = 0; i < outer_length; i++) {
00411 for (j = 0; j < inner_length; j++) {
00412 new_data[il*i+j] = data[inner_length*i+j];
00413 }
00414 }
00415 data.resize(ol * il);
00416
00417 data = new_data;
00418 } else {
00419 data.resize(ol * il);
00420 }
00421
00422 outer_length = ol;
00423 inner_length = il;
00424
00425 if (data.size() > 0) {
00426
00427 size_t i;
00428 rows.clear();
00429 rows.reserve(outer_length);
00430 pointers.clear();
00431 pointers.reserve(outer_length);
00432 for (i = 0; i < outer_length; i++) {
00433 rows.push_back(row(&(data[0])+inner_length*i, inner_length));
00434 pointers.push_back(&(data[0])+inner_length*i);
00435 }
00436 }
00437 } else {
00438
00439 data.clear();
00440 rows.clear();
00441 }
00442 }
00443
00445 inline void clear() {
00446 rows.clear();
00447 data.clear();
00448 }
00449
00451 inline void reset()
00452 {
00453 data.assign(data.size(), T(0.0));
00454 }
00455
00456 inline size_t size() const
00457 {
00458 return data.size();
00459 }
00460
00462 inline matrix2d()
00463 : outer_length(0), inner_length(0)
00464 {
00465 this->resize(0, 0);
00466 }
00467
00468 inline matrix2d(size_t const ol, size_t const il)
00469 : outer_length(ol), inner_length(il)
00470 {
00471 this->resize(outer_length, inner_length);
00472 reset();
00473 }
00474
00476 inline matrix2d(matrix2d<T> const &m)
00477 : outer_length(m.outer_length), inner_length(m.inner_length)
00478 {
00479
00480 this->resize(outer_length, inner_length);
00481
00482 data = m.data;
00483 }
00484
00486 inline ~matrix2d() {
00487 this->clear();
00488 }
00489
00491 inline std::vector<T> &data_array()
00492 {
00493 return data;
00494 }
00495
00496 inline row & operator [] (size_t const i)
00497 {
00498 return rows[i];
00499 }
00500 inline row const & operator [] (size_t const i) const
00501 {
00502 return rows[i];
00503 }
00504
00506 inline matrix2d<T> & operator = (matrix2d<T> const &m)
00507 {
00508 if ((outer_length != m.outer_length) || (inner_length != m.inner_length)){
00509 this->clear();
00510 outer_length = m.outer_length;
00511 inner_length = m.inner_length;
00512 this->resize(outer_length, inner_length);
00513 }
00514 data = m.data;
00515 return *this;
00516 }
00517
00519 inline T ** c_array() {
00520 if (rows.size() > 0) {
00521 return &(pointers[0]);
00522 } else {
00523 return NULL;
00524 }
00525 }
00526
00527 inline static void check_sizes(matrix2d<T> const &m1, matrix2d<T> const &m2)
00528 {
00529 if ((m1.outer_length != m2.outer_length) ||
00530 (m1.inner_length != m2.inner_length)) {
00531 cvm::error("Error: trying to perform an operation between "
00532 "matrices of different sizes, "+
00533 cvm::to_str(m1.outer_length)+"x"+
00534 cvm::to_str(m1.inner_length)+" and "+
00535 cvm::to_str(m2.outer_length)+"x"+
00536 cvm::to_str(m2.inner_length)+".\n");
00537 }
00538 }
00539
00540 inline void operator += (matrix2d<T> const &m)
00541 {
00542 check_sizes(*this, m);
00543 size_t i;
00544 for (i = 0; i < data.size(); i++) {
00545 data[i] += m.data[i];
00546 }
00547 }
00548
00549 inline void operator -= (matrix2d<T> const &m)
00550 {
00551 check_sizes(*this, m);
00552 size_t i;
00553 for (i = 0; i < data.size(); i++) {
00554 data[i] -= m.data[i];
00555 }
00556 }
00557
00558 inline void operator *= (cvm::real a)
00559 {
00560 size_t i;
00561 for (i = 0; i < data.size(); i++) {
00562 data[i] *= a;
00563 }
00564 }
00565
00566 inline void operator /= (cvm::real a)
00567 {
00568 size_t i;
00569 for (i = 0; i < data.size(); i++) {
00570 data[i] /= a;
00571 }
00572 }
00573
00574 inline friend matrix2d<T> operator + (matrix2d<T> const &m1,
00575 matrix2d<T> const &m2)
00576 {
00577 check_sizes(m1, m2);
00578 matrix2d<T> result(m1.outer_length, m1.inner_length);
00579 size_t i;
00580 for (i = 0; i < m1.data.size(); i++) {
00581 result.data[i] = m1.data[i] + m2.data[i];
00582 }
00583 return result;
00584 }
00585
00586 inline friend matrix2d<T> operator - (matrix2d<T> const &m1,
00587 matrix2d<T> const &m2)
00588 {
00589 check_sizes(m1, m2);
00590 matrix2d<T> result(m1.outer_length, m1.inner_length);
00591 size_t i;
00592 for (i = 0; i < m1.data.size(); i++) {
00593 result.data[i] = m1.data[i] - m1.data[i];
00594 }
00595 return result;
00596 }
00597
00598 inline friend matrix2d<T> operator * (matrix2d<T> const &m, cvm::real a)
00599 {
00600 matrix2d<T> result(m.outer_length, m.inner_length);
00601 size_t i;
00602 for (i = 0; i < m.data.size(); i++) {
00603 result.data[i] = m.data[i] * a;
00604 }
00605 return result;
00606 }
00607
00608 inline friend matrix2d<T> operator * (cvm::real a, matrix2d<T> const &m)
00609 {
00610 return m * a;
00611 }
00612
00613 inline friend matrix2d<T> operator / (matrix2d<T> const &m, cvm::real a)
00614 {
00615 matrix2d<T> result(m.outer_length, m.inner_length);
00616 size_t i;
00617 for (i = 0; i < m.data.size(); i++) {
00618 result.data[i] = m.data[i] * a;
00619 }
00620 return result;
00621 }
00622
00624 inline friend vector1d<T> operator * (vector1d<T> const &v,
00625 matrix2d<T> const &m)
00626 {
00627 vector1d<T> result(m.inner_length);
00628 if (m.outer_length != v.size()) {
00629 cvm::error("Error: trying to multiply a vector and a matrix "
00630 "of incompatible sizes, "+
00631 cvm::to_str(v.size()) + " and " +
00632 cvm::to_str(m.outer_length)+"x"+cvm::to_str(m.inner_length) +
00633 ".\n");
00634 } else {
00635 size_t i, k;
00636 for (i = 0; i < m.inner_length; i++) {
00637 for (k = 0; k < m.outer_length; k++) {
00638 result[i] += m[k][i] * v[k];
00639 }
00640 }
00641 }
00642 return result;
00643 }
00644
00646 friend std::ostream & operator << (std::ostream &os,
00647 matrix2d<T> const &m)
00648 {
00649 std::streamsize const w = os.width();
00650 std::streamsize const p = os.precision();
00651
00652 os.width(2);
00653 os << "( ";
00654 size_t i;
00655 for (i = 0; i < m.outer_length; i++) {
00656 os << " ( ";
00657 size_t j;
00658 for (j = 0; j < m.inner_length-1; j++) {
00659 os.width(w);
00660 os.precision(p);
00661 os << m[i][j] << " , ";
00662 }
00663 os.width(w);
00664 os.precision(p);
00665 os << m[i][m.inner_length-1] << " )";
00666 }
00667
00668 os << " )";
00669 return os;
00670 }
00671
00672 inline std::string to_simple_string() const
00673 {
00674 if (this->size() == 0) return std::string("");
00675 std::ostringstream os;
00676 os.setf(std::ios::scientific, std::ios::floatfield);
00677 os.precision(cvm::cv_prec);
00678 os << (*this)[0];
00679 size_t i;
00680 for (i = 1; i < data.size(); i++) {
00681 os << " " << data[i];
00682 }
00683 return os.str();
00684 }
00685
00686 inline int from_simple_string(std::string const &s)
00687 {
00688 std::stringstream stream(s);
00689 size_t i = 0;
00690 while ((i < data.size()) && (stream >> data[i])) {
00691 i++;
00692 }
00693 if (i < data.size()) {
00694 return COLVARS_ERROR;
00695 }
00696 return COLVARS_OK;
00697 }
00698
00699 };
00700
00701
00703 class colvarmodule::rvector {
00704
00705 public:
00706
00707 cvm::real x, y, z;
00708
00709 inline rvector()
00710 {
00711 reset();
00712 }
00713
00715 inline void reset()
00716 {
00717 set(0.0);
00718 }
00719
00720 inline rvector(cvm::real x_i, cvm::real y_i, cvm::real z_i)
00721 {
00722 set(x_i, y_i, z_i);
00723 }
00724
00725 inline rvector(cvm::vector1d<cvm::real> const &v)
00726 {
00727 set(v[0], v[1], v[2]);
00728 }
00729
00730 inline rvector(cvm::real t)
00731 {
00732 set(t);
00733 }
00734
00736 inline void set(cvm::real value)
00737 {
00738 x = y = z = value;
00739 }
00740
00742 inline void set(cvm::real x_i, cvm::real y_i, cvm::real z_i)
00743 {
00744 x = x_i;
00745 y = y_i;
00746 z = z_i;
00747 }
00748
00750 inline cvm::real & operator [] (int i) {
00751 return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x;
00752 }
00753
00755 inline cvm::real operator [] (int i) const {
00756 return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x;
00757 }
00758
00759 inline cvm::vector1d<cvm::real> const as_vector() const
00760 {
00761 cvm::vector1d<cvm::real> result(3);
00762 result[0] = this->x;
00763 result[1] = this->y;
00764 result[2] = this->z;
00765 return result;
00766 }
00767
00768 inline void operator += (cvm::rvector const &v)
00769 {
00770 x += v.x;
00771 y += v.y;
00772 z += v.z;
00773 }
00774
00775 inline void operator -= (cvm::rvector const &v)
00776 {
00777 x -= v.x;
00778 y -= v.y;
00779 z -= v.z;
00780 }
00781
00782 inline void operator *= (cvm::real v)
00783 {
00784 x *= v;
00785 y *= v;
00786 z *= v;
00787 }
00788
00789 inline void operator /= (cvm::real const& v)
00790 {
00791 x /= v;
00792 y /= v;
00793 z /= v;
00794 }
00795
00796 inline cvm::real norm2() const
00797 {
00798 return (x*x + y*y + z*z);
00799 }
00800
00801 inline cvm::real norm() const
00802 {
00803 return cvm::sqrt(this->norm2());
00804 }
00805
00806 inline cvm::rvector unit() const
00807 {
00808 const cvm::real n = this->norm();
00809 return (n > 0. ? cvm::rvector(x, y, z)/n : cvm::rvector(1., 0., 0.));
00810 }
00811
00812 static inline size_t output_width(size_t real_width)
00813 {
00814 return 3*real_width + 10;
00815 }
00816
00817
00818 static inline cvm::rvector outer(cvm::rvector const &v1,
00819 cvm::rvector const &v2)
00820 {
00821 return cvm::rvector( v1.y*v2.z - v2.y*v1.z,
00822 -v1.x*v2.z + v2.x*v1.z,
00823 v1.x*v2.y - v2.x*v1.y);
00824 }
00825
00826 friend inline cvm::rvector operator - (cvm::rvector const &v)
00827 {
00828 return cvm::rvector(-v.x, -v.y, -v.z);
00829 }
00830
00831 friend inline cvm::rvector operator + (cvm::rvector const &v1,
00832 cvm::rvector const &v2)
00833 {
00834 return cvm::rvector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
00835 }
00836 friend inline cvm::rvector operator - (cvm::rvector const &v1,
00837 cvm::rvector const &v2)
00838 {
00839 return cvm::rvector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
00840 }
00841
00843 friend inline cvm::real operator * (cvm::rvector const &v1,
00844 cvm::rvector const &v2)
00845 {
00846 return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
00847 }
00848
00849 friend inline cvm::rvector operator * (cvm::real a, cvm::rvector const &v)
00850 {
00851 return cvm::rvector(a*v.x, a*v.y, a*v.z);
00852 }
00853
00854 friend inline cvm::rvector operator * (cvm::rvector const &v, cvm::real a)
00855 {
00856 return cvm::rvector(a*v.x, a*v.y, a*v.z);
00857 }
00858
00859 friend inline cvm::rvector operator / (cvm::rvector const &v, cvm::real a)
00860 {
00861 return cvm::rvector(v.x/a, v.y/a, v.z/a);
00862 }
00863
00864 std::string to_simple_string() const;
00865 int from_simple_string(std::string const &s);
00866 };
00867
00868
00871 class colvarmodule::rmatrix {
00872
00873 public:
00874
00875 cvm::real xx, xy, xz, yx, yy, yz, zx, zy, zz;
00876
00878 inline rmatrix()
00879 {
00880 reset();
00881 }
00882
00884 inline rmatrix(cvm::real xxi, cvm::real xyi, cvm::real xzi,
00885 cvm::real yxi, cvm::real yyi, cvm::real yzi,
00886 cvm::real zxi, cvm::real zyi, cvm::real zzi)
00887 {
00888 xx = xxi;
00889 xy = xyi;
00890 xz = xzi;
00891 yx = yxi;
00892 yy = yyi;
00893 yz = yzi;
00894 zx = zxi;
00895 zy = zyi;
00896 zz = zzi;
00897 }
00898
00900 inline ~rmatrix()
00901 {}
00902
00903 inline void reset()
00904 {
00905 xx = xy = xz = yx = yy = yz = zx = zy = zz = 0.0;
00906 }
00907
00909 inline cvm::real determinant() const
00910 {
00911 return
00912 ( xx * (yy*zz - zy*yz))
00913 - (yx * (xy*zz - zy*xz))
00914 + (zx * (xy*yz - yy*xz));
00915 }
00916
00917 inline cvm::rmatrix transpose() const
00918 {
00919 return cvm::rmatrix(xx, yx, zx,
00920 xy, yy, zy,
00921 xz, yz, zz);
00922 }
00923
00924 inline friend cvm::rvector operator * (cvm::rmatrix const &m,
00925 cvm::rvector const &r)
00926 {
00927 return cvm::rvector(m.xx*r.x + m.xy*r.y + m.xz*r.z,
00928 m.yx*r.x + m.yy*r.y + m.yz*r.z,
00929 m.zx*r.x + m.zy*r.y + m.zz*r.z);
00930 }
00931 };
00932
00933
00934
00937 class colvarmodule::quaternion {
00938
00939 public:
00940
00941 cvm::real q0, q1, q2, q3;
00942
00944 inline quaternion(cvm::real x, cvm::real y, cvm::real z)
00945 : q0(0.0), q1(x), q2(y), q3(z)
00946 {}
00947
00949 inline quaternion(cvm::real const qv[4])
00950 : q0(qv[0]), q1(qv[1]), q2(qv[2]), q3(qv[3])
00951 {}
00952
00954 inline quaternion(cvm::real q0i,
00955 cvm::real q1i,
00956 cvm::real q2i,
00957 cvm::real q3i)
00958 : q0(q0i), q1(q1i), q2(q2i), q3(q3i)
00959 {}
00960
00961 inline quaternion(cvm::vector1d<cvm::real> const &v)
00962 : q0(v[0]), q1(v[1]), q2(v[2]), q3(v[3])
00963 {}
00964
00968 inline void set_from_euler_angles(cvm::real phi_in,
00969 cvm::real theta_in,
00970 cvm::real psi_in)
00971 {
00972 q0 = ( (cvm::cos(phi_in/2.0)) * (cvm::cos(theta_in/2.0)) * (cvm::cos(psi_in/2.0)) +
00973 (cvm::sin(phi_in/2.0)) * (cvm::sin(theta_in/2.0)) * (cvm::sin(psi_in/2.0)) );
00974
00975 q1 = ( (cvm::sin(phi_in/2.0)) * (cvm::cos(theta_in/2.0)) * (cvm::cos(psi_in/2.0)) -
00976 (cvm::cos(phi_in/2.0)) * (cvm::sin(theta_in/2.0)) * (cvm::sin(psi_in/2.0)) );
00977
00978 q2 = ( (cvm::cos(phi_in/2.0)) * (cvm::sin(theta_in/2.0)) * (cvm::cos(psi_in/2.0)) +
00979 (cvm::sin(phi_in/2.0)) * (cvm::cos(theta_in/2.0)) * (cvm::sin(psi_in/2.0)) );
00980
00981 q3 = ( (cvm::cos(phi_in/2.0)) * (cvm::cos(theta_in/2.0)) * (cvm::sin(psi_in/2.0)) -
00982 (cvm::sin(phi_in/2.0)) * (cvm::sin(theta_in/2.0)) * (cvm::cos(psi_in/2.0)) );
00983 }
00984
00986 inline quaternion()
00987 {
00988 reset();
00989 }
00990
00992 inline void set(cvm::real value)
00993 {
00994 q0 = q1 = q2 = q3 = value;
00995 }
00996
00998 inline void reset()
00999 {
01000 set(0.0);
01001 }
01002
01005 inline void reset_rotation()
01006 {
01007 q0 = 1.0;
01008 q1 = q2 = q3 = 0.0;
01009 }
01010
01012 static inline size_t output_width(size_t real_width)
01013 {
01014 return 4*real_width + 13;
01015 }
01016
01017 std::string to_simple_string() const;
01018 int from_simple_string(std::string const &s);
01019
01021 friend std::ostream & operator << (std::ostream &os, cvm::quaternion const &q);
01023 friend std::istream & operator >> (std::istream &is, cvm::quaternion &q);
01024
01026 inline cvm::real & operator [] (int i) {
01027 switch (i) {
01028 case 0:
01029 return this->q0;
01030 case 1:
01031 return this->q1;
01032 case 2:
01033 return this->q2;
01034 case 3:
01035 return this->q3;
01036 default:
01037 cvm::error("Error: incorrect quaternion component.\n");
01038 return q0;
01039 }
01040 }
01041
01043 inline cvm::real operator [] (int i) const {
01044 switch (i) {
01045 case 0:
01046 return this->q0;
01047 case 1:
01048 return this->q1;
01049 case 2:
01050 return this->q2;
01051 case 3:
01052 return this->q3;
01053 default:
01054 cvm::error("Error: trying to access a quaternion "
01055 "component which is not between 0 and 3.\n");
01056 return 0.0;
01057 }
01058 }
01059
01060 inline cvm::vector1d<cvm::real> const as_vector() const
01061 {
01062 cvm::vector1d<cvm::real> result(4);
01063 result[0] = q0;
01064 result[1] = q1;
01065 result[2] = q2;
01066 result[3] = q3;
01067 return result;
01068 }
01069
01071 inline cvm::real norm2() const
01072 {
01073 return q0*q0 + q1*q1 + q2*q2 + q3*q3;
01074 }
01075
01077 inline cvm::real norm() const
01078 {
01079 return cvm::sqrt(this->norm2());
01080 }
01081
01083 inline cvm::quaternion conjugate() const
01084 {
01085 return cvm::quaternion(q0, -q1, -q2, -q3);
01086 }
01087
01088 inline void operator *= (cvm::real a)
01089 {
01090 q0 *= a; q1 *= a; q2 *= a; q3 *= a;
01091 }
01092
01093 inline void operator /= (cvm::real a)
01094 {
01095 q0 /= a; q1 /= a; q2 /= a; q3 /= a;
01096 }
01097
01098 inline void set_positive()
01099 {
01100 if (q0 > 0.0) return;
01101 q0 = -q0;
01102 q1 = -q1;
01103 q2 = -q2;
01104 q3 = -q3;
01105 }
01106
01107 inline void operator += (cvm::quaternion const &h)
01108 {
01109 q0+=h.q0; q1+=h.q1; q2+=h.q2; q3+=h.q3;
01110 }
01111 inline void operator -= (cvm::quaternion const &h)
01112 {
01113 q0-=h.q0; q1-=h.q1; q2-=h.q2; q3-=h.q3;
01114 }
01115
01117 inline cvm::rvector get_vector() const
01118 {
01119 return cvm::rvector(q1, q2, q3);
01120 }
01121
01122
01123 friend inline cvm::quaternion operator + (cvm::quaternion const &h,
01124 cvm::quaternion const &q)
01125 {
01126 return cvm::quaternion(h.q0+q.q0, h.q1+q.q1, h.q2+q.q2, h.q3+q.q3);
01127 }
01128
01129 friend inline cvm::quaternion operator - (cvm::quaternion const &h,
01130 cvm::quaternion const &q)
01131 {
01132 return cvm::quaternion(h.q0-q.q0, h.q1-q.q1, h.q2-q.q2, h.q3-q.q3);
01133 }
01134
01137 friend inline cvm::quaternion operator * (cvm::quaternion const &h,
01138 cvm::quaternion const &q)
01139 {
01140 return cvm::quaternion(h.q0*q.q0 - h.q1*q.q1 - h.q2*q.q2 - h.q3*q.q3,
01141 h.q0*q.q1 + h.q1*q.q0 + h.q2*q.q3 - h.q3*q.q2,
01142 h.q0*q.q2 + h.q2*q.q0 + h.q3*q.q1 - h.q1*q.q3,
01143 h.q0*q.q3 + h.q3*q.q0 + h.q1*q.q2 - h.q2*q.q1);
01144 }
01145
01146 friend inline cvm::quaternion operator * (cvm::real c,
01147 cvm::quaternion const &q)
01148 {
01149 return cvm::quaternion(c*q.q0, c*q.q1, c*q.q2, c*q.q3);
01150 }
01151 friend inline cvm::quaternion operator * (cvm::quaternion const &q,
01152 cvm::real c)
01153 {
01154 return cvm::quaternion(q.q0*c, q.q1*c, q.q2*c, q.q3*c);
01155 }
01156 friend inline cvm::quaternion operator / (cvm::quaternion const &q,
01157 cvm::real c)
01158 {
01159 return cvm::quaternion(q.q0/c, q.q1/c, q.q2/c, q.q3/c);
01160 }
01161
01162
01165 inline cvm::rvector rotate(cvm::rvector const &v) const
01166 {
01167 return ( (*this) * cvm::quaternion(0.0, v.x, v.y, v.z) *
01168 this->conjugate() ).get_vector();
01169 }
01170
01173 inline cvm::quaternion rotate(cvm::quaternion const &Q2) const
01174 {
01175 cvm::rvector const vq_rot = this->rotate(Q2.get_vector());
01176 return cvm::quaternion(Q2.q0, vq_rot.x, vq_rot.y, vq_rot.z);
01177 }
01178
01180 inline cvm::rmatrix rotation_matrix() const
01181 {
01182 cvm::rmatrix R;
01183
01184 R.xx = q0*q0 + q1*q1 - q2*q2 - q3*q3;
01185 R.yy = q0*q0 - q1*q1 + q2*q2 - q3*q3;
01186 R.zz = q0*q0 - q1*q1 - q2*q2 + q3*q3;
01187
01188 R.xy = 2.0 * (q1*q2 - q0*q3);
01189 R.xz = 2.0 * (q0*q2 + q1*q3);
01190
01191 R.yx = 2.0 * (q0*q3 + q1*q2);
01192 R.yz = 2.0 * (q2*q3 - q0*q1);
01193
01194 R.zx = 2.0 * (q1*q3 - q0*q2);
01195 R.zy = 2.0 * (q0*q1 + q2*q3);
01196
01197 return R;
01198 }
01199
01200
01203 cvm::quaternion position_derivative_inner(cvm::rvector const &pos,
01204 cvm::rvector const &vec) const;
01205
01206
01209 inline cvm::real cosine(cvm::quaternion const &q) const
01210 {
01211 cvm::real const iprod = this->inner(q);
01212 return 2.0*iprod*iprod - 1.0;
01213 }
01214
01218 inline cvm::real dist2(cvm::quaternion const &Q2) const
01219 {
01220 cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 +
01221 this->q2*Q2.q2 + this->q3*Q2.q3;
01222
01223 cvm::real const omega = cvm::acos( (cos_omega > 1.0) ? 1.0 :
01224 ( (cos_omega < -1.0) ? -1.0 : cos_omega) );
01225
01226
01227 if (cos_omega > 0.0)
01228 return omega * omega;
01229 else
01230 return (PI-omega) * (PI-omega);
01231 }
01232
01235 inline cvm::quaternion dist2_grad(cvm::quaternion const &Q2) const
01236 {
01237 cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 + this->q2*Q2.q2 + this->q3*Q2.q3;
01238 cvm::real const omega = cvm::acos( (cos_omega > 1.0) ? 1.0 :
01239 ( (cos_omega < -1.0) ? -1.0 : cos_omega) );
01240 cvm::real const sin_omega = cvm::sin(omega);
01241
01242 if (cvm::fabs(sin_omega) < 1.0E-14) {
01243
01244 return cvm::quaternion(0.0, 0.0, 0.0, 0.0);
01245 }
01246
01247 cvm::quaternion const
01248 grad1((-1.0)*sin_omega*Q2.q0 + cos_omega*(this->q0-cos_omega*Q2.q0)/sin_omega,
01249 (-1.0)*sin_omega*Q2.q1 + cos_omega*(this->q1-cos_omega*Q2.q1)/sin_omega,
01250 (-1.0)*sin_omega*Q2.q2 + cos_omega*(this->q2-cos_omega*Q2.q2)/sin_omega,
01251 (-1.0)*sin_omega*Q2.q3 + cos_omega*(this->q3-cos_omega*Q2.q3)/sin_omega);
01252
01253 if (cos_omega > 0.0) {
01254 return 2.0*omega*grad1;
01255 } else {
01256 return -2.0*(PI-omega)*grad1;
01257 }
01258 }
01259
01262 inline void match(cvm::quaternion &Q2) const
01263 {
01264 cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 +
01265 this->q2*Q2.q2 + this->q3*Q2.q3;
01266 if (cos_omega < 0.0) Q2 *= -1.0;
01267 }
01268
01271 inline cvm::real inner(cvm::quaternion const &Q2) const
01272 {
01273 cvm::real const prod = this->q0*Q2.q0 + this->q1*Q2.q1 +
01274 this->q2*Q2.q2 + this->q3*Q2.q3;
01275 return prod;
01276 }
01277
01278
01279 };
01280
01281
01284 class colvarmodule::rotation
01285 {
01286 public:
01287
01289 cvm::quaternion q;
01290
01292 cvm::real lambda;
01293
01295 bool b_debug_gradients;
01296
01298 cvm::rmatrix C;
01299
01301 cvm::matrix2d<cvm::real> S;
01302
01304 cvm::vector1d<cvm::real> S_eigval;
01305
01307 cvm::matrix2d<cvm::real> S_eigvec;
01308
01310 cvm::matrix2d<cvm::real> S_backup;
01311
01313 std::vector< cvm::matrix2d<cvm::rvector> > dS_1, dS_2;
01315 std::vector< cvm::rvector > dL0_1, dL0_2;
01317 std::vector< cvm::vector1d<cvm::rvector> > dQ0_1, dQ0_2;
01318
01320 inline void request_group1_gradients(size_t n)
01321 {
01322 dS_1.resize(n, cvm::matrix2d<cvm::rvector>(4, 4));
01323 dL0_1.resize(n, cvm::rvector(0.0, 0.0, 0.0));
01324 dQ0_1.resize(n, cvm::vector1d<cvm::rvector>(4));
01325 }
01326
01328 inline void request_group2_gradients(size_t n)
01329 {
01330 dS_2.resize(n, cvm::matrix2d<cvm::rvector>(4, 4));
01331 dL0_2.resize(n, cvm::rvector(0.0, 0.0, 0.0));
01332 dQ0_2.resize(n, cvm::vector1d<cvm::rvector>(4));
01333 }
01334
01345 void calc_optimal_rotation(std::vector<atom_pos> const &pos1,
01346 std::vector<atom_pos> const &pos2);
01347
01349 int init();
01350
01352 rotation();
01353
01355 rotation(cvm::quaternion const &qi);
01356
01358 rotation(cvm::real angle, cvm::rvector const &axis);
01359
01361 ~rotation();
01362
01364 inline cvm::rvector rotate(cvm::rvector const &v) const
01365 {
01366 return q.rotate(v);
01367 }
01368
01370 inline cvm::rotation inverse() const
01371 {
01372 return cvm::rotation(this->q.conjugate());
01373 }
01374
01376 inline cvm::rmatrix matrix() const
01377 {
01378 return q.rotation_matrix();
01379 }
01380
01383 inline cvm::real spin_angle(cvm::rvector const &axis) const
01384 {
01385 cvm::rvector const q_vec = q.get_vector();
01386 cvm::real alpha = (180.0/PI) * 2.0 * cvm::atan2(axis * q_vec, q.q0);
01387 while (alpha > 180.0) alpha -= 360;
01388 while (alpha < -180.0) alpha += 360;
01389 return alpha;
01390 }
01391
01394 inline cvm::quaternion dspin_angle_dq(cvm::rvector const &axis) const
01395 {
01396 cvm::rvector const q_vec = q.get_vector();
01397 cvm::real const iprod = axis * q_vec;
01398
01399 if (q.q0 != 0.0) {
01400
01401 cvm::real const dspindx =
01402 (180.0/PI) * 2.0 * (1.0 / (1.0 + (iprod*iprod)/(q.q0*q.q0)));
01403
01404 return cvm::quaternion( dspindx * (iprod * (-1.0) / (q.q0*q.q0)),
01405 dspindx * ((1.0/q.q0) * axis.x),
01406 dspindx * ((1.0/q.q0) * axis.y),
01407 dspindx * ((1.0/q.q0) * axis.z));
01408 } else {
01409
01410
01411
01412 return cvm::quaternion((180.0/PI) * 2.0 * ((-1.0)/iprod), 0.0, 0.0, 0.0);
01413 }
01414 }
01415
01418 inline cvm::real cos_theta(cvm::rvector const &axis) const
01419 {
01420 cvm::rvector const q_vec = q.get_vector();
01421 cvm::real const alpha =
01422 (180.0/PI) * 2.0 * cvm::atan2(axis * q_vec, q.q0);
01423
01424 cvm::real const cos_spin_2 = cvm::cos(alpha * (PI/180.0) * 0.5);
01425 cvm::real const cos_theta_2 = ( (cos_spin_2 != 0.0) ?
01426 (q.q0 / cos_spin_2) :
01427 (0.0) );
01428
01429 return 2.0 * (cos_theta_2*cos_theta_2) - 1.0;
01430 }
01431
01433 inline cvm::quaternion dcos_theta_dq(cvm::rvector const &axis) const
01434 {
01435 cvm::rvector const q_vec = q.get_vector();
01436 cvm::real const iprod = axis * q_vec;
01437
01438 cvm::real const cos_spin_2 = cvm::cos(cvm::atan2(iprod, q.q0));
01439
01440 if (q.q0 != 0.0) {
01441
01442 cvm::real const d_cos_theta_dq0 =
01443 (4.0 * q.q0 / (cos_spin_2*cos_spin_2)) *
01444 (1.0 - (iprod*iprod)/(q.q0*q.q0) / (1.0 + (iprod*iprod)/(q.q0*q.q0)));
01445
01446 cvm::real const d_cos_theta_dqn =
01447 (4.0 * q.q0 / (cos_spin_2*cos_spin_2) *
01448 (iprod/q.q0) / (1.0 + (iprod*iprod)/(q.q0*q.q0)));
01449
01450 return cvm::quaternion(d_cos_theta_dq0,
01451 d_cos_theta_dqn * axis.x,
01452 d_cos_theta_dqn * axis.y,
01453 d_cos_theta_dqn * axis.z);
01454 } else {
01455
01456 cvm::real const d_cos_theta_dqn =
01457 (4.0 / (cos_spin_2*cos_spin_2 * iprod));
01458
01459 return cvm::quaternion(0.0,
01460 d_cos_theta_dqn * axis.x,
01461 d_cos_theta_dqn * axis.y,
01462 d_cos_theta_dqn * axis.z);
01463 }
01464 }
01465
01467 static bool monitor_crossings;
01469 static cvm::real crossing_threshold;
01470
01471 protected:
01472
01476 cvm::quaternion q_old;
01477
01479 void build_correlation_matrix(std::vector<cvm::atom_pos> const &pos1,
01480 std::vector<cvm::atom_pos> const &pos2);
01481
01483 void compute_overlap_matrix();
01484
01486 void *jacobi;
01487 };
01488
01489
01490 #endif