LCOV - code coverage report
Current view: top level - colvar - Distance.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 136 138 98.6 %
Date: 2026-11-05 10:19:04 Functions: 6 6 100.0 %

          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             : #ifndef __PLUMED_colvar_Distance_h
      23             : #define __PLUMED_colvar_Distance_h
      24             : #include "Colvar.h"
      25             : #include "ColvarInput.h"
      26             : #include "MultiColvarTemplate.h"
      27             : #include "tools/Pbc.h"
      28             : 
      29             : namespace PLMD {
      30             : namespace colvar {
      31             : 
      32             : template <typename T=double>
      33             : class Distance : public Colvar {
      34             :   enum components:unsigned {squared=3,scaled=2,standard=1,scalar=0} mode{scalar};
      35             :   bool pbc;
      36             : 
      37             :   //not Typep, the float version is only used for the PTM
      38             :   std::vector<double> value;
      39             :   std::vector<double> derivs;
      40             : public:
      41             :   using precision = T;
      42             :   static void registerKeywords( Keywords& keys );
      43             :   explicit Distance(const ActionOptions&);
      44             :   static void parseAtomList( const int& num,
      45             :                              std::vector<AtomNumber>& t,
      46             :                              ActionAtomistic* aa );
      47             :   static unsigned getModeAndSetupValues( ActionWithValue* av );
      48             : // active methods:
      49             :   void calculate() override;
      50             :   static void calculateCV( const ColvarInput<T>& cvin,
      51             :                            ColvarOutput<T>& cvout );
      52             : };
      53             : 
      54             : template <typename T>
      55        5296 : void  Distance<T>::registerKeywords( Keywords& keys ) {
      56        5296 :   Colvar::registerKeywords( keys );
      57       10592 :   keys.setDisplayName("DISTANCE");
      58             :   constexpr auto scalarOrVector = Keywords::componentType::scalar
      59             :                                   | Keywords::componentType::vector;
      60        5296 :   keys.add("atoms","ATOMS","the pair of atom that we are calculating the distance between");
      61        5296 :   keys.addFlag("SQUARED",false,"calculate and store the square of the distance");
      62        5296 :   keys.addFlag("COMPONENTS",false,"calculate the x, y and z components of the distance separately and store them as label.x, label.y and label.z");
      63        5296 :   keys.addFlag("SCALED_COMPONENTS",false,"calculate the a, b and c scaled components of the distance separately and store them as label.a, label.b and label.c");
      64       10592 :   keys.addOutputComponent("x","COMPONENTS",scalarOrVector,"the x-component of the vector connecting the two atoms");
      65       10592 :   keys.addOutputComponent("y","COMPONENTS",scalarOrVector,"the y-component of the vector connecting the two atoms");
      66       10592 :   keys.addOutputComponent("z","COMPONENTS",scalarOrVector,"the z-component of the vector connecting the two atoms");
      67       10592 :   keys.addOutputComponent("a","SCALED_COMPONENTS",scalarOrVector,"the normalized projection on the first lattice vector of the vector connecting the two atoms");
      68       10592 :   keys.addOutputComponent("b","SCALED_COMPONENTS",scalarOrVector,"the normalized projection on the second lattice vector of the vector connecting the two atoms");
      69       10592 :   keys.addOutputComponent("c","SCALED_COMPONENTS",scalarOrVector,"the normalized projection on the third lattice vector of the vector connecting the two atoms");
      70        5296 :   keys.add("hidden","NO_ACTION_LOG","suppresses printing from action on the log");
      71        5296 :   keys.setValueDescription(scalarOrVector,"the DISTANCE between this pair of atoms");
      72        5296 :   keys.addDOI("10.1007/978-1-4939-9608-7_21");
      73       10592 :   keys.reset_style("NUMERICAL_DERIVATIVES","hidden");
      74        5296 : }
      75             : 
      76             : template <typename T>
      77        1441 : Distance<T>::Distance(const ActionOptions&ao):
      78             :   PLUMED_COLVAR_INIT(ao),
      79        1441 :   pbc(true),
      80        1441 :   value(1) {
      81        1441 :   std::vector<AtomNumber> atoms;
      82        1441 :   parseAtomList(-1,atoms,this);
      83        1441 :   if(atoms.size()!=2) {
      84           1 :     error("Number of specified atoms should be 2");
      85             :   }
      86             : 
      87        1440 :   bool nopbc=!pbc;
      88        1440 :   parseFlag("NOPBC",nopbc);
      89        1440 :   pbc=!nopbc;
      90             : 
      91        1440 :   if(pbc) {
      92         763 :     log.printf("  using periodic boundary conditions\n");
      93             :   } else {
      94         677 :     log.printf("  without periodic boundary conditions\n");
      95             :   }
      96             : 
      97        1440 :   mode = static_cast<components>(getModeAndSetupValues(this));
      98        1439 :   if( mode == components::standard || mode == components::scaled ) {
      99         275 :     value.resize(3);
     100             :   }
     101        1439 :   requestAtoms(atoms);
     102        1445 : }
     103             : 
     104             : template <typename T>
     105      231507 : void  Distance<T>::parseAtomList( const int& num,
     106             :                                   std::vector<AtomNumber>& t,
     107             :                                   ActionAtomistic* aa ) {
     108      463014 :   aa->parseAtomList("ATOMS",num,t);
     109      231507 :   if( t.size()==2 ) {
     110      231287 :     aa->log.printf("  between atoms %d %d\n",t[0].serial(),t[1].serial());
     111             :   }
     112      231507 : }
     113             : 
     114             : template <typename T>
     115        1659 : unsigned  Distance<T>::getModeAndSetupValues( ActionWithValue* av ) {
     116             :   bool s;
     117        1659 :   av->parseFlag("SQUARED",s);
     118             :   bool c;
     119        1659 :   av->parseFlag("COMPONENTS",c);
     120             :   bool sc;
     121        1659 :   av->parseFlag("SCALED_COMPONENTS",sc);
     122        1659 :   if( c && sc ) {
     123           1 :     av->error("COMPONENTS and SCALED_COMPONENTS are not compatible");
     124             :   }
     125        1658 :   if ( s & c ) {
     126           0 :     av->error("SQUARED and COMPONENTS are not compatible");
     127             :   }
     128        1658 :   if ( s & sc ) {
     129           0 :     av->error("SQUARED and SCALED_COMPONENTS are not compatible");
     130             :   }
     131        1658 :   if(c) {
     132         678 :     av->addComponentWithDerivatives("x");
     133         339 :     av->componentIsNotPeriodic("x");
     134         678 :     av->addComponentWithDerivatives("y");
     135         339 :     av->componentIsNotPeriodic("y");
     136         678 :     av->addComponentWithDerivatives("z");
     137         339 :     av->componentIsNotPeriodic("z");
     138         339 :     av->log<<"  WARNING: components will not have the proper periodicity - see manual\n";
     139         339 :     return components::standard;
     140        1319 :   } else if(sc) {
     141          12 :     av->addComponentWithDerivatives("a");
     142          12 :     av->componentIsPeriodic("a","-0.5","+0.5");
     143          12 :     av->addComponentWithDerivatives("b");
     144          12 :     av->componentIsPeriodic("b","-0.5","+0.5");
     145          12 :     av->addComponentWithDerivatives("c");
     146          12 :     av->componentIsPeriodic("c","-0.5","+0.5");
     147           6 :     return components::scaled;
     148             :   }
     149        1313 :   av->addValueWithDerivatives();
     150        1313 :   av->setNotPeriodic();
     151        1313 :   if(s) {
     152           1 :     return components::squared;
     153             :   }
     154             :   return components::scalar;
     155             : }
     156             : 
     157             : // calculator
     158             : template <typename T>
     159      218599 : void  Distance<T>::calculate() {
     160             : 
     161      218599 :   if(pbc) {
     162       83334 :     makeWhole();
     163             :   }
     164             :   using CVInput= ColvarInput<double>;
     165             :   using CVOutput=ColvarOutput<double>;
     166      218599 :   auto cvout =  CVOutput::createColvarOutput(value, derivs, this);
     167      218599 :   Distance<double>::calculateCV( CVInput::createColvarInput( mode, getPositions(), this ), cvout );
     168      218599 :   if( mode==components::standard ) {
     169        2001 :     Value* valuex=getPntrToComponent("x");
     170        2001 :     Value* valuey=getPntrToComponent("y");
     171        2001 :     Value* valuez=getPntrToComponent("z");
     172             : 
     173        6003 :     for(unsigned i=0; i<2; ++i) {
     174        4002 :       setAtomsDerivatives(valuex,i,cvout.getAtomDerivatives(0,i) );
     175             :     }
     176        2001 :     setBoxDerivatives(valuex,cvout.virial[0]);
     177        2001 :     valuex->set(value[0]);
     178             : 
     179        6003 :     for(unsigned i=0; i<2; ++i) {
     180        4002 :       setAtomsDerivatives(valuey,i,cvout.getAtomDerivatives(1,i) );
     181             :     }
     182        2001 :     setBoxDerivatives(valuey,cvout.virial[1]);
     183        2001 :     valuey->set(value[1]);
     184             : 
     185        6003 :     for(unsigned i=0; i<2; ++i) {
     186        4002 :       setAtomsDerivatives(valuez,i,cvout.getAtomDerivatives(2,i) );
     187             :     }
     188        2001 :     setBoxDerivatives(valuez,cvout.virial[2]);
     189        2001 :     valuez->set(value[2]);
     190      216598 :   } else if( mode==components::scaled ) {
     191             : 
     192          26 :     Value* valuea=getPntrToComponent("a");
     193          26 :     Value* valueb=getPntrToComponent("b");
     194          26 :     Value* valuec=getPntrToComponent("c");
     195          78 :     for(unsigned i=0; i<2; ++i) {
     196          52 :       setAtomsDerivatives(valuea,i,cvout.getAtomDerivatives(0,i) );
     197             :     }
     198          26 :     valuea->set(value[0]);
     199          78 :     for(unsigned i=0; i<2; ++i) {
     200          52 :       setAtomsDerivatives(valueb,i,cvout.getAtomDerivatives(1,i) );
     201             :     }
     202          26 :     valueb->set(value[1]);
     203          78 :     for(unsigned i=0; i<2; ++i) {
     204          52 :       setAtomsDerivatives(valuec,i,cvout.getAtomDerivatives(2,i) );
     205             :     }
     206          26 :     valuec->set(value[2]);
     207             :   } else  {
     208      649716 :     for(unsigned i=0; i<2; ++i) {
     209      433144 :       setAtomsDerivatives(i,cvout.getAtomDerivatives(0,i) );
     210             :     }
     211      216572 :     setBoxDerivatives(cvout.virial[0]);
     212      216572 :     setValue           (value[0]);
     213             :   }
     214      218599 : }
     215             : 
     216             : template <typename T>
     217     2739991 : void  Distance<T>::calculateCV( const ColvarInput<T>& cvin, ColvarOutput<T>& cvout ) {
     218     2739991 :   auto distance=delta(cvin.pos[0],cvin.pos[1]);
     219             :   //these six can be compacted in a scoped `using namespac3 PLMD::Versors` but plumedcheck won't approve (even in a comment, hence the 3)
     220             :   using PLMD::Versors::xp;
     221             :   using PLMD::Versors::xm;
     222             :   using PLMD::Versors::yp;
     223             :   using PLMD::Versors::ym;
     224             :   using PLMD::Versors::zp;
     225             :   using PLMD::Versors::zm;
     226     2739991 :   if(cvin.mode==components::standard) {
     227             : 
     228             :     cvout.derivs[0][0] = xm<T>;
     229             :     cvout.derivs[0][1] = xp<T>;
     230      106175 :     cvout.values[0] = distance[0];
     231             : 
     232             :     cvout.derivs[1][0] = ym<T>;
     233             :     cvout.derivs[1][1] = yp<T>;
     234      106175 :     cvout.values[1] = distance[1];
     235             : 
     236             :     cvout.derivs[2][0] = zm<T>;
     237             :     cvout.derivs[2][1] = zp<T>;
     238      106175 :     cvout.values[2] = distance[2];
     239      106175 :     ColvarInput<T>::setBoxDerivativesNoPbc( cvin, cvout );
     240     2633816 :   } else if(cvin.mode==components::scaled) {
     241          41 :     auto d=cvin.pbc.realToScaled(distance);
     242          41 :     cvout.derivs[0][0].copyConv(matmul(cvin.pbc.getInvBox(),xm<T>));
     243          41 :     cvout.derivs[0][1].copyConv(matmul(cvin.pbc.getInvBox(),xp<T>));
     244          41 :     cvout.values[0] = Tools::pbc(d[0]);
     245          41 :     cvout.derivs[1][0].copyConv(matmul(cvin.pbc.getInvBox(),ym<T>));
     246          41 :     cvout.derivs[1][1].copyConv(matmul(cvin.pbc.getInvBox(),yp<T>));
     247          41 :     cvout.values[1] = Tools::pbc(d[1]);
     248          41 :     cvout.derivs[2][0].copyConv(matmul(cvin.pbc.getInvBox(),zm<T>));
     249          41 :     cvout.derivs[2][1].copyConv(matmul(cvin.pbc.getInvBox(),zp<T>));
     250          41 :     cvout.values[2] = Tools::pbc(d[2]);
     251     2633775 :   } else if(cvin.mode==components::squared) {
     252             :     const double value=distance.modulo2();
     253             :     cvout.derivs[0][0] = -2*distance;
     254             :     cvout.derivs[0][1] = 2*distance;
     255       13400 :     ColvarInput<T>::setBoxDerivativesNoPbc( cvin, cvout );
     256       13400 :     cvout.values[0] = value;
     257             :   } else {
     258     2620375 :     const double value=distance.modulo();
     259     2620375 :     const double invvalue=1.0/value;
     260     2620375 :     cvout.derivs[0][0] = -invvalue*distance;
     261             :     cvout.derivs[0][1] = invvalue*distance;
     262     2620375 :     ColvarInput<T>::setBoxDerivativesNoPbc( cvin, cvout );
     263     2620375 :     cvout.values[0] = value;
     264             :   }
     265     2739991 : }
     266             : 
     267             : } //namespace colvar
     268             : } //namespace PLMD
     269             : 
     270             : #endif //__PLUMED_colvar_Distance_h
     271             : 
     272             : 

Generated by: LCOV version 1.16