LCOV - code coverage report
Current view: top level - multicolvar - Angles.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 56 80 70.0 %
Date: 2026-11-05 10:19:04 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-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             : 
      26             : #include <string>
      27             : #include <cmath>
      28             : 
      29             : namespace PLMD {
      30             : namespace multicolvar {
      31             : 
      32             : //+PLUMEDOC COLVAR ANGLES
      33             : /*
      34             : Calculate functions of the distribution of angles.
      35             : 
      36             : __This shortcut action allows you to calculate function of a distribution of angles and reproduces the syntax in older PLUMED versions.
      37             : If you look at the example inputs below you can
      38             : see how the new syntax operates. We would strongly encourage you to use the newer syntax as it offers greater flexibility.__
      39             : 
      40             : You can use this command to calculate functions, $g$, such as:
      41             : 
      42             : $$
      43             :  f(x) = \sum_{ijk} g( \theta_{ijk} )
      44             : $$
      45             : 
      46             : where $\theta_{ijk}$ is the angle between the vector connecting atom $i$ and $j$ and the vector connecting atom $j$ and atom $k$.
      47             : Alternatively you can use this command to calculate functions such as:
      48             : 
      49             : $$
      50             : f(x) = \sum_{ijk} s(r_{ij})s(r_{jk}) g(\theta_{ijk})
      51             : $$
      52             : 
      53             : where $s(r)$ is a switching function.  This second form means that you can
      54             : use this to calculate functions of the angles in the first coordination sphere of
      55             : an atom / molecule and hence use the CVs described in the paper in the bibliography below.
      56             : 
      57             : The following example tells plumed to calculate all angles involving
      58             : at least one atom from GROUPA and two atoms from GROUPB in which the distances
      59             : are less than 1.0. The number of angles between $\frac{\pi}{4}$ and
      60             : $\frac{3\pi}{4}$ is then output
      61             : 
      62             : ```plumed
      63             : a1: ANGLES GROUPA=1-10 GROUPB=11-100 BETWEEN={GAUSSIAN LOWER=0.25pi UPPER=0.75pi} SWITCH={GAUSSIAN R_0=1.0}
      64             : PRINT ARG=a1.between FILE=colvar
      65             : ```
      66             : 
      67             : */
      68             : //+ENDPLUMEDOC
      69             : 
      70             : class Angles : public ActionShortcut {
      71             : public:
      72             :   explicit Angles(const ActionOptions&);
      73             :   static void registerKeywords( Keywords& keys );
      74             : };
      75             : 
      76             : PLUMED_REGISTER_ACTION(Angles,"ANGLES")
      77             : 
      78          11 : void Angles::registerKeywords( Keywords& keys ) {
      79          11 :   ActionShortcut::registerKeywords( keys );
      80          11 :   keys.add("atoms-1","GROUP","Calculate angles for each distinct set of three atoms in the group");
      81          11 :   keys.add("atoms-2","GROUPA","A group of central atoms about which angles should be calculated");
      82          11 :   keys.add("atoms-2","GROUPB","When used in conjunction with GROUPA this keyword instructs plumed "
      83             :            "to calculate all distinct angles involving one atom from GROUPA "
      84             :            "and two atoms from GROUPB. The atom from GROUPA is the central atom.");
      85          11 :   keys.add("atoms-3","GROUPC","This must be used in conjunction with GROUPA and GROUPB.  All angles "
      86             :            "involving one atom from GROUPA, one atom from GROUPB and one atom from "
      87             :            "GROUPC are calculated. The GROUPA atoms are assumed to be the central "
      88             :            "atoms");
      89          11 :   keys.add("optional","SWITCH","the switching function specifies that only those bonds that have a length that is less than a certain threshold are considered");
      90          11 :   keys.addDOI("https://doi.org/10.1063/1.3628676");
      91          22 :   keys.setValueDescription("vector","the ANGLE for each set of three atoms that were specified");
      92          11 :   MultiColvarShortcuts::shortcutKeywords( keys );
      93          11 :   keys.needsAction("ANGLE");
      94          11 :   keys.needsAction("COORD_ANGLES");
      95          11 :   keys.setDeprecated("ANGLE");
      96          11 : }
      97             : 
      98           6 : Angles::Angles(const ActionOptions&ao):
      99             :   Action(ao),
     100           6 :   ActionShortcut(ao) {
     101             :   std::string swit;
     102          16 :   parse("SWITCH",swit);
     103           6 :   if( swit.length()>0 ) {
     104             :     std::string cat, grp;
     105           1 :     parse("GROUPA",cat);
     106           2 :     parse("GROUPB",grp);
     107           1 :     if( cat.length()==0 || grp.length()==0 ) {
     108           0 :       error("must use GROUPA/GROUPB when using SWITCH");
     109             :     }
     110           5 :     readInputLine( getShortcutLabel() + ": COORD_ANGLES SWITCH={" +  swit + "} CATOMS=" + cat + " GROUP=" + grp + " " + convertInputLineToString() );
     111             :     return;
     112             :   }
     113           5 :   std::vector<std::string> group;
     114           5 :   parseVector("GROUP",group);
     115           5 :   std::vector<std::string> groupa;
     116           5 :   parseVector("GROUPA",groupa);
     117           5 :   std::vector<std::string> groupb;
     118           5 :   parseVector("GROUPB",groupb);
     119           5 :   std::vector<std::string> groupc;
     120          10 :   parseVector("GROUPC",groupc);
     121           5 :   if( group.size()>0 ) {
     122           1 :     if( groupa.size()>0 || groupb.size()>0 || groupc.size()>0 ) {
     123           0 :       error("should only be GROUP keyword in input not GROUPA/GROUPB/GROUPC");
     124             :     }
     125           1 :     Tools::interpretRanges( group );
     126           1 :     if( group.size()<3 ) {
     127           1 :       error("GROUP must contain at least three atoms");
     128             :     }
     129           0 :     std::string ainput = getShortcutLabel() + ": ANGLE";
     130           0 :     unsigned n=1;
     131             :     // Not sure if this triple sum makes any sense
     132           0 :     for(unsigned i=2; i<group.size(); ++i ) {
     133           0 :       for(unsigned j=1; j<i; ++j ) {
     134           0 :         for(unsigned k=0; k<j; ++k) {
     135             :           std::string str_n;
     136           0 :           Tools::convert( n, str_n );
     137           0 :           ainput += " ATOMS" + str_n + "=" + group[i] + "," + group[j] + "," + group[k];
     138           0 :           n++;
     139             :         }
     140             :       }
     141             :     }
     142           0 :     readInputLine( ainput );
     143           4 :   } else if( groupc.size()>0 ) {
     144           1 :     if( groupa.size()==0 || groupb.size()==0 ) {
     145           1 :       error("GROUPC must be used together with GROUPA and GROUPB");
     146             :     }
     147           0 :     Tools::interpretRanges( groupa );
     148           0 :     Tools::interpretRanges( groupb );
     149           0 :     Tools::interpretRanges( groupc );
     150           0 :     unsigned n=1;
     151           0 :     std::string ainput = getShortcutLabel() + ": ANGLE";
     152           0 :     for(unsigned i=0; i<groupa.size(); ++i ) {
     153           0 :       for(unsigned j=0; j<groupb.size(); ++j ) {
     154           0 :         for(unsigned k=0; k<groupc.size(); ++k) {
     155             :           std::string str_n;
     156           0 :           Tools::convert( n, str_n );
     157           0 :           ainput += " ATOMS" + str_n + "=" + groupb[j] + "," + groupa[i] + "," + groupc[k];
     158           0 :           n++;
     159             :         }
     160             :       }
     161             :     }
     162           0 :     readInputLine( ainput );
     163           3 :   } else if( groupa.size()>0 ) {
     164           2 :     if( groupb.size()==0 ) {
     165           1 :       error("GROUPA must be used together with GROUPB");
     166             :     }
     167           1 :     Tools::interpretRanges( groupa );
     168           1 :     Tools::interpretRanges( groupb );
     169           1 :     if( groupb.size()<2 ) {
     170           0 :       error("GROUPB must contain at least two atoms");
     171             :     }
     172           1 :     unsigned n=1;
     173             :     std::string ainput;
     174           1 :     ainput = getShortcutLabel() + ": ANGLE";
     175           2 :     for(unsigned i=0; i<groupa.size(); ++i ) {
     176           9 :       for(unsigned j=1; j<groupb.size(); ++j ) {
     177          44 :         for(unsigned k=0; k<j; ++k) {
     178             :           std::string str_n;
     179          36 :           Tools::convert( n, str_n );
     180         144 :           ainput += " ATOMS" + str_n + "=" + groupb[j] + "," + groupa[i] + "," + groupb[k];
     181          36 :           n++;
     182             :         }
     183             :       }
     184             :     }
     185           1 :     readInputLine( ainput );
     186             :   } else {
     187           1 :     error("found no atoms: use GROUP, GROUPA and GROUPB, or GROUPA, GROUPB and GROUPC");
     188             :   }
     189           1 :   MultiColvarShortcuts::expandFunctions( getShortcutLabel(), getShortcutLabel(), "", this );
     190          25 : }
     191             : 
     192             : }
     193             : }
     194             : 
     195             : 
     196             : 

Generated by: LCOV version 1.16