Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-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 "Colvar.h"
23 : #include "ColvarShortcut.h"
24 : #include "MultiColvarTemplate.h"
25 : #include "core/ActionRegister.h"
26 : #include "tools/Torsion.h"
27 :
28 : namespace PLMD {
29 : namespace colvar {
30 :
31 : //+PLUMEDOC COLVAR TORSION
32 : /*
33 : Calculate a torsional angle.
34 :
35 : This command can be used to compute the torsion between four atoms or alternatively
36 : to calculate the angle between two vectors projected on the plane
37 : orthogonal to an axis.
38 :
39 : \par Examples
40 :
41 : This input tells plumed to print the torsional angle between atoms 1, 2, 3 and 4
42 : on file COLVAR.
43 : \plumedfile
44 : t: TORSION ATOMS=1,2,3,4
45 : # this is an alternative, equivalent, definition:
46 : # t: TORSION VECTOR1=2,1 AXIS=2,3 VECTOR2=3,4
47 : PRINT ARG=t FILE=COLVAR
48 : \endplumedfile
49 :
50 : If you are working with a protein you can specify the special named torsion angles \f$\phi\f$, \f$\psi\f$, \f$\omega\f$ and \f$\chi_1\f$
51 : by using TORSION in combination with the \ref MOLINFO command. This can be done by using the following
52 : syntax.
53 :
54 : \plumedfile
55 : #SETTINGS MOLFILE=regtest/basic/rt32/helix.pdb
56 : MOLINFO MOLTYPE=protein STRUCTURE=myprotein.pdb
57 : t1: TORSION ATOMS=@phi-3
58 : t2: TORSION ATOMS=@psi-4
59 : PRINT ARG=t1,t2 FILE=colvar STRIDE=10
60 : \endplumedfile
61 :
62 : Here, \@phi-3 tells plumed that you would like to calculate the \f$\phi\f$ angle in the third residue of the protein.
63 : Similarly \@psi-4 tells plumed that you want to calculate the \f$\psi\f$ angle of the fourth residue of the protein.
64 :
65 : Both of the previous examples specify that the torsion angle should be calculated based on the position of four atoms.
66 : For the first example in particular the assumption when the torsion is specified in this way is that there are chemical
67 : bonds between atoms 1 and 2, atoms 2 and 3 and atoms 3 and 4. In general, however, a torsional angle measures the angle
68 : between two planes, which have at least one vector in common. As shown below, there is thus an alternate, more general, way
69 : through which we can define a torsional angle:
70 :
71 : \plumedfile
72 : t1: TORSION VECTOR1=1,2 AXIS=3,4 VECTOR2=5,6
73 : PRINT ARG=t1 FILE=colvar STRIDE=20
74 : \endplumedfile
75 :
76 : This input instructs PLUMED to calculate the angle between the plane containing the vector connecting atoms 1 and 2 and the vector
77 : connecting atoms 3 and 4 and the plane containing this second vector and the vector connecting atoms 5 and 6. We can even use
78 : PLUMED to calculate the torsional angle between two bond vectors around the z-axis as shown below:
79 :
80 : \plumedfile
81 : a0: FIXEDATOM AT=0,0,0
82 : az: FIXEDATOM AT=0,0,1
83 : t1: TORSION VECTOR1=1,2 AXIS=a0,az VECTOR2=5,6
84 : PRINT ARG=t1 FILE=colvar STRIDE=20
85 : \endplumedfile
86 :
87 :
88 : */
89 : //+ENDPLUMEDOC
90 :
91 : //+PLUMEDOC COLVAR TORSION_SCALAR
92 : /*
93 : Calculate a torsional angle.
94 :
95 : \par Examples
96 :
97 : */
98 : //+ENDPLUMEDOC
99 :
100 : //+PLUMEDOC MCOLVAR TORSION_VECTOR
101 : /*
102 : Calculate multiple torsional angles.
103 :
104 : \par Examples
105 :
106 : */
107 : //+ENDPLUMEDOC
108 :
109 : class Torsion : public Colvar {
110 : bool pbc;
111 : bool do_cosine;
112 :
113 : std::vector<double> value, masses, charges;
114 : std::vector<std::vector<Vector> > derivs;
115 : std::vector<Tensor> virial;
116 : public:
117 : explicit Torsion(const ActionOptions&);
118 : static void parseAtomList( const int& num, std::vector<AtomNumber>& t, ActionAtomistic* aa );
119 : static unsigned getModeAndSetupValues( ActionWithValue* av );
120 : // active methods:
121 : void calculate() override;
122 : static void calculateCV( const unsigned& mode, const std::vector<double>& masses, const std::vector<double>& charges,
123 : const std::vector<Vector>& pos, std::vector<double>& vals, std::vector<std::vector<Vector> >& derivs,
124 : std::vector<Tensor>& virial, const ActionAtomistic* aa );
125 : static void registerKeywords(Keywords& keys);
126 : };
127 :
128 : typedef ColvarShortcut<Torsion> TorsionShortcut;
129 : PLUMED_REGISTER_ACTION(TorsionShortcut,"TORSION")
130 : PLUMED_REGISTER_ACTION(Torsion,"TORSION_SCALAR")
131 : typedef MultiColvarTemplate<Torsion> TorsionMulti;
132 : PLUMED_REGISTER_ACTION(TorsionMulti,"TORSION_VECTOR")
133 :
134 2130 : void Torsion::registerKeywords(Keywords& keys) {
135 2130 : Colvar::registerKeywords( keys ); keys.setDisplayName("TORSION");
136 4260 : keys.add("atoms-1","ATOMS","the four atoms involved in the torsional angle");
137 4260 : keys.add("atoms-2","AXIS","two atoms that define an axis. You can use this to find the angle in the plane perpendicular to the axis between the vectors specified using the VECTORA and VECTORB keywords.");
138 4260 : keys.add("atoms-2","VECTORA","two atoms that define a vector. You can use this in combination with VECTOR2 and AXIS");
139 4260 : keys.add("atoms-2","VECTORB","two atoms that define a vector. You can use this in combination with VECTOR1 and AXIS");
140 4260 : keys.add("atoms-3","VECTOR1","two atoms that define a vector. You can use this in combination with VECTOR2 and AXIS");
141 4260 : keys.add("atoms-3","VECTOR2","two atoms that define a vector. You can use this in combination with VECTOR1 and AXIS");
142 4260 : keys.addFlag("COSINE",false,"calculate cosine instead of dihedral");
143 4260 : keys.add("hidden","NO_ACTION_LOG","suppresses printing from action on the log");
144 4260 : keys.setValueDescription("scalar/vector","the TORSION involving these atoms");
145 2130 : }
146 :
147 691 : Torsion::Torsion(const ActionOptions&ao):
148 : PLUMED_COLVAR_INIT(ao),
149 691 : pbc(true),
150 691 : do_cosine(false),
151 691 : value(1),
152 693 : derivs(1),
153 1382 : virial(1)
154 : {
155 691 : derivs[0].resize(6); std::vector<AtomNumber> atoms;
156 1382 : std::vector<AtomNumber> v1; ActionAtomistic::parseAtomList("VECTOR1",v1);
157 691 : if( v1.size()>0 ) {
158 4 : std::vector<AtomNumber> v2; ActionAtomistic::parseAtomList("VECTOR2",v2);
159 4 : std::vector<AtomNumber> axis; ActionAtomistic::parseAtomList("AXIS",axis);
160 2 : if( !(v1.size()==2 && v2.size()==2 && axis.size()==2)) error("VECTOR1, VECTOR2 and AXIS should specify 2 atoms each");
161 2 : atoms.resize(6);
162 2 : atoms[0]=v1[1];
163 2 : atoms[1]=v1[0];
164 2 : atoms[2]=axis[0];
165 2 : atoms[3]=axis[1];
166 2 : atoms[4]=v2[0];
167 2 : atoms[5]=v2[1];
168 2 : log.printf(" between lines %d-%d and %d-%d, projected on the plane orthogonal to line %d-%d\n",
169 : v1[0].serial(),v1[1].serial(),v2[0].serial(),v2[1].serial(),axis[0].serial(),axis[1].serial());
170 689 : } else parseAtomList(-1,atoms,this);
171 690 : unsigned mode=getModeAndSetupValues(this);
172 690 : if( mode==1 ) do_cosine=true;
173 :
174 690 : bool nopbc=!pbc;
175 692 : parseFlag("NOPBC",nopbc);
176 690 : pbc=!nopbc;
177 690 : checkRead();
178 :
179 689 : if(pbc) log.printf(" using periodic boundary conditions\n");
180 112 : else log.printf(" without periodic boundary conditions\n");
181 689 : requestAtoms(atoms);
182 695 : }
183 :
184 794 : void Torsion::parseAtomList( const int& num, std::vector<AtomNumber>& t, ActionAtomistic* aa ) {
185 : std::vector<AtomNumber> v1,v2,axis;
186 794 : aa->parseAtomList("ATOMS",num,t);
187 794 : aa->parseAtomList("VECTORA",num,v1);
188 794 : aa->parseAtomList("VECTORB",num,v2);
189 1588 : aa->parseAtomList("AXIS",num,axis);
190 :
191 794 : if(t.size()==4) {
192 747 : if(!(v1.empty() && v2.empty() && axis.empty()))
193 0 : aa->error("ATOMS keyword is not compatible with VECTORA, VECTORB and AXIS keywords");
194 747 : aa->log.printf(" between atoms %d %d %d %d\n",t[0].serial(),t[1].serial(),t[2].serial(),t[3].serial());
195 747 : t.resize(6);
196 747 : t[5]=t[3];
197 747 : t[4]=t[2];
198 747 : t[3]=t[2];
199 747 : t[2]=t[1];
200 47 : } else if(t.empty()) {
201 46 : if( num>0 && v1.empty() && v2.empty() && axis.empty() ) return;
202 32 : if(!(v1.size()==2 && v2.size()==2 && axis.size()==2))
203 0 : aa->error("VECTORA, VECTORB and AXIS should specify 2 atoms each");
204 32 : aa->log.printf(" between lines %d-%d and %d-%d, projected on the plane orthogonal to line %d-%d\n",
205 : v1[0].serial(),v1[1].serial(),v2[0].serial(),v2[1].serial(),axis[0].serial(),axis[1].serial());
206 32 : t.resize(6);
207 32 : t[0]=v1[1];
208 32 : t[1]=v1[0];
209 32 : t[2]=axis[0];
210 32 : t[3]=axis[1];
211 32 : t[4]=v2[0];
212 32 : t[5]=v2[1];
213 2 : } else if( t.size()!=4 ) aa->error("ATOMS should specify 4 atoms");
214 : }
215 :
216 704 : unsigned Torsion::getModeAndSetupValues( ActionWithValue* av ) {
217 704 : bool do_cos; av->parseFlag("COSINE",do_cos);
218 704 : if(do_cos) av->log.printf(" calculating cosine instead of torsion\n");
219 :
220 704 : av->addValueWithDerivatives();
221 1404 : if(!do_cos) { av->setPeriodic("-pi","pi"); return 0; }
222 4 : av->setNotPeriodic(); return 1;
223 : }
224 :
225 : // calculator
226 37137 : void Torsion::calculate() {
227 37137 : if(pbc) makeWhole();
228 37137 : if(do_cosine) calculateCV( 1, masses, charges, getPositions(), value, derivs, virial, this );
229 37122 : else calculateCV( 0, masses, charges, getPositions(), value, derivs, virial, this );
230 259959 : for(unsigned i=0; i<6; ++i) setAtomsDerivatives(i,derivs[0][i] );
231 37137 : setValue(value[0]); setBoxDerivatives( virial[0] );
232 37137 : }
233 :
234 37916 : void Torsion::calculateCV( const unsigned& mode, const std::vector<double>& masses, const std::vector<double>& charges,
235 : const std::vector<Vector>& pos, std::vector<double>& vals, std::vector<std::vector<Vector> >& derivs,
236 : std::vector<Tensor>& virial, const ActionAtomistic* aa ) {
237 37916 : Vector d0=delta(pos[1],pos[0]);
238 37916 : Vector d1=delta(pos[3],pos[2]);
239 37916 : Vector d2=delta(pos[5],pos[4]);
240 37916 : Vector dd0,dd1,dd2;
241 : PLMD::Torsion t;
242 37916 : vals[0] = t.compute(d0,d1,d2,dd0,dd1,dd2);
243 37916 : if(mode==1) {
244 30 : dd0 *= -std::sin(vals[0]);
245 30 : dd1 *= -std::sin(vals[0]);
246 30 : dd2 *= -std::sin(vals[0]);
247 30 : vals[0] = std::cos(vals[0]);
248 : }
249 37916 : derivs[0][0] = dd0;
250 37916 : derivs[0][1] = -dd0;
251 37916 : derivs[0][2] = dd1;
252 37916 : derivs[0][3] = -dd1;
253 37916 : derivs[0][4] = dd2;
254 37916 : derivs[0][5] = -dd2;
255 37916 : setBoxDerivativesNoPbc( pos, derivs, virial );
256 37916 : }
257 :
258 : }
259 : }
260 :
261 :
262 :
|