All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
RMSD.cpp
Go to the documentation of this file.
1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2  Copyright (c) 2013 The plumed team
3  (see the PEOPLE file at the root of the distribution for a list of names)
4 
5  See http://www.plumed-code.org for more information.
6 
7  This file is part of plumed, version 2.0.
8 
9  plumed is free software: you can redistribute it and/or modify
10  it under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  (at your option) any later version.
13 
14  plumed is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public License
20  along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 #include "RMSD.h"
23 #include "PDB.h"
24 #include "Log.h"
25 #include "OptimalAlignment.h"
26 #include "Exception.h"
27 #include <cmath>
28 #include <iostream>
29 #include "Matrix.h"
30 #include "Tools.h"
31 
32 using namespace std;
33 namespace PLMD{
34 
35 RMSD::RMSD(Log & log ):
36  alignmentMethod(SIMPLE),
37  myoptimalalignment(NULL),
38  log(&log){}
39 
43  align=v.align;
45 // in this manner the new RMSD is built empty and will just allocate its own
46 // myoptimalalignment when used (in calculate())
47  myoptimalalignment=NULL;
48 
49  log=v.log;
50  return *this ;
51 }
52 
53 
54 RMSD::RMSD(const RMSD & oldrmsd):
55  alignmentMethod(oldrmsd.alignmentMethod),
56  reference(oldrmsd.reference),
57  align(oldrmsd.align),
58  displace(oldrmsd.align),
59 // in this manner the new RMSD is built empty and will just allocate its own
60 // myoptimalalignment when used (in calculate())
61  myoptimalalignment(NULL),
62  log( oldrmsd.log )
63  { }
64 
65 void RMSD::set(const PDB&pdb, string mytype ){
66 
68  setAlign(pdb.getOccupancy());
69  setDisplace(pdb.getBeta());
70  setType(mytype);
71 }
72 
73 void RMSD::setType(string mytype){
74  myoptimalalignment=NULL;
75 
76  alignmentMethod=SIMPLE; // initialize with the simplest case: no rotation
77  if (mytype=="SIMPLE"){
79  log->printf("RMSD IS DONE WITH SIMPLE METHOD(NO ROTATION)\n");
80  }
81  else if (mytype=="OPTIMAL"){
83  log->printf("RMSD IS DONE WITH OPTIMAL ALIGNMENT METHOD\n");
84  }
85  else if (mytype=="OPTIMAL-FAST"){
87  log->printf("RMSD IS DONE WITH OPTIMAL-FAST ALIGNMENT METHOD (fast version, numerically less stable, only valid with align==displace)\n");
88  }
89  else plumed_merror("unknown RMSD type" + mytype);
90 
91 }
92 
93 void RMSD::clear(){
94  reference.clear();
95  align.clear();
96  displace.clear();
97 }
99  if(myoptimalalignment!=NULL) delete myoptimalalignment;
100 }
101 
103  string mystring;
104  switch(alignmentMethod){
105  case SIMPLE: mystring.assign("SIMPLE");break;
106  case OPTIMAL: mystring.assign("OPTIMAL");break;
107  case OPTIMAL_FAST: mystring.assign("OPTIMAL-FAST");break;
108  }
109  return mystring;
110 }
111 
112 void RMSD::setReference(const vector<Vector> & reference){
113  unsigned n=reference.size();
114  this->reference=reference;
115  plumed_massert(align.empty(),"you should first clear() an RMSD object, then set a new referece");
116  plumed_massert(displace.empty(),"you should first clear() an RMSD object, then set a new referece");
117  align.resize(n,1.0);
118  displace.resize(n,1.0);
119 }
120 
121 void RMSD::setAlign(const vector<double> & align){
122  plumed_massert(this->align.size()==align.size(),"mismatch in dimension of align/displace arrays");
123  this->align=align;
124 }
125 
126 void RMSD::setDisplace(const vector<double> & displace){
127  plumed_massert(this->displace.size()==displace.size(),"mismatch in dimension of align/displace arrays");
128  this->displace=displace;
129 }
130 
131 double RMSD::calculate(const std::vector<Vector> & positions,std::vector<Vector> &derivatives, bool squared){
132 
133  double ret=0.;
134 
135  switch(alignmentMethod){
136  case SIMPLE:
137  // do a simple alignment without rotation
138  ret=simpleAlignment(align,displace,positions,reference,log,derivatives,squared);
139  break;
140  case OPTIMAL_FAST:
141  // this is calling the fastest option:
142  ret=optimalAlignment<false>(align,displace,positions,reference,derivatives,squared);
143  break;
144  case OPTIMAL:
145  bool fastversion=true;
146  // this is because fast version only works with align==displace
147  if (align!=displace) fastversion=false;
148  if (fastversion){
149  // this is the fast routine but in the "safe" mode, which gives less numerical error:
150  ret=optimalAlignment<true>(align,displace,positions,reference,derivatives,squared);
151  } else {
152  if (myoptimalalignment==NULL){ // do full initialization
153  //
154  // I create the object only here
155  // since the alignment object require to know both position and reference
156  // and it is possible only at calculate time
157  //
158  myoptimalalignment=new OptimalAlignment(align,displace,positions,reference,log);
159  }
160  // this changes the P0 according the running frame
161  (*myoptimalalignment).assignP0(positions);
162  ret=(*myoptimalalignment).calculate(squared, derivatives);
163  //(*myoptimalalignment).weightedFindiffTest(false);
164  }
165  break;
166  }
167 
168  return ret;
169 
170 }
171 
172 double RMSD::simpleAlignment(const std::vector<double> & align,
173  const std::vector<double> & displace,
174  const std::vector<Vector> & positions,
175  const std::vector<Vector> & reference ,
176  Log* &log,
177  std::vector<Vector> & derivatives, bool squared) {
178  double dist(0);
179  double anorm(0);
180  double dnorm(0);
181  unsigned n=reference.size();
182 
183  Vector apositions;
184  Vector areference;
185  Vector dpositions;
186  Vector dreference;
187 
188  for(unsigned i=0;i<n;i++){
189  double aw=align[i];
190  double dw=displace[i];
191  anorm+=aw;
192  dnorm+=dw;
193  apositions+=positions[i]*aw;
194  areference+=reference[i]*aw;
195  dpositions+=positions[i]*dw;
196  dreference+=reference[i]*dw;
197  }
198 
199  double invdnorm=1.0/dnorm;
200  double invanorm=1.0/anorm;
201 
202  apositions*=invanorm;
203  areference*=invanorm;
204  dpositions*=invdnorm;
205  dreference*=invdnorm;
206 
207  Vector shift=((apositions-areference)-(dpositions-dreference));
208  for(unsigned i=0;i<n;i++){
209  Vector d=(positions[i]-apositions)-(reference[i]-areference);
210  dist+=displace[i]*d.modulo2();
211  derivatives[i]=2*(invdnorm*displace[i]*d+invanorm*align[i]*shift);
212  }
213  dist*=invdnorm;
214 
215  if(!squared){
216  // sqrt and normalization
217  dist=sqrt(dist);
218  ///// sqrt and normalization on derivatives
219  for(unsigned i=0;i<n;i++){derivatives[i]*=(0.5/dist);}
220  }
221  return dist;
222 }
223 
224 template <bool safe>
225 double RMSD::optimalAlignment(const std::vector<double> & align,
226  const std::vector<double> & displace,
227  const std::vector<Vector> & positions,
228  const std::vector<Vector> & reference ,
229  std::vector<Vector> & derivatives, bool squared) {
230  plumed_massert(displace==align,"OPTIMAL_FAST version of RMSD can only be used when displace weights are same as align weights");
231 
232  double dist(0);
233  double norm(0);
234  const unsigned n=reference.size();
235 // This is the trace of positions*positions + reference*reference
236  double sum00w(0);
237 // This is positions*reference
238  Tensor sum01w;
239 
240  derivatives.resize(n);
241 
242  Vector cpositions;
243  Vector creference;
244 
245 // first expensive loop: compute centers
246  for(unsigned iat=0;iat<n;iat++){
247  double w=align[iat];
248  norm+=w;
249  cpositions+=positions[iat]*w;
250  creference+=reference[iat]*w;
251  }
252  double invnorm=1.0/norm;
253 
254  cpositions*=invnorm;
255  creference*=invnorm;
256 
257 // second expensive loop: compute second moments wrt centers
258  for(unsigned iat=0;iat<n;iat++){
259  double w=align[iat];
260  sum00w+=(dotProduct(positions[iat]-cpositions,positions[iat]-cpositions)
261  +dotProduct(reference[iat]-creference,reference[iat]-creference))*w;
262  sum01w+=Tensor(positions[iat]-cpositions,reference[iat]-creference)*w;
263  }
264 
265  double rr00=sum00w*invnorm;
266  Tensor rr01=sum01w*invnorm;
267 
269  m[0][0]=rr00+2.0*(-rr01[0][0]-rr01[1][1]-rr01[2][2]);
270  m[1][1]=rr00+2.0*(-rr01[0][0]+rr01[1][1]+rr01[2][2]);
271  m[2][2]=rr00+2.0*(+rr01[0][0]-rr01[1][1]+rr01[2][2]);
272  m[3][3]=rr00+2.0*(+rr01[0][0]+rr01[1][1]-rr01[2][2]);
273  m[0][1]=2.0*(-rr01[1][2]+rr01[2][1]);
274  m[0][2]=2.0*(+rr01[0][2]-rr01[2][0]);
275  m[0][3]=2.0*(-rr01[0][1]+rr01[1][0]);
276  m[1][2]=2.0*(-rr01[0][1]-rr01[1][0]);
277  m[1][3]=2.0*(-rr01[0][2]-rr01[2][0]);
278  m[2][3]=2.0*(-rr01[1][2]-rr01[2][1]);
279  m[1][0] = m[0][1];
280  m[2][0] = m[0][2];
281  m[2][1] = m[1][2];
282  m[3][0] = m[0][3];
283  m[3][1] = m[1][3];
284  m[3][2] = m[2][3];
285 
286  vector<double> eigenvals;
287  Matrix<double> eigenvecs;
288  int diagerror=diagMat(m, eigenvals, eigenvecs );
289 
290  if (diagerror!=0){
291  string sdiagerror;
292  Tools::convert(diagerror,sdiagerror);
293  string msg="DIAGONALIZATION FAILED WITH ERROR CODE "+sdiagerror;
294  plumed_merror(msg);
295  }
296 
297  dist=eigenvals[0];
298 
299  Matrix<double> ddist_dm(4,4);
300 
301  Vector4d q(eigenvecs[0][0],eigenvecs[0][1],eigenvecs[0][2],eigenvecs[0][3]);
302 
303 // This is the rotation matrix that brings reference to positions
304 // i.e. matmul(rotation,reference[iat])+shift is fitted to positions[iat]
305 
306  Tensor rotation;
307  rotation[0][0]=q[0]*q[0]+q[1]*q[1]-q[2]*q[2]-q[3]*q[3];
308  rotation[1][1]=q[0]*q[0]-q[1]*q[1]+q[2]*q[2]-q[3]*q[3];
309  rotation[2][2]=q[0]*q[0]-q[1]*q[1]-q[2]*q[2]+q[3]*q[3];
310  rotation[0][1]=2*(+q[0]*q[3]+q[1]*q[2]);
311  rotation[0][2]=2*(-q[0]*q[2]+q[1]*q[3]);
312  rotation[1][2]=2*(+q[0]*q[1]+q[2]*q[3]);
313  rotation[1][0]=2*(-q[0]*q[3]+q[1]*q[2]);
314  rotation[2][0]=2*(+q[0]*q[2]+q[1]*q[3]);
315  rotation[2][1]=2*(-q[0]*q[1]+q[2]*q[3]);
316 
317  double prefactor=2.0*invnorm;
318  Vector shift=cpositions-matmul(rotation,creference);
319 
320  if(!squared) prefactor*=0.5/sqrt(dist);
321 
322 // if "safe", recompute dist here to a better accuracy
323  if(safe) dist=0.0;
324 
325 // If safe is set to "false", MSD is taken from the eigenvalue of the M matrix
326 // If safe is set to "true", MSD is recomputed from the rotational matrix
327 // For some reason, this last approach leads to less numerical noise but adds an overhead
328 
329 // third expensive loop: derivatives
330  for(unsigned iat=0;iat<n;iat++){
331 // there is no need for derivatives of rotation and shift here as it is by construction zero
332 // (similar to Hellman-Feynman forces)
333  Vector d(positions[iat]-shift - matmul(rotation,reference[iat]));
334  derivatives[iat]= prefactor*align[iat]*d;
335  if(safe) dist+=align[iat]*invnorm*modulo2(d);
336  }
337 
338  if(!squared) dist=sqrt(dist);
339 
340  return dist;
341 }
342 
343 }
std::vector< Vector > reference
Definition: RMSD.h:66
Class implementing fixed size matrices of doubles.
Definition: Tensor.h:70
TensorGeneric< n, l > matmul(const TensorGeneric< n, m > &a, const TensorGeneric< m, l > &b)
Definition: Tensor.h:343
void clear()
clear the structure
Definition: RMSD.cpp:93
Class implementing fixed size vectors of doubles.
Definition: Vector.h:74
static bool convert(const std::string &str, double &t)
Convert a string to a double, reading it.
Definition: Tools.cpp:74
double optimalAlignment(const std::vector< double > &align, const std::vector< double > &displace, const std::vector< Vector > &positions, const std::vector< Vector > &reference, std::vector< Vector > &derivatives, bool squared=false)
Definition: RMSD.cpp:225
STL namespace.
A class that implements RMSD calculations This is a class that implements the various infrastructure ...
Definition: RMSD.h:62
double calculate(const std::vector< Vector > &positions, std::vector< Vector > &derivatives, bool squared=false)
Compute rmsd.
Definition: RMSD.cpp:131
Class containing the log stream.
Definition: Log.h:35
void const char const char int * n
Definition: Matrix.h:42
void setAlign(const std::vector< double > &align)
set weights
Definition: RMSD.cpp:121
RMSD(Log &log)
Constructor.
Definition: RMSD.cpp:35
const std::vector< Vector > & getPositions() const
Access to the position array.
Definition: PDB.cpp:31
const std::vector< double > & getBeta() const
Access to the beta array.
Definition: PDB.cpp:39
A class that is intended to include or combine various optimal alignment algorithms.
int printf(const char *fmt,...)
Formatted output with explicit format - a la printf.
Definition: OFile.cpp:82
const std::vector< double > & getOccupancy() const
Access to the occupancy array.
Definition: PDB.cpp:35
OptimalAlignment * myoptimalalignment
Definition: RMSD.h:69
T dotProduct(const std::vector< T > &A, const std::vector< T > &B)
Calculate the dot product between two vectors.
Definition: Matrix.h:54
void setReference(const std::vector< Vector > &reference)
set reference coordinates
Definition: RMSD.cpp:112
double modulo2() const
compute the squared modulo
Definition: Vector.h:267
void const char const char int double int double double int int double int double * w
Definition: Matrix.h:42
void set(const PDB &, std::string mytype)
set reference, align and displace from input pdb structure
Definition: RMSD.cpp:65
Minimalistic pdb parser.
Definition: PDB.h:38
int diagMat(const Matrix< T > &A, std::vector< double > &eigenvals, Matrix< double > &eigenvecs)
Definition: Matrix.h:203
~RMSD()
the destructor needs to delete the myalignment object eventually
Definition: RMSD.cpp:98
double modulo2(const VectorGeneric< n > &v)
Definition: Vector.h:330
void const char const char int double int double double int int double int * m
Definition: Matrix.h:42
Log * log
Definition: RMSD.h:70
std::vector< double > displace
Definition: RMSD.h:68
RMSD & operator=(const RMSD &)
assignment
Definition: RMSD.cpp:40
Tensor3d Tensor
Definition: Tensor.h:425
void setDisplace(const std::vector< double > &displace)
set align
Definition: RMSD.cpp:126
std::string getMethod()
Definition: RMSD.cpp:102
std::vector< double > align
Definition: RMSD.h:67
double simpleAlignment(const std::vector< double > &align, const std::vector< double > &displace, const std::vector< Vector > &positions, const std::vector< Vector > &reference, Log *&log, std::vector< Vector > &derivatives, bool squared=false)
Definition: RMSD.cpp:172
void setType(std::string mytype)
set the type of alignment we are doing
Definition: RMSD.cpp:73
AlignmentMethod alignmentMethod
Definition: RMSD.h:65
T norm(const std::vector< T > &A)
Calculate the dot product between a vector and itself.
Definition: Matrix.h:61