LCOV - code coverage report
Current view: top level - reference - MultiDomainRMSD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 121 144 84.0 %
Date: 2026-03-30 13:16:06 Functions: 10 13 76.9 %

          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 "MultiDomainRMSD.h"
      23             : #include "SingleDomainRMSD.h"
      24             : #include "MetricRegister.h"
      25             : #include "tools/PDB.h"
      26             : 
      27             : namespace PLMD {
      28             : 
      29       13795 : PLUMED_REGISTER_METRIC(MultiDomainRMSD,"MULTI")
      30             : 
      31           5 : MultiDomainRMSD::MultiDomainRMSD( const ReferenceConfigurationOptions& ro ):
      32             :   ReferenceConfiguration(ro),
      33             :   ReferenceAtoms(ro),
      34           5 :   ftype(ro.getMultiRMSDType()) {
      35           5 : }
      36             : 
      37           5 : void MultiDomainRMSD::read( const PDB& pdb ) {
      38           5 :   unsigned nblocks =  pdb.getNumberOfAtomBlocks();
      39           5 :   if( nblocks<2 ) {
      40           0 :     error("multidomain RMSD only has one block of atoms");
      41             :   }
      42             : 
      43             :   std::vector<Vector> positions;
      44             :   std::vector<double> align, displace;
      45             :   std::string num;
      46           5 :   blocks.resize( nblocks+1 );
      47           5 :   blocks[0]=0;
      48          15 :   for(unsigned i=0; i<nblocks; ++i) {
      49          10 :     blocks[i+1]=pdb.getAtomBlockEnds()[i];
      50             :   }
      51             : 
      52             :   double tmp, lower=0.0, upper=std::numeric_limits<double>::max( );
      53          10 :   if( pdb.getArgumentValue("LOWER_CUTOFF",tmp) ) {
      54           0 :     lower=tmp;
      55             :   }
      56          10 :   if( pdb.getArgumentValue("UPPER_CUTOFF",tmp) ) {
      57           0 :     upper=tmp;
      58             :   }
      59           5 :   bool nopbc=pdb.hasFlag("NOPBC");
      60             : 
      61           5 :   domains.resize(0);
      62           5 :   weights.resize(0);
      63          15 :   for(unsigned i=1; i<=nblocks; ++i) {
      64          10 :     Tools::convert(i,num);
      65          10 :     if( ftype=="RMSD" ) {
      66             :       // parse("TYPE"+num, ftype );
      67             :       lower=0.0;
      68             :       upper=std::numeric_limits<double>::max( );
      69           0 :       if( pdb.getArgumentValue("LOWER_CUTOFF"+num,tmp) ) {
      70           0 :         lower=tmp;
      71             :       }
      72           0 :       if( pdb.getArgumentValue("UPPER_CUTOFF"+num,tmp) ) {
      73           0 :         upper=tmp;
      74             :       }
      75           0 :       nopbc=pdb.hasFlag("NOPBC");
      76             :     }
      77          10 :     domains.emplace_back( metricRegister().create<SingleDomainRMSD>( ftype ) );
      78          10 :     positions.resize( blocks[i] - blocks[i-1] );
      79          10 :     align.resize( blocks[i] - blocks[i-1] );
      80          10 :     displace.resize( blocks[i] - blocks[i-1] );
      81             :     unsigned n=0;
      82          69 :     for(unsigned j=blocks[i-1]; j<blocks[i]; ++j) {
      83          59 :       positions[n]=pdb.getPositions()[j];
      84          59 :       align[n]=pdb.getOccupancy()[j];
      85          59 :       displace[n]=pdb.getBeta()[j];
      86          59 :       n++;
      87             :     }
      88          10 :     domains[i-1]->setBoundsOnDistances( !nopbc, lower, upper );
      89          10 :     domains[i-1]->setReferenceAtoms( positions, align, displace );
      90          10 :     domains[i-1]->setupRMSDObject();
      91             : 
      92          10 :     double ww=0;
      93          20 :     if( !pdb.getArgumentValue("WEIGHT"+num,ww) ) {
      94          10 :       weights.push_back( 1.0 );
      95             :     } else {
      96           0 :       weights.push_back( ww );
      97             :     }
      98             :   }
      99             :   // And set the atom numbers for this object
     100           5 :   indices.resize(0);
     101           5 :   atom_der_index.resize(0);
     102          64 :   for(unsigned i=0; i<pdb.size(); ++i) {
     103          59 :     indices.push_back( pdb.getAtomNumbers()[i] );
     104          59 :     atom_der_index.push_back(i);
     105             :   }
     106             :   // setAtomNumbers( pdb.getAtomNumbers() );
     107           5 : }
     108             : 
     109           0 : void MultiDomainRMSD::setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ) {
     110           0 :   plumed_error();
     111             : }
     112             : 
     113          37 : double MultiDomainRMSD::calculate( const std::vector<Vector>& pos, const Pbc& pbc, ReferenceValuePack& myder, const bool& squared ) const {
     114             :   double totd=0.;
     115          37 :   Tensor tvirial;
     116             :   std::vector<Vector> mypos;
     117          37 :   MultiValue tvals( 1, 3*pos.size()+9 );
     118          37 :   ReferenceValuePack tder( 0, getNumberOfAtoms(), tvals );
     119          37 :   myder.clear();
     120             : 
     121         111 :   for(unsigned i=0; i<domains.size(); ++i) {
     122             :     // Must extract appropriate positions here
     123          74 :     mypos.resize( blocks[i+1] - blocks[i] );
     124          74 :     if( myder.calcUsingPCAOption() ) {
     125          44 :       domains[i]->setupPCAStorage( tder );
     126             :     }
     127             :     unsigned n=0;
     128         453 :     for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) {
     129             :       tder.setAtomIndex(n,j);
     130         379 :       mypos[n]=pos[j];
     131         379 :       n++;
     132             :     }
     133         379 :     for(unsigned k=n; k<getNumberOfAtoms(); ++k) {
     134         379 :       tder.setAtomIndex(k,3*pos.size()+10);
     135             :     }
     136             :     // This actually does the calculation
     137          74 :     totd += weights[i]*domains[i]->calculate( mypos, pbc, tder, true );
     138             :     // Now merge the derivative
     139          74 :     myder.copyScaledDerivatives( 0, weights[i], tvals );
     140             :     // If PCA copy PCA stuff
     141          74 :     if( myder.calcUsingPCAOption() ) {
     142             :       unsigned n=0;
     143          44 :       if( tder.centeredpos.size()>0 ) {
     144          22 :         myder.rot[i]=tder.rot[0];
     145             :       }
     146         198 :       for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) {
     147         154 :         myder.displacement[j]=weights[i]*tder.displacement[n];  // Multiplication by weights here ensures that normalisation is done correctly
     148         154 :         if( tder.centeredpos.size()>0 ) {
     149          77 :           myder.centeredpos[j]=tder.centeredpos[n];
     150         308 :           for(unsigned p=0; p<3; ++p)
     151         924 :             for(unsigned q=0; q<3; ++q) {
     152         693 :               myder.DRotDPos(p,q)[j]=tder.DRotDPos(p,q)[n];
     153             :             }
     154             :         }
     155         154 :         n++;
     156             :       }
     157             :     }
     158             :     // Make sure virial status is set correctly in output derivative pack
     159             :     // This is only done here so I do this by using class friendship
     160          74 :     if( tder.virialWasSet() ) {
     161          10 :       myder.boxWasSet=true;
     162             :     }
     163             :   }
     164          37 :   if( !myder.updateComplete() ) {
     165          37 :     myder.updateDynamicLists();
     166             :   }
     167             : 
     168          37 :   if( !squared ) {
     169          15 :     totd=std::sqrt(totd);
     170          15 :     double xx=0.5/totd;
     171          15 :     myder.scaleAllDerivatives( xx );
     172             :   }
     173          37 :   return totd;
     174          37 : }
     175             : 
     176          22 : double MultiDomainRMSD::calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg,
     177             :                               ReferenceValuePack& myder, const bool& squared ) const {
     178             :   plumed_dbg_assert( vals.size()==0 && pos.size()==getNumberOfAtoms() && arg.size()==0 );
     179          22 :   return calculate( pos, pbc, myder, squared );
     180             : }
     181             : 
     182           2 : bool MultiDomainRMSD::pcaIsEnabledForThisReference() {
     183             :   bool enabled=true;
     184           6 :   for(unsigned i=0; i<domains.size(); ++i) {
     185           4 :     if( !domains[i]->pcaIsEnabledForThisReference() ) {
     186             :       enabled=false;
     187             :     }
     188             :   }
     189           2 :   return enabled;
     190             : }
     191             : 
     192           2 : void MultiDomainRMSD::setupPCAStorage( ReferenceValuePack& mypack ) {
     193             :   plumed_dbg_assert( pcaIsEnabledForThisReference() );
     194             :   mypack.switchOnPCAOption();
     195           2 :   mypack.displacement.resize( getNumberOfAtoms() );
     196           2 :   mypack.centeredpos.resize( getNumberOfAtoms() );
     197             :   mypack.DRotDPos.resize(3,3);
     198           2 :   mypack.rot.resize( domains.size() );
     199           8 :   for(unsigned i=0; i<3; ++i)
     200          24 :     for(unsigned j=0; j<3; ++j) {
     201          18 :       mypack.DRotDPos(i,j).resize( getNumberOfAtoms() );
     202             :     }
     203           2 : }
     204             : 
     205             : // Vector MultiDomainRMSD::getAtomicDisplacement( const unsigned& iatom ){
     206             : //   for(unsigned i=0;i<domains.size();++i){
     207             : //       unsigned n=0;
     208             : //       for(unsigned j=blocks[i];j<blocks[i+1];++j){
     209             : //           if( j==iatom ) return weights[i]*domains[i]->getAtomicDisplacement(n);
     210             : //           n++;
     211             : //       }
     212             : //   }
     213             : // }
     214             : 
     215           0 : void MultiDomainRMSD::extractAtomicDisplacement( const std::vector<Vector>& pos, std::vector<Vector>& direction ) const {
     216             :   std::vector<Vector> mypos, mydir;
     217           0 :   for(unsigned i=0; i<domains.size(); ++i) {
     218             :     // Must extract appropriate positions here
     219           0 :     mypos.resize( blocks[i+1] - blocks[i] );
     220           0 :     mydir.resize( blocks[i+1] - blocks[i] );
     221             :     unsigned n=0;
     222           0 :     for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) {
     223           0 :       mypos[n]=pos[j];
     224           0 :       n++;
     225             :     }
     226             :     // Do the calculation
     227           0 :     domains[i]->extractAtomicDisplacement( mypos, mydir );
     228             :     // Extract the direction
     229             :     n=0;
     230           0 :     for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) {
     231           0 :       direction[j]=weights[i]*mydir[n];
     232           0 :       n++;
     233             :     }
     234             :   }
     235           0 : }
     236             : 
     237          44 : double MultiDomainRMSD::projectAtomicDisplacementOnVector( const bool& normalized, const std::vector<Vector>& vecs, ReferenceValuePack& mypack ) const {
     238             :   double totd=0.;
     239             :   std::vector<Vector> tvecs;
     240          44 :   mypack.clear();
     241          44 :   MultiValue tvals( 1, mypack.getNumberOfDerivatives() );
     242          44 :   ReferenceValuePack tder( 0, getNumberOfAtoms(), tvals );
     243         132 :   for(unsigned i=0; i<domains.size(); ++i) {
     244             :     // Must extract appropriate positions here
     245          88 :     tvecs.resize( blocks[i+1] - blocks[i] );
     246          88 :     domains[i]->setupPCAStorage( tder );
     247          88 :     if( tder.centeredpos.size()>0 ) {
     248         176 :       for(unsigned p=0; p<3; ++p)
     249         528 :         for(unsigned q=0; q<3; ++q) {
     250         396 :           tder.DRotDPos(p,q).resize( tvecs.size() );
     251             :         }
     252             :     }
     253             :     // Extract information from storage pack and put in local pack
     254          88 :     if( tder.centeredpos.size()>0 ) {
     255          44 :       tder.rot[0]=mypack.rot[i];
     256             :     }
     257             :     unsigned n=0;
     258         396 :     for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) {
     259             :       tder.setAtomIndex(n,j);
     260         308 :       tvecs[n] = vecs[j];
     261         308 :       tder.displacement[n]=mypack.displacement[j] / weights[i];
     262         308 :       if( tder.centeredpos.size()>0 ) {
     263         154 :         tder.centeredpos[n]=mypack.centeredpos[j];
     264         616 :         for(unsigned p=0; p<3; ++p)
     265        1848 :           for(unsigned q=0; q<3; ++q) {
     266        1386 :             tder.DRotDPos(p,q)[n]=mypack.DRotDPos(p,q)[j];
     267             :           }
     268             :       }
     269         308 :       n++;
     270             :     }
     271         396 :     for(unsigned k=n; k<getNumberOfAtoms(); ++k) {
     272         308 :       tder.setAtomIndex(k,3*vecs.size()+10);
     273             :     }
     274             : 
     275             :     // Do the calculations
     276          88 :     totd += weights[i]*domains[i]->projectAtomicDisplacementOnVector( normalized, tvecs, tder );
     277             : 
     278             :     // And derivatives
     279          88 :     mypack.copyScaledDerivatives( 0, weights[i], tvals );
     280             :   }
     281          44 :   if( !mypack.updateComplete() ) {
     282          44 :     mypack.updateDynamicLists();
     283             :   }
     284             : 
     285          44 :   return totd;
     286          44 : }
     287             : 
     288             : }

Generated by: LCOV version 1.16