All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
OptimalAlignment.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 "OptimalAlignment.h"
23 #include "Kearsley.h"
24 #include "Log.h"
25 #include <cmath>
26 #include <iostream>
27 #include <cstdlib>
28 #include "Random.h"
29 
30 using namespace std;
31 namespace PLMD{
32 
33 OptimalAlignment::OptimalAlignment( const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & p0, const std::vector<Vector> & p1 , Log* &log )
34 :log(log){
35 
36  // kearsley init to null
37  mykearsley=NULL;
38  if (mykearsley==NULL) {
39  mykearsley=new Kearsley(p0,p1,align,log);
40  }
41  // copy the structure into place
42  assignP0(p0);
43  assignP1(p1);
44  assignAlign(align);
45  assignDisplace(displace);
46 
47  // basic check
48  if(p0.size() != p1.size()){
49  (this->log)->printf("THE SIZE OF THE TWO FRAMES TO BE ALIGNED ARE DIFFERENT\n");
50  }
51  // fast behaviour: if all the alignment and displacement are 1.0 then go for fast
52  fast=true;
53  for (unsigned i=0;i<align.size();i++ ){
54  if(align[i]!=displace[i] || align[i]!=1.0)fast=false;
55  }
56 
57 }
58 
60  if (mykearsley!=NULL)delete mykearsley;
61 }
62 
63 void OptimalAlignment::assignP0( const std::vector<Vector> & p0 ){
64  this->p0=p0;
65  if(mykearsley!=NULL){mykearsley->assignP0(p0);}else{cerr<<"kearsley is not initialized"<<endl; exit(0);}
66 }
67 
68 void OptimalAlignment::assignP1( const std::vector<Vector> & p1 ){
69  this->p1=p1;
70  if(mykearsley!=NULL){mykearsley->assignP1(p1);}else{cerr<<"kearsley is not initialized"<<endl; exit(0);}
71 }
72 
73 void OptimalAlignment::assignAlign( const std::vector<double> & align ){
74  this->align=align;
75  if(mykearsley!=NULL){mykearsley->assignAlign(align);}else{cerr<<"kearsley is not initialized"<<endl; exit(0);}
76 }
77 
78 void OptimalAlignment::assignDisplace( const std::vector<double> & displace ){
79  this->displace=displace;
80 }
81 
82 
83 double OptimalAlignment::calculate(bool squared, std::vector<Vector> & derivatives){
84 
85  bool rmsd=!squared ;
86 
87  double err;
88 
89  // at this point everything should be already in place for calculating the alignment (p1,p2,align)
90  // here everything is done with kearsley algorithm. Extension to other optimal alignment algos is
91  // possible here below with a switch
92 
93  err=mykearsley->calculate(rmsd); // this calculates the MSD: transform into RMSD
94 
95  // check findiff alignment
96  //mykearsley->finiteDifferenceInterface(rmsd);
97 
98  if(fast){
99  //log->printf("Doing fast: ERR %12.6f \n",err);
102  derivatives=derrdp0;
103  }else{
104  /// TODO this interface really sucks since is strongly asymmetric should be re-engineered.
105  err=weightedAlignment(rmsd);
106  //log->printf("Doing slow: ERR %12.6f \n",err);
107  derivatives=derrdp0;
108  }
109  // destroy the kearsley object?
110 
111  return err;
112 }
113 
114 #ifdef __INTEL_COMPILER
115 #pragma intel optimization_level 2
116 #endif
117 /// this does the weighed alignment if the vector of alignment is different from displacement
119  double tmp0,tmp1,walign,wdisplace,const1,ret;
120  unsigned i,k,l,m,n,o,oo,mm;
121 
122  unsigned natoms=p0.size();
123 
124  Kearsley *myk=mykearsley; /// just a shortcut
125 
126  /// TODO : these two blocks can be calculated once forever after the initialization (exception for certain methods?)
127 
128  /// clear derivatives
129  if (derrdp0.size()!=natoms)derrdp0.resize(natoms);
130  if (derrdp1.size()!=natoms)derrdp1.resize(natoms);
131 
132  // clear the container
133  for(i=0;i<natoms;i++){
134  derrdp0[i][0]=derrdp0[i][1]=derrdp0[i][2]=0.;
135  derrdp1[i][0]=derrdp1[i][1]=derrdp1[i][2]=0.;
136  }
137 
138  walign=0.;
139  vector<int> alignmap;
140  for(i=0;i<natoms;i++){
141  if (align[i]>0.){
142  alignmap.push_back(i);
143  walign+=align[i];
144  }
145  if (align[i]<0.){cerr<<"FOUND ALIGNMENT WEIGHT NEGATIVE!"<<endl;exit(0);};
146  }
147 
148  wdisplace=0.;
149  vector<int> displacemap;
150  for(i=0;i<natoms;i++){
151  if (displace[i]>0.){
152  displacemap.push_back(i);
153  wdisplace+=displace[i];
154  }
155  if (displace[i]<0.){cerr<<"FOUND ALIGNMENT WEIGHT NEGATIVE!"<<endl;exit(0);};
156  }
157 
158 
159  tmp0=0.;
160 
161  vector<Vector> array_n_3;
162  array_n_3.resize(natoms);
163  for(i=0;i<array_n_3.size();i++)array_n_3[i][0]=array_n_3[i][1]=array_n_3[i][2]=0.;
164 
165  // err= (1/totdisplace) sum_k_l displace_k*((p0reset_k_l- sum_k_m rot_l_m*p1reset_k_m )**2)
166 
167  //for(kk=0;kk<displacemap.size();kk++){
168  // k=displacemap[kk];
169  for(k=0;k<natoms;k++){
170 
171  for(l=0;l<3;l++){
172 
173  tmp1=0.;
174  // contribution from rotated reference frame //
175  for(m=0;m<3;m++){
176  tmp1-=myk->rotmat0on1[l][m]*myk->p1reset[k][m];
177  }
178 
179  // contribution from running centered frame //
180  tmp1+= myk->p0reset[k][l];
181 
182  array_n_3[k][l]=tmp1; // store coefficents for derivative usage//
183  tmp0+=tmp1*tmp1*displace[k]; //squared distance added//
184  }
185 
186  }
187 
188  tmp0=tmp0/wdisplace;
189 
190  // log->printf(" ERRR NEW %f \n",tmp0);
191 
192  ret=tmp0;
193 
194  /* DERIVATIVE CALCULATION:respect to running frame */
195  for(k=0;k<natoms;k++){
196  for(l=0;l<3;l++){
197 
198  tmp1 =2.*array_n_3[k][l]*displace[k]/wdisplace ; //ok
199 
200  const1=2.*align[k]/(walign*wdisplace);
201 
202  if(const1>0.){
203  for(oo=0;oo<displacemap.size();oo++){
204  o=displacemap[oo];
205  tmp1 -=const1*array_n_3[o][l]*displace[o]; //ok
206  }
207  }
208 
209  for(mm=0;mm<displacemap.size();mm++){
210  m=displacemap[mm];
211  const1=2.* displace[m]/wdisplace ;
212  for(n=0;n<3;n++){
213  tmp0=0.;
214  for(o=0;o<3;o++){
215  int ind=n*3*3*natoms+o*3*natoms+l*natoms+k; //ok
216  tmp0+=myk->dmatdp0[ind]*myk->p1reset[m][o];
217  }
218  tmp0*=-const1*array_n_3[m][n];
219 
220  tmp1+=tmp0;
221  }
222  }
223 
224  derrdp0[k][l]=tmp1;
225 
226  }
227  }
228  //exit(0);
229 
230  //return ret;
231  bool do_frameref_der=true;
232 
233  // derivatives of
234  // err= (1/totdisplace) sum_k_l displace_k*((p0reset_k_l- sum_m rot_l_m*p1reset_k_m )**2)
235  // respect p1:
236  // derr_dp1=(1/totdisplace) sum_k_l 2*displace_k*(p0reset_k_l- sum_m rot_l_m*p1reset_k_m )
237  // *d/dp1 ( p0reset_k_l- sum_m rot_l_m*p1reset_k_m)
238  // =
239  // (1/totdisplace) sum_k_l 2*displace_k*(p0reset_k_l- sum_m rot_l_m*p1reset_k_m )*
240  // *(d/dp1 p0reset_k_l
241  // - sum_m (d/dp1 rot_l_m)*p1reset_k_m
242  // - sum_m rot_l_m*(d/dp1 p1reset_k_m ) )
243  // =
244  // sum_k_l 2*displace_k/totdisplace* array_n_3_k_l
245  // *(- sum_m (d/dp1 rot_l_m)*p1reset_k_m
246  // - sum_m rot_l_m*(d/dp1 p1reset_k_m ) )
247 
248  if(do_frameref_der){
249  for(k=0;k<natoms;k++){
250 // for(kk=0;kk<displacemap.size();kk++){
251 // k=displacemap[kk];
252 
253  for(l=0;l<3;l++){
254 
255  tmp1=0.;
256  for(mm=0;mm<displacemap.size();mm++){
257  m=displacemap[mm];
258  const1=2.* displace[m]/wdisplace ;
259  for(n=0;n<3;n++){
260  tmp0=0.;
261  for(o=0;o<3;o++){
262  int ind=n*3*3*natoms+o*3*natoms+l*natoms+k;
263  tmp0+=myk->dmatdp1[ind]*myk->p1reset[m][o];
264  }
265  tmp0*=-const1*array_n_3[m][n];
266  tmp1+= tmp0;
267  }
268 
269  }
270 
271  tmp0=0.;
272  for(o=0;o<3;o++){
273  tmp0+=array_n_3[k][o]*myk->rotmat0on1[o][l];
274  }
275  tmp1+=-tmp0*2.*displace[k]/wdisplace;
276 
277  tmp0=0.;
278 
279  for(mm=0;mm<displacemap.size();mm++){
280  m=displacemap[mm];
281  for(o=0;o<3;o++){
282  tmp0+=array_n_3[m][o]*myk->rotmat0on1[o][l]*displace[m];
283  }
284  }
285  tmp1 += tmp0*2.*align[k]/(walign*wdisplace);
286 
287  derrdp1[k][l]=tmp1;
288 
289  }
290  }
291  }
292 
293  /// probably not really the way it should be
294  if (rmsd){
295  ret=sqrt(ret);
296  double tmp=0.5/ret;
297  for(unsigned i=0;i<natoms;i++){
298  derrdp0[i][0]=derrdp0[i][0]*tmp;
299  derrdp0[i][1]=derrdp0[i][1]*tmp;
300  derrdp0[i][2]=derrdp0[i][2]*tmp;
301  derrdp1[i][0]=derrdp1[i][0]*tmp;
302  derrdp1[i][1]=derrdp1[i][1]*tmp;
303  derrdp1[i][2]=derrdp1[i][2]*tmp;
304 
305  }
306  }
307 
308  return ret;
309 }
310 
312 
313  Random rnd;
314 
315  log->printf("Entering rmsd finite difference test system\n ");
316  log->printf("RMSD OR MSD: %s\n",(rmsd)?"rmsd":"msd");
317  log->printf("-------------------------------------------\n");
318  log->printf("TEST1: derivative of the value (derr_dr0/derr_dr1)\n");
319  //// test 1
320  double step=1.e-8,olderr,delta,err;
321  vector<Vector> fakederivatives;
322  fakederivatives.resize(p0.size());
323  fast=false;
324  // randomizing alignments and displacements
325 /* for (i=0;i<p0.size();i++){
326  // draw a random number
327  delta=drand48();
328  delta1=drand48();
329  if(delta>delta1){
330  align[i]=delta;
331  }else{align[i]=0.;};
332  delta=drand48();
333  delta1=drand48();
334  if(delta>delta1){
335  displace[i]=delta;
336  }else{displace[i]=0.;}
337  }*/
338  //// get initial value of the error and derivative of it
341  olderr=calculate(rmsd, fakederivatives);
342 
343  log->printf("INITIAL ERROR VALUE: %e\n",olderr);
344 
345  // randomizing alignments and displacements
346  log->printf("TESTING: derrdp0 \n");
347 
348  for(unsigned j=0;j<3;j++){
349  for(unsigned i=0;i<derrdp0.size();i++){
350  // random displacement
351  delta=(rnd.RandU01()-0.5)*2*step;
352  p0[i][j]+=delta;
353  assignP0( p0 );
354  err=calculate(rmsd, fakederivatives);
355  p0[i][j]-=delta;
356  assignP0( p0 );
357  switch(j){
358  case 0:
359  log->printf("TESTING: X %4u ANAL %18.9f NUMER %18.9f DELTA %18.9f DISP %6.2f ALIGN %6.2f \n",i,derrdp0[i][j],(err-olderr)/delta,derrdp0[i][j]-(err-olderr)/delta,displace[i],align[i]);break;
360  case 1:
361  log->printf("TESTING: Y %4u ANAL %18.9f NUMER %18.9f DELTA %18.9f DISP %6.2f ALIGN %6.2f \n",i,derrdp0[i][j],(err-olderr)/delta,derrdp0[i][j]-(err-olderr)/delta,displace[i],align[i]);break;
362  case 2:
363  log->printf("TESTING: Z %4u ANAL %18.9f NUMER %18.9f DELTA %18.9f DISP %6.2f ALIGN %6.2f \n",i,derrdp0[i][j],(err-olderr)/delta,derrdp0[i][j]-(err-olderr)/delta,displace[i],align[i]);break;
364 
365  }
366  }
367  }
368 
369  log->printf("TESTING: derrdp1 \n");
370  for(unsigned j=0;j<3;j++){
371  for(unsigned i=0;i<derrdp1.size();i++){
372  // random displacement
373  delta=(rnd.RandU01()-0.5)*2*step;
374  p1[i][j]+=delta;
375  assignP1( p1 );
376  err=calculate(rmsd, fakederivatives);
377  p1[i][j]-=delta;
378  assignP1( p1 );
379  switch(j){
380  case 0:
381  log->printf("TESTING: X %4u ANAL %18.9f NUMER %18.9f DELTA %18.9f DISP %6.2f ALIGN %6.2f \n",i,derrdp1[i][j],(err-olderr)/delta,derrdp1[i][j]-(err-olderr)/delta,displace[i],align[i]);break;
382  case 1:
383  log->printf("TESTING: Y %4u ANAL %18.9f NUMER %18.9f DELTA %18.9f DISP %6.2f ALIGN %6.2f \n",i,derrdp1[i][j],(err-olderr)/delta,derrdp1[i][j]-(err-olderr)/delta,displace[i],align[i]);break;
384  case 2:
385  log->printf("TESTING: Z %4u ANAL %18.9f NUMER %18.9f DELTA %18.9f DISP %6.2f ALIGN %6.2f \n",i,derrdp1[i][j],(err-olderr)/delta,derrdp1[i][j]-(err-olderr)/delta,displace[i],align[i]);break;
386 
387  }
388  }
389  }
390  exit(0);
391 
392 // This is to avoid warnings:
393  return 0.0;
394 
395 }
396 
397 
398 
399 }
std::vector< double > dmatdp1
Definition: Kearsley.h:220
double weightedFindiffTest(bool rmsd)
double calculate(bool rmsd, std::vector< Vector > &derivatives)
this does the real calculation
void assignP0(const std::vector< Vector > &p0)
assignment of the running frame p0
std::vector< Vector > p0
position of one frame (generally the MD)
void assignP1(const std::vector< Vector > &p1)
assignment to the reference frame p1
STL namespace.
void assignDisplace(const std::vector< double > &displace)
std::vector< Vector > p1
position of the reference frames
Class containing the log stream.
Definition: Log.h:35
void const char const char int * n
Definition: Matrix.h:42
std::vector< Vector > p1reset
position resetted wrt coms p1
Definition: Kearsley.h:206
Kearsley * mykearsley
a pointer to the object that performs the optimal alignment via quaternions
std::vector< Vector > derrdp1
derivatives: derivative of the error respect p1
Definition: Kearsley.h:216
std::vector< double > align
alignment vector: a double that says if the atom has to be used in reset COM and makeing the alignmen...
void assignP0(const std::vector< Vector > &p0)
switch the assignment of the structure p0 (e.g. at each md step)
Definition: Kearsley.cpp:729
double calculate(bool rmsd)
Definition: Kearsley.cpp:65
int printf(const char *fmt,...)
Formatted output with explicit format - a la printf.
Definition: OFile.cpp:82
VectorGeneric< n > delta(const VectorGeneric< n > &v1, const VectorGeneric< n > &v2)
Definition: Vector.h:262
std::vector< Vector > p0reset
position resetted wrt coms p0
Definition: Kearsley.h:204
double weightedAlignment(bool rmsd)
this should perform the weighted alignment
void assignAlign(const std::vector< double > &align)
void assignP1(const std::vector< Vector > &p1)
derivatives: derivative of the error respect p1
Definition: Kearsley.cpp:725
std::vector< double > displace
displacement vector : a double that says if the coordinate should be used in calculating the RMSD/MSD...
bool fast
a bool that decides to make the fast version (alignment vec= displacement vec) or the slower case ...
std::vector< Vector > derrdp0
derivatives of the error respect to the p0 (MD running frame)
void const char const char int double int double double int int double int * m
Definition: Matrix.h:42
double RandU01()
Definition: Random.cpp:56
std::vector< Vector > derrdp1
derivatives of the error respect to the p1 (static frame, do not remove: useful for SM) ...
~OptimalAlignment()
the destructor: delete kearsley
void assignAlign(const std::vector< double > &align)
transfer the alignment vector
Definition: Kearsley.cpp:734
std::vector< double > dmatdp0
derivative of the rotation matrix note the dimension 3x3 x 3 x N
Definition: Kearsley.h:219
Tensor rotmat0on1
rotation matrices p0 on p1 and reverse (p1 over p0)
Definition: Kearsley.h:212
std::vector< Vector > derrdp0
derivatives: derivative of the error respect p0
Definition: Kearsley.h:214
Log * log
the pointer to the logfile