Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2012-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 "core/ActionShortcut.h"
23 : #include "core/ActionRegister.h"
24 : #include "MultiColvarShortcuts.h"
25 : #include <string>
26 : #include <cmath>
27 :
28 : //+PLUMEDOC MCOLVAR DISTANCES
29 : /*
30 : Calculate the distances between multiple piars of atoms
31 :
32 : __This shortcut action allows you to calculate function of the distribution of distatnces and reproduces the syntax in older PLUMED versions.
33 : If you look at the example inputs below you can
34 : see how the new syntax operates. We would strongly encourage you to use the newer syntax as it offers greater flexibility.__
35 :
36 : The following input tells plumed to calculate the distances between atoms 3 and 5 and
37 : between atoms 1 and 2 and to print the minimum for these two distances.
38 :
39 : ```plumed
40 : d1: DISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1}
41 : PRINT ARG=d1.min
42 : ```
43 :
44 : The following input tells plumed to calculate the distances between atoms 3 and 5 and between atoms 1 and 2
45 : and then to calculate the number of these distances that are less than 0.1 nm. The number of distances
46 : less than 0.1nm is then printed to a file.
47 :
48 : ```plumed
49 : d1: DISTANCES ATOMS1=3,5 ATOMS2=1,2 LESS_THAN={RATIONAL R_0=0.1}
50 : PRINT ARG=d1.lessthan
51 : ```
52 :
53 : The following input tells plumed to calculate all the distances between atoms 1, 2 and 3 (i.e. the distances between atoms
54 : 1 and 2, atoms 1 and 3 and atoms 2 and 3). The average of these distances is then calculated.
55 :
56 : ```plumed
57 : d1: DISTANCES GROUP=1-3 MEAN
58 : PRINT ARG=d1.mean
59 : ```
60 :
61 : The following input tells plumed to calculate all the distances between the atoms in GROUPA and the atoms in GROUPB.
62 : In other words the distances between atoms 1 and 2 and the distance between atoms 1 and 3. The number of distances
63 : more than 0.1 is then printed to a file.
64 :
65 : ```plumed
66 : d1: DISTANCES GROUPA=1 GROUPB=2,3 MORE_THAN={RATIONAL R_0=0.1}
67 : PRINT ARG=d1.morethan
68 : ```
69 :
70 : ## Calculating minimum distances
71 :
72 : To calculate and print the minimum distance between two groups of atoms you use the following commands
73 :
74 : ```plumed
75 : d1: DISTANCES GROUPA=1-10 GROUPB=11-20 MIN={BETA=500.}
76 : PRINT ARG=d1.min FILE=colvar STRIDE=10
77 : ```
78 :
79 : In order to ensure that the minimum value has continuous derivatives we use the following function:
80 :
81 : $$
82 : s = \frac{\beta}{ \log \sum_i \exp\left( \frac{\beta}{s_i} \right) }
83 : $$
84 :
85 : where $\beta$ is a user specified parameter.
86 :
87 : This input is used rather than a separate MINDIST colvar so that the same routine and the same input style can be
88 : used to calculate minimum coordination numbers (see [COORDINATIONNUMBER](COORDINATIONNUMBER.md)), minimum
89 : angles (see [ANGLES](ANGLES.md)) and many other variables.
90 :
91 : This new way of calculating mindist is part of plumed 2's multicolvar functionality. These special actions
92 : allow you to calculate multiple functions of a distribution of simple collective variables. As an example you
93 : can calculate the number of distances less than 1.0, the minimum distance, the number of distances more than
94 : 2.0 and the number of distances between 1.0 and 2.0 by using the following command:
95 :
96 : ```plumed
97 : d1: DISTANCES ...
98 : GROUPA=1-10 GROUPB=11-20
99 : LESS_THAN={RATIONAL R_0=1.0}
100 : MORE_THAN={RATIONAL R_0=2.0}
101 : BETWEEN={GAUSSIAN LOWER=1.0 UPPER=2.0}
102 : MIN={BETA=500.}
103 : ...
104 : PRINT ARG=d1.lessthan,d1.morethan,d1.between,d1.min FILE=colvar STRIDE=10
105 : ```
106 :
107 : A calculation performed this way is fast because the expensive part of the calculation - the calculation of all the distances - is only done once per step.
108 :
109 : */
110 : //+ENDPLUMEDOC
111 :
112 : //+PLUMEDOC MCOLVAR XDISTANCES
113 : /*
114 : Calculate the x components of the vectors connecting one or many pairs of atoms.
115 :
116 : __This shortcut action allows you to calculate functions of the distribution of the x components of the vectors connecting pairs of atoms and
117 : reproduces the syntax in older PLUMED versions.
118 : If you look at the example inputs below you can
119 : see how the new syntax operates. We would strongly encourage you to use the newer syntax as it offers greater flexibility.__
120 :
121 : The following input tells plumed to calculate the x-component of the vector connecting atom 3 to atom 5 and
122 : the x-component of the vector connecting atom 1 to atom 2. The minimum of these two quantities is then
123 : printed
124 :
125 : ```plumed
126 : d1: XDISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1}
127 : PRINT ARG=d1.min
128 : ```
129 :
130 : The following input tells plumed to calculate the x-component of the vector connecting atom 3 to atom 5 and
131 : the x-component of the vector connecting atom 1 to atom 2. The number of values that are
132 : less than 0.1nm is then printed to a file.
133 :
134 : ```plumed
135 : d1: XDISTANCES ATOMS1=3,5 ATOMS2=1,2 LESS_THAN={RATIONAL R_0=0.1}
136 : PRINT ARG=d1.lessthan
137 : ```
138 :
139 : The following input tells plumed to calculate the x-components of all the distinct vectors that can be created
140 : between atoms 1, 2 and 3 (i.e. the vectors between atoms 1 and 2, atoms 1 and 3 and atoms 2 and 3).
141 : The average of these quantities is then calculated.
142 :
143 : ```plumed
144 : d1: XDISTANCES GROUP=1-3 MEAN
145 : PRINT ARG=d1.mean
146 : ```
147 :
148 : The following input tells plumed to calculate all the vectors connecting the the atoms in GROUPA to the atoms in GROUPB.
149 : In other words the vector between atoms 1 and 2 and the vector between atoms 1 and 3. The number of values
150 : more than 0.1 is then printed to a file.
151 :
152 : ```plumed
153 : d1: XDISTANCES GROUPA=1 GROUPB=2,3 MORE_THAN={RATIONAL R_0=0.1}
154 : PRINT ARG=d1.morethan
155 : ```
156 :
157 : */
158 : //+ENDPLUMEDOC
159 :
160 :
161 : //+PLUMEDOC MCOLVAR YDISTANCES
162 : /*
163 : Calculate the y components of the vectors connecting one or many pairs of atoms.
164 :
165 : __This shortcut action allows you to calculate functions of the distribution of the y components of the vectors connecting pairs of atoms and
166 : reproduces the syntax in older PLUMED versions.
167 : If you look at the example inputs below you can
168 : see how the new syntax operates. We would strongly encourage you to use the newer syntax as it offers greater flexibility.__
169 :
170 : The following input tells plumed to calculate the y-component of the vector connecting atom 3 to atom 5 and
171 : the y-component of the vector connecting atom 1 to atom 2. The minimum of these two quantities is then
172 : printed
173 :
174 : ```plumed
175 : d1: YDISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1}
176 : PRINT ARG=d1.min
177 : ```
178 :
179 : The following input tells plumed to calculate the y-component of the vector connecting atom 3 to atom 5 and
180 : the y-component of the vector connecting atom 1 to atom 2. The number of values that are
181 : less than 0.1nm is then printed to a file.
182 :
183 : ```plumed
184 : d1: YDISTANCES ATOMS1=3,5 ATOMS2=1,2 LESS_THAN={RATIONAL R_0=0.1}
185 : PRINT ARG=d1.lessthan
186 : ```
187 :
188 : The following input tells plumed to calculate the y-components of all the distinct vectors that can be created
189 : between atoms 1, 2 and 3 (i.e. the vectors between atoms 1 and 2, atoms 1 and 3 and atoms 2 and 3).
190 : The average of these quantities is then calculated.
191 :
192 : ```plumed
193 : d1: YDISTANCES GROUP=1-3 MEAN
194 : PRINT ARG=d1.mean
195 : ```
196 :
197 : The following input tells plumed to calculate all the vectors connecting the the atoms in GROUPA to the atoms in GROUPB.
198 : In other words the vector between atoms 1 and 2 and the vector between atoms 1 and 3. The number of values
199 : more than 0.1 is then printed to a file.
200 :
201 : ```plumed
202 : d1: YDISTANCES GROUPA=1 GROUPB=2,3 MORE_THAN={RATIONAL R_0=0.1}
203 : PRINT ARG=d1.morethan
204 : ```
205 :
206 : */
207 : //+ENDPLUMEDOC
208 :
209 : //+PLUMEDOC MCOLVAR ZDISTANCES
210 : /*
211 : Calculate the z components of the vectors connecting one or many pairs of atoms.
212 :
213 : __This shortcut action allows you to calculate functions of the distribution of the z components of the vectors connecting pairs of atoms and
214 : reproduces the syntax in older PLUMED versions.
215 : If you look at the example inputs below you can
216 : see how the new syntax operates. We would strongly encourage you to use the newer syntax as it offers greater flexibility.__
217 :
218 : The following input tells plumed to calculate the z-component of the vector connecting atom 3 to atom 5 and
219 : the z-component of the vector connecting atom 1 to atom 2. The minimum of these two quantities is then
220 : printed
221 :
222 : ```plumed
223 : d1: ZDISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1}
224 : PRINT ARG=d1.min
225 : ```
226 :
227 : The following input tells plumed to calculate the z-component of the vector connecting atom 3 to atom 5 and
228 : the z-component of the vector connecting atom 1 to atom 2. The number of values that are
229 : less than 0.1nm is then printed to a file.
230 :
231 : ```plumed
232 : d1: ZDISTANCES ATOMS1=3,5 ATOMS2=1,2 LESS_THAN={RATIONAL R_0=0.1}
233 : PRINT ARG=d1.lessthan
234 : ```
235 :
236 : The following input tells plumed to calculate the z-components of all the distinct vectors that can be created
237 : between atoms 1, 2 and 3 (i.e. the vectors between atoms 1 and 2, atoms 1 and 3 and atoms 2 and 3).
238 : The average of these quantities is then calculated.
239 :
240 : ```plumed
241 : d1: ZDISTANCES GROUP=1-3 MEAN
242 : PRINT ARG=d1.mean
243 : ```
244 :
245 : The following input tells plumed to calculate all the vectors connecting the the atoms in GROUPA to the atoms in GROUPB.
246 : In other words the vector between atoms 1 and 2 and the vector between atoms 1 and 3. The number of values
247 : more than 0.1 is then printed to a file.
248 :
249 : ```plumed
250 : d1: ZDISTANCES GROUPA=1 GROUPB=2,3 MORE_THAN={RATIONAL R_0=0.1}
251 : PRINT ARG=d1.morethan
252 : ```
253 :
254 : */
255 : //+ENDPLUMEDOC
256 :
257 :
258 : namespace PLMD {
259 : namespace multicolvar {
260 :
261 : class Distances : public ActionShortcut {
262 : public:
263 : static void registerKeywords(Keywords& keys);
264 : explicit Distances(const ActionOptions&);
265 : };
266 :
267 : PLUMED_REGISTER_ACTION(Distances,"DISTANCES")
268 : PLUMED_REGISTER_ACTION(Distances,"XDISTANCES")
269 : PLUMED_REGISTER_ACTION(Distances,"YDISTANCES")
270 : PLUMED_REGISTER_ACTION(Distances,"ZDISTANCES")
271 :
272 131 : void Distances::registerKeywords(Keywords& keys) {
273 131 : ActionShortcut::registerKeywords( keys );
274 131 : keys.add("atoms-1","GROUP","Calculate the distance between each distinct pair of atoms in the group");
275 131 : keys.add("atoms-2","GROUPA","Calculate the distances between all the atoms in GROUPA and all "
276 : "the atoms in GROUPB. This must be used in conjunction with GROUPB.");
277 131 : keys.add("atoms-2","GROUPB","Calculate the distances between all the atoms in GROUPA and all the atoms "
278 : "in GROUPB. This must be used in conjunction with GROUPA.");
279 131 : keys.add("numbered","ATOMS","the pairs of atoms that you would like to calculate the angles for");
280 131 : keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
281 131 : keys.addFlag("COMPONENTS",false,"calculate the x, y and z components of the distance separately and store them as label.x, label.y and label.z");
282 131 : keys.addFlag("SCALED_COMPONENTS",false,"calculate the a, b and c scaled components of the distance separately and store them as label.a, label.b and label.c");
283 131 : keys.addFlag("LOWMEM",false,"this flag does nothing and is present only to ensure back-compatibility");
284 262 : keys.reset_style("ATOMS","atoms");
285 131 : MultiColvarShortcuts::shortcutKeywords( keys );
286 131 : keys.add("atoms","ORIGIN","calculate the distance of all the atoms specified using the ATOMS keyword from this point");
287 131 : keys.add("numbered","LOCATION","the location at which the CV is assumed to be in space");
288 262 : keys.reset_style("LOCATION","atoms");
289 262 : keys.setValueDescription("vector","the DISTANCES between the each pair of atoms that were specified");
290 262 : keys.addOutputComponent("x","COMPONENTS","vector","the x-components of the distance vectors");
291 262 : keys.addOutputComponent("y","COMPONENTS","vector","the y-components of the distance vectors");
292 262 : keys.addOutputComponent("z","COMPONENTS","vector","the z-components of the distance vectors");
293 131 : keys.needsAction("GROUP");
294 131 : keys.needsAction("DISTANCE");
295 131 : keys.needsAction("CENTER");
296 131 : }
297 :
298 58 : Distances::Distances(const ActionOptions& ao):
299 : Action(ao),
300 58 : ActionShortcut(ao) {
301 : // Create distances
302 : bool lowmem;
303 58 : parseFlag("LOWMEM",lowmem);
304 58 : if( lowmem ) {
305 0 : warning("LOWMEM flag is deprecated and is no longer required for this action");
306 : }
307 58 : std::string dline = getShortcutLabel() + ": DISTANCE";
308 : bool nopbc;
309 58 : parseFlag("NOPBC",nopbc);
310 58 : if( nopbc ) {
311 : dline += " NOPBC";
312 : }
313 58 : if( getName()=="DISTANCES" ) {
314 : bool comp;
315 55 : parseFlag("COMPONENTS",comp);
316 55 : if( comp ) {
317 : dline += " COMPONENTS";
318 : }
319 : bool scomp;
320 55 : parseFlag("SCALED_COMPONENTS",scomp);
321 55 : if( scomp ) {
322 : dline += " SCALED_COMPONENTS";
323 : }
324 : } else {
325 : dline += " COMPONENTS";
326 : }
327 : // Parse origin
328 : std::string num, ostr;
329 116 : parse("ORIGIN",ostr);
330 58 : if( ostr.length()>0 ) {
331 : // Parse atoms
332 : std::vector<std::string> afstr;
333 23 : MultiColvarShortcuts::parseAtomList("ATOMS",afstr,this);
334 17118 : for(unsigned i=0; i<afstr.size(); ++i) {
335 17095 : Tools::convert( i+1, num );
336 34190 : dline += " ATOMS" + num + "=" + ostr + "," + afstr[i];
337 : }
338 23 : } else {
339 : std::vector<std::string> grp;
340 70 : MultiColvarShortcuts::parseAtomList("GROUP",grp,this);
341 : std::vector<std::string> grpa;
342 70 : MultiColvarShortcuts::parseAtomList("GROUPA",grpa,this);
343 35 : if( grp.size()>0 ) {
344 3 : if( grpa.size()>0 ) {
345 0 : error("should not be using GROUPA in tandem with GROUP");
346 : }
347 : unsigned n=0;
348 203 : for(unsigned i=1; i<grp.size(); ++i) {
349 10103 : for(unsigned j=0; j<i; ++j) {
350 : std::string num;
351 9903 : Tools::convert( n+1, num );
352 : n++;
353 19806 : dline += " ATOMS" + num + "=" + grp[i] + "," + grp[j];
354 : }
355 : }
356 32 : } else if( grpa.size()>0 ) {
357 : std::vector<std::string> grpb;
358 2 : MultiColvarShortcuts::parseAtomList("GROUPB",grpb,this);
359 1 : if( grpb.size()==0 ) {
360 0 : error("found GROUPA but no corresponding GROUPB");
361 : }
362 : bool printcomment=false;
363 4 : for(unsigned i=0; i<grpa.size(); ++i) {
364 294 : for(unsigned j=0; j<grpb.size(); ++j) {
365 291 : Tools::convert( i*grpb.size() + j + 1, num );
366 582 : dline += " ATOMS" + num + "=" + grpa[i] + "," + grpb[j];
367 : }
368 : }
369 1 : } else {
370 31 : std::string grpstr = getShortcutLabel() + "_grp: GROUP ATOMS=";
371 31 : for(unsigned i=1;; ++i) {
372 : std::string atstring;
373 1844 : parseNumbered("ATOMS",i,atstring);
374 922 : if( atstring.length()==0 ) {
375 : break;
376 : }
377 : std::string locstr;
378 1782 : parseNumbered("LOCATION",i,locstr);
379 891 : if( locstr.length()==0 ) {
380 : std::string num;
381 281 : Tools::convert( i, num );
382 562 : readInputLine( getShortcutLabel() + "_vatom" + num + ": CENTER ATOMS=" + atstring );
383 281 : if( i==1 ) {
384 54 : grpstr += getShortcutLabel() + "_vatom" + num;
385 : } else {
386 508 : grpstr += "," + getShortcutLabel() + "_vatom" + num;
387 : }
388 : } else {
389 610 : if( i==1 ) {
390 : grpstr += locstr;
391 : } else {
392 1212 : grpstr += "," + locstr;
393 : }
394 : }
395 : std::string num;
396 891 : Tools::convert( i, num );
397 1782 : dline += " ATOMS" + num + "=" + atstring;
398 891 : }
399 31 : readInputLine( grpstr );
400 : }
401 35 : }
402 58 : readInputLine( dline );
403 : // Add shortcuts to label
404 58 : if( getName()=="DISTANCES" ) {
405 110 : MultiColvarShortcuts::expandFunctions( getShortcutLabel(), getShortcutLabel(), "", this );
406 3 : } else if( getName()=="XDISTANCES" ) {
407 2 : MultiColvarShortcuts::expandFunctions( getShortcutLabel(), getShortcutLabel() + ".x", "", this );
408 2 : } else if( getName()=="YDISTANCES" ) {
409 2 : MultiColvarShortcuts::expandFunctions( getShortcutLabel(), getShortcutLabel() + ".y", "", this );
410 1 : } else if( getName()=="ZDISTANCES" ) {
411 2 : MultiColvarShortcuts::expandFunctions( getShortcutLabel(), getShortcutLabel() + ".z", "", this );
412 : }
413 58 : }
414 :
415 : }
416 : }
|