LCOV - code coverage report
Current view: top level - reference - OptimalRMSD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 75 75 100.0 %
Date: 2026-03-30 13:16:06 Functions: 11 12 91.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-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             : #include "MetricRegister.h"
      23             : #include "RMSDBase.h"
      24             : #include "tools/Matrix.h"
      25             : #include "tools/RMSD.h"
      26             : 
      27             : namespace PLMD {
      28             : 
      29             : class OptimalRMSD : public RMSDBase {
      30             : private:
      31             :   bool fast;
      32             :   RMSD myrmsd;
      33             : public:
      34             :   explicit OptimalRMSD(const ReferenceConfigurationOptions& ro);
      35             :   void read( const PDB& ) override;
      36             :   double calc( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const override;
      37          45 :   bool pcaIsEnabledForThisReference() override {
      38          45 :     return true;
      39             :   }
      40         473 :   void setupRMSDObject() override {
      41         473 :     myrmsd.clear();
      42         473 :     myrmsd.set(getAlign(),getDisplace(),getReferencePositions(),"OPTIMAL");
      43         473 :   }
      44          72 :   void setupPCAStorage( ReferenceValuePack& mypack ) override {
      45             :     mypack.switchOnPCAOption();
      46          72 :     mypack.centeredpos.resize( getNumberOfAtoms() );
      47          72 :     mypack.displacement.resize( getNumberOfAtoms() );
      48             :     mypack.DRotDPos.resize(3,3);
      49          72 :     mypack.rot.resize(1);
      50          72 :   }
      51             :   void extractAtomicDisplacement( const std::vector<Vector>& pos, std::vector<Vector>& direction ) const override;
      52             :   double projectAtomicDisplacementOnVector( const bool& normalized, const std::vector<Vector>& vecs, ReferenceValuePack& mypack ) const override;
      53             : };
      54             : 
      55       14695 : PLUMED_REGISTER_METRIC(OptimalRMSD,"OPTIMAL")
      56             : 
      57         455 : OptimalRMSD::OptimalRMSD(const ReferenceConfigurationOptions& ro ):
      58             :   ReferenceConfiguration(ro),
      59         455 :   RMSDBase(ro) {
      60         455 :   fast=ro.usingFastOption();
      61         455 : }
      62             : 
      63         427 : void OptimalRMSD::read( const PDB& pdb ) {
      64         427 :   readReference( pdb );
      65         427 :   setupRMSDObject();
      66         427 : }
      67             : 
      68      273521 : double OptimalRMSD::calc( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const {
      69             :   double d;
      70      273521 :   if( myder.calcUsingPCAOption() ) {
      71        2786 :     std::vector<Vector> centeredreference( getNumberOfAtoms () );
      72        2786 :     d=myrmsd.calc_PCAelements(pos,myder.getAtomVector(),myder.rot[0],myder.DRotDPos,myder.getAtomsDisplacementVector(),myder.centeredpos,centeredreference,squared);
      73        2786 :     unsigned nat = pos.size();
      74       48548 :     for(unsigned i=0; i<nat; ++i) {
      75       45762 :       myder.getAtomsDisplacementVector()[i] -= getReferencePosition(i);
      76       45762 :       myder.getAtomsDisplacementVector()[i] *= getDisplace()[i];
      77             :     }
      78      270735 :   } else if( fast ) {
      79      219934 :     if( getAlign()==getDisplace() ) {
      80      219932 :       d=myrmsd.optimalAlignment<false,true>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared);
      81             :     } else {
      82           2 :       d=myrmsd.optimalAlignment<false,false>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared);
      83             :     }
      84             :   } else {
      85       50801 :     if( getAlign()==getDisplace() ) {
      86       50690 :       d=myrmsd.optimalAlignment<true,true>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared);
      87             :     } else {
      88         111 :       d=myrmsd.optimalAlignment<true,false>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared);
      89             :     }
      90             :   }
      91      273521 :   myder.clear();
      92    19454789 :   for(unsigned i=0; i<pos.size(); ++i) {
      93    19181268 :     myder.setAtomDerivatives( i, myder.getAtomVector()[i] );
      94             :   }
      95      273521 :   if( !myder.updateComplete() ) {
      96      273521 :     myder.updateDynamicLists();
      97             :   }
      98      273521 :   return d;
      99             : }
     100             : 
     101        1107 : void OptimalRMSD::extractAtomicDisplacement( const std::vector<Vector>& pos, std::vector<Vector>& direction ) const {
     102        1107 :   std::vector<Tensor> rot(1);
     103             :   Matrix<std::vector<Vector> > DRotDPos( 3, 3 );
     104        1107 :   std::vector<Vector> centeredreference( getNumberOfAtoms() ), centeredpos( getNumberOfAtoms() ), avector( getNumberOfAtoms() );
     105        1107 :   myrmsd.calc_PCAelements(pos,avector,rot[0],DRotDPos,direction,centeredpos,centeredreference,true);
     106        1107 :   unsigned nat = pos.size();
     107       15498 :   for(unsigned i=0; i<nat; ++i) {
     108       14391 :     direction[i] = getDisplace()[i]*( direction[i] - getReferencePosition(i) );
     109             :   }
     110        1107 : }
     111             : 
     112        1158 : double OptimalRMSD::projectAtomicDisplacementOnVector( const bool& normalized, const std::vector<Vector>& vecs, ReferenceValuePack& mypack ) const {
     113             :   plumed_dbg_assert( mypack.calcUsingPCAOption() );
     114             : 
     115             :   double proj=0.0;
     116        1158 :   mypack.clear();
     117       15662 :   for(unsigned i=0; i<vecs.size(); ++i) {
     118       14504 :     proj += dotProduct( mypack.getAtomsDisplacementVector()[i], vecs[i] );
     119             :   }
     120        4632 :   for(unsigned a=0; a<3; a++) {
     121       13896 :     for(unsigned b=0; b<3; b++) {
     122             :       double tmp1=0.;
     123      140958 :       for(unsigned n=0; n<getNumberOfAtoms(); n++) {
     124      130536 :         tmp1+=mypack.centeredpos[n][b]*vecs[n][a];
     125             :       }
     126             : 
     127      140958 :       for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     128      130536 :         if( normalized ) {
     129        2772 :           mypack.addAtomDerivatives( iat, getDisplace()[iat]*mypack.DRotDPos[a][b][iat]*tmp1 );
     130             :         } else {
     131      127764 :           mypack.addAtomDerivatives( iat, mypack.DRotDPos[a][b][iat]*tmp1 );
     132             :         }
     133             :       }
     134             :     }
     135             :   }
     136        1158 :   Tensor trot=mypack.rot[0].transpose();
     137        1158 :   Vector v1;
     138        1158 :   v1.zero();
     139        1158 :   double prefactor = 1. / static_cast<double>( getNumberOfAtoms() );
     140       15662 :   for(unsigned n=0; n<getNumberOfAtoms(); n++) {
     141       14504 :     v1+=prefactor*matmul(trot,vecs[n]);
     142             :   }
     143        1158 :   if( normalized ) {
     144         374 :     for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     145         308 :       mypack.addAtomDerivatives( iat, getDisplace()[iat]*(matmul(trot,vecs[iat]) - v1) );
     146             :     }
     147             :   } else {
     148       15288 :     for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     149       14196 :       mypack.addAtomDerivatives( iat, (matmul(trot,vecs[iat]) - v1) );
     150             :     }
     151             :   }
     152        1158 :   if( !mypack.updateComplete() ) {
     153        1158 :     mypack.updateDynamicLists();
     154             :   }
     155             : 
     156        1158 :   return proj;
     157             : }
     158             : 
     159             : }

Generated by: LCOV version 1.16