LCOV - code coverage report
Current view: top level - colvar - Torsion.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 69 76 90.8 %
Date: 2026-03-30 13:16:06 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 "ActionRegister.h"
      24             : #include "tools/Torsion.h"
      25             : 
      26             : namespace PLMD {
      27             : namespace colvar {
      28             : 
      29             : //+PLUMEDOC COLVAR TORSION
      30             : /*
      31             : Calculate a torsional angle.
      32             : 
      33             : This command can be used to compute the torsion between four atoms or alternatively
      34             : to calculate the angle between two vectors projected on the plane
      35             : orthogonal to an axis.
      36             : 
      37             : \par Examples
      38             : 
      39             : This input tells plumed to print the torsional angle between atoms 1, 2, 3 and 4
      40             : on file COLVAR.
      41             : \plumedfile
      42             : t: TORSION ATOMS=1,2,3,4
      43             : # this is an alternative, equivalent, definition:
      44             : # t: TORSION VECTOR1=2,1 AXIS=2,3 VECTOR2=3,4
      45             : PRINT ARG=t FILE=COLVAR
      46             : \endplumedfile
      47             : 
      48             : If you are working with a protein you can specify the special named torsion angles \f$\phi\f$, \f$\psi\f$, \f$\omega\f$ and \f$\chi_1\f$
      49             : by using TORSION in combination with the \ref MOLINFO command.  This can be done by using the following
      50             : syntax.
      51             : 
      52             : \plumedfile
      53             : #SETTINGS MOLFILE=regtest/basic/rt32/helix.pdb
      54             : MOLINFO MOLTYPE=protein STRUCTURE=myprotein.pdb
      55             : t1: TORSION ATOMS=@phi-3
      56             : t2: TORSION ATOMS=@psi-4
      57             : PRINT ARG=t1,t2 FILE=colvar STRIDE=10
      58             : \endplumedfile
      59             : 
      60             : Here, \@phi-3 tells plumed that you would like to calculate the \f$\phi\f$ angle in the third residue of the protein.
      61             : Similarly \@psi-4 tells plumed that you want to calculate the \f$\psi\f$ angle of the fourth residue of the protein.
      62             : 
      63             : Both of the previous examples specify that the torsion angle should be calculated based on the position of four atoms.
      64             : For the first example in particular the assumption when the torsion is specified in this way is that there are chemical
      65             : bonds between atoms 1 and 2, atoms 2 and 3 and atoms 3 and 4. In general, however, a torsional angle measures the angle
      66             : between two planes, which have at least one vector in common.  As shown below, there is thus an alternate, more general, way
      67             : through which we can define a torsional angle:
      68             : 
      69             : \plumedfile
      70             : t1: TORSION VECTOR1=1,2 AXIS=3,4 VECTOR2=5,6
      71             : PRINT ARG=t1 FILE=colvar STRIDE=20
      72             : \endplumedfile
      73             : 
      74             : This input instructs PLUMED to calculate the angle between the plane containing the vector connecting atoms 1 and 2 and the vector
      75             : connecting atoms 3 and 4 and the plane containing this second vector and the vector connecting atoms 5 and 6.  We can even use
      76             : PLUMED to calculate the torsional angle between two bond vectors around the z-axis as shown below:
      77             : 
      78             : \plumedfile
      79             : a0: FIXEDATOM AT=0,0,0
      80             : az: FIXEDATOM AT=0,0,1
      81             : t1: TORSION VECTOR1=1,2 AXIS=a0,az VECTOR2=5,6
      82             : PRINT ARG=t1 FILE=colvar STRIDE=20
      83             : \endplumedfile
      84             : 
      85             : 
      86             : */
      87             : //+ENDPLUMEDOC
      88             : 
      89             : class Torsion : public Colvar {
      90             :   bool pbc;
      91             :   bool do_cosine;
      92             : 
      93             : public:
      94             :   explicit Torsion(const ActionOptions&);
      95             : // active methods:
      96             :   void calculate() override;
      97             :   static void registerKeywords(Keywords& keys);
      98             : };
      99             : 
     100       15137 : PLUMED_REGISTER_ACTION(Torsion,"TORSION")
     101             : 
     102         681 : void Torsion::registerKeywords(Keywords& keys) {
     103         681 :   Colvar::registerKeywords( keys );
     104        1362 :   keys.add("atoms-1","ATOMS","the four atoms involved in the torsional angle");
     105        1362 :   keys.add("atoms-2","AXIS","two atoms that define an axis.  You can use this to find the angle in the plane perpendicular to the axis between the vectors specified using the VECTOR1 and VECTOR2 keywords.");
     106        1362 :   keys.add("atoms-2","VECTOR1","two atoms that define a vector.  You can use this in combination with VECTOR2 and AXIS");
     107        1362 :   keys.add("atoms-2","VECTOR2","two atoms that define a vector.  You can use this in combination with VECTOR1 and AXIS");
     108        1362 :   keys.addFlag("COSINE",false,"calculate cosine instead of dihedral");
     109         681 : }
     110             : 
     111         677 : Torsion::Torsion(const ActionOptions&ao):
     112             :   PLUMED_COLVAR_INIT(ao),
     113         677 :   pbc(true),
     114         677 :   do_cosine(false) {
     115             :   std::vector<AtomNumber> atoms,v1,v2,axis;
     116         677 :   parseAtomList("ATOMS",atoms);
     117         677 :   parseAtomList("VECTOR1",v1);
     118         677 :   parseAtomList("VECTOR2",v2);
     119         677 :   parseAtomList("AXIS",axis);
     120             : 
     121         677 :   parseFlag("COSINE",do_cosine);
     122             : 
     123         677 :   bool nopbc=!pbc;
     124         677 :   parseFlag("NOPBC",nopbc);
     125         677 :   pbc=!nopbc;
     126         677 :   checkRead();
     127             : 
     128         677 :   if(atoms.size()==4) {
     129         672 :     if(!(v1.empty() && v2.empty() && axis.empty())) {
     130           1 :       error("ATOMS keyword is not compatible with VECTOR1, VECTOR2 and AXIS keywords");
     131             :     }
     132         671 :     log.printf("  between atoms %d %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial());
     133         671 :     atoms.resize(6);
     134         671 :     atoms[5]=atoms[3];
     135         671 :     atoms[4]=atoms[2];
     136         671 :     atoms[3]=atoms[2];
     137         671 :     atoms[2]=atoms[1];
     138           5 :   } else if(atoms.empty()) {
     139           4 :     if(!(v1.size()==2 && v2.size()==2 && axis.size()==2)) {
     140           0 :       error("VECTOR1, VECTOR2 and AXIS should specify 2 atoms each");
     141             :     }
     142           4 :     log.printf("  between lines %d-%d and %d-%d, projected on the plane orthogonal to line %d-%d\n",
     143             :                v1[0].serial(),v1[1].serial(),v2[0].serial(),v2[1].serial(),axis[0].serial(),axis[1].serial());
     144           4 :     atoms.resize(6);
     145           4 :     atoms[0]=v1[1];
     146           4 :     atoms[1]=v1[0];
     147           4 :     atoms[2]=axis[0];
     148           4 :     atoms[3]=axis[1];
     149           4 :     atoms[4]=v2[0];
     150           4 :     atoms[5]=v2[1];
     151             :   } else {
     152           1 :     error("ATOMS should specify 4 atoms");
     153             :   }
     154             : 
     155         675 :   if(pbc) {
     156         563 :     log.printf("  using periodic boundary conditions\n");
     157             :   } else {
     158         112 :     log.printf("  without periodic boundary conditions\n");
     159             :   }
     160             : 
     161         675 :   if(do_cosine) {
     162           0 :     log.printf("  calculating cosine instead of torsion\n");
     163             :   }
     164             : 
     165         675 :   addValueWithDerivatives();
     166         675 :   if(!do_cosine) {
     167        1352 :     setPeriodic("-pi","pi");
     168             :   } else {
     169           0 :     setNotPeriodic();
     170             :   }
     171         675 :   requestAtoms(atoms);
     172         679 : }
     173             : 
     174             : // calculator
     175       36005 : void Torsion::calculate() {
     176             : 
     177       36005 :   Vector d0,d1,d2;
     178       36005 :   if(pbc) {
     179       33733 :     makeWhole();
     180             :   }
     181       36005 :   d0=delta(getPosition(1),getPosition(0));
     182       36005 :   d1=delta(getPosition(3),getPosition(2));
     183       36005 :   d2=delta(getPosition(5),getPosition(4));
     184       36005 :   Vector dd0,dd1,dd2;
     185             :   PLMD::Torsion t;
     186       36005 :   double torsion=t.compute(d0,d1,d2,dd0,dd1,dd2);
     187       36005 :   if(do_cosine) {
     188           0 :     dd0 *= -std::sin(torsion);
     189           0 :     dd1 *= -std::sin(torsion);
     190           0 :     dd2 *= -std::sin(torsion);
     191           0 :     torsion = std::cos(torsion);
     192             :   }
     193       36005 :   setAtomsDerivatives(0,dd0);
     194       36005 :   setAtomsDerivatives(1,-dd0);
     195       36005 :   setAtomsDerivatives(2,dd1);
     196       36005 :   setAtomsDerivatives(3,-dd1);
     197       36005 :   setAtomsDerivatives(4,dd2);
     198       36005 :   setAtomsDerivatives(5,-dd2);
     199             : 
     200       36005 :   setValue           (torsion);
     201       36005 :   setBoxDerivativesNoPbc();
     202       36005 : }
     203             : 
     204             : }
     205             : }
     206             : 
     207             : 
     208             : 

Generated by: LCOV version 1.16