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

colvartypes.h

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 #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         // copy previous data
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         // copy them back
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         // rebuild rows
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       // zero size
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     // reinitialize data and rows arrays
00480     this->resize(outer_length, inner_length);
00481     // copy data
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     // get the minimum distance: x and -x are the same quaternion
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       // return a null 4d vector
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       // (1/(1+x^2)) ~ (1/x)^2
01410       // The documentation of spinAngle discourages its use when q_vec and
01411       // axis are not close
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     // cos(2t) = 2*cos(t)^2 - 1
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

Generated on Sat Apr 20 02:42:30 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002