LCOV - code coverage report
Current view: top level - secondarystructure - SecondaryStructureRMSD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 37 38 97.4 %
Date: 2026-11-05 10:19:04 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2017-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 "SecondaryStructureBase.h"
      23             : #include "core/ActionRegister.h"
      24             : #include "tools/RMSD.h"
      25             : 
      26             : //+PLUMEDOC MCOLVAR SECONDARY_STRUCTURE_RMSD
      27             : /*
      28             : Calclulate the RMSD between segments of a protein and a reference structure of interest
      29             : 
      30             : This action is used in the shortcuts [ALPHARMSD](ALPHARMSD.md), [ANTIBETARMSD](ANTIBETARMSD.md) and [PARABETARMSD](PARABETARMSD.md).  It calculates a
      31             : vector of [RMSD](RMSD.md) values between a single reference multiple configurations and the instantaneous
      32             : positions of various groups of atoms.  For example, in the following input we define a single set of reference
      33             : set of coordinates for 3 atoms.
      34             : 
      35             : ```plumed
      36             : c1: SECONDARY_STRUCTURE_RMSD ...
      37             :     ATOMS=13-24
      38             :     STRUCTURE1=1,0,0,0,1,0,0,0,1
      39             :     SEGMENT1=0,1,2 SEGMENT2=3,4,5
      40             :     SEGMENT3=6,7,8 SEGMENT4=9,10,11
      41             :     TYPE=OPTIMAL
      42             : ...
      43             : PRINT ARG=c1 FILE=colvar
      44             : ```
      45             : 
      46             : A four dimensional vector is then returned that contains the RMSD distances between the 4 sets of 3 atoms that were specified using the `SEGMENT` keywords
      47             : and the reference coordinates.  Notice that you can use multiple instances of the `STRUCTURE` keyword.  In general the number of vectors output
      48             : is equal to the number of times the `STRUCTURE` keyword is used.  Further note that the indices specified to the SEGMENT keywords give the indices in the list
      49             : of atoms specified by the ATOMS keyword.  `SEGMENT1=0,1,2` in the above input is measuring the distance between the instantaneous positions of atoms 13, 14 and 15
      50             : and the reference structure.
      51             : 
      52             : ## Periodic boundary conditions
      53             : 
      54             : If you turn off periodic boundary conditions by using the NOPBC flag as shown below:
      55             : 
      56             : ```plumed
      57             : c1: SECONDARY_STRUCTURE_RMSD ...
      58             :     ATOMS=13-24 NOPBC
      59             :     STRUCTURE1=1,0,0,0,1,0,0,0,1
      60             :     SEGMENT1=0,1,2 SEGMENT2=3,4,5
      61             :     SEGMENT3=6,7,8 SEGMENT4=9,10,11
      62             :     TYPE=SIMPLE
      63             : ...
      64             : PRINT ARG=c1 FILE=colvar
      65             : ```
      66             : 
      67             : the distances between in the instantaneous structure are evaluated in a way that does not take the periodic boundary conditions
      68             : into account.  Whenver this flag is __not__ present the distances in the instantaneous structure are evaluated in a way that takes the periodic boundary conditions
      69             : into account.
      70             : 
      71             : If you use the `ALIGN_STRANDS` flag to evaluate the distances in a way that takes the periodic boundary conditions into accounts means that
      72             : calculating the distance between the positions of the 7th and 22nd atoms ($\mathbf{x}_7$ and $\mathbf{x}_{22}$) of the instanenous structures
      73             : using the periodic boundary conditions.  The 22 atom is the repositioned at:
      74             : 
      75             : $$
      76             : \mathbf{x}_{22} = \mathbf{x}_7 + ( \mathbf{x}_{22} - \mathbf{x}_7 )
      77             : $$
      78             : 
      79             : where the difference in the second term on the right of the equality sign is evaluated using the periodic boundary conditions. New positions are then determined
      80             : for atoms 16 through 30 by adding the difference (evaluated without PBC) between the new position for atom 22 after the above transformation has been performed and the
      81             : original position of this atom.  This treatment is designed for making sure that the two strands of the [ANTIBETARMSD](ANTIBETARMSD.md) and [PARABETARMSD](PARABETARMSD.md)
      82             : sheets are not broken by the periodic boundaries.
      83             : 
      84             : ## Working with beta sheet like structures
      85             : 
      86             : As discussed in the documentation for [ANTIBETARMSD](ANTIBETARMSD.md) and [PARABETARMSD](PARABETARMSD.md) using the STRANDS_KEYWORD cutoff can speed up the calculation
      87             : dramatically.  The reason this keyword gives such dramatric speed ups is illustrated by the example input:
      88             : 
      89             : ```plumed
      90             : ab_cut_dists: DISTANCE ...
      91             :   ATOMS1=19,69 ATOMS2=19,79
      92             :   ATOMS3=19,89 ATOMS4=19,99
      93             :   ATOMS5=19,109
      94             : ...
      95             : ab_cut: CUSTOM ARG=ab_cut_dists FUNC=step(1-x) PERIODIC=NO
      96             : ab_rmsd: SECONDARY_STRUCTURE_RMSD ...
      97             :    TYPE=OPTIMAL ALIGN_STRANDS MASK=ab_cut
      98             :    ATOMS=7,9,11,15,16,17,19,21,25,26,27,29,31,35,36,37,39,41,45,46,47,49,51,55,56,57,59,61,65,66,67,69,71,75,76,77,79,81,85,86,87,89,91,95,96,97,99,101,105,106,107,109,111,115,116,117,119,121,125,126
      99             :    SEGMENT1=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39
     100             :    SEGMENT2=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44
     101             :    SEGMENT3=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49
     102             :    SEGMENT4=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54
     103             :    SEGMENT5=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59
     104             :    STRUCTURE1=2.263,-3.795,1.722,2.493,-2.426,2.263,3.847,-1.838,1.761,1.301,-1.517,1.921,0.852,-1.504,0.739,0.818,-0.738,2.917,-0.299,0.243,2.748,-1.421,-0.076,3.757,0.273,1.68,2.854,0.902,1.993,3.888,0.119,2.532,1.813,0.683,3.916,1.68,1.58,3.94,0.395,-0.394,5.011,1.63,-1.459,4.814,0.982,-2.962,3.559,-1.359,-2.439,2.526,-2.287,-1.189,3.006,-3.087,-2.081,1.231,-1.52,-1.524,1.324,-0.409,-2.326,0.037,-2.095,-1.858,-1.269,-1.554,-3.053,-2.199,-1.291,-0.869,-1.949,-2.512,-1.255,-2.07,-3.71,0.326,-2.363,-2.072,1.405,-2.992,-2.872,2.699,-2.129,-2.917,1.745,-4.399,-2.33,1.899,-4.545,-1.102
     105             : ...
     106             : ab_ltu: LESS_THAN ARG=ab_rmsd SWITCH={RATIONAL R_0=0.1 D_0=0.0 NN=8 MM=12} MASK=ab_cut
     107             : ab_lt: CUSTOM ARG=ab_ltu,ab_cut FUNC=x*y PERIODIC=NO
     108             : ab: SUM ARG=ab_lt PERIODIC=NO
     109             : PRINT ARG=ab FILE=colvar
     110             : ```
     111             : 
     112             : The input above illustrates the input that is used by the shortcut that computes the [ANTIBETARMSD](ANTIBETARMSD.md). You can see that the distances between the atoms on the two strands of the
     113             : beta sheet are computed in a [DISTANCE](DISTANCE.md) action before we computed the SECONDARY_STRUCTURE_RMSD values.  These distances are then transformed by a Heavyside function that is 1 if
     114             : the distance is less than 1 nm and zero otherwise.  This vector of ones and zeros is then fed into the SECONDARY_STRUCTURE_RMSD action as a mask.  By doing this we ensure that SECONDARY_STRUCTURE_RMSD
     115             : values are only computed for parts of the strand that are close together. This avoids performing unnecessarily expensive calculations and is also a reasonable thing to do as if the two strands are more than
     116             : 1 nm apart the residues in question are not at all similar to a beta sheet structure.
     117             : 
     118             : */
     119             : //+ENDPLUMEDOC
     120             : 
     121             : namespace PLMD {
     122             : namespace secondarystructure {
     123             : 
     124          40 : class SecondaryStructureRMSDInput {
     125             : /// The list of reference configurations
     126             :   std::vector<RMSD> myrmsd;
     127             : public:
     128          73 :   static void registerKeywords( Keywords& keys ) {
     129          73 :     keys.setDisplayName("SECONDARY_STRUCTURE_RMSD");
     130          73 :   }
     131             :   static constexpr bool needsType=true;
     132             : /// The number of atoms
     133             :   std::size_t natoms{0};
     134             : /// The number of structures
     135             :   std::size_t nstructures{0};
     136             : /// The number of indices per task
     137             :   std::size_t nindices_per_task{0};
     138             : /// Are we operating without periodic boundary conditions
     139             :   bool nopbc{false};
     140             : /// Variables for strands cutoff
     141             :   bool align_strands{false};
     142             : /// The atoms involved in each of the secondary structure segments
     143             :   Matrix<unsigned> colvar_atoms;
     144             : //   void toACCDevice()const {
     145             : // #pragma acc enter data copyin(this[0:1], myrmsd[0:nstructures],natoms,nstructures,nopbc,align_strands)
     146             : //     colvar_atoms.toACCDevice();
     147             : //   }
     148             : //   void removeFromACCDevice() const {
     149             : //     colvar_atoms.removeFromACCDevice();
     150             : // #pragma acc exit data delete(align_strands,nopbc,nstructures,natoms,myrmsd[0:nstructures],this[0:1])
     151             : 
     152             :   static void calculateDistance( unsigned n, bool noderiv, const SecondaryStructureRMSDInput& actiondata, View<Vector> pos, ColvarOutput<double>& output );
     153             :   void setReferenceStructure( const std::string& type, double bondlength, std::vector<Vector>& structure );
     154          80 :   SecondaryStructureRMSDInput() = default;
     155             :   SecondaryStructureRMSDInput( const SecondaryStructureRMSDInput& m ) {
     156             :     *this = m;
     157             :   }
     158          32 :   SecondaryStructureRMSDInput& operator=( const SecondaryStructureRMSDInput& m ) {
     159          32 :     if( this==&m ) {
     160             :       return *this;
     161             :     }
     162          32 :     natoms = m.natoms;
     163          32 :     nstructures = m.nstructures;
     164          32 :     nindices_per_task = m.nindices_per_task;
     165          32 :     nopbc = m.nopbc;
     166          32 :     align_strands = m.align_strands;
     167          32 :     colvar_atoms=m.colvar_atoms;
     168             :     // setReferenceStructure appends to myrmsd, so the structures that are already here have to go
     169          32 :     myrmsd.clear();
     170          79 :     for(unsigned i=0; i<m.myrmsd.size(); ++i) {
     171          47 :       std::vector<Vector> mystruct( m.myrmsd[i].getReference() );
     172          47 :       setReferenceStructure( m.myrmsd[i].getMethod(), 0.0, mystruct );
     173          47 :     }
     174             :     return *this;
     175             :   }
     176             : };
     177             : 
     178             : typedef SecondaryStructureBase<SecondaryStructureRMSDInput> colv;
     179             : PLUMED_REGISTER_ACTION(colv,"SECONDARY_STRUCTURE_RMSD")
     180             : 
     181          96 : void SecondaryStructureRMSDInput::setReferenceStructure( const std::string& type, double bondlength, std::vector<Vector>& structure ) {
     182          96 :   if( !myrmsd.empty() && structure.size()!=natoms ) {
     183           0 :     plumed_merror("input structures have a different number of atoms");
     184             :   }
     185             :   // RMSD::set puts the center of the reference in the origin
     186          96 :   std::vector<double> align( structure.size(), 1.0 ), displace( structure.size(), 1.0 );
     187          96 :   RMSD newrmsd;
     188          96 :   newrmsd.clear();
     189          96 :   newrmsd.set(align,displace,structure,type,true,true);
     190          96 :   myrmsd.push_back( newrmsd );
     191          96 :   nstructures=myrmsd.size();
     192          96 :   natoms=structure.size();
     193         192 : }
     194             : 
     195      191632 : void SecondaryStructureRMSDInput::calculateDistance( unsigned n,
     196             :     bool noderiv,
     197             :     const SecondaryStructureRMSDInput& actiondata,
     198             :     const View<Vector> pos,
     199             :     ColvarOutput<double>& output ) {
     200      191632 :   std::vector<Vector> myderivs( actiondata.natoms );
     201      191632 :   output.values[n] = actiondata.myrmsd[n].calculate( pos, myderivs, false );
     202             : 
     203      191632 :   if( noderiv ) {
     204             :     return;
     205             :   }
     206       92786 :   Tensor v;
     207             :   v.zero();
     208     2873522 :   for(unsigned j=0; j<pos.size(); ++j) {
     209             :     output.derivs[n][j] = myderivs[j];
     210     5561472 :     v +=  (-1.0*Tensor( pos[j], myderivs[j] ));
     211             :   }
     212       92786 :   output.virial.set( n, v );
     213      191632 : }
     214             : 
     215             : }
     216             : }

Generated by: LCOV version 1.16