1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 Copyright (c) 2016-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 "core/ActionRegister.h"
25 #include "tools/Torsion.h"
26 #include "tools/SwitchingFunction.h"
27
28 #include <string>
29 #include <cmath>
30
31 using namespace std;
32
33 namespace PLMD {
34 namespace multicolvar {
35
36 //+PLUMEDOC MCOLVAR XYTORSIONS
37 /*
38 Calculate the torsional angle around the x axis from the positive y direction.
39
40 \par Examples
41
42 The following input tells plumed to calculate the angle around the x direction between the positive y-axis and the vector connecting atom 3 to atom 5 and
43 the angle around the x direction between the positive y axis and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output
44 \plumedfile
45 d1: XYTORSIONS ATOMS1=3,5 ATOMS2=1,2 BETWEEN={GAUSSIAN LOWER=0 UPPER=pi SMEAR=0.1}
46 PRINT ARG=d1.between
47 \endplumedfile
48 (See also \ref PRINT).
49 */
50 //+ENDPLUMEDOC
51
52 //+PLUMEDOC MCOLVAR XZTORSIONS
53 /*
54 Calculate the torsional angle around the x axis from the positive z direction.
55
56 \par Examples
57
58 The following input tells plumed to calculate the angle around the x direction between the positive z-axis and the vector connecting atom 3 to atom 5 and
59 the angle around the x direction between the positive z direction and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output
60 \plumedfile
61 d1: XZTORSIONS ATOMS1=3,5 ATOMS2=1,2 BETWEEN={GAUSSIAN LOWER=0 UPPER=pi SMEAR=0.1}
62 PRINT ARG=d1.*
63 \endplumedfile
64 (See also \ref PRINT).
65 */
66 //+ENDPLUMEDOC
67
68 //+PLUMEDOC MCOLVAR YXTORSIONS
69 /*
70 Calculate the torsional angle around the y axis from the positive x direction.
71
72 \par Examples
73
74 The following input tells plumed to calculate the angle around the y direction between the positive x-direction and the vector connecting atom 3 to atom 5 and
75 the angle around the y direction between the positive x axis and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output
76 \plumedfile
77 d1: YXTORSIONS ATOMS1=3,5 ATOMS2=1,2 BETWEEN={GAUSSIAN LOWER=0 UPPER=pi SMEAR=0.1}
78 PRINT ARG=d1.*
79 \endplumedfile
80 (See also \ref PRINT).
81 */
82 //+ENDPLUMEDOC
83
84 //+PLUMEDOC MCOLVAR YZTORSIONS
85 /*
86 Calculate the torsional angle around the y axis from the positive z direction.
87
88 \par Examples
89
90 The following input tells plumed to calculate the angle around the y direction between the positive z-direction and the vector connecting atom 3 to atom 5 and
91 the angle around the y direction between the positive z direction and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output
92 \plumedfile
93 d1: YZTORSIONS ATOMS1=3,5 ATOMS2=1,2 BETWEEN={GAUSSIAN LOWER=0 UPPER=pi SMEAR=0.1}
94 PRINT ARG=d1.*
95 \endplumedfile
96 (See also \ref PRINT).
97 */
98 //+ENDPLUMEDOC
99
100 //+PLUMEDOC MCOLVAR ZXTORSIONS
101 /*
102 Calculate the torsional angle around the z axis from the positive x direction.
103
104 \par Examples
105
106 The following input tells plumed to calculate the angle around the z direction between the positive x-direction and the vector connecting atom 3 to atom 5 and
107 the angle around the z direction between the positive x-direction and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output
108 \plumedfile
109 d1: ZXTORSIONS ATOMS1=3,5 ATOMS2=1,2 BETWEEN={GAUSSIAN LOWER=0 UPPER=pi SMEAR=0.1}
110 PRINT ARG=d1.*
111 \endplumedfile
112 (See also \ref PRINT).
113 */
114 //+ENDPLUMEDOC
115
116 //+PLUMEDOC MCOLVAR ZYTORSIONS
117 /*
118 Calculate the torsional angle around the z axis from the positive y direction.
119
120 \par Examples
121
122 The following input tells plumed to calculate the angle around the z direction between the positive y-axis and the vector connecting atom 3 to atom 5 and
123 the angle around the z direction between the positive y axis and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output
124 \plumedfile
125 d1: ZYTORSIONS ATOMS1=3,5 ATOMS2=1,2 BETWEEN={GAUSSIAN LOWER=0 UPPER=pi SMEAR=0.1}
126 PRINT ARG=d1.*
127 \endplumedfile
128 (See also \ref PRINT).
129 */
130 //+ENDPLUMEDOC
131
132
133
134
135 class XYTorsion : public MultiColvarBase {
136 private:
137 bool use_sf;
138 unsigned myc1, myc2;
139 SwitchingFunction sf1;
140 public:
141 static void registerKeywords( Keywords& keys );
142 explicit XYTorsion(const ActionOptions&);
143 // active methods:
144 double compute( const unsigned& tindex, AtomValuePack& myatoms ) const override;
145 double calculateWeight( const unsigned& taskCode, const double& weight, AtomValuePack& ) const override;
146 /// Returns the number of coordinates of the field
isPeriodic()147 bool isPeriodic() override { return true; }
retrieveDomain(std::string & min,std::string & max)148 void retrieveDomain( std::string& min, std::string& max) override { min="-pi"; max="pi"; }
149 };
150
151 PLUMED_REGISTER_ACTION(XYTorsion,"XYTORSIONS")
152 PLUMED_REGISTER_ACTION(XYTorsion,"XZTORSIONS")
153 PLUMED_REGISTER_ACTION(XYTorsion,"YXTORSIONS")
154 PLUMED_REGISTER_ACTION(XYTorsion,"YZTORSIONS")
155 PLUMED_REGISTER_ACTION(XYTorsion,"ZXTORSIONS")
156 PLUMED_REGISTER_ACTION(XYTorsion,"ZYTORSIONS")
157
registerKeywords(Keywords & keys)158 void XYTorsion::registerKeywords( Keywords& keys ) {
159 MultiColvarBase::registerKeywords( keys );
160 keys.use("MAX"); keys.use("ALT_MIN");
161 keys.use("MEAN"); keys.use("MIN");
162 keys.use("LOWEST"); keys.use("HIGHEST");
163 keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS");
164 keys.add("numbered","ATOMS","the atoms involved in each of the torsion angles you wish to calculate. "
165 "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one torsion will be "
166 "calculated for each ATOM keyword you specify (all ATOM keywords should "
167 "specify the indices of two atoms). The eventual number of quantities calculated by this "
168 "action will depend on what functions of the distribution you choose to calculate.");
169 keys.reset_style("ATOMS","atoms");
170 keys.add("atoms-1","GROUP","Calculate the distance between each distinct pair of atoms in the group");
171 keys.add("atoms-2","GROUPA","Calculate the distances between all the atoms in GROUPA and all "
172 "the atoms in GROUPB. This must be used in conjunction with GROUPB.");
173 keys.add("atoms-2","GROUPB","Calculate the distances between all the atoms in GROUPA and all the atoms "
174 "in GROUPB. This must be used in conjunction with GROUPA.");
175 keys.add("optional","SWITCH","A switching function that ensures that only angles are only computed when atoms are within "
176 "are within a certain fixed cutoff. The following provides information on the \\ref switchingfunction that are available.");
177 }
178
XYTorsion(const ActionOptions & ao)179 XYTorsion::XYTorsion(const ActionOptions&ao):
180 Action(ao),
181 MultiColvarBase(ao),
182 use_sf(false)
183 {
184 if( getName().find("XY")!=std::string::npos) { myc1=0; myc2=1; }
185 else if( getName().find("XZ")!=std::string::npos) { myc1=0; myc2=2; }
186 else if( getName().find("YX")!=std::string::npos) { myc1=1; myc2=0; }
187 else if( getName().find("YZ")!=std::string::npos) { myc1=1; myc2=2; }
188 else if( getName().find("ZX")!=std::string::npos) { myc1=2; myc2=0; }
189 else if( getName().find("ZY")!=std::string::npos) { myc1=2; myc2=1; }
190 else plumed_error();
191
192 // Read in switching function
193 std::string sfinput, errors; parse("SWITCH",sfinput);
194 if( sfinput.length()>0 ) {
195 use_sf=true; weightHasDerivatives=true;
196 sf1.set(sfinput,errors);
197 if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors );
198 log.printf(" only calculating angles for atoms separated by less than %s\n", sf1.description().c_str() );
199 setLinkCellCutoff( sf1.get_dmax() );
200 }
201
202 // Read in the atoms
203 std::vector<AtomNumber> all_atoms;
204 readTwoGroups( "GROUP", "GROUPA", "GROUPB", all_atoms );
205 if( atom_lab.size()==0 ) readAtomsLikeKeyword( "ATOMS", 2, all_atoms );
206 setupMultiColvarBase( all_atoms );
207 // And check everything has been read in correctly
208 checkRead();
209 }
210
calculateWeight(const unsigned & taskCode,const double & weight,AtomValuePack & myatoms) const211 double XYTorsion::calculateWeight( const unsigned& taskCode, const double& weight, AtomValuePack& myatoms ) const {
212 if(!use_sf) return 1.0;
213
214 Vector distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
215 double dw, w = sf1.calculateSqr( distance.modulo2(), dw );
216 addAtomDerivatives( 0, 0, (-dw)*distance, myatoms );
217 addAtomDerivatives( 0, 1, (+dw)*distance, myatoms );
218 myatoms.addBoxDerivatives( 0, (-dw)*Tensor(distance,distance) );
219 return w;
220 }
221
compute(const unsigned & tindex,AtomValuePack & myatoms) const222 double XYTorsion::compute( const unsigned& tindex, AtomValuePack& myatoms ) const {
223 Vector dd0, dd1, dd2, axis, rot, distance;
224 axis.zero(); rot.zero(); rot[myc1]=1; axis[myc2]=1;
225 distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
226 PLMD::Torsion t; double torsion=t.compute( distance, rot, axis, dd0, dd1, dd2 );
227
228 addAtomDerivatives( 1, 0, -dd0, myatoms );
229 addAtomDerivatives( 1, 1, dd0, myatoms );
230 myatoms.addBoxDerivatives( 1, -extProduct(distance,dd0) );
231 return torsion;
232 }
233
234 }
235 }
236
237