LCOV - code coverage report
Current view: top level - tools - RMSD.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 30 35 85.7 %
Date: 2024-10-18 14:00:25 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2023 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             : #ifndef __PLUMED_tools_RMSD_h
      23             : #define __PLUMED_tools_RMSD_h
      24             : 
      25             : #include "Vector.h"
      26             : #include "Matrix.h"
      27             : #include "Tensor.h"
      28             : #include <vector>
      29             : #include <string>
      30             : #include <array>
      31             : 
      32             : namespace PLMD {
      33             : 
      34             : class Log;
      35             : class PDB;
      36             : 
      37             : /** \ingroup TOOLBOX
      38             : A class that implements RMSD calculations
      39             : This is a class that implements the various infrastructure to calculate the
      40             : RMSD or MSD respect a given frame. It can be done through an optimal alignment scheme
      41             : as Kearsley or, more simply, by resetting the center of mass.
      42             : This is the class that decides this. A very simple use is
      43             : \verbatim
      44             : #include "tools/PDB.h"
      45             : #include "tools/RMSD.h"
      46             : #include "tools/Vector.h"
      47             : using namespace PLMD;
      48             : RMSD rmsd;
      49             : PDB pdb;
      50             : // get the pdb (see PDB documentation)
      51             : pdb.read("file.pdb",true,1.0);
      52             : string type;
      53             : type.assign("OPTIMAL");
      54             : // set the reference and the type
      55             : rmsd.set(pdb,type);
      56             : // this calculates the rmsd and the derivatives
      57             : vector<Vector> derivs;
      58             : double val;
      59             : val=rmsd.calculate(getPositions(),derivs,true);
      60             : \endverbatim
      61             : 
      62             : **/
      63             : 
      64             : class RMSD
      65             : {
      66             :   enum AlignmentMethod {SIMPLE, OPTIMAL, OPTIMAL_FAST};
      67             :   AlignmentMethod alignmentMethod;
      68             : // Reference coordinates
      69             :   std::vector<Vector> reference;
      70             : // Weights for alignment
      71             :   std::vector<double> align;
      72             : // Weights for deviation
      73             :   std::vector<double> displace;
      74             : // Center for reference and flag for its calculation
      75             :   Vector reference_center;
      76             :   bool reference_center_is_calculated;
      77             :   bool reference_center_is_removed;
      78             : // Center for running position (not used in principle but here to reflect reference/positio symmetry
      79             :   Vector positions_center;
      80             :   bool positions_center_is_calculated;
      81             :   bool positions_center_is_removed;
      82             : // calculates the center from the position provided
      83       13173 :   Vector calculateCenter(const std::vector<Vector> &p,const std::vector<double> &w) {
      84       13173 :     plumed_massert(p.size()==w.size(),"mismatch in dimension of position/align arrays while calculating the center");
      85       13173 :     unsigned n; n=p.size();
      86       13173 :     Vector c; c.zero();
      87      209488 :     for(unsigned i=0; i<n; i++)c+=p[i]*w[i];
      88       13173 :     return c;
      89             :   };
      90             : // removes the center for the position provided
      91       26341 :   void removeCenter(std::vector<Vector> &p, const Vector &c) {
      92       26341 :     unsigned n; n=p.size();
      93      418946 :     for(unsigned i=0; i<n; i++)p[i]-=c;
      94       26341 :   };
      95             : // add center
      96       13173 :   void addCenter(std::vector<Vector> &p, const Vector &c) {Vector cc=c*-1.; removeCenter(p,cc);};
      97             : 
      98             : public:
      99             : /// Constructor
     100             :   RMSD();
     101             : /// clear the structure
     102             :   void clear();
     103             : /// set reference, align and displace from input pdb structure: evtl remove com from the initial structure and normalize the input weights from the pdb
     104             :   void set(const PDB&,const std::string & mytype, bool remove_center=true, bool normalize_weights=true);
     105             : /// set align displace reference and type from input vectors
     106             :   void set(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & reference,const std::string & mytype, bool remove_center=true, bool normalize_weights=true );
     107             : /// set the type of alignment we are doing
     108             :   void setType(const std::string & mytype);
     109             : /// set reference coordinates, remove the com by using uniform weights
     110             :   void setReference(const std::vector<Vector> & reference);
     111             :   const std::vector<Vector>& getReference() const ;
     112             : /// set weights and remove the center from reference with normalized weights. If the com has been removed, it resets to the new value
     113             :   void setAlign(const std::vector<double> & align, bool normalize_weights=true, bool remove_center=true);
     114             :   std::vector<double> getAlign();
     115             : /// set align
     116             :   void setDisplace(const std::vector<double> & displace, bool normalize_weights=true);
     117             :   std::vector<double> getDisplace();
     118             : ///
     119             :   std::string getMethod();
     120             : /// workhorses
     121             :   double simpleAlignment(const  std::vector<double>  & align,
     122             :                          const  std::vector<double>  & displace,
     123             :                          const std::vector<Vector> & positions,
     124             :                          const std::vector<Vector> & reference,
     125             :                          std::vector<Vector>  & derivatives,
     126             :                          std::vector<Vector>  & displacement,
     127             :                          bool squared=false)const;
     128             :   template <bool safe,bool alEqDis>
     129             :   double optimalAlignment(const  std::vector<double>  & align,
     130             :                           const  std::vector<double>  & displace,
     131             :                           const std::vector<Vector> & positions,
     132             :                           const std::vector<Vector> & reference,
     133             :                           std::vector<Vector>  & DDistDPos, bool squared=false)const;
     134             : 
     135             :   template <bool safe, bool alEqDis>
     136             :   double optimalAlignmentWithCloseStructure(const  std::vector<double>  & align,
     137             :       const  std::vector<double>  & displace,
     138             :       const std::vector<Vector> & positions,
     139             :       const std::vector<Vector> & reference,
     140             :       std::vector<Vector>  & derivatives,
     141             :       const Tensor & rotationPosClose,
     142             :       const Tensor & rotationRefClose,
     143             :       std::array<std::array<Tensor,3>,3> & drotationPosCloseDrr01,
     144             :       bool squared=false)const;
     145             : 
     146             :   template <bool safe, bool alEqDis>
     147             :   double optimalAlignment_Rot_DRotDRr01(const  std::vector<double>  & align,
     148             :                                         const  std::vector<double>  & displace,
     149             :                                         const std::vector<Vector> & positions,
     150             :                                         const std::vector<Vector> & reference,
     151             :                                         Tensor & Rotation,
     152             :                                         std::array<std::array<Tensor,3>,3> & drotationPosCloseDrr01,
     153             :                                         bool squared=false)const;
     154             : 
     155             :   template <bool safe, bool alEqDis>
     156             :   double optimalAlignment_Rot(const  std::vector<double>  & align,
     157             :                               const  std::vector<double>  & displace,
     158             :                               const std::vector<Vector> & positions,
     159             :                               const std::vector<Vector> & reference,
     160             :                               std::vector<Vector>  & derivatives,
     161             :                               Tensor & Rotation,
     162             :                               bool squared=false)const;
     163             : 
     164             :   template <bool safe,bool alEqDis>
     165             :   double optimalAlignment_DDistDRef(const  std::vector<double>  & align,
     166             :                                     const  std::vector<double>  & displace,
     167             :                                     const std::vector<Vector> & positions,
     168             :                                     const std::vector<Vector> & reference,
     169             :                                     std::vector<Vector>  & DDistDPos,
     170             :                                     std::vector<Vector> &  DDistDRef,
     171             :                                     bool squared=false) const;
     172             : 
     173             :   template <bool safe,bool alEqDis>
     174             :   double optimalAlignment_SOMA(const  std::vector<double>  & align,
     175             :                                const  std::vector<double>  & displace,
     176             :                                const std::vector<Vector> & positions,
     177             :                                const std::vector<Vector> & reference,
     178             :                                std::vector<Vector>  & DDistDPos,
     179             :                                std::vector<Vector> &  DDistDRef,
     180             :                                bool squared=false) const;
     181             : 
     182             :   template <bool safe,bool alEqDis>
     183             :   double optimalAlignment_DDistDRef_Rot_DRotDPos(const  std::vector<double>  & align,
     184             :       const  std::vector<double>  & displace,
     185             :       const std::vector<Vector> & positions,
     186             :       const std::vector<Vector> & reference,
     187             :       std::vector<Vector>  & DDistDPos,
     188             :       std::vector<Vector> &  DDistDRef,
     189             :       Tensor & Rotation,
     190             :       Matrix<std::vector<Vector> > &DRotDPos,
     191             :       bool squared=false) const;
     192             : 
     193             :   template <bool safe,bool alEqDis>
     194             :   double optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef(const  std::vector<double>  & align,
     195             :       const  std::vector<double>  & displace,
     196             :       const std::vector<Vector> & positions,
     197             :       const std::vector<Vector> & reference,
     198             :       std::vector<Vector>  & DDistDPos,
     199             :       std::vector<Vector> &  DDistDRef,
     200             :       Tensor & Rotation,
     201             :       Matrix<std::vector<Vector> > &DRotDPos,
     202             :       Matrix<std::vector<Vector> > &DRotDRef,
     203             :       bool squared=false) const;
     204             : 
     205             :   template <bool safe,bool alEqDis>
     206             :   double optimalAlignment_PCA(const  std::vector<double>  & align,
     207             :                               const  std::vector<double>  & displace,
     208             :                               const std::vector<Vector> & positions,
     209             :                               const std::vector<Vector> & reference,
     210             :                               std::vector<Vector> & alignedpositions,
     211             :                               std::vector<Vector> & centeredpositions,
     212             :                               std::vector<Vector> & centeredreference,
     213             :                               Tensor & Rotation,
     214             :                               std::vector<Vector> & DDistDPos,
     215             :                               Matrix<std::vector<Vector> > & DRotDPos,
     216             :                               bool squared=false) const ;
     217             : 
     218             :   template <bool safe,bool alEqDis>
     219             :   double optimalAlignment_Fit(const  std::vector<double>  & align,
     220             :                               const  std::vector<double>  & displace,
     221             :                               const std::vector<Vector> & positions,
     222             :                               const std::vector<Vector> & reference,
     223             :                               Tensor & Rotation,
     224             :                               Matrix<std::vector<Vector> > & DRotDPos,
     225             :                               std::vector<Vector> & centeredpositions,
     226             :                               Vector & center_positions,
     227             :                               bool squared=false);
     228             : 
     229             : 
     230             : /// Compute rmsd: note that this is an intermediate layer which is kept in order to evtl expand with more alignment types/user options to be called while keeping the workhorses separated
     231             :   double calculate(const std::vector<Vector> & positions,std::vector<Vector> &derivatives, bool squared=false)const;
     232             : /// Other convenience methods:
     233             : /// calculate the derivative of distance respect to position(DDistDPos) and reference (DDistDPos)
     234             :   double calc_DDistDRef( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef, const bool squared=false   );
     235             : /// calculate the derivative for SOMA (i.e. derivative respect to reference frame without the matrix derivative)
     236             :   double calc_SOMA( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef, const bool squared=false   );
     237             : ///
     238             :   double calc_DDistDRef_Rot_DRotDPos( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef, Tensor & Rotation,Matrix<std::vector<Vector> > &DRotDPos, const bool squared=false   );
     239             :   double calc_DDistDRef_Rot_DRotDPos_DRotDRef( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef, Tensor & Rotation,Matrix<std::vector<Vector> > &DRotDPos,Matrix<std::vector<Vector> > &DRotDRef, const bool squared=false   );
     240             : /// convenience method to retrieve all the bits and pieces for PCA
     241             :   double calc_PCAelements( const std::vector<Vector>& pos, 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=false) const ;
     242             : /// convenience method to retrieve all the bits and pieces needed by FitToTemplate
     243             :   double calc_FitElements( const std::vector<Vector>& pos, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos,std::vector<Vector> & centeredpositions,Vector & center_positions, const bool& squared=false );
     244             : ///calculate rotation matrix, derivative of rotation matrix w.r.t. positions, derivative of rotation matrix w.r.t. rr01
     245             :   double calc_Rot_DRotDRr01( const std::vector<Vector>& positions, Tensor & Rotation, std::array<std::array<Tensor,3>,3> & DRotDRr01, const bool squared=false   );
     246             : ///calculate rotation matrix, derivative of rotation matrix w.r.t. positions
     247             :   double calc_Rot( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, Tensor & Rotation, const bool squared=false   );
     248             : ///calculate with close structure, i.e. approximate the RMSD without expensive computation of rotation matrix by reusing saved rotation matrices from previous iterations
     249             :   double calculateWithCloseStructure( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, const Tensor & rotationPosClose, const Tensor & rotationRefClose, std::array<std::array<Tensor,3>,3> & drotationPosCloseDrr01, const bool squared=false   );
     250             : /// static convenience method to get the matrix i,a from drotdpos (which is a bit tricky)
     251         900 :   static  Tensor getMatrixFromDRot(const Matrix< std::vector<Vector> > &drotdpos, const unsigned &i, const unsigned &a) {
     252         900 :     Tensor t;
     253         900 :     t[0][0]=drotdpos(0,0)[i][a]; t[0][1]=drotdpos(0,1)[i][a]; t[0][2]=drotdpos(0,2)[i][a];
     254         900 :     t[1][0]=drotdpos(1,0)[i][a]; t[1][1]=drotdpos(1,1)[i][a]; t[1][2]=drotdpos(1,2)[i][a];
     255         900 :     t[2][0]=drotdpos(2,0)[i][a]; t[2][1]=drotdpos(2,1)[i][a]; t[2][2]=drotdpos(2,2)[i][a];
     256         900 :     return t;
     257             :   };
     258             : };
     259             : 
     260             : /// this is a class which is needed to share information across the various non-threadsafe routines
     261             : /// so that the public function of rmsd are threadsafe while the inner core can safely share information
     262      103848 : class RMSDCoreData
     263             : {
     264             : private:
     265             :   bool alEqDis;
     266             :   bool distanceIsMSD; // default is RMSD but can deliver the MSD
     267             :   bool hasDistance;  // distance is already calculated
     268             :   bool isInitialized;
     269             :   bool safe;
     270             : 
     271             :   // this need to be copied and they are small, should not affect the performance
     272             :   Vector creference;
     273             :   bool creference_is_calculated;
     274             :   bool creference_is_removed;
     275             :   Vector cpositions;
     276             :   bool cpositions_is_calculated;
     277             :   bool cpositions_is_removed;
     278             :   bool retrieve_only_rotation;
     279             : 
     280             :   // use reference assignment to speed up instead of copying
     281             :   const std::vector<Vector> &positions;
     282             :   const std::vector<Vector> &reference;
     283             :   const std::vector<double> &align;
     284             :   const std::vector<double> &displace;
     285             : 
     286             :   // the needed stuff for distance and more (one could use eigenvecs components and eigenvals for some reason)
     287             :   double dist;
     288             :   Vector4d eigenvals;
     289             :   Tensor4d eigenvecs;
     290             :   double rr00; //  sum of positions squared (needed for dist calc)
     291             :   double rr11; //  sum of reference squared (needed for dist calc)
     292             :   Tensor rotation; // rotation derived from the eigenvector having the smallest eigenvalue
     293             :   std::array<std::array<Tensor,3>,3> drotation_drr01; // derivative of the rotation only available when align!=displace
     294             :   Tensor ddist_drr01;
     295             :   Tensor ddist_drotation;
     296             :   std::vector<Vector> d; // difference of components
     297             : public:
     298             :   /// the constructor (note: only references are passed, therefore is rather fast)
     299             :   /// note: this aligns the reference onto the positions
     300             :   ///
     301             :   /// this method assumes that the centers are already calculated and subtracted
     302             :   RMSDCoreData(const std::vector<double> &a,const std::vector<double> &d,const std::vector<Vector> &p, const std::vector<Vector> &r, Vector &cp, Vector &cr ):
     303             :     alEqDis(false),distanceIsMSD(false),hasDistance(false),isInitialized(false),safe(false),
     304             :     creference(cr),creference_is_calculated(true),creference_is_removed(true),
     305             :     cpositions(cp),cpositions_is_calculated(true),cpositions_is_removed(true),retrieve_only_rotation(false),positions(p),reference(r),align(a),displace(d),dist(0.0),rr00(0.0),rr11(0.0) {};
     306             : 
     307             :   // this constructor does not assume that the positions and reference have the center subtracted
     308      103848 :   RMSDCoreData(const std::vector<double> &a,const std::vector<double> &d,const std::vector<Vector> &p, const std::vector<Vector> &r):
     309      103848 :     alEqDis(false),distanceIsMSD(false),hasDistance(false),isInitialized(false),safe(false),
     310      103848 :     creference_is_calculated(false),creference_is_removed(false),
     311      103848 :     cpositions_is_calculated(false),cpositions_is_removed(false),retrieve_only_rotation(false),positions(p),reference(r),align(a),displace(d),dist(0.0),rr00(0.0),rr11(0.0)
     312      103848 :   {cpositions.zero(); creference.zero();};
     313             : 
     314             :   // set the center on the fly without subtracting
     315      103848 :   void calcPositionsCenter() {
     316      103848 :     plumed_massert(!cpositions_is_calculated,"the center was already calculated");
     317     1939353 :     cpositions.zero(); for(unsigned i=0; i<positions.size(); i++) {cpositions+=positions[i]*align[i];} cpositions_is_calculated=true;
     318      103848 :   }
     319           0 :   void calcReferenceCenter() {
     320           0 :     plumed_massert(!creference_is_calculated,"the center was already calculated");
     321           0 :     creference.zero(); for(unsigned i=0; i<reference.size(); i++) {creference+=reference[i]*align[i];} creference_is_calculated=true;
     322           0 :   };
     323             :   // assume the center is given externally
     324             :   // cppcheck-suppress passedByValue
     325           0 :   void setPositionsCenter(Vector v) {plumed_massert(!cpositions_is_calculated,"You are setting the center two times!"); cpositions=v; cpositions_is_calculated=true;};
     326             :   // cppcheck-suppress passedByValue
     327      103848 :   void setReferenceCenter(Vector v) {plumed_massert(!creference_is_calculated,"You are setting the center two times!"); creference=v; creference_is_calculated=true;};
     328             :   // the center is already removed
     329      103848 :   void setPositionsCenterIsRemoved(bool t) {cpositions_is_removed=t;};
     330      103848 :   void setReferenceCenterIsRemoved(bool t) {creference_is_removed=t;};
     331             :   bool getPositionsCenterIsRemoved() {return cpositions_is_removed;};
     332             :   bool getReferenceCenterIsRemoved() {return creference_is_removed;};
     333             :   //  does the core calc : first thing to call after the constructor:
     334             :   // only_rotation=true does not retrieve the derivatives, just retrieve the optimal rotation (the same calc cannot be exploit further)
     335             :   void doCoreCalc(bool safe,bool alEqDis, bool only_rotation=false);
     336             :   // do calculation with close structure data structures
     337             :   void doCoreCalcWithCloseStructure(bool safe,bool alEqDis, const Tensor & rotationPosClose, const Tensor & rotationRefClose, std::array<std::array<Tensor,3>,3> & drotationPosCloseDrr01);
     338             :   // retrieve the distance if required after doCoreCalc
     339             :   double getDistance(bool squared);
     340             :   // retrieve the derivative of the distance respect to the position
     341             :   std::vector<Vector> getDDistanceDPositions();
     342             :   // retrieve the derivative of the distance respect to the reference
     343             :   std::vector<Vector> getDDistanceDReference();
     344             :   // specific version for SOMA calculation (i.e. does not need derivative respect to rotation matrix)
     345             :   std::vector<Vector> getDDistanceDReferenceSOMA();
     346             :   // get aligned reference onto position
     347             :   std::vector<Vector> getAlignedReferenceToPositions();
     348             :   // get aligned position onto reference
     349             :   std::vector<Vector> getAlignedPositionsToReference();
     350             :   // get centered positions
     351             :   std::vector<Vector> getCenteredPositions();
     352             :   // get centered reference
     353             :   std::vector<Vector> getCenteredReference();
     354             :   // get center of positions
     355             :   Vector getPositionsCenter();
     356             :   // get center of reference
     357             :   Vector getReferenceCenter();
     358             :   // get rotation matrix (reference ->positions)
     359             :   Tensor getRotationMatrixReferenceToPositions();
     360             :   // get rotation matrix (positions -> reference)
     361             :   Tensor getRotationMatrixPositionsToReference();
     362             :   // get the derivative of the rotation matrix respect to positions
     363             :   // note that the this transformation overlap the  reference onto position
     364             :   // if inverseTransform=true then aligns the positions onto reference
     365             :   Matrix<std::vector<Vector> > getDRotationDPositions( bool inverseTransform=false );
     366             :   // get the derivative of the rotation matrix respect to reference
     367             :   // note that the this transformation overlap the  reference onto position
     368             :   // if inverseTransform=true then aligns the positions onto reference
     369             :   Matrix<std::vector<Vector> >  getDRotationDReference(bool inverseTransform=false );
     370             :   const std::array<std::array<Tensor,3>,3> & getDRotationDRr01() const;
     371             : };
     372             : 
     373             : }
     374             : 
     375             : #endif
     376             : 

Generated by: LCOV version 1.16