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