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 "ActionRegister.h"
24 : #include "tools/Angle.h"
25 :
26 : namespace PLMD {
27 : namespace colvar {
28 :
29 : //+PLUMEDOC COLVAR ANGLE
30 : /*
31 : Calculate an angle.
32 :
33 : This command can be used to compute the angle between three atoms. Alternatively
34 : if four atoms appear in the atom
35 : specification it calculates the angle between
36 : two vectors identified by two pairs of atoms.
37 :
38 : If _three_ atoms are given, the angle is defined as:
39 : \f[
40 : \theta=\arccos\left(\frac{ {\bf r}_{21}\cdot {\bf r}_{23}}{
41 : |{\bf r}_{21}| |{\bf r}_{23}|}\right)
42 : \f]
43 : Here \f$ {\bf r}_{ij}\f$ is the distance vector among the
44 : \f$i\f$th and the \f$j\f$th listed atom.
45 :
46 : If _four_ atoms are given, the angle is defined as:
47 : \f[
48 : \theta=\arccos\left(\frac{ {\bf r}_{21}\cdot {\bf r}_{34}}{
49 : |{\bf r}_{21}| |{\bf r}_{34}|}\right)
50 : \f]
51 :
52 : Notice that angles defined in this way are non-periodic variables and
53 : their value is limited by definition between 0 and \f$\pi\f$.
54 :
55 : The vectors \f$ {\bf r}_{ij}\f$ are by default evaluated taking
56 : periodic boundary conditions into account.
57 : This behavior can be changed with the NOPBC flag.
58 :
59 : \par Examples
60 :
61 : This command tells plumed to calculate the angle between the vector connecting atom 1 to atom 2 and
62 : the vector connecting atom 2 to atom 3 and to print it on file COLVAR1. At the same time,
63 : the angle between vector connecting atom 1 to atom 2 and the vector connecting atom 3 to atom 4 is printed
64 : on file COLVAR2.
65 : \plumedfile
66 :
67 : a: ANGLE ATOMS=1,2,3
68 : # equivalently one could state:
69 : # a: ANGLE ATOMS=1,2,2,3
70 :
71 : b: ANGLE ATOMS=1,2,3,4
72 :
73 : PRINT ARG=a FILE=COLVAR1
74 : PRINT ARG=b FILE=COLVAR2
75 : \endplumedfile
76 :
77 :
78 : */
79 : //+ENDPLUMEDOC
80 :
81 : class Angle : public Colvar {
82 : bool pbc;
83 :
84 : public:
85 : explicit Angle(const ActionOptions&);
86 : // active methods:
87 : void calculate() override;
88 : static void registerKeywords( Keywords& keys );
89 : };
90 :
91 13820 : PLUMED_REGISTER_ACTION(Angle,"ANGLE")
92 :
93 22 : void Angle::registerKeywords( Keywords& keys ) {
94 22 : Colvar::registerKeywords(keys);
95 44 : keys.add("atoms","ATOMS","the list of atoms involved in this collective variable (either 3 or 4 atoms)");
96 22 : }
97 :
98 18 : Angle::Angle(const ActionOptions&ao):
99 : PLUMED_COLVAR_INIT(ao),
100 18 : pbc(true) {
101 : std::vector<AtomNumber> atoms;
102 18 : parseAtomList("ATOMS",atoms);
103 18 : bool nopbc=!pbc;
104 18 : parseFlag("NOPBC",nopbc);
105 18 : pbc=!nopbc;
106 :
107 18 : if(atoms.size()==3) {
108 12 : log.printf(" between atoms %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial());
109 12 : atoms.resize(4);
110 12 : atoms[3]=atoms[2];
111 12 : atoms[2]=atoms[1];
112 6 : } else if(atoms.size()==4) {
113 5 : log.printf(" between lines %d-%d and %d-%d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial());
114 : } else {
115 2 : error("Number of specified atoms should be either 3 or 4");
116 : }
117 :
118 17 : if(pbc) {
119 17 : log.printf(" using periodic boundary conditions\n");
120 : } else {
121 0 : log.printf(" without periodic boundary conditions\n");
122 : }
123 :
124 17 : addValueWithDerivatives();
125 17 : setNotPeriodic();
126 17 : requestAtoms(atoms);
127 17 : checkRead();
128 19 : }
129 :
130 : // calculator
131 304 : void Angle::calculate() {
132 :
133 304 : if(pbc) {
134 304 : makeWhole();
135 : }
136 :
137 304 : Vector dij,dik;
138 304 : dij=delta(getPosition(2),getPosition(3));
139 304 : dik=delta(getPosition(1),getPosition(0));
140 304 : Vector ddij,ddik;
141 : PLMD::Angle a;
142 304 : double angle=a.compute(dij,dik,ddij,ddik);
143 304 : setAtomsDerivatives(0,ddik);
144 304 : setAtomsDerivatives(1,-ddik);
145 304 : setAtomsDerivatives(2,-ddij);
146 304 : setAtomsDerivatives(3,ddij);
147 304 : setValue (angle);
148 304 : setBoxDerivativesNoPbc();
149 304 : }
150 :
151 : }
152 : }
153 :
154 :
155 :
|