LCOV - code coverage report
Current view: top level - reference - MultiDomainRMSD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 90 103 87.4 %
Date: 2024-10-11 08:09:47 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       10429 : 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             : {
      36           5 : }
      37             : 
      38           5 : void MultiDomainRMSD::read( const PDB& pdb ) {
      39           5 :   unsigned nblocks =  pdb.getNumberOfAtomBlocks();
      40           5 :   if( nblocks<2 ) error("multidomain RMSD only has one block of atoms");
      41             : 
      42             :   std::vector<Vector> positions; std::vector<double> align, displace;
      43           5 :   std::string num; blocks.resize( nblocks+1 ); blocks[0]=0;
      44          15 :   for(unsigned i=0; i<nblocks; ++i) blocks[i+1]=pdb.getAtomBlockEnds()[i];
      45             : 
      46             :   double tmp, lower=0.0, upper=std::numeric_limits<double>::max( );
      47          10 :   if( pdb.getArgumentValue("LOWER_CUTOFF",tmp) ) lower=tmp;
      48          10 :   if( pdb.getArgumentValue("UPPER_CUTOFF",tmp) ) upper=tmp;
      49           5 :   bool nopbc=pdb.hasFlag("NOPBC");
      50             : 
      51           5 :   domains.resize(0); weights.resize(0);
      52          15 :   for(unsigned i=1; i<=nblocks; ++i) {
      53          10 :     Tools::convert(i,num);
      54          10 :     if( ftype=="RMSD" ) {
      55             :       // parse("TYPE"+num, ftype );
      56             :       lower=0.0; upper=std::numeric_limits<double>::max( );
      57           0 :       if( pdb.getArgumentValue("LOWER_CUTOFF"+num,tmp) ) lower=tmp;
      58           0 :       if( pdb.getArgumentValue("UPPER_CUTOFF"+num,tmp) ) upper=tmp;
      59           0 :       nopbc=pdb.hasFlag("NOPBC");
      60             :     }
      61          10 :     domains.emplace_back( metricRegister().create<SingleDomainRMSD>( ftype ) );
      62          10 :     positions.resize( blocks[i] - blocks[i-1] );
      63          10 :     align.resize( blocks[i] - blocks[i-1] );
      64          10 :     displace.resize( blocks[i] - blocks[i-1] );
      65             :     unsigned n=0;
      66          69 :     for(unsigned j=blocks[i-1]; j<blocks[i]; ++j) {
      67          59 :       positions[n]=pdb.getPositions()[j];
      68          59 :       align[n]=pdb.getOccupancy()[j];
      69          59 :       displace[n]=pdb.getBeta()[j];
      70          59 :       n++;
      71             :     }
      72          10 :     domains[i-1]->setBoundsOnDistances( !nopbc, lower, upper );
      73          10 :     domains[i-1]->setReferenceAtoms( positions, align, displace );
      74          10 :     domains[i-1]->setupRMSDObject();
      75             : 
      76          10 :     double ww=0;
      77          20 :     if( !pdb.getArgumentValue("WEIGHT"+num,ww) ) weights.push_back( 1.0 );
      78           0 :     else weights.push_back( ww );
      79             :   }
      80             :   // And set the atom numbers for this object
      81           5 :   indices.resize(0); atom_der_index.resize(0);
      82          64 :   for(unsigned i=0; i<pdb.size(); ++i) { indices.push_back( pdb.getAtomNumbers()[i] ); atom_der_index.push_back(i); }
      83             :   // setAtomNumbers( pdb.getAtomNumbers() );
      84           5 : }
      85             : 
      86           0 : void MultiDomainRMSD::setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ) {
      87           0 :   plumed_error();
      88             : }
      89             : 
      90          37 : double MultiDomainRMSD::calculate( const std::vector<Vector>& pos, const Pbc& pbc, ReferenceValuePack& myder, const bool& squared ) const {
      91          37 :   double totd=0.; Tensor tvirial; std::vector<Vector> mypos; MultiValue tvals( 1, 3*pos.size()+9 );
      92          37 :   ReferenceValuePack tder( 0, getNumberOfAtoms(), tvals ); myder.clear();
      93             : 
      94         111 :   for(unsigned i=0; i<domains.size(); ++i) {
      95             :     // Must extract appropriate positions here
      96          74 :     mypos.resize( blocks[i+1] - blocks[i] );
      97          74 :     if( myder.calcUsingPCAOption() ) domains[i]->setupPCAStorage( tder );
      98         453 :     unsigned n=0; for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) { tder.setAtomIndex(n,j); mypos[n]=pos[j]; n++; }
      99         453 :     for(unsigned k=n; k<getNumberOfAtoms(); ++k) tder.setAtomIndex(k,3*pos.size()+10);
     100             :     // This actually does the calculation
     101          74 :     totd += weights[i]*domains[i]->calculate( mypos, pbc, tder, true );
     102             :     // Now merge the derivative
     103          74 :     myder.copyScaledDerivatives( 0, weights[i], tvals );
     104             :     // If PCA copy PCA stuff
     105          74 :     if( myder.calcUsingPCAOption() ) {
     106             :       unsigned n=0;
     107          44 :       if( tder.centeredpos.size()>0 ) myder.rot[i]=tder.rot[0];
     108         198 :       for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) {
     109         154 :         myder.displacement[j]=weights[i]*tder.displacement[n];  // Multiplication by weights here ensures that normalisation is done correctly
     110         154 :         if( tder.centeredpos.size()>0 ) {
     111          77 :           myder.centeredpos[j]=tder.centeredpos[n];
     112        1001 :           for(unsigned p=0; p<3; ++p) for(unsigned q=0; q<3; ++q) myder.DRotDPos(p,q)[j]=tder.DRotDPos(p,q)[n];
     113             :         }
     114         154 :         n++;
     115             :       }
     116             :     }
     117             :     // Make sure virial status is set correctly in output derivative pack
     118             :     // This is only done here so I do this by using class friendship
     119          74 :     if( tder.virialWasSet() ) myder.boxWasSet=true;
     120             :   }
     121          37 :   if( !myder.updateComplete() ) myder.updateDynamicLists();
     122             : 
     123          37 :   if( !squared ) {
     124          15 :     totd=std::sqrt(totd); double xx=0.5/totd;
     125          15 :     myder.scaleAllDerivatives( xx );
     126             :   }
     127          37 :   return totd;
     128          37 : }
     129             : 
     130          22 : double MultiDomainRMSD::calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg,
     131             :                               ReferenceValuePack& myder, const bool& squared ) const {
     132             :   plumed_dbg_assert( vals.size()==0 && pos.size()==getNumberOfAtoms() && arg.size()==0 );
     133          22 :   return calculate( pos, pbc, myder, squared );
     134             : }
     135             : 
     136           2 : bool MultiDomainRMSD::pcaIsEnabledForThisReference() {
     137             :   bool enabled=true;
     138           6 :   for(unsigned i=0; i<domains.size(); ++i) {
     139           4 :     if( !domains[i]->pcaIsEnabledForThisReference() ) enabled=false;
     140             :   }
     141           2 :   return enabled;
     142             : }
     143             : 
     144           2 : void MultiDomainRMSD::setupPCAStorage( ReferenceValuePack& mypack ) {
     145             :   plumed_dbg_assert( pcaIsEnabledForThisReference() );
     146             :   mypack.switchOnPCAOption();
     147           2 :   mypack.displacement.resize( getNumberOfAtoms() );
     148           2 :   mypack.centeredpos.resize( getNumberOfAtoms() );
     149           2 :   mypack.DRotDPos.resize(3,3); mypack.rot.resize( domains.size() );
     150          26 :   for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) mypack.DRotDPos(i,j).resize( getNumberOfAtoms() );
     151           2 : }
     152             : 
     153             : // Vector MultiDomainRMSD::getAtomicDisplacement( const unsigned& iatom ){
     154             : //   for(unsigned i=0;i<domains.size();++i){
     155             : //       unsigned n=0;
     156             : //       for(unsigned j=blocks[i];j<blocks[i+1];++j){
     157             : //           if( j==iatom ) return weights[i]*domains[i]->getAtomicDisplacement(n);
     158             : //           n++;
     159             : //       }
     160             : //   }
     161             : // }
     162             : 
     163           0 : void MultiDomainRMSD::extractAtomicDisplacement( const std::vector<Vector>& pos, std::vector<Vector>& direction ) const {
     164             :   std::vector<Vector> mypos, mydir;
     165           0 :   for(unsigned i=0; i<domains.size(); ++i) {
     166             :     // Must extract appropriate positions here
     167           0 :     mypos.resize( blocks[i+1] - blocks[i] ); mydir.resize( blocks[i+1] - blocks[i] );
     168           0 :     unsigned n=0; for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) { mypos[n]=pos[j]; n++; }
     169             :     // Do the calculation
     170           0 :     domains[i]->extractAtomicDisplacement( mypos, mydir );
     171             :     // Extract the direction
     172           0 :     n=0; for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) { direction[j]=weights[i]*mydir[n];  n++; }
     173             :   }
     174           0 : }
     175             : 
     176          44 : double MultiDomainRMSD::projectAtomicDisplacementOnVector( const bool& normalized, const std::vector<Vector>& vecs, ReferenceValuePack& mypack ) const {
     177          44 :   double totd=0.; std::vector<Vector> tvecs; mypack.clear();
     178          44 :   MultiValue tvals( 1, mypack.getNumberOfDerivatives() ); ReferenceValuePack tder( 0, getNumberOfAtoms(), tvals );
     179         132 :   for(unsigned i=0; i<domains.size(); ++i) {
     180             :     // Must extract appropriate positions here
     181          88 :     tvecs.resize( blocks[i+1] - blocks[i] ); domains[i]->setupPCAStorage( tder );
     182          88 :     if( tder.centeredpos.size()>0 ) {
     183         572 :       for(unsigned p=0; p<3; ++p) for(unsigned q=0; q<3; ++q) tder.DRotDPos(p,q).resize( tvecs.size() );
     184             :     }
     185             :     // Extract information from storage pack and put in local pack
     186          88 :     if( tder.centeredpos.size()>0 ) tder.rot[0]=mypack.rot[i];
     187             :     unsigned n=0;
     188         396 :     for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) {
     189         308 :       tder.setAtomIndex(n,j); tvecs[n] = vecs[j]; tder.displacement[n]=mypack.displacement[j] / weights[i];
     190         308 :       if( tder.centeredpos.size()>0 ) {
     191         154 :         tder.centeredpos[n]=mypack.centeredpos[j];
     192        2002 :         for(unsigned p=0; p<3; ++p) for(unsigned q=0; q<3; ++q) tder.DRotDPos(p,q)[n]=mypack.DRotDPos(p,q)[j];
     193             :       }
     194         308 :       n++;
     195             :     }
     196         396 :     for(unsigned k=n; k<getNumberOfAtoms(); ++k) tder.setAtomIndex(k,3*vecs.size()+10);
     197             : 
     198             :     // Do the calculations
     199          88 :     totd += weights[i]*domains[i]->projectAtomicDisplacementOnVector( normalized, tvecs, tder );
     200             : 
     201             :     // And derivatives
     202          88 :     mypack.copyScaledDerivatives( 0, weights[i], tvals );
     203             :   }
     204          44 :   if( !mypack.updateComplete() ) mypack.updateDynamicLists();
     205             : 
     206          44 :   return totd;
     207          44 : }
     208             : 
     209             : }

Generated by: LCOV version 1.15