LCOV - code coverage report
Current view: top level - colvar - Angle.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 61 62 98.4 %
Date: 2025-03-25 09:33:27 Functions: 6 7 85.7 %

          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/Angle.h"
      27             : 
      28             : namespace PLMD {
      29             : namespace colvar {
      30             : 
      31             : //+PLUMEDOC COLVAR ANGLE
      32             : /*
      33             : Calculate one or multiple angle/s.
      34             : 
      35             : The following input instructs PLUMED to calculate and print the angle between the vector
      36             : connecting atom 2 and atom 1 and the vector connecting atom 2 and atom 3.
      37             : 
      38             : ```plumed
      39             : a1: ANGLE ATOMS=1,2,3
      40             : PRINT ARG=a1 FILE=colvar
      41             : ```
      42             : 
      43             : In other words, the angle that is output by the input above is calculated as:
      44             : 
      45             : $$
      46             : \theta=\arccos\left(\frac{ r_{21}\cdot r_{23}}{
      47             : | r_{21}| | r_{23}|}\right)
      48             : $$
      49             : 
      50             : Here $r_{ij}$ is the vector connecting the $i$th and $j$th atoms, which by default is evaluated
      51             : in a way that takes periodic boundary conditions into account. If you wish to disregard the PBC you
      52             : can use the NOPBC flag.
      53             : 
      54             : Alternatively, we can instruct PLUMED to calculate the angle between the vectors connecting
      55             : atoms 1 and atom 2 and atoms 3 and atom 4 by using the following input:
      56             : 
      57             : ```plumed
      58             : a2: ANGLE ATOMS=1,2,3,4
      59             : PRINT ARG=a2 FILE=colvar
      60             : 
      61             : The angle in this input is calculated using:
      62             : 
      63             : $$
      64             : \theta=\arccos\left(\frac{ r_{21}\cdot r_{34}}{
      65             : | r_{21}| | r_{34}|}\right)
      66             : $$
      67             : 
      68             : Notice that angles defined in this way are non-periodic variables - their values must lie in between 0 and $\pi$.
      69             : 
      70             : You can specify multiple sets of three or four atoms to calculate vectors of angles as illustrated in the following
      71             : input which instructs PLUMED to calculate and output three angles:
      72             : 
      73             : ```plumed
      74             : a3: ANGLE ATOMS1=1,2,3 ATOMS2=4,5,6 ATOMS3=7,8,9
      75             : PRINT ARG=a3 FILE=colvar
      76             : ```
      77             : 
      78             : It is common to assume when using this feature that all the angles being computed are indistinguishable
      79             : so it makes sense to perform the same series of operations on every element of the output vector. The input
      80             : file below is more approrpriate if the angles are not indistinguishable:
      81             : 
      82             : ```plumed
      83             : a4: ANGLE ATOMS=1,2,3
      84             : a5: ANGLE ATOMS=4,5,6
      85             : a6: ANGLE ATOMS=7,8,9
      86             : PRINT ARG=a4,a5,a6 FILE=colvar
      87             : ```
      88             : 
      89             : */
      90             : //+ENDPLUMEDOC
      91             : 
      92             : //+PLUMEDOC COLVAR ANGLE_SCALAR
      93             : /*
      94             : Calculate an angle.
      95             : 
      96             : \par Examples
      97             : 
      98             : */
      99             : //+ENDPLUMEDOC
     100             : 
     101             : //+PLUMEDOC COLVAR ANGLE_VECTOR
     102             : /*
     103             : Calculate multiple angles.
     104             : 
     105             : \par Examples
     106             : 
     107             : */
     108             : //+ENDPLUMEDOC
     109             : 
     110             : class Angle : public Colvar {
     111             :   bool pbc;
     112             :   std::vector<double> value, masses, charges;
     113             :   std::vector<std::vector<Vector> > derivs;
     114             :   std::vector<Tensor> virial;
     115             : public:
     116             :   explicit Angle(const ActionOptions&);
     117             : // active methods:
     118             :   void calculate() override;
     119             :   static void registerKeywords( Keywords& keys );
     120             :   static void parseAtomList( const int& num, std::vector<AtomNumber>& t, ActionAtomistic* aa );
     121             :   static unsigned getModeAndSetupValues( ActionWithValue* av );
     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             : };
     126             : 
     127             : typedef ColvarShortcut<Angle> AngleShortcut;
     128             : PLUMED_REGISTER_ACTION(AngleShortcut,"ANGLE")
     129             : PLUMED_REGISTER_ACTION(Angle,"ANGLE_SCALAR")
     130             : typedef MultiColvarTemplate<Angle> AngleMulti;
     131             : PLUMED_REGISTER_ACTION(AngleMulti,"ANGLE_VECTOR")
     132             : 
     133          89 : void Angle::registerKeywords( Keywords& keys ) {
     134          89 :   Colvar::registerKeywords(keys);
     135         178 :   keys.setDisplayName("ANGLE");
     136          89 :   keys.add("atoms","ATOMS","the list of atoms involved in this collective variable (either 3 or 4 atoms)");
     137          89 :   keys.add("hidden","NO_ACTION_LOG","suppresses printing from action on the log");
     138         178 :   keys.setValueDescription("scalar/vector","the ANGLE involving these atoms");
     139          89 : }
     140             : 
     141          73 : void Angle::parseAtomList( const int& num, std::vector<AtomNumber>& atoms, ActionAtomistic* aa ) {
     142         146 :   aa->parseAtomList("ATOMS",num,atoms);
     143          73 :   if(atoms.size()==3) {
     144          62 :     aa->log.printf("  between atoms %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial());
     145          62 :     atoms.resize(4);
     146          62 :     atoms[3]=atoms[2];
     147          62 :     atoms[2]=atoms[1];
     148          11 :   } else if(atoms.size()==4) {
     149           7 :     aa->log.printf("  between lines %d-%d and %d-%d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial());
     150           4 :   } else if( num<0 || atoms.size()>0 ) {
     151           1 :     aa->error("Number of specified atoms should be either 3 or 4");
     152             :   }
     153          72 : }
     154             : 
     155           3 : unsigned Angle::getModeAndSetupValues( ActionWithValue* av ) {
     156           3 :   av->addValueWithDerivatives();
     157           3 :   av->setNotPeriodic();
     158           3 :   return 0;
     159             : }
     160             : 
     161          23 : Angle::Angle(const ActionOptions&ao):
     162             :   PLUMED_COLVAR_INIT(ao),
     163          23 :   pbc(true),
     164          23 :   value(1),
     165          24 :   derivs(1),
     166          46 :   virial(1) {
     167          23 :   derivs[0].resize(4);
     168             :   std::vector<AtomNumber> atoms;
     169          23 :   parseAtomList( -1, atoms, this );
     170          22 :   bool nopbc=!pbc;
     171          22 :   parseFlag("NOPBC",nopbc);
     172          22 :   pbc=!nopbc;
     173             : 
     174          22 :   if(pbc) {
     175          22 :     log.printf("  using periodic boundary conditions\n");
     176             :   } else {
     177           0 :     log.printf("  without periodic boundary conditions\n");
     178             :   }
     179             : 
     180          23 :   addValueWithDerivatives();
     181          22 :   setNotPeriodic();
     182          22 :   requestAtoms(atoms);
     183          22 :   checkRead();
     184          25 : }
     185             : 
     186             : // calculator
     187         319 : void Angle::calculate() {
     188             : 
     189         319 :   if(pbc) {
     190         319 :     makeWhole();
     191             :   }
     192         319 :   calculateCV( 0, masses, charges, getPositions(), value, derivs, virial, this );
     193         319 :   setValue( value[0] );
     194        1595 :   for(unsigned i=0; i<derivs[0].size(); ++i) {
     195        1276 :     setAtomsDerivatives( i, derivs[0][i] );
     196             :   }
     197         319 :   setBoxDerivatives( virial[0] );
     198         319 : }
     199             : 
     200         554 : void Angle::calculateCV( const unsigned& mode, const std::vector<double>& masses, const std::vector<double>& charges,
     201             :                          const std::vector<Vector>& pos, std::vector<double>& vals, std::vector<std::vector<Vector> >& derivs,
     202             :                          std::vector<Tensor>& virial, const ActionAtomistic* aa ) {
     203         554 :   Vector dij,dik;
     204         554 :   dij=delta(pos[2],pos[3]);
     205         554 :   dik=delta(pos[1],pos[0]);
     206         554 :   Vector ddij,ddik;
     207             :   PLMD::Angle a;
     208         554 :   vals[0]=a.compute(dij,dik,ddij,ddik);
     209         554 :   derivs[0][0]=ddik;
     210         554 :   derivs[0][1]=-ddik;
     211         554 :   derivs[0][2]=-ddij;
     212         554 :   derivs[0][3]=ddij;
     213         554 :   setBoxDerivativesNoPbc( pos, derivs, virial );
     214         554 : }
     215             : 
     216             : }
     217             : }
     218             : 
     219             : 
     220             : 

Generated by: LCOV version 1.16