LCOV - code coverage report
Current view: top level - tools - RMSD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 479 649 73.8 %
Date: 2018-12-19 07:49:13 Functions: 33 62 53.2 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2018 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.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       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 "Exception.h"
      26             : #include <cmath>
      27             : #include <iostream>
      28             : #include "Tools.h"
      29             : using namespace std;
      30             : namespace PLMD {
      31             : 
      32        1923 : RMSD::RMSD() : alignmentMethod(SIMPLE),reference_center_is_calculated(false),reference_center_is_removed(false),positions_center_is_calculated(false),positions_center_is_removed(false) {}
      33             : 
      34             : ///
      35             : /// general method to set all the rmsd property at once by using a pdb where occupancy column sets the weights for the atoms involved in the
      36             : /// alignment and beta sets the weight that are used for calculating the displacement.
      37             : ///
      38         949 : void RMSD::set(const PDB&pdb, const string & mytype, bool remove_center, bool normalize_weights ) {
      39             : 
      40         949 :   set(pdb.getOccupancy(),pdb.getBeta(),pdb.getPositions(),mytype,remove_center,normalize_weights);
      41             : 
      42         949 : }
      43        1877 : void RMSD::set(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & reference, const string & mytype, bool remove_center, bool normalize_weights ) {
      44             : 
      45        1877 :   setReference(reference); // this by default remove the com and assumes uniform weights
      46        1877 :   setAlign(align, normalize_weights, remove_center); // this recalculates the com with weights. If remove_center=false then it restore the center back
      47        1877 :   setDisplace(displace, normalize_weights);  // this is does not affect any calculation of the weights
      48        1877 :   setType(mytype);
      49             : 
      50        1877 : }
      51             : 
      52        1877 : void RMSD::setType(const string & mytype) {
      53             : 
      54        1877 :   alignmentMethod=SIMPLE; // initialize with the simplest case: no rotation
      55        1877 :   if (mytype=="SIMPLE") {
      56           0 :     alignmentMethod=SIMPLE;
      57             :   }
      58        1877 :   else if (mytype=="OPTIMAL") {
      59        1877 :     alignmentMethod=OPTIMAL;
      60             :   }
      61           0 :   else if (mytype=="OPTIMAL-FAST") {
      62           0 :     alignmentMethod=OPTIMAL_FAST;
      63             :   }
      64           0 :   else plumed_merror("unknown RMSD type" + mytype);
      65             : 
      66        1877 : }
      67             : 
      68         923 : void RMSD::clear() {
      69         923 :   reference.clear();
      70         923 :   reference_center_is_calculated=false;
      71         923 :   reference_center_is_removed=false;
      72         923 :   align.clear();
      73         923 :   displace.clear();
      74         923 :   positions_center_is_calculated=false;
      75         923 :   positions_center_is_removed=false;
      76         923 : }
      77             : 
      78           4 : string RMSD::getMethod() {
      79           4 :   string mystring;
      80           4 :   switch(alignmentMethod) {
      81           0 :   case SIMPLE: mystring.assign("SIMPLE"); break;
      82           4 :   case OPTIMAL: mystring.assign("OPTIMAL"); break;
      83           0 :   case OPTIMAL_FAST: mystring.assign("OPTIMAL-FAST"); break;
      84             :   }
      85           4 :   return mystring;
      86             : }
      87             : ///
      88             : /// this calculates the center of mass for the reference and removes it from the reference itself
      89             : /// considering uniform weights for alignment
      90             : ///
      91        1877 : void RMSD::setReference(const vector<Vector> & reference) {
      92        1877 :   unsigned n=reference.size();
      93        1877 :   this->reference=reference;
      94        1877 :   plumed_massert(align.empty(),"you should first clear() an RMSD object, then set a new reference");
      95        1877 :   plumed_massert(displace.empty(),"you should first clear() an RMSD object, then set a new reference");
      96        1877 :   align.resize(n,1.0/n);
      97        1877 :   displace.resize(n,1.0/n);
      98        1877 :   for(unsigned i=0; i<n; i++) reference_center+=this->reference[i]*align[i];
      99        1877 :   for(unsigned i=0; i<n; i++) this->reference[i]-=reference_center;
     100        1877 :   reference_center_is_calculated=true;
     101        1877 :   reference_center_is_removed=true;
     102        1877 : }
     103             : ///
     104             : /// the alignment weights are here normalized to 1 and  the center of the reference is removed accordingly
     105             : ///
     106        1877 : void RMSD::setAlign(const vector<double> & align, bool normalize_weights, bool remove_center) {
     107        1877 :   unsigned n=reference.size();
     108        1877 :   plumed_massert(this->align.size()==align.size(),"mismatch in dimension of align/displace arrays");
     109        1877 :   this->align=align;
     110        1877 :   if(normalize_weights) {
     111        1873 :     double w=0.0;
     112        1873 :     for(unsigned i=0; i<n; i++) w+=this->align[i];
     113        1873 :     double inv=1.0/w;
     114        1873 :     for(unsigned i=0; i<n; i++) this->align[i]*=inv;
     115             :   }
     116             :   // recalculate the center anyway
     117             :   // just remove the center if that is asked
     118             :   // if the center was removed before, then add it and store the new one
     119        1877 :   if(reference_center_is_removed) {
     120        1877 :     plumed_massert(reference_center_is_calculated," seems that the reference center has been removed but not calculated and stored!");
     121        1877 :     addCenter(reference,reference_center);
     122             :   }
     123        1877 :   reference_center=calculateCenter(reference,this->align);
     124        1877 :   reference_center_is_calculated=true;
     125        1877 :   if(remove_center) {
     126        1873 :     removeCenter(reference,reference_center);
     127        1873 :     reference_center_is_removed=true;
     128             :   } else {
     129           4 :     reference_center_is_removed=false;
     130             :   }
     131        1877 : }
     132             : ///
     133             : /// here the weigth for normalized weighths are normalized and set
     134             : ///
     135        1877 : void RMSD::setDisplace(const vector<double> & displace, bool normalize_weights) {
     136        1877 :   unsigned n=reference.size();
     137        1877 :   plumed_massert(this->displace.size()==displace.size(),"mismatch in dimension of align/displace arrays");
     138        1877 :   this->displace=displace;
     139        1877 :   double w=0.0;
     140        1877 :   for(unsigned i=0; i<n; i++) w+=this->displace[i];
     141        1877 :   double inv=1.0/w;
     142        1877 :   if(normalize_weights) {for(unsigned i=0; i<n; i++) this->displace[i]*=inv;}
     143        1877 : }
     144             : ///
     145             : /// This is the main workhorse for rmsd that decides to use specific optimal alignment versions
     146             : ///
     147      285145 : double RMSD::calculate(const std::vector<Vector> & positions,std::vector<Vector> &derivatives, bool squared)const {
     148             : 
     149      285145 :   double ret=0.;
     150             : 
     151      285145 :   switch(alignmentMethod) {
     152             :   case SIMPLE : {
     153             :     //  do a simple alignment without rotation
     154           0 :     std::vector<Vector> displacement( derivatives.size() );
     155           0 :     ret=simpleAlignment(align,displace,positions,reference,derivatives,displacement,squared);
     156           0 :     break;
     157             :   } case OPTIMAL_FAST : {
     158             :     // this is calling the fastest option:
     159           0 :     if(align==displace) ret=optimalAlignment<false,true>(align,displace,positions,reference,derivatives,squared);
     160           0 :     else                ret=optimalAlignment<false,false>(align,displace,positions,reference,derivatives,squared);
     161           0 :     break;
     162             : 
     163             :   } case OPTIMAL : {
     164             :     // this is the fast routine but in the "safe" mode, which gives less numerical error:
     165      285145 :     if(align==displace) ret=optimalAlignment<true,true>(align,displace,positions,reference,derivatives,squared);
     166           1 :     else ret=optimalAlignment<true,false>(align,displace,positions,reference,derivatives,squared);
     167      285145 :     break;
     168             :   }
     169             :   }
     170             : 
     171      285145 :   return ret;
     172             : 
     173             : }
     174             : 
     175             : 
     176             : /// convenience method for calculating the standard derivatives and the derivative of the rmsd respect to the reference position
     177           1 : double RMSD::calc_DDistDRef( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, const bool squared  ) {
     178           1 :   double ret=0.;
     179           1 :   switch(alignmentMethod) {
     180             :   case SIMPLE:
     181           0 :     plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
     182             :     break;
     183             :   case OPTIMAL_FAST:
     184           0 :     if(align==displace) ret=optimalAlignment_DDistDRef<false,true>(align,displace,positions,reference,derivatives,DDistDRef, squared);
     185           0 :     else                ret=optimalAlignment_DDistDRef<false,false>(align,displace,positions,reference,derivatives,DDistDRef,squared);
     186           0 :     break;
     187             :   case OPTIMAL:
     188           1 :     if(align==displace) ret=optimalAlignment_DDistDRef<true,true>(align,displace,positions,reference,derivatives,DDistDRef,squared);
     189           1 :     else                ret=optimalAlignment_DDistDRef<true,false>(align,displace,positions,reference,derivatives,DDistDRef,squared);
     190           1 :     break;
     191             :   }
     192           1 :   return ret;
     193             : 
     194             : }
     195             : 
     196             : /// convenience method for calculating the standard derivatives and the derivative of the rmsd respect to the reference position without the matrix contribution
     197             : /// as required by SOMA
     198           0 : double RMSD::calc_SOMA( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, const bool squared  ) {
     199           0 :   double ret=0.;
     200           0 :   switch(alignmentMethod) {
     201             :   case SIMPLE:
     202           0 :     plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
     203             :     break;
     204             :   case OPTIMAL_FAST:
     205           0 :     if(align==displace) ret=optimalAlignment_SOMA<false,true>(align,displace,positions,reference,derivatives,DDistDRef, squared);
     206           0 :     else                ret=optimalAlignment_SOMA<false,false>(align,displace,positions,reference,derivatives,DDistDRef,squared);
     207           0 :     break;
     208             :   case OPTIMAL:
     209           0 :     if(align==displace) ret=optimalAlignment_SOMA<true,true>(align,displace,positions,reference,derivatives,DDistDRef,squared);
     210           0 :     else                ret=optimalAlignment_SOMA<true,false>(align,displace,positions,reference,derivatives,DDistDRef,squared);
     211           0 :     break;
     212             :   }
     213           0 :   return ret;
     214             : 
     215             : }
     216             : 
     217           0 : double RMSD::calc_DDistDRef_Rot_DRotDPos( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, Tensor & Rot, Matrix<std::vector<Vector> > &DRotDPos, const bool squared  ) {
     218           0 :   double ret=0.;
     219           0 :   switch(alignmentMethod) {
     220             :   case SIMPLE:
     221           0 :     plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
     222             :     break;
     223             :   case OPTIMAL_FAST:
     224           0 :     if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos<false,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos,  squared);
     225           0 :     else                ret=optimalAlignment_DDistDRef_Rot_DRotDPos<false,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared);
     226           0 :     break;
     227             :   case OPTIMAL:
     228           0 :     if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos<true,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared);
     229           0 :     else                ret=optimalAlignment_DDistDRef_Rot_DRotDPos<true,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared);
     230           0 :     break;
     231             :   }
     232           0 :   return ret;
     233             : }
     234             : 
     235           0 : double RMSD::calc_DDistDRef_Rot_DRotDPos_DRotDRef( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, Tensor & Rot, Matrix<std::vector<Vector> > &DRotDPos,  Matrix<std::vector<Vector> > &DRotDRef, const bool squared  ) {
     236           0 :   double ret=0.;
     237           0 :   switch(alignmentMethod) {
     238             :   case SIMPLE:
     239           0 :     plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
     240             :     break;
     241             :   case OPTIMAL_FAST:
     242           0 :     if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<false,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef,   squared);
     243           0 :     else                ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<false,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef,  squared);
     244           0 :     break;
     245             :   case OPTIMAL:
     246           0 :     if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<true,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared);
     247           0 :     else                ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<true,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared);
     248           0 :     break;
     249             :   }
     250           0 :   return ret;
     251             : }
     252             : 
     253        1670 : double RMSD::calc_PCAelements( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos,std::vector<Vector>  & alignedpositions, std::vector<Vector> & centeredpositions, std::vector<Vector> &centeredreference, const bool& squared  ) const {
     254        1670 :   double ret=0.;
     255        1670 :   switch(alignmentMethod) {
     256             :   case SIMPLE:
     257           0 :     plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
     258             :     break;
     259             :   case OPTIMAL_FAST:
     260           0 :     if(align==displace) ret=optimalAlignment_PCA<false,true>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared);
     261           0 :     else                ret=optimalAlignment_PCA<false,false>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared);
     262           0 :     break;
     263             :   case OPTIMAL:
     264        1670 :     if(align==displace) ret=optimalAlignment_PCA<true,true>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared);
     265           0 :     else                ret=optimalAlignment_PCA<true,false>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared);
     266        1670 :     break;
     267             :   }
     268        1670 :   return ret;
     269             : }
     270             : 
     271             : 
     272          48 : double RMSD::calc_FitElements( const std::vector<Vector>& positions, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos, std::vector<Vector> & centeredpositions, Vector &center_positions, const bool& squared  ) {
     273          48 :   double ret=0.;
     274          48 :   switch(alignmentMethod) {
     275             :   case SIMPLE:
     276           0 :     plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
     277             :     break;
     278             :   case OPTIMAL_FAST:
     279           0 :     if(align==displace)ret=optimalAlignment_Fit<false,true>(align,displace,positions,reference, Rotation,DRotDPos,centeredpositions,center_positions,squared);
     280           0 :     else               ret=optimalAlignment_Fit<false,false>(align,displace,positions,reference, Rotation,DRotDPos,centeredpositions,center_positions,squared);
     281           0 :     break;
     282             :   case OPTIMAL:
     283          48 :     if(align==displace)ret=optimalAlignment_Fit<true,true>(align,displace,positions,reference,Rotation,DRotDPos,centeredpositions,center_positions,squared);
     284          48 :     else               ret=optimalAlignment_Fit<true,false>(align,displace,positions,reference,Rotation,DRotDPos,centeredpositions,center_positions,squared);
     285          48 :     break;
     286             :   }
     287          48 :   return ret;
     288             : }
     289             : 
     290             : 
     291             : 
     292             : 
     293             : 
     294             : 
     295         148 : double RMSD::simpleAlignment(const  std::vector<double>  & align,
     296             :                              const  std::vector<double>  & displace,
     297             :                              const std::vector<Vector> & positions,
     298             :                              const std::vector<Vector> & reference,
     299             :                              std::vector<Vector>  & derivatives,
     300             :                              std::vector<Vector>  & displacement,
     301             :                              bool squared)const {
     302             : 
     303         148 :   double dist(0);
     304         148 :   unsigned n=reference.size();
     305             : 
     306         148 :   Vector apositions;
     307         148 :   Vector areference;
     308         148 :   Vector dpositions;
     309         148 :   Vector dreference;
     310             : 
     311        2417 :   for(unsigned i=0; i<n; i++) {
     312        2269 :     double aw=align[i];
     313        2269 :     double dw=displace[i];
     314        2269 :     apositions+=positions[i]*aw;
     315        2269 :     areference+=reference[i]*aw;
     316        2269 :     dpositions+=positions[i]*dw;
     317        2269 :     dreference+=reference[i]*dw;
     318             :   }
     319             : 
     320         148 :   Vector shift=((apositions-areference)-(dpositions-dreference));
     321        2417 :   for(unsigned i=0; i<n; i++) {
     322        2269 :     displacement[i]=(positions[i]-apositions)-(reference[i]-areference);
     323        2269 :     dist+=displace[i]*displacement[i].modulo2();
     324        2269 :     derivatives[i]=2*(displace[i]*displacement[i]+align[i]*shift);
     325             :   }
     326             : 
     327         148 :   if(!squared) {
     328             :     // sqrt
     329         105 :     dist=sqrt(dist);
     330             :     ///// sqrt on derivatives
     331         105 :     for(unsigned i=0; i<n; i++) {derivatives[i]*=(0.5/dist);}
     332             :   }
     333         148 :   return dist;
     334             : }
     335             : 
     336             : // this below enable the standard case for rmsd where the rmsd is calculated and the derivative of rmsd respect to positions is retrieved
     337             : // additionally this assumes that the com of the reference is already subtracted.
     338             : #define OLDRMSD
     339             : #ifdef OLDRMSD
     340             : // notice that in the current implementation the safe argument only makes sense for
     341             : // align==displace
     342             : template <bool safe,bool alEqDis>
     343      476203 : double RMSD::optimalAlignment(const  std::vector<double>  & align,
     344             :                               const  std::vector<double>  & displace,
     345             :                               const std::vector<Vector> & positions,
     346             :                               const std::vector<Vector> & reference,
     347             :                               std::vector<Vector>  & derivatives, bool squared)const {
     348      476203 :   double dist(0);
     349      476203 :   const unsigned n=reference.size();
     350             : // This is the trace of positions*positions + reference*reference
     351      476665 :   double rr00(0);
     352      476665 :   double rr11(0);
     353             : // This is positions*reference
     354      476665 :   Tensor rr01;
     355             : 
     356      477309 :   derivatives.resize(n);
     357             : 
     358      477506 :   Vector cpositions;
     359             : 
     360             : // first expensive loop: compute centers
     361    21363800 :   for(unsigned iat=0; iat<n; iat++) {
     362    20887338 :     double w=align[iat];
     363    20890490 :     cpositions+=positions[iat]*w;
     364             :   }
     365             : 
     366             : // second expensive loop: compute second moments wrt centers
     367    21368884 :   for(unsigned iat=0; iat<n; iat++) {
     368    20891098 :     double w=align[iat];
     369    20891399 :     rr00+=dotProduct(positions[iat]-cpositions,positions[iat]-cpositions)*w;
     370    20888944 :     rr11+=dotProduct(reference[iat],reference[iat])*w;
     371    20890731 :     rr01+=Tensor(positions[iat]-cpositions,reference[iat])*w;
     372             :   }
     373             : 
     374      477786 :   Matrix<double> m=Matrix<double>(4,4);
     375      477797 :   m[0][0]=2.0*(-rr01[0][0]-rr01[1][1]-rr01[2][2]);
     376      477697 :   m[1][1]=2.0*(-rr01[0][0]+rr01[1][1]+rr01[2][2]);
     377      477716 :   m[2][2]=2.0*(+rr01[0][0]-rr01[1][1]+rr01[2][2]);
     378      477731 :   m[3][3]=2.0*(+rr01[0][0]+rr01[1][1]-rr01[2][2]);
     379      477716 :   m[0][1]=2.0*(-rr01[1][2]+rr01[2][1]);
     380      477758 :   m[0][2]=2.0*(+rr01[0][2]-rr01[2][0]);
     381      477731 :   m[0][3]=2.0*(-rr01[0][1]+rr01[1][0]);
     382      477710 :   m[1][2]=2.0*(-rr01[0][1]-rr01[1][0]);
     383      477747 :   m[1][3]=2.0*(-rr01[0][2]-rr01[2][0]);
     384      477751 :   m[2][3]=2.0*(-rr01[1][2]-rr01[2][1]);
     385      477753 :   m[1][0] = m[0][1];
     386      477757 :   m[2][0] = m[0][2];
     387      477767 :   m[2][1] = m[1][2];
     388      477752 :   m[3][0] = m[0][3];
     389      477762 :   m[3][1] = m[1][3];
     390      477752 :   m[3][2] = m[2][3];
     391             : 
     392      477734 :   Tensor dm_drr01[4][4];
     393             :   if(!alEqDis) {
     394         114 :     dm_drr01[0][0] = 2.0*Tensor(-1.0, 0.0, 0.0,  0.0,-1.0, 0.0,  0.0, 0.0,-1.0);
     395         114 :     dm_drr01[1][1] = 2.0*Tensor(-1.0, 0.0, 0.0,  0.0,+1.0, 0.0,  0.0, 0.0,+1.0);
     396         114 :     dm_drr01[2][2] = 2.0*Tensor(+1.0, 0.0, 0.0,  0.0,-1.0, 0.0,  0.0, 0.0,+1.0);
     397         114 :     dm_drr01[3][3] = 2.0*Tensor(+1.0, 0.0, 0.0,  0.0,+1.0, 0.0,  0.0, 0.0,-1.0);
     398         114 :     dm_drr01[0][1] = 2.0*Tensor( 0.0, 0.0, 0.0,  0.0, 0.0,-1.0,  0.0,+1.0, 0.0);
     399         114 :     dm_drr01[0][2] = 2.0*Tensor( 0.0, 0.0,+1.0,  0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
     400         114 :     dm_drr01[0][3] = 2.0*Tensor( 0.0,-1.0, 0.0, +1.0, 0.0, 0.0,  0.0, 0.0, 0.0);
     401         114 :     dm_drr01[1][2] = 2.0*Tensor( 0.0,-1.0, 0.0, -1.0, 0.0, 0.0,  0.0, 0.0, 0.0);
     402         114 :     dm_drr01[1][3] = 2.0*Tensor( 0.0, 0.0,-1.0,  0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
     403         114 :     dm_drr01[2][3] = 2.0*Tensor( 0.0, 0.0, 0.0,  0.0, 0.0,-1.0,  0.0,-1.0, 0.0);
     404         114 :     dm_drr01[1][0] = dm_drr01[0][1];
     405         114 :     dm_drr01[2][0] = dm_drr01[0][2];
     406         114 :     dm_drr01[2][1] = dm_drr01[1][2];
     407         114 :     dm_drr01[3][0] = dm_drr01[0][3];
     408         114 :     dm_drr01[3][1] = dm_drr01[1][3];
     409         114 :     dm_drr01[3][2] = dm_drr01[2][3];
     410             :   }
     411             : 
     412      955557 :   vector<double> eigenvals;
     413      955087 :   Matrix<double> eigenvecs;
     414      477793 :   int diagerror=diagMat(m, eigenvals, eigenvecs );
     415             : 
     416      476878 :   if (diagerror!=0) {
     417           0 :     string sdiagerror;
     418           0 :     Tools::convert(diagerror,sdiagerror);
     419           0 :     string msg="DIAGONALIZATION FAILED WITH ERROR CODE "+sdiagerror;
     420           0 :     plumed_merror(msg);
     421             :   }
     422             : 
     423      476878 :   dist=eigenvals[0]+rr00+rr11;
     424             : 
     425      954751 :   Matrix<double> ddist_dm(4,4);
     426             : 
     427      477790 :   Vector4d q(eigenvecs[0][0],eigenvecs[0][1],eigenvecs[0][2],eigenvecs[0][3]);
     428             : 
     429      477427 :   Tensor dq_drr01[4];
     430             :   if(!alEqDis) {
     431             :     double dq_dm[4][4][4];
     432        7410 :     for(unsigned i=0; i<4; i++) for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) {
     433        7296 :           double tmp=0.0;
     434             : // perturbation theory for matrix m
     435        7296 :           for(unsigned l=1; l<4; l++) tmp+=eigenvecs[l][j]*eigenvecs[l][i]/(eigenvals[0]-eigenvals[l])*eigenvecs[0][k];
     436        7296 :           dq_dm[i][j][k]=tmp;
     437             :         }
     438             : // propagation to _drr01
     439         570 :     for(unsigned i=0; i<4; i++) {
     440         456 :       Tensor tmp;
     441        7752 :       for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) {
     442        7296 :           tmp+=dq_dm[i][j][k]*dm_drr01[j][k];
     443             :         }
     444         456 :       dq_drr01[i]=tmp;
     445             :     }
     446             :   }
     447             : 
     448             : // This is the rotation matrix that brings reference to positions
     449             : // i.e. matmul(rotation,reference[iat])+shift is fitted to positions[iat]
     450             : 
     451      477772 :   Tensor rotation;
     452      477664 :   rotation[0][0]=q[0]*q[0]+q[1]*q[1]-q[2]*q[2]-q[3]*q[3];
     453      477606 :   rotation[1][1]=q[0]*q[0]-q[1]*q[1]+q[2]*q[2]-q[3]*q[3];
     454      477562 :   rotation[2][2]=q[0]*q[0]-q[1]*q[1]-q[2]*q[2]+q[3]*q[3];
     455      477610 :   rotation[0][1]=2*(+q[0]*q[3]+q[1]*q[2]);
     456      477679 :   rotation[0][2]=2*(-q[0]*q[2]+q[1]*q[3]);
     457      477656 :   rotation[1][2]=2*(+q[0]*q[1]+q[2]*q[3]);
     458      477647 :   rotation[1][0]=2*(-q[0]*q[3]+q[1]*q[2]);
     459      477203 :   rotation[2][0]=2*(+q[0]*q[2]+q[1]*q[3]);
     460      477433 :   rotation[2][1]=2*(-q[0]*q[1]+q[2]*q[3]);
     461             : 
     462             : 
     463      477302 :   Tensor drotation_drr01[3][3];
     464             :   if(!alEqDis) {
     465         114 :     drotation_drr01[0][0]=2*q[0]*dq_drr01[0]+2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3];
     466         114 :     drotation_drr01[1][1]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]+2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3];
     467         114 :     drotation_drr01[2][2]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]+2*q[3]*dq_drr01[3];
     468         114 :     drotation_drr01[0][1]=2*(+(q[0]*dq_drr01[3]+dq_drr01[0]*q[3])+(q[1]*dq_drr01[2]+dq_drr01[1]*q[2]));
     469         114 :     drotation_drr01[0][2]=2*(-(q[0]*dq_drr01[2]+dq_drr01[0]*q[2])+(q[1]*dq_drr01[3]+dq_drr01[1]*q[3]));
     470         114 :     drotation_drr01[1][2]=2*(+(q[0]*dq_drr01[1]+dq_drr01[0]*q[1])+(q[2]*dq_drr01[3]+dq_drr01[2]*q[3]));
     471         114 :     drotation_drr01[1][0]=2*(-(q[0]*dq_drr01[3]+dq_drr01[0]*q[3])+(q[1]*dq_drr01[2]+dq_drr01[1]*q[2]));
     472         114 :     drotation_drr01[2][0]=2*(+(q[0]*dq_drr01[2]+dq_drr01[0]*q[2])+(q[1]*dq_drr01[3]+dq_drr01[1]*q[3]));
     473         114 :     drotation_drr01[2][1]=2*(-(q[0]*dq_drr01[1]+dq_drr01[0]*q[1])+(q[2]*dq_drr01[3]+dq_drr01[2]*q[3]));
     474             :   }
     475             : 
     476      477753 :   double prefactor=2.0;
     477             : 
     478      477639 :   if(!squared && alEqDis) prefactor*=0.5/sqrt(dist);
     479             : 
     480             : // if "safe", recompute dist here to a better accuracy
     481      308634 :   if(safe || !alEqDis) dist=0.0;
     482             : 
     483             : // If safe is set to "false", MSD is taken from the eigenvalue of the M matrix
     484             : // If safe is set to "true", MSD is recomputed from the rotational matrix
     485             : // For some reason, this last approach leads to less numerical noise but adds an overhead
     486             : 
     487      477753 :   Tensor ddist_drotation;
     488      477778 :   Vector ddist_dcpositions;
     489             : 
     490             : // third expensive loop: derivatives
     491    21369757 :   for(unsigned iat=0; iat<n; iat++) {
     492    20891963 :     Vector d(positions[iat]-cpositions - matmul(rotation,reference[iat]));
     493             :     if(alEqDis) {
     494             : // there is no need for derivatives of rotation and shift here as it is by construction zero
     495             : // (similar to Hellman-Feynman forces)
     496    20889971 :       derivatives[iat]= prefactor*align[iat]*d;
     497     4333883 :       if(safe) dist+=align[iat]*modulo2(d);
     498             :     } else {
     499             : // the case for align != displace is different, sob:
     500        2176 :       dist+=displace[iat]*modulo2(d);
     501             : // these are the derivatives assuming the roto-translation as frozen
     502        2176 :       derivatives[iat]=2*displace[iat]*d;
     503             : // here I accumulate derivatives wrt rotation matrix ..
     504        2176 :       ddist_drotation+=-2*displace[iat]*extProduct(d,reference[iat]);
     505             : // .. and cpositions
     506        2176 :       ddist_dcpositions+=-2*displace[iat]*d;
     507             :     }
     508             :   }
     509             : 
     510             :   if(!alEqDis) {
     511         114 :     Tensor ddist_drr01;
     512         114 :     for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) ddist_drr01+=ddist_drotation[i][j]*drotation_drr01[i][j];
     513        2290 :     for(unsigned iat=0; iat<n; iat++) {
     514             : // this is propagating to positions.
     515             : // I am implicitly using the derivative of rr01 wrt positions here
     516        2176 :       derivatives[iat]+=matmul(ddist_drr01,reference[iat])*align[iat];
     517        2176 :       derivatives[iat]+=ddist_dcpositions*align[iat];
     518             :     }
     519             :   }
     520      477794 :   if(!squared) {
     521       74160 :     dist=sqrt(dist);
     522             :     if(!alEqDis) {
     523         114 :       double xx=0.5/dist;
     524         114 :       for(unsigned iat=0; iat<n; iat++) derivatives[iat]*=xx;
     525             :     }
     526             :   }
     527             : 
     528      955589 :   return dist;
     529             : }
     530             : #else
     531             : /// note that this method is intended to be repeatedly invoked
     532             : /// when the reference does already have the center subtracted
     533             : /// but the position has not calculated center and not subtracted
     534             : template <bool safe,bool alEqDis>
     535             : double RMSD::optimalAlignment(const  std::vector<double>  & align,
     536             :                               const  std::vector<double>  & displace,
     537             :                               const std::vector<Vector> & positions,
     538             :                               const std::vector<Vector> & reference,
     539             :                               std::vector<Vector>  & derivatives,
     540             :                               bool squared) const {
     541             :   //std::cerr<<"setting up the core data \n";
     542             :   RMSDCoreData cd(align,displace,positions,reference);
     543             : 
     544             :   // transfer the settings for the center to let the CoreCalc deal with it
     545             :   cd.setPositionsCenterIsRemoved(positions_center_is_removed);
     546             :   if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
     547             :   else {cd.calcPositionsCenter();};
     548             : 
     549             :   cd.setReferenceCenterIsRemoved(reference_center_is_removed);
     550             :   if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
     551             :   else {cd.setReferenceCenter(reference_center);}
     552             : 
     553             :   // Perform the diagonalization and all the needed stuff
     554             :   cd.doCoreCalc(safe,alEqDis);
     555             :   // make the core calc distance
     556             :   double dist=cd.getDistance(squared);
     557             : //  make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
     558             :   derivatives=cd.getDDistanceDPositions();
     559             :   return dist;
     560             : }
     561             : #endif
     562             : template <bool safe,bool alEqDis>
     563           1 : double RMSD::optimalAlignment_DDistDRef(const  std::vector<double>  & align,
     564             :                                         const  std::vector<double>  & displace,
     565             :                                         const std::vector<Vector> & positions,
     566             :                                         const std::vector<Vector> & reference,
     567             :                                         std::vector<Vector>  & derivatives,
     568             :                                         std::vector<Vector> & ddistdref,
     569             :                                         bool squared) const {
     570             :   //initialize the data into the structure
     571             :   // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
     572           1 :   RMSDCoreData cd(align,displace,positions,reference);
     573             :   // transfer the settings for the center to let the CoreCalc deal with it
     574             :   // transfer the settings for the center to let the CoreCalc deal with it
     575           1 :   cd.setPositionsCenterIsRemoved(positions_center_is_removed);
     576           1 :   if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
     577           1 :   else {cd.calcPositionsCenter();};
     578             : 
     579           1 :   cd.setReferenceCenterIsRemoved(reference_center_is_removed);
     580           1 :   if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
     581           1 :   else {cd.setReferenceCenter(reference_center);}
     582             : 
     583             :   // Perform the diagonalization and all the needed stuff
     584           1 :   cd.doCoreCalc(safe,alEqDis);
     585             :   // make the core calc distance
     586           1 :   double dist=cd.getDistance(squared);
     587             : //  make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
     588           1 :   derivatives=cd.getDDistanceDPositions();
     589           1 :   ddistdref=cd.getDDistanceDReference();
     590           1 :   return dist;
     591             : }
     592             : 
     593             : template <bool safe,bool alEqDis>
     594           0 : double RMSD::optimalAlignment_SOMA(const  std::vector<double>  & align,
     595             :                                    const  std::vector<double>  & displace,
     596             :                                    const std::vector<Vector> & positions,
     597             :                                    const std::vector<Vector> & reference,
     598             :                                    std::vector<Vector>  & derivatives,
     599             :                                    std::vector<Vector> & ddistdref,
     600             :                                    bool squared) const {
     601             :   //initialize the data into the structure
     602             :   // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
     603           0 :   RMSDCoreData cd(align,displace,positions,reference);
     604             :   // transfer the settings for the center to let the CoreCalc deal with it
     605             :   // transfer the settings for the center to let the CoreCalc deal with it
     606           0 :   cd.setPositionsCenterIsRemoved(positions_center_is_removed);
     607           0 :   if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
     608           0 :   else {cd.calcPositionsCenter();};
     609             : 
     610           0 :   cd.setReferenceCenterIsRemoved(reference_center_is_removed);
     611           0 :   if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
     612           0 :   else {cd.setReferenceCenter(reference_center);}
     613             : 
     614             :   // Perform the diagonalization and all the needed stuff
     615           0 :   cd.doCoreCalc(safe,alEqDis);
     616             :   // make the core calc distance
     617           0 :   double dist=cd.getDistance(squared);
     618             : //  make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
     619           0 :   derivatives=cd.getDDistanceDPositions();
     620           0 :   ddistdref=cd.getDDistanceDReferenceSOMA();
     621           0 :   return dist;
     622             : }
     623             : 
     624             : 
     625             : template <bool safe,bool alEqDis>
     626           0 : double RMSD::optimalAlignment_DDistDRef_Rot_DRotDPos(const  std::vector<double>  & align,
     627             :     const  std::vector<double>  & displace,
     628             :     const std::vector<Vector> & positions,
     629             :     const std::vector<Vector> & reference,
     630             :     std::vector<Vector>  & derivatives,
     631             :     std::vector<Vector> & ddistdref,
     632             :     Tensor & Rotation,
     633             :     Matrix<std::vector<Vector> > &DRotDPos,
     634             :     bool squared) const {
     635             :   //initialize the data into the structure
     636             :   // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
     637           0 :   RMSDCoreData cd(align,displace,positions,reference);
     638             :   // transfer the settings for the center to let the CoreCalc deal with it
     639             :   // transfer the settings for the center to let the CoreCalc deal with it
     640           0 :   cd.setPositionsCenterIsRemoved(positions_center_is_removed);
     641           0 :   if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
     642           0 :   else {cd.calcPositionsCenter();};
     643             : 
     644           0 :   cd.setReferenceCenterIsRemoved(reference_center_is_removed);
     645           0 :   if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
     646           0 :   else {cd.setReferenceCenter(reference_center);}
     647             : 
     648             :   // Perform the diagonalization and all the needed stuff
     649           0 :   cd.doCoreCalc(safe,alEqDis);
     650             :   // make the core calc distance
     651           0 :   double dist=cd.getDistance(squared);
     652             : //  make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
     653           0 :   derivatives=cd.getDDistanceDPositions();
     654           0 :   ddistdref=cd.getDDistanceDReference();
     655             :   // get the rotation matrix
     656           0 :   Rotation=cd.getRotationMatrixReferenceToPositions();
     657             :   // get its derivative
     658           0 :   DRotDPos=cd.getDRotationDPositions();
     659           0 :   return dist;
     660             : }
     661             : 
     662             : template <bool safe,bool alEqDis>
     663           0 : double RMSD::optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef(const  std::vector<double>  & align,
     664             :     const  std::vector<double>  & displace,
     665             :     const std::vector<Vector> & positions,
     666             :     const std::vector<Vector> & reference,
     667             :     std::vector<Vector>  & derivatives,
     668             :     std::vector<Vector> & ddistdref,
     669             :     Tensor & Rotation,
     670             :     Matrix<std::vector<Vector> > &DRotDPos,
     671             :     Matrix<std::vector<Vector> > &DRotDRef,
     672             :     bool squared) const {
     673             :   //initialize the data into the structure
     674             :   // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
     675           0 :   RMSDCoreData cd(align,displace,positions,reference);
     676             :   // transfer the settings for the center to let the CoreCalc deal with it
     677             :   // transfer the settings for the center to let the CoreCalc deal with it
     678           0 :   cd.setPositionsCenterIsRemoved(positions_center_is_removed);
     679           0 :   if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
     680           0 :   else {cd.calcPositionsCenter();};
     681             : 
     682           0 :   cd.setReferenceCenterIsRemoved(reference_center_is_removed);
     683           0 :   if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
     684           0 :   else {cd.setReferenceCenter(reference_center);}
     685             : 
     686             :   // Perform the diagonalization and all the needed stuff
     687           0 :   cd.doCoreCalc(safe,alEqDis);
     688             :   // make the core calc distance
     689           0 :   double dist=cd.getDistance(squared);
     690             : //  make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
     691           0 :   derivatives=cd.getDDistanceDPositions();
     692           0 :   ddistdref=cd.getDDistanceDReference();
     693             :   // get the rotation matrix
     694           0 :   Rotation=cd.getRotationMatrixReferenceToPositions();
     695             :   // get its derivative
     696           0 :   DRotDPos=cd.getDRotationDPositions();
     697           0 :   DRotDRef=cd.getDRotationDReference();
     698           0 :   return dist;
     699             : }
     700             : 
     701             : template <bool safe,bool alEqDis>
     702        1670 : double RMSD::optimalAlignment_PCA(const  std::vector<double>  & align,
     703             :                                   const  std::vector<double>  & displace,
     704             :                                   const std::vector<Vector> & positions,
     705             :                                   const std::vector<Vector> & reference,
     706             :                                   std::vector<Vector> & alignedpositions,
     707             :                                   std::vector<Vector> & centeredpositions,
     708             :                                   std::vector<Vector> & centeredreference,
     709             :                                   Tensor & Rotation,
     710             :                                   std::vector<Vector> & DDistDPos,
     711             :                                   Matrix<std::vector<Vector> > & DRotDPos,
     712             :                                   bool squared) const {
     713             :   //initialize the data into the structure
     714             :   // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
     715        1670 :   RMSDCoreData cd(align,displace,positions,reference);
     716             :   // transfer the settings for the center to let the CoreCalc deal with it
     717        1670 :   cd.setPositionsCenterIsRemoved(positions_center_is_removed);
     718        1670 :   if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
     719        1670 :   else {cd.calcPositionsCenter();};
     720             : 
     721        1670 :   cd.setReferenceCenterIsRemoved(reference_center_is_removed);
     722        1670 :   if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
     723        1670 :   else {cd.setReferenceCenter(reference_center);}
     724             : 
     725             :   // Perform the diagonalization and all the needed stuff
     726        1670 :   cd.doCoreCalc(safe,alEqDis);
     727             :   // make the core calc distance
     728        1670 :   double dist=cd.getDistance(squared);
     729             :   // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
     730        1670 :   DDistDPos=cd.getDDistanceDPositions();
     731             :   // get the rotation matrix
     732        1670 :   Rotation=cd.getRotationMatrixPositionsToReference();
     733             :   // get its derivative
     734        1670 :   DRotDPos=cd.getDRotationDPositions(true); // this gives back the inverse
     735             :   // get aligned positions
     736        1670 :   alignedpositions=cd.getAlignedPositionsToReference();
     737             :   // get centered positions
     738        1670 :   centeredpositions=cd.getCenteredPositions();
     739             :   // get centered reference
     740        1670 :   centeredreference=cd.getCenteredReference();
     741        1670 :   return dist;
     742             : }
     743             : 
     744             : 
     745             : template <bool safe,bool alEqDis>
     746          48 : double RMSD::optimalAlignment_Fit(const  std::vector<double>  & align,
     747             :                                   const  std::vector<double>  & displace,
     748             :                                   const std::vector<Vector> & positions,
     749             :                                   const std::vector<Vector> & reference,
     750             :                                   Tensor & Rotation,
     751             :                                   Matrix<std::vector<Vector> > & DRotDPos,
     752             :                                   std::vector<Vector> & centeredpositions,
     753             :                                   Vector & center_positions,
     754             :                                   bool squared) {
     755             :   //initialize the data into the structure
     756             :   // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
     757          48 :   RMSDCoreData cd(align,displace,positions,reference);
     758             :   // transfer the settings for the center to let the CoreCalc deal with it
     759          48 :   cd.setPositionsCenterIsRemoved(positions_center_is_removed);
     760          48 :   if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
     761          48 :   else {cd.calcPositionsCenter();};
     762             : 
     763          48 :   cd.setReferenceCenterIsRemoved(reference_center_is_removed);
     764          48 :   if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
     765          48 :   else {cd.setReferenceCenter(reference_center);}
     766             : 
     767             :   // Perform the diagonalization and all the needed stuff
     768          48 :   cd.doCoreCalc(safe,alEqDis);
     769             :   // make the core calc distance
     770          48 :   double dist=cd.getDistance(squared);
     771             :   // get the rotation matrix
     772          48 :   Rotation=cd.getRotationMatrixPositionsToReference();
     773             :   // get its derivative
     774          48 :   DRotDPos=cd.getDRotationDPositions(true); // this gives back the inverse
     775             :   // get centered positions
     776          48 :   centeredpositions=cd.getCenteredPositions();
     777             :   // get center
     778          48 :   center_positions=cd.getPositionsCenter();
     779          48 :   return dist;
     780             : }
     781             : 
     782             : 
     783             : 
     784             : 
     785             : 
     786             : 
     787             : /// This calculates the elements needed by the quaternion to calculate everything that is needed
     788             : /// additional calls retrieve different components
     789             : /// note that this considers that the centers of both reference and positions are already setted
     790             : /// but automatically should properly account for non removed components: if not removed then it
     791             : /// removes prior to calculation of the alignment
     792        1719 : void RMSDCoreData::doCoreCalc(bool safe,bool alEqDis, bool only_rotation) {
     793             : 
     794        1719 :   retrieve_only_rotation=only_rotation;
     795        1719 :   const unsigned n=static_cast<unsigned int>(reference.size());
     796             : 
     797        1719 :   plumed_massert(creference_is_calculated,"the center of the reference frame must be already provided at this stage");
     798        1719 :   plumed_massert(cpositions_is_calculated,"the center of the positions frame must be already provided at this stage");
     799             : 
     800             : // This is the trace of positions*positions + reference*reference
     801        1719 :   rr00=0.;
     802        1719 :   rr11=0.;
     803             : // This is positions*reference
     804        1719 :   Tensor rr01;
     805             : // center of mass managing: must subtract the center from the position or not?
     806        1719 :   Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
     807        1719 :   Vector cr; cr.zero(); if(!creference_is_removed)cr=creference;
     808             : // second expensive loop: compute second moments wrt centers
     809       32976 :   for(unsigned iat=0; iat<n; iat++) {
     810       31257 :     double w=align[iat];
     811       31257 :     rr00+=dotProduct(positions[iat]-cp,positions[iat]-cp)*w;
     812       31257 :     rr11+=dotProduct(reference[iat]-cr,reference[iat]-cr)*w;
     813       31257 :     rr01+=Tensor(positions[iat]-cp,reference[iat]-cr)*w;
     814             :   }
     815             : 
     816             : // the quaternion matrix: this is internal
     817        1719 :   Matrix<double> m=Matrix<double>(4,4);
     818             : 
     819        1719 :   m[0][0]=2.0*(-rr01[0][0]-rr01[1][1]-rr01[2][2]);
     820        1719 :   m[1][1]=2.0*(-rr01[0][0]+rr01[1][1]+rr01[2][2]);
     821        1719 :   m[2][2]=2.0*(+rr01[0][0]-rr01[1][1]+rr01[2][2]);
     822        1719 :   m[3][3]=2.0*(+rr01[0][0]+rr01[1][1]-rr01[2][2]);
     823        1719 :   m[0][1]=2.0*(-rr01[1][2]+rr01[2][1]);
     824        1719 :   m[0][2]=2.0*(+rr01[0][2]-rr01[2][0]);
     825        1719 :   m[0][3]=2.0*(-rr01[0][1]+rr01[1][0]);
     826        1719 :   m[1][2]=2.0*(-rr01[0][1]-rr01[1][0]);
     827        1719 :   m[1][3]=2.0*(-rr01[0][2]-rr01[2][0]);
     828        1719 :   m[2][3]=2.0*(-rr01[1][2]-rr01[2][1]);
     829        1719 :   m[1][0] = m[0][1];
     830        1719 :   m[2][0] = m[0][2];
     831        1719 :   m[2][1] = m[1][2];
     832        1719 :   m[3][0] = m[0][3];
     833        1719 :   m[3][1] = m[1][3];
     834        1719 :   m[3][2] = m[2][3];
     835             : 
     836             : 
     837        1719 :   Tensor dm_drr01[4][4];
     838        1719 :   if(!alEqDis or !retrieve_only_rotation) {
     839        1719 :     dm_drr01[0][0] = 2.0*Tensor(-1.0, 0.0, 0.0,  0.0,-1.0, 0.0,  0.0, 0.0,-1.0);
     840        1719 :     dm_drr01[1][1] = 2.0*Tensor(-1.0, 0.0, 0.0,  0.0,+1.0, 0.0,  0.0, 0.0,+1.0);
     841        1719 :     dm_drr01[2][2] = 2.0*Tensor(+1.0, 0.0, 0.0,  0.0,-1.0, 0.0,  0.0, 0.0,+1.0);
     842        1719 :     dm_drr01[3][3] = 2.0*Tensor(+1.0, 0.0, 0.0,  0.0,+1.0, 0.0,  0.0, 0.0,-1.0);
     843        1719 :     dm_drr01[0][1] = 2.0*Tensor( 0.0, 0.0, 0.0,  0.0, 0.0,-1.0,  0.0,+1.0, 0.0);
     844        1719 :     dm_drr01[0][2] = 2.0*Tensor( 0.0, 0.0,+1.0,  0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
     845        1719 :     dm_drr01[0][3] = 2.0*Tensor( 0.0,-1.0, 0.0, +1.0, 0.0, 0.0,  0.0, 0.0, 0.0);
     846        1719 :     dm_drr01[1][2] = 2.0*Tensor( 0.0,-1.0, 0.0, -1.0, 0.0, 0.0,  0.0, 0.0, 0.0);
     847        1719 :     dm_drr01[1][3] = 2.0*Tensor( 0.0, 0.0,-1.0,  0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
     848        1719 :     dm_drr01[2][3] = 2.0*Tensor( 0.0, 0.0, 0.0,  0.0, 0.0,-1.0,  0.0,-1.0, 0.0);
     849        1719 :     dm_drr01[1][0] = dm_drr01[0][1];
     850        1719 :     dm_drr01[2][0] = dm_drr01[0][2];
     851        1719 :     dm_drr01[2][1] = dm_drr01[1][2];
     852        1719 :     dm_drr01[3][0] = dm_drr01[0][3];
     853        1719 :     dm_drr01[3][1] = dm_drr01[1][3];
     854        1719 :     dm_drr01[3][2] = dm_drr01[2][3];
     855             :   }
     856             : 
     857             : 
     858        1719 :   int diagerror=diagMat(m, eigenvals, eigenvecs );
     859             : 
     860        1719 :   if (diagerror!=0) {
     861           0 :     std::string sdiagerror;
     862           0 :     Tools::convert(diagerror,sdiagerror);
     863           0 :     std::string msg="DIAGONALIZATION FAILED WITH ERROR CODE "+sdiagerror;
     864           0 :     plumed_merror(msg);
     865             :   }
     866             : 
     867        1719 :   Vector4d q(eigenvecs[0][0],eigenvecs[0][1],eigenvecs[0][2],eigenvecs[0][3]);
     868             : //  cerr<<"EIGENVAL "<<eigenvals[0]<<" "<<eigenvals[1]<<" "<<eigenvals[2]<<" "<<eigenvals[3]<<"\n";
     869             : 
     870        1719 :   Tensor dq_drr01[4];
     871        1719 :   if(!alEqDis or !only_rotation) {
     872             :     double dq_dm[4][4][4];
     873      111735 :     for(unsigned i=0; i<4; i++) for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) {
     874      110016 :           double tmp=0.0;
     875             : // perturbation theory for matrix m
     876      110016 :           for(unsigned l=1; l<4; l++) tmp+=eigenvecs[l][j]*eigenvecs[l][i]/(eigenvals[0]-eigenvals[l])*eigenvecs[0][k];
     877      110016 :           dq_dm[i][j][k]=tmp;
     878             :         }
     879             : // propagation to _drr01
     880        8595 :     for(unsigned i=0; i<4; i++) {
     881        6876 :       Tensor tmp;
     882      116892 :       for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) {
     883      110016 :           tmp+=dq_dm[i][j][k]*dm_drr01[j][k];
     884             :         }
     885        6876 :       dq_drr01[i]=tmp;
     886             :     }
     887             :   }
     888             : 
     889             : // This is the rotation matrix that brings reference to positions
     890             : // i.e. matmul(rotation,reference[iat])+shift is fitted to positions[iat]
     891             : 
     892        1719 :   rotation[0][0]=q[0]*q[0]+q[1]*q[1]-q[2]*q[2]-q[3]*q[3];
     893        1719 :   rotation[1][1]=q[0]*q[0]-q[1]*q[1]+q[2]*q[2]-q[3]*q[3];
     894        1719 :   rotation[2][2]=q[0]*q[0]-q[1]*q[1]-q[2]*q[2]+q[3]*q[3];
     895        1719 :   rotation[0][1]=2*(+q[0]*q[3]+q[1]*q[2]);
     896        1719 :   rotation[0][2]=2*(-q[0]*q[2]+q[1]*q[3]);
     897        1719 :   rotation[1][2]=2*(+q[0]*q[1]+q[2]*q[3]);
     898        1719 :   rotation[1][0]=2*(-q[0]*q[3]+q[1]*q[2]);
     899        1719 :   rotation[2][0]=2*(+q[0]*q[2]+q[1]*q[3]);
     900        1719 :   rotation[2][1]=2*(-q[0]*q[1]+q[2]*q[3]);
     901             : 
     902             : 
     903        1719 :   if(!alEqDis or !only_rotation) {
     904        1719 :     drotation_drr01[0][0]=2*q[0]*dq_drr01[0]+2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3];
     905        1719 :     drotation_drr01[1][1]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]+2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3];
     906        1719 :     drotation_drr01[2][2]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]+2*q[3]*dq_drr01[3];
     907        1719 :     drotation_drr01[0][1]=2*(+(q[0]*dq_drr01[3]+dq_drr01[0]*q[3])+(q[1]*dq_drr01[2]+dq_drr01[1]*q[2]));
     908        1719 :     drotation_drr01[0][2]=2*(-(q[0]*dq_drr01[2]+dq_drr01[0]*q[2])+(q[1]*dq_drr01[3]+dq_drr01[1]*q[3]));
     909        1719 :     drotation_drr01[1][2]=2*(+(q[0]*dq_drr01[1]+dq_drr01[0]*q[1])+(q[2]*dq_drr01[3]+dq_drr01[2]*q[3]));
     910        1719 :     drotation_drr01[1][0]=2*(-(q[0]*dq_drr01[3]+dq_drr01[0]*q[3])+(q[1]*dq_drr01[2]+dq_drr01[1]*q[2]));
     911        1719 :     drotation_drr01[2][0]=2*(+(q[0]*dq_drr01[2]+dq_drr01[0]*q[2])+(q[1]*dq_drr01[3]+dq_drr01[1]*q[3]));
     912        1719 :     drotation_drr01[2][1]=2*(-(q[0]*dq_drr01[1]+dq_drr01[0]*q[1])+(q[2]*dq_drr01[3]+dq_drr01[2]*q[3]));
     913             :   }
     914             : 
     915        1719 :   d.resize(n);
     916             : 
     917             :   // calculate rotation matrix derivatives and components distances needed for components only when align!=displacement
     918        1719 :   if(!alEqDis)ddist_drotation.zero();
     919       32976 :   for(unsigned iat=0; iat<n; iat++) {
     920             :     // components differences: this is useful externally
     921       31257 :     d[iat]=positions[iat]-cp - matmul(rotation,reference[iat]-cr);
     922             :     //cerr<<"D "<<iat<<" "<<d[iat][0]<<" "<<d[iat][1]<<" "<<d[iat][2]<<"\n";
     923             : 
     924             :     // ddist_drotation if needed
     925       31257 :     if(!alEqDis or !only_rotation) ddist_drotation+=-2*displace[iat]*extProduct(d[iat],reference[iat]-cr);
     926             :   }
     927             : 
     928        1719 :   if(!alEqDis or !only_rotation) {
     929        1719 :     ddist_drr01.zero();
     930        1719 :     for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) ddist_drr01+=ddist_drotation[i][j]*drotation_drr01[i][j];
     931             :   }
     932             :   // transfer this bools to the cd so that this settings will be reflected in the other calls
     933        1719 :   this->alEqDis=alEqDis;
     934        1719 :   this->safe=safe;
     935        1719 :   isInitialized=true;
     936             : 
     937        1719 : }
     938             : /// just retrieve the distance already calculated
     939        1719 : double RMSDCoreData::getDistance( bool squared) {
     940             : 
     941        1719 :   if(!isInitialized)plumed_merror("getDistance cannot calculate the distance without being initialized first by doCoreCalc ");
     942        1719 :   dist=eigenvals[0]+rr00+rr11;
     943             : 
     944        1719 :   if(safe || !alEqDis) dist=0.0;
     945        1719 :   const unsigned n=static_cast<unsigned int>(reference.size());
     946       32976 :   for(unsigned iat=0; iat<n; iat++) {
     947       31257 :     if(alEqDis) {
     948       30162 :       if(safe) dist+=align[iat]*modulo2(d[iat]);
     949             :     } else {
     950        1095 :       dist+=displace[iat]*modulo2(d[iat]);
     951             :     }
     952             :   }
     953        1719 :   if(!squared) {
     954          49 :     dist=sqrt(dist);
     955          49 :     distanceIsMSD=false;
     956             :   } else {
     957        1670 :     distanceIsMSD=true;
     958             :   }
     959        1719 :   hasDistance=true;
     960        1719 :   return dist;
     961             : }
     962             : 
     963        1671 : std::vector<Vector> RMSDCoreData::getDDistanceDPositions() {
     964        1671 :   std::vector<Vector>  derivatives;
     965        1671 :   const unsigned n=static_cast<unsigned int>(reference.size());
     966        1671 :   Vector ddist_dcpositions;
     967        1671 :   derivatives.resize(n);
     968        1671 :   double prefactor=1.0;
     969        1671 :   if(!distanceIsMSD) prefactor*=0.5/dist;
     970        1671 :   plumed_massert(!retrieve_only_rotation,"You used  only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
     971        1671 :   if(!hasDistance)plumed_merror("getDPositionsDerivatives needs to calculate the distance via getDistance first !");
     972        1671 :   if(!isInitialized)plumed_merror("getDPositionsDerivatives needs to initialize the coreData first!");
     973        1671 :   Vector csum;
     974        1671 :   Vector tmp1,tmp2;
     975       32688 :   for(unsigned iat=0; iat<n; iat++) {
     976       31017 :     if(alEqDis) {
     977             : // there is no need for derivatives of rotation and shift here as it is by construction zero
     978             : // (similar to Hellman-Feynman forces)
     979       30162 :       derivatives[iat]= 2*prefactor*align[iat]*d[iat];
     980             :     } else {
     981             : // these are the derivatives assuming the roto-translation as frozen
     982         855 :       tmp1=2*displace[iat]*d[iat];
     983         855 :       derivatives[iat]=tmp1;
     984             : // derivative of cpositions
     985         855 :       ddist_dcpositions+=-tmp1;
     986             :       // these needed for com corrections
     987         855 :       tmp2=matmul(ddist_drr01,reference[iat]-creference)*align[iat];
     988         855 :       derivatives[iat]+=tmp2;
     989         855 :       csum+=tmp2;
     990             :     }
     991             :   }
     992             : 
     993        1671 :   if(!alEqDis)  for(unsigned iat=0; iat<n; iat++) {derivatives[iat]= prefactor*(derivatives[iat]+(ddist_dcpositions-csum)*align[iat]); }
     994             : 
     995        1671 :   return derivatives;
     996             : }
     997             : 
     998           1 : std::vector<Vector>  RMSDCoreData::getDDistanceDReference() {
     999           1 :   std::vector<Vector>  derivatives;
    1000           1 :   const unsigned n=static_cast<unsigned int>(reference.size());
    1001           1 :   Vector ddist_dcreference;
    1002           1 :   derivatives.resize(n);
    1003           1 :   double prefactor=1.0;
    1004           1 :   if(!distanceIsMSD) prefactor*=0.5/dist;
    1005           1 :   Vector csum,tmp1,tmp2;
    1006             : 
    1007           1 :   plumed_massert(!retrieve_only_rotation,"You used  only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
    1008           1 :   if(!hasDistance)plumed_merror("getDDistanceDReference needs to calculate the distance via getDistance first !");
    1009           1 :   if(!isInitialized)plumed_merror("getDDistanceDReference to initialize the coreData first!");
    1010             :   // get the transpose rotation
    1011           1 :   Tensor t_rotation=rotation.transpose();
    1012           1 :   Tensor t_ddist_drr01=ddist_drr01.transpose();
    1013             : 
    1014             : // third expensive loop: derivatives
    1015         856 :   for(unsigned iat=0; iat<n; iat++) {
    1016         855 :     if(alEqDis) {
    1017             : // there is no need for derivatives of rotation and shift here as it is by construction zero
    1018             : // (similar to Hellman-Feynman forces)
    1019             :       //TODO: check this derivative down here
    1020           0 :       derivatives[iat]= -2*prefactor*align[iat]*matmul(t_rotation,d[iat]);
    1021             :     } else {
    1022             : // these are the derivatives assuming the roto-translation as frozen
    1023         855 :       tmp1=2*displace[iat]*matmul(t_rotation,d[iat]);
    1024         855 :       derivatives[iat]= -tmp1;
    1025             : // derivative of cpositions
    1026         855 :       ddist_dcreference+=tmp1;
    1027             :       // these below are needed for com correction
    1028         855 :       tmp2=matmul(t_ddist_drr01,positions[iat]-cpositions)*align[iat];
    1029         855 :       derivatives[iat]+=tmp2;
    1030         855 :       csum+=tmp2;
    1031             :     }
    1032             :   }
    1033             : 
    1034           1 :   if(!alEqDis)  for(unsigned iat=0; iat<n; iat++) {derivatives[iat]= prefactor*(derivatives[iat]+(ddist_dcreference-csum)*align[iat]);}
    1035             : 
    1036           1 :   return derivatives;
    1037             : }
    1038             : 
    1039             : /// this version does not calculate the derivative of rotation matrix as needed for SOMA
    1040           0 : std::vector<Vector>  RMSDCoreData::getDDistanceDReferenceSOMA() {
    1041           0 :   std::vector<Vector>  derivatives;
    1042           0 :   const unsigned n=static_cast<unsigned int>(reference.size());
    1043           0 :   Vector ddist_dcreference;
    1044           0 :   derivatives.resize(n);
    1045           0 :   double prefactor=1.0;
    1046           0 :   if(!distanceIsMSD) prefactor*=0.5/dist;
    1047           0 :   Vector csum,tmp1,tmp2;
    1048             : 
    1049           0 :   plumed_massert(!retrieve_only_rotation,"You used  only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
    1050           0 :   if(!hasDistance)plumed_merror("getDDistanceDReference needs to calculate the distance via getDistance first !");
    1051           0 :   if(!isInitialized)plumed_merror("getDDistanceDReference to initialize the coreData first!");
    1052             :   // get the transpose rotation
    1053           0 :   Tensor t_rotation=rotation.transpose();
    1054             : 
    1055             : // third expensive loop: derivatives
    1056           0 :   for(unsigned iat=0; iat<n; iat++) {
    1057           0 :     if(alEqDis) {
    1058             : // there is no need for derivatives of rotation and shift here as it is by construction zero
    1059             : // (similar to Hellman-Feynman forces)
    1060             :       //TODO: check this derivative down here
    1061           0 :       derivatives[iat]= -2*prefactor*align[iat]*matmul(t_rotation,d[iat]);
    1062             :     } else {
    1063             : // these are the derivatives assuming the roto-translation as frozen
    1064           0 :       tmp1=2*displace[iat]*matmul(t_rotation,d[iat]);
    1065           0 :       derivatives[iat]= -tmp1;
    1066             : // derivative of cpositions
    1067           0 :       ddist_dcreference+=tmp1;
    1068             :     }
    1069             :   }
    1070             : 
    1071           0 :   if(!alEqDis) for(unsigned iat=0; iat<n; iat++)derivatives[iat]=prefactor*(derivatives[iat]+ddist_dcreference*align[iat]);
    1072             : 
    1073           0 :   return derivatives;
    1074             : }
    1075             : 
    1076             : 
    1077             : 
    1078             : /*
    1079             : This below is the derivative of the rotation matrix that aligns the reference onto the positions
    1080             : respect to positions
    1081             : note that the this transformation overlap the  reference onto position
    1082             : if inverseTransform=true then aligns the positions onto reference
    1083             : */
    1084        1718 : Matrix<std::vector<Vector> >  RMSDCoreData::getDRotationDPositions( bool inverseTransform ) {
    1085        1718 :   const unsigned n=static_cast<unsigned int>(reference.size());
    1086        1718 :   plumed_massert(!retrieve_only_rotation,"You used  only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
    1087        1718 :   if(!isInitialized)plumed_merror("getDRotationDPosition to initialize the coreData first!");
    1088        1718 :   Matrix<std::vector<Vector> > DRotDPos=Matrix<std::vector<Vector> >(3,3);
    1089             :   // remember drotation_drr01 is Tensor drotation_drr01[3][3]
    1090             :   //           (3x3 rot) (3x3 components of rr01)
    1091        3436 :   std::vector<Vector> v(n);
    1092        1718 :   Vector csum;
    1093             :   // these below could probably be calculated in the main routine
    1094        1718 :   Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
    1095        1718 :   Vector cr; cr.zero(); if(!creference_is_removed)cr=creference;
    1096        1718 :   for(unsigned iat=0; iat<n; iat++) csum+=(reference[iat]-cr)*align[iat];
    1097        1718 :   for(unsigned iat=0; iat<n; iat++) v[iat]=(reference[iat]-cr-csum)*align[iat];
    1098        6872 :   for(unsigned a=0; a<3; a++) {
    1099       20616 :     for(unsigned b=0; b<3; b++) {
    1100       15462 :       if(inverseTransform) {
    1101       15462 :         DRotDPos[b][a].resize(n);
    1102      289080 :         for(unsigned iat=0; iat<n; iat++) {
    1103      273618 :           DRotDPos[b][a][iat]=matmul(drotation_drr01[a][b],v[iat]);
    1104             :         }
    1105             :       } else {
    1106           0 :         DRotDPos[a][b].resize(n);
    1107           0 :         for(unsigned iat=0; iat<n; iat++) {
    1108           0 :           DRotDPos[a][b][iat]=matmul(drotation_drr01[a][b],v[iat]);
    1109             :         }
    1110             :       }
    1111             :     }
    1112             :   }
    1113        3436 :   return DRotDPos;
    1114             : }
    1115             : 
    1116             : /*
    1117             : This below is the derivative of the rotation matrix that aligns the reference onto the positions
    1118             : respect to reference
    1119             : note that the this transformation overlap the  reference onto position
    1120             : if inverseTransform=true then aligns the positions onto reference
    1121             : */
    1122           0 : Matrix<std::vector<Vector> >  RMSDCoreData::getDRotationDReference( bool inverseTransform ) {
    1123           0 :   const unsigned n=static_cast<unsigned int>(reference.size());
    1124           0 :   plumed_massert(!retrieve_only_rotation,"You used  only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
    1125           0 :   if(!isInitialized)plumed_merror("getDRotationDPositions to initialize the coreData first!");
    1126           0 :   Matrix<std::vector<Vector> > DRotDRef=Matrix<std::vector<Vector> >(3,3);
    1127             :   // remember drotation_drr01 is Tensor drotation_drr01[3][3]
    1128             :   //           (3x3 rot) (3x3 components of rr01)
    1129           0 :   std::vector<Vector> v(n);
    1130           0 :   Vector csum;
    1131             :   // these below could probably be calculated in the main routine
    1132           0 :   Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
    1133           0 :   Vector cr; cr.zero(); if(!creference_is_removed)cr=creference;
    1134           0 :   for(unsigned iat=0; iat<n; iat++) csum+=(positions[iat]-cp)*align[iat];
    1135           0 :   for(unsigned iat=0; iat<n; iat++) v[iat]=(positions[iat]-cp-csum)*align[iat];
    1136             : 
    1137           0 :   for(unsigned a=0; a<3; a++) {
    1138           0 :     for(unsigned b=0; b<3; b++) {
    1139           0 :       Tensor t_drotation_drr01=drotation_drr01[a][b].transpose();
    1140           0 :       if(inverseTransform) {
    1141           0 :         DRotDRef[b][a].resize(n);
    1142           0 :         for(unsigned iat=0; iat<n; iat++) {
    1143           0 :           DRotDRef[b][a][iat]=matmul(t_drotation_drr01,v[iat]);
    1144             :         }
    1145             :       } else {
    1146           0 :         DRotDRef[a][b].resize(n);
    1147           0 :         for(unsigned iat=0; iat<n; iat++) {
    1148           0 :           DRotDRef[a][b][iat]=matmul(t_drotation_drr01,v[iat]);
    1149             :         }
    1150             :       }
    1151             :     }
    1152             :   }
    1153           0 :   return DRotDRef;
    1154             : }
    1155             : 
    1156             : 
    1157           0 : std::vector<Vector> RMSDCoreData::getAlignedReferenceToPositions() {
    1158           0 :   std::vector<Vector> alignedref;
    1159           0 :   const unsigned n=static_cast<unsigned int>(reference.size());
    1160           0 :   alignedref.resize(n);
    1161           0 :   if(!isInitialized)plumed_merror("getAlignedReferenceToPostions needs to initialize the coreData first!");
    1162             :   // avoid to calculate matrix element but use the sum of what you have
    1163           0 :   Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
    1164           0 :   for(unsigned iat=0; iat<n; iat++)alignedref[iat]=-d[iat]+positions[iat]-cp;
    1165           0 :   return alignedref;
    1166             : }
    1167        1670 : std::vector<Vector> RMSDCoreData::getAlignedPositionsToReference() {
    1168        1670 :   std::vector<Vector> alignedpos;
    1169        1670 :   if(!isInitialized)plumed_merror("getAlignedPostionsToReference needs to initialize the coreData first!");
    1170        1670 :   const unsigned n=static_cast<unsigned int>(positions.size());
    1171        1670 :   alignedpos.resize(n);
    1172        1670 :   Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
    1173             :   // avoid to calculate matrix element but use the sum of what you have
    1174        1670 :   for(unsigned iat=0; iat<n; iat++)alignedpos[iat]=matmul(rotation.transpose(),positions[iat]-cp);
    1175        1670 :   return alignedpos;
    1176             : }
    1177             : 
    1178             : 
    1179        1718 : std::vector<Vector> RMSDCoreData::getCenteredPositions() {
    1180        1718 :   std::vector<Vector> centeredpos;
    1181        1718 :   const unsigned n=static_cast<unsigned int>(reference.size());
    1182        1718 :   centeredpos.resize(n);
    1183        1718 :   if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!");
    1184             :   // avoid to calculate matrix element but use the sum of what you have
    1185        1718 :   for(unsigned iat=0; iat<n; iat++)centeredpos[iat]=positions[iat]-cpositions;
    1186        1718 :   return centeredpos;
    1187             : }
    1188             : 
    1189        1670 : std::vector<Vector> RMSDCoreData::getCenteredReference() {
    1190        1670 :   std::vector<Vector> centeredref;
    1191        1670 :   const unsigned n=static_cast<unsigned int>(reference.size());
    1192        1670 :   centeredref.resize(n);
    1193        1670 :   if(!isInitialized)plumed_merror("getCenteredReference needs to initialize the coreData first!");
    1194             :   // avoid to calculate matrix element but use the sum of what you have
    1195        1670 :   Vector cr; cr.zero(); if(!creference_is_removed)cr=creference;
    1196        1670 :   for(unsigned iat=0; iat<n; iat++)centeredref[iat]=reference[iat]-cr;
    1197        1670 :   return centeredref;
    1198             : }
    1199             : 
    1200             : 
    1201          48 : Vector RMSDCoreData::getPositionsCenter() {
    1202          48 :   if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!");
    1203          48 :   return cpositions;
    1204             : }
    1205             : 
    1206           0 : Vector RMSDCoreData::getReferenceCenter() {
    1207           0 :   if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!");
    1208           0 :   return creference;
    1209             : }
    1210             : 
    1211           0 : Tensor RMSDCoreData::getRotationMatrixReferenceToPositions() {
    1212           0 :   if(!isInitialized)plumed_merror("getRotationMatrixReferenceToPositions needs to initialize the coreData first!");
    1213           0 :   return rotation;
    1214             : }
    1215             : 
    1216        1718 : Tensor RMSDCoreData::getRotationMatrixPositionsToReference() {
    1217        1718 :   if(!isInitialized)plumed_merror("getRotationMatrixReferenceToPositions needs to initialize the coreData first!");
    1218        1718 :   return rotation.transpose();
    1219             : }
    1220             : 
    1221             : 
    1222             : template double RMSD::optimalAlignment<true,true>(const  std::vector<double>  & align,
    1223             :     const  std::vector<double>  & displace,
    1224             :     const std::vector<Vector> & positions,
    1225             :     const std::vector<Vector> & reference,
    1226             :     std::vector<Vector>  & derivatives, bool squared)const;
    1227             : template double RMSD::optimalAlignment<true,false>(const  std::vector<double>  & align,
    1228             :     const  std::vector<double>  & displace,
    1229             :     const std::vector<Vector> & positions,
    1230             :     const std::vector<Vector> & reference,
    1231             :     std::vector<Vector>  & derivatives, bool squared)const;
    1232             : template double RMSD::optimalAlignment<false,true>(const  std::vector<double>  & align,
    1233             :     const  std::vector<double>  & displace,
    1234             :     const std::vector<Vector> & positions,
    1235             :     const std::vector<Vector> & reference,
    1236             :     std::vector<Vector>  & derivatives, bool squared)const;
    1237             : template double RMSD::optimalAlignment<false,false>(const  std::vector<double>  & align,
    1238             :     const  std::vector<double>  & displace,
    1239             :     const std::vector<Vector> & positions,
    1240             :     const std::vector<Vector> & reference,
    1241             :     std::vector<Vector>  & derivatives, bool squared)const;
    1242             : 
    1243             : 
    1244             : 
    1245        2523 : }

Generated by: LCOV version 1.13