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 10454 : PLUMED_REGISTER_ACTION(Angle,"ANGLE") 92 : 93 19 : void Angle::registerKeywords( Keywords& keys ) { 94 19 : Colvar::registerKeywords(keys); 95 38 : keys.add("atoms","ATOMS","the list of atoms involved in this collective variable (either 3 or 4 atoms)"); 96 19 : } 97 : 98 18 : Angle::Angle(const ActionOptions&ao): 99 : PLUMED_COLVAR_INIT(ao), 100 18 : pbc(true) 101 : { 102 : std::vector<AtomNumber> atoms; 103 18 : parseAtomList("ATOMS",atoms); 104 18 : bool nopbc=!pbc; 105 18 : parseFlag("NOPBC",nopbc); 106 18 : pbc=!nopbc; 107 : 108 18 : if(atoms.size()==3) { 109 12 : log.printf(" between atoms %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial()); 110 12 : atoms.resize(4); 111 12 : atoms[3]=atoms[2]; 112 12 : atoms[2]=atoms[1]; 113 6 : } else if(atoms.size()==4) { 114 5 : log.printf(" between lines %d-%d and %d-%d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial()); 115 2 : } else error("Number of specified atoms should be either 3 or 4"); 116 : 117 17 : if(pbc) log.printf(" using periodic boundary conditions\n"); 118 0 : else log.printf(" without periodic boundary conditions\n"); 119 : 120 17 : addValueWithDerivatives(); setNotPeriodic(); 121 17 : requestAtoms(atoms); 122 17 : checkRead(); 123 19 : } 124 : 125 : // calculator 126 304 : void Angle::calculate() { 127 : 128 304 : if(pbc) makeWhole(); 129 : 130 304 : Vector dij,dik; 131 304 : dij=delta(getPosition(2),getPosition(3)); 132 304 : dik=delta(getPosition(1),getPosition(0)); 133 304 : Vector ddij,ddik; 134 : PLMD::Angle a; 135 304 : double angle=a.compute(dij,dik,ddij,ddik); 136 304 : setAtomsDerivatives(0,ddik); 137 304 : setAtomsDerivatives(1,-ddik); 138 304 : setAtomsDerivatives(2,-ddij); 139 304 : setAtomsDerivatives(3,ddij); 140 304 : setValue (angle); 141 304 : setBoxDerivativesNoPbc(); 142 304 : } 143 : 144 : } 145 : } 146 : 147 : 148 :