1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2013-2021 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 "MultiColvarBase.h"
23 #include "AtomValuePack.h"
24 #include "tools/Torsion.h"
25 #include "core/ActionRegister.h"
26 
27 #include <string>
28 #include <cmath>
29 
30 using namespace std;
31 
32 namespace PLMD {
33 namespace multicolvar {
34 
35 //+PLUMEDOC COLVAR DIHCOR
36 /*
37 Measures the degree of similarity between dihedral angles.
38 
39 This colvar calculates the following quantity.
40 
41 \f[
42 s = \frac{1}{2} \sum_i \left[ 1 + \cos( \phi_i - \psi_i ) \right]
43 \f]
44 
45 where the \f$\phi_i\f$ and \f$\psi\f$ values and the instantaneous values for the \ref TORSION angles of interest.
46 
47 \par Examples
48 
49 The following provides an example input for the DIHCOR action
50 
51 \plumedfile
52 DIHCOR ...
53   ATOMS1=1,2,3,4,5,6,7,8
54   ATOMS2=5,6,7,8,9,10,11,12
55   LABEL=dih
56 ... DIHCOR
57 PRINT ARG=dih FILE=colvar STRIDE=10
58 \endplumedfile
59 
60 In the above input we are calculating the correlation between the torsion angle involving atoms 1, 2, 3 and 4 and the torsion angle
61 involving atoms 5, 6, 7 and 8.	This is then added to the correlation between the torsion angle involving atoms 5, 6, 7 and 8 and the
62 correlation angle involving atoms 9, 10, 11 and 12.
63 
64 Writing out the atoms involved in all the torsion angles in this way can be rather tedious. Thankfully if you are working with protein you
65 can avoid this by using the \ref MOLINFO command.  PLUMED uses the pdb file that you provide to this command to learn
66 about the topology of the protein molecule.  This means that you can specify torsion angles using the following syntax:
67 
68 \plumedfile
69 #SETTINGS MOLFILE=regtest/basic/rt32/helix.pdb
70 MOLINFO MOLTYPE=protein STRUCTURE=myprotein.pdb
71 dih: DIHCOR ...
72 ATOMS1=@phi-3,@psi-3
73 ATOMS2=@psi-3,@phi-4
74 ATOMS3=@phi-4,@psi-4
75 ...
76 PRINT ARG=dih FILE=colvar STRIDE=10
77 \endplumedfile
78 
79 Here, \@phi-3 tells plumed that you would like to calculate the \f$\phi\f$ angle in the third residue of the protein.
80 Similarly \@psi-4 tells plumed that you want to calculate the \f$\psi\f$ angle of the fourth residue of the protein.
81 
82 */
83 //+ENDPLUMEDOC
84 
85 class DihedralCorrelation : public MultiColvarBase {
86 private:
87 public:
88   static void registerKeywords( Keywords& keys );
89   explicit DihedralCorrelation(const ActionOptions&);
90   double compute( const unsigned& tindex, AtomValuePack& myatoms ) const override;
isPeriodic()91   bool isPeriodic() override { return false; }
92 };
93 
94 PLUMED_REGISTER_ACTION(DihedralCorrelation,"DIHCOR")
95 
registerKeywords(Keywords & keys)96 void DihedralCorrelation::registerKeywords( Keywords& keys ) {
97   MultiColvarBase::registerKeywords( keys );
98   keys.add("numbered","ATOMS","the atoms involved in each of the dihedral correlation values you wish to calculate. "
99            "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one dihedral correlation will be "
100            "calculated for each ATOM keyword you specify (all ATOM keywords should "
101            "specify the indices of 8 atoms).  The eventual number of quantities calculated by this "
102            "action will depend on what functions of the distribution you choose to calculate.");
103   keys.reset_style("ATOMS","atoms");
104 }
105 
DihedralCorrelation(const ActionOptions & ao)106 DihedralCorrelation::DihedralCorrelation(const ActionOptions&ao):
107   Action(ao),
108   MultiColvarBase(ao)
109 {
110   // Read in the atoms
111   std::vector<AtomNumber> all_atoms;
112   readAtomsLikeKeyword( "ATOMS", 8, all_atoms );
113   setupMultiColvarBase( all_atoms );
114   // Stuff for central atoms
115   std::vector<bool> catom_ind(8, false);
116   catom_ind[1]=catom_ind[2]=catom_ind[5]=catom_ind[6]=true;
117   setAtomsForCentralAtom( catom_ind );
118 
119   // And setup the ActionWithVessel
120   if( getNumberOfVessels()==0 ) {
121     std::string fake_input;
122     addVessel( "SUM", fake_input, -1 );  // -1 here means that this value will be named getLabel()
123     readVesselKeywords();  // This makes sure resizing is done
124   }
125 
126   // And check everything has been read in correctly
127   checkRead();
128 }
129 
compute(const unsigned & tindex,AtomValuePack & myatoms) const130 double DihedralCorrelation::compute( const unsigned& tindex, AtomValuePack& myatoms ) const {
131   const Vector d10=getSeparation(myatoms.getPosition(1),myatoms.getPosition(0));
132   const Vector d11=getSeparation(myatoms.getPosition(2),myatoms.getPosition(1));
133   const Vector d12=getSeparation(myatoms.getPosition(3),myatoms.getPosition(2));
134 
135   Vector dd10,dd11,dd12;
136   PLMD::Torsion t1;
137   const double phi1  = t1.compute(d10,d11,d12,dd10,dd11,dd12);
138 
139   const Vector d20=getSeparation(myatoms.getPosition(5),myatoms.getPosition(4));
140   const Vector d21=getSeparation(myatoms.getPosition(6),myatoms.getPosition(5));
141   const Vector d22=getSeparation(myatoms.getPosition(7),myatoms.getPosition(6));
142 
143   Vector dd20,dd21,dd22;
144   PLMD::Torsion t2;
145   const double phi2 = t2.compute( d20, d21, d22, dd20, dd21, dd22 );
146 
147   // Calculate value
148   const double diff = phi2 - phi1;
149   const double value = 0.5*(1.+cos(diff));
150   // Derivatives wrt phi1
151   const double dval = 0.5*sin(diff);
152   dd10 *= dval;
153   dd11 *= dval;
154   dd12 *= dval;
155   // And add
156   addAtomDerivatives(1, 0, dd10, myatoms );
157   addAtomDerivatives(1, 1, dd11-dd10, myatoms );
158   addAtomDerivatives(1, 2, dd12-dd11, myatoms );
159   addAtomDerivatives(1, 3, -dd12, myatoms );
160   myatoms.addBoxDerivatives  (1, -(extProduct(d10,dd10)+extProduct(d11,dd11)+extProduct(d12,dd12)));
161   // Derivative wrt phi2
162   dd20 *= -dval;
163   dd21 *= -dval;
164   dd22 *= -dval;
165   // And add
166   addAtomDerivatives(1, 4, dd20, myatoms );
167   addAtomDerivatives(1, 5, dd21-dd20, myatoms );
168   addAtomDerivatives(1, 6, dd22-dd21, myatoms );
169   addAtomDerivatives(1, 7, -dd22, myatoms );
170   myatoms.addBoxDerivatives(1, -(extProduct(d20,dd20)+extProduct(d21,dd21)+extProduct(d22,dd22)));
171 
172   return value;
173 }
174 
175 }
176 }
177