LCOV - code coverage report
Current view: top level - colvar - Distance.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 120 120 100.0 %
Date: 2024-10-18 14:00:25 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/Pbc.h"
      27             : 
      28             : namespace PLMD {
      29             : namespace colvar {
      30             : 
      31             : //+PLUMEDOC COLVAR DISTANCE
      32             : /*
      33             : Calculate the distance between a pair of atoms.
      34             : 
      35             : By default the distance is computed taking into account periodic
      36             : boundary conditions. This behavior can be changed with the NOPBC flag.
      37             : Moreover, single components in Cartesian space (x,y, and z, with COMPONENTS)
      38             : or single components projected to the three lattice vectors (a,b, and c, with SCALED_COMPONENTS)
      39             : can be also computed.
      40             : 
      41             : Notice that Cartesian components will not have the proper periodicity!
      42             : If you have to study e.g. the permeation of a molecule across a membrane,
      43             : better to use SCALED_COMPONENTS.
      44             : 
      45             : \par Examples
      46             : 
      47             : The following input tells plumed to print the distance between atoms 3 and 5,
      48             : the distance between atoms 2 and 4 and the x component of the distance between atoms 2 and 4.
      49             : \plumedfile
      50             : d1:  DISTANCE ATOMS=3,5
      51             : d2:  DISTANCE ATOMS=2,4
      52             : d2c: DISTANCE ATOMS=2,4 COMPONENTS
      53             : PRINT ARG=d1,d2,d2c.x
      54             : \endplumedfile
      55             : 
      56             : The following input computes the end-to-end distance for a polymer
      57             : of 100 atoms and keeps it at a value around 5.
      58             : \plumedfile
      59             : WHOLEMOLECULES ENTITY0=1-100
      60             : e2e: DISTANCE ATOMS=1,100 NOPBC
      61             : RESTRAINT ARG=e2e KAPPA=1 AT=5
      62             : \endplumedfile
      63             : 
      64             : Notice that NOPBC is used
      65             : to be sure that if the end-to-end distance is larger than half the simulation
      66             : box the distance is compute properly. Also notice that, since many MD
      67             : codes break molecules across cell boundary, it might be necessary to
      68             : use the \ref WHOLEMOLECULES keyword (also notice that it should be
      69             : _before_ distance). The list of atoms provided to \ref WHOLEMOLECULES
      70             : here contains all the atoms between 1 and 100. Strictly speaking, this
      71             : is not necessary. If you know for sure that atoms with difference in
      72             : the index say equal to 10 are _not_ going to be farther than half cell
      73             : you can e.g. use
      74             : \plumedfile
      75             : WHOLEMOLECULES ENTITY0=1,10,20,30,40,50,60,70,80,90,100
      76             : e2e: DISTANCE ATOMS=1,100 NOPBC
      77             : RESTRAINT ARG=e2e KAPPA=1 AT=5
      78             : \endplumedfile
      79             : Just be sure that the ordered list provide to \ref WHOLEMOLECULES has the following
      80             : properties:
      81             : - Consecutive atoms should be closer than half-cell throughout the entire simulation.
      82             : - Atoms required later for the distance (e.g. 1 and 100) should be included in the list
      83             : 
      84             : The following example shows how to take into account periodicity e.g.
      85             : in z-component of a distance
      86             : \plumedfile
      87             : # this is a center of mass of a large group
      88             : c: COM ATOMS=1-100
      89             : # this is the distance between atom 101 and the group
      90             : d: DISTANCE ATOMS=c,101 COMPONENTS
      91             : # this makes a new variable, dd, equal to d and periodic, with domain -10,10
      92             : # this is the right choise if e.g. the cell is orthorombic and its size in
      93             : # z direction is 20.
      94             : dz: COMBINE ARG=d.z PERIODIC=-10,10
      95             : # metadynamics on dd
      96             : METAD ARG=dz SIGMA=0.1 HEIGHT=0.1 PACE=200
      97             : \endplumedfile
      98             : 
      99             : Using SCALED_COMPONENTS this problem should not arise because they are always periodic
     100             : with domain (-0.5,+0.5).
     101             : 
     102             : 
     103             : 
     104             : 
     105             : */
     106             : //+ENDPLUMEDOC
     107             : 
     108             : //+PLUMEDOC MCOLVAR DISTANCE_SCALAR
     109             : /*
     110             : Calculate the distance between a pair of atoms
     111             : 
     112             : \par Examples
     113             : 
     114             : */
     115             : //+ENDPLUMEDOC
     116             : 
     117             : //+PLUMEDOC MCOLVAR DISTANCE_VECTOR
     118             : /*
     119             : Calculate a vector containing the distances between various pairs of atoms
     120             : 
     121             : \par Examples
     122             : 
     123             : */
     124             : //+ENDPLUMEDOC
     125             : 
     126             : class Distance : public Colvar {
     127             :   bool components;
     128             :   bool scaled_components;
     129             :   bool pbc;
     130             : 
     131             :   std::vector<double> value, masses, charges;
     132             :   std::vector<std::vector<Vector> > derivs;
     133             :   std::vector<Tensor> virial;
     134             : public:
     135             :   static void registerKeywords( Keywords& keys );
     136             :   explicit Distance(const ActionOptions&);
     137             :   static void parseAtomList( const int& num, std::vector<AtomNumber>& t, ActionAtomistic* aa );
     138             :   static unsigned getModeAndSetupValues( ActionWithValue* av );
     139             : // active methods:
     140             :   void calculate() override;
     141             :   static void calculateCV( const unsigned& mode, const std::vector<double>& masses, const std::vector<double>& charges,
     142             :                            const std::vector<Vector>& pos, std::vector<double>& vals, std::vector<std::vector<Vector> >& derivs,
     143             :                            std::vector<Tensor>& virial, const ActionAtomistic* aa );
     144             : };
     145             : 
     146             : typedef ColvarShortcut<Distance> DistanceShortcut;
     147             : PLUMED_REGISTER_ACTION(DistanceShortcut,"DISTANCE")
     148             : PLUMED_REGISTER_ACTION(Distance,"DISTANCE_SCALAR")
     149             : typedef MultiColvarTemplate<Distance> DistanceMulti;
     150             : PLUMED_REGISTER_ACTION(DistanceMulti,"DISTANCE_VECTOR")
     151             : 
     152        2380 : void Distance::registerKeywords( Keywords& keys ) {
     153        2380 :   Colvar::registerKeywords( keys ); keys.setDisplayName("DISTANCE");
     154        4760 :   keys.add("atoms","ATOMS","the pair of atom that we are calculating the distance between");
     155        4760 :   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");
     156        4760 :   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");
     157        4760 :   keys.addOutputComponent("x","COMPONENTS","the x-component of the vector connecting the two atoms");
     158        4760 :   keys.addOutputComponent("y","COMPONENTS","the y-component of the vector connecting the two atoms");
     159        4760 :   keys.addOutputComponent("z","COMPONENTS","the z-component of the vector connecting the two atoms");
     160        4760 :   keys.addOutputComponent("a","SCALED_COMPONENTS","the normalized projection on the first lattice vector of the vector connecting the two atoms");
     161        4760 :   keys.addOutputComponent("b","SCALED_COMPONENTS","the normalized projection on the second lattice vector of the vector connecting the two atoms");
     162        4760 :   keys.addOutputComponent("c","SCALED_COMPONENTS","the normalized projection on the third lattice vector of the vector connecting the two atoms");
     163        4760 :   keys.add("hidden","NO_ACTION_LOG","suppresses printing from action on the log");
     164        2380 :   keys.setValueDescription("the DISTANCE between this pair of atoms");
     165        2380 : }
     166             : 
     167         623 : Distance::Distance(const ActionOptions&ao):
     168             :   PLUMED_COLVAR_INIT(ao),
     169         623 :   components(false),
     170         623 :   scaled_components(false),
     171         623 :   pbc(true),
     172         623 :   value(1),
     173         625 :   derivs(1),
     174        1246 :   virial(1)
     175             : {
     176         623 :   derivs[0].resize(2);
     177             :   std::vector<AtomNumber> atoms;
     178         623 :   parseAtomList(-1,atoms,this);
     179         623 :   if(atoms.size()!=2)
     180           1 :     error("Number of specified atoms should be 2");
     181             : 
     182         622 :   bool nopbc=!pbc;
     183         624 :   parseFlag("NOPBC",nopbc);
     184         622 :   pbc=!nopbc;
     185             : 
     186         622 :   if(pbc) log.printf("  using periodic boundary conditions\n");
     187           4 :   else    log.printf("  without periodic boundary conditions\n");
     188             : 
     189         622 :   unsigned mode = getModeAndSetupValues( this );
     190         621 :   if(mode==1) components=true; else if(mode==2) scaled_components=true;
     191         621 :   if( components || scaled_components ) {
     192          40 :     value.resize(3); derivs.resize(3); virial.resize(3);
     193         160 :     for(unsigned i=0; i<3; ++i) derivs[i].resize(2);
     194             :   }
     195         621 :   requestAtoms(atoms);
     196         627 : }
     197             : 
     198       30941 : void Distance::parseAtomList( const int& num, std::vector<AtomNumber>& t, ActionAtomistic* aa ) {
     199       61882 :   aa->parseAtomList("ATOMS",num,t);
     200       30941 :   if( t.size()==2 ) aa->log.printf("  between atoms %d %d\n",t[0].serial(),t[1].serial());
     201       30941 : }
     202             : 
     203         730 : unsigned Distance::getModeAndSetupValues( ActionWithValue* av ) {
     204         730 :   bool c; av->parseFlag("COMPONENTS",c);
     205         730 :   bool sc; av->parseFlag("SCALED_COMPONENTS",sc);
     206         730 :   if( c && sc ) av->error("COMPONENTS and SCALED_COMPONENTS are not compatible");
     207             : 
     208         729 :   if(c) {
     209         160 :     av->addComponentWithDerivatives("x"); av->componentIsNotPeriodic("x");
     210         160 :     av->addComponentWithDerivatives("y"); av->componentIsNotPeriodic("y");
     211         160 :     av->addComponentWithDerivatives("z"); av->componentIsNotPeriodic("z");
     212          80 :     av->log<<"  WARNING: components will not have the proper periodicity - see manual\n";
     213          80 :     return 1;
     214         649 :   } else if(sc) {
     215          18 :     av->addComponentWithDerivatives("a"); av->componentIsPeriodic("a","-0.5","+0.5");
     216          18 :     av->addComponentWithDerivatives("b"); av->componentIsPeriodic("b","-0.5","+0.5");
     217          18 :     av->addComponentWithDerivatives("c"); av->componentIsPeriodic("c","-0.5","+0.5");
     218           6 :     return 2;
     219             :   }
     220        1286 :   av->addValueWithDerivatives(); av->setNotPeriodic();
     221             :   return 0;
     222             : }
     223             : 
     224             : // calculator
     225       74406 : void Distance::calculate() {
     226             : 
     227       74406 :   if(pbc) makeWhole();
     228             : 
     229       74406 :   if( components ) {
     230         409 :     calculateCV( 1, masses, charges, getPositions(), value, derivs, virial, this );
     231         409 :     Value* valuex=getPntrToComponent("x");
     232         409 :     Value* valuey=getPntrToComponent("y");
     233         409 :     Value* valuez=getPntrToComponent("z");
     234             : 
     235        1227 :     for(unsigned i=0; i<2; ++i) setAtomsDerivatives(valuex,i,derivs[0][i] );
     236         409 :     setBoxDerivatives(valuex,virial[0]);
     237         409 :     valuex->set(value[0]);
     238             : 
     239        1227 :     for(unsigned i=0; i<2; ++i) setAtomsDerivatives(valuey,i,derivs[1][i] );
     240         409 :     setBoxDerivatives(valuey,virial[1]);
     241         409 :     valuey->set(value[1]);
     242             : 
     243        1227 :     for(unsigned i=0; i<2; ++i) setAtomsDerivatives(valuez,i,derivs[2][i] );
     244         409 :     setBoxDerivatives(valuez,virial[2]);
     245         409 :     valuez->set(value[2]);
     246       73997 :   } else if( scaled_components ) {
     247          26 :     calculateCV( 2, masses, charges, getPositions(), value, derivs, virial, this );
     248             : 
     249          26 :     Value* valuea=getPntrToComponent("a");
     250          26 :     Value* valueb=getPntrToComponent("b");
     251          26 :     Value* valuec=getPntrToComponent("c");
     252          78 :     for(unsigned i=0; i<2; ++i) setAtomsDerivatives(valuea,i,derivs[0][i] );
     253          26 :     valuea->set(value[0]);
     254          78 :     for(unsigned i=0; i<2; ++i) setAtomsDerivatives(valueb,i,derivs[1][i] );
     255          26 :     valueb->set(value[1]);
     256          78 :     for(unsigned i=0; i<2; ++i) setAtomsDerivatives(valuec,i,derivs[2][i] );
     257          26 :     valuec->set(value[2]);
     258             :   } else  {
     259       73971 :     calculateCV( 0, masses, charges, getPositions(), value, derivs, virial, this );
     260      221913 :     for(unsigned i=0; i<2; ++i) setAtomsDerivatives(i,derivs[0][i] );
     261       73971 :     setBoxDerivatives(virial[0]);
     262       73971 :     setValue           (value[0]);
     263             :   }
     264       74406 : }
     265             : 
     266      406099 : void Distance::calculateCV( const unsigned& mode, const std::vector<double>& masses, const std::vector<double>& charges,
     267             :                             const std::vector<Vector>& pos, std::vector<double>& vals, std::vector<std::vector<Vector> >& derivs,
     268             :                             std::vector<Tensor>& virial, const ActionAtomistic* aa ) {
     269      406099 :   Vector distance=delta(pos[0],pos[1]);
     270      406099 :   const double value=distance.modulo();
     271      406099 :   const double invvalue=1.0/value;
     272             : 
     273      406099 :   if(mode==1) {
     274       94377 :     derivs[0][0] = Vector(-1,0,0);
     275       94377 :     derivs[0][1] = Vector(+1,0,0);
     276       94377 :     vals[0] = distance[0];
     277             : 
     278       94377 :     derivs[1][0] = Vector(0,-1,0);
     279       94377 :     derivs[1][1] = Vector(0,+1,0);
     280       94377 :     vals[1] = distance[1];
     281             : 
     282       94377 :     derivs[2][0] = Vector(0,0,-1);
     283       94377 :     derivs[2][1] = Vector(0,0,+1);
     284       94377 :     vals[2] = distance[2];
     285       94377 :     setBoxDerivativesNoPbc( pos, derivs, virial );
     286      311722 :   } else if(mode==2) {
     287          41 :     Vector d=aa->getPbc().realToScaled(distance);
     288          41 :     derivs[0][0] = matmul(aa->getPbc().getInvBox(),Vector(-1,0,0));
     289          41 :     derivs[0][1] = matmul(aa->getPbc().getInvBox(),Vector(+1,0,0));
     290          41 :     vals[0] = Tools::pbc(d[0]);
     291          41 :     derivs[1][0] = matmul(aa->getPbc().getInvBox(),Vector(0,-1,0));
     292          41 :     derivs[1][1] = matmul(aa->getPbc().getInvBox(),Vector(0,+1,0));
     293          41 :     vals[1] = Tools::pbc(d[1]);
     294          41 :     derivs[2][0] = matmul(aa->getPbc().getInvBox(),Vector(0,0,-1));
     295          41 :     derivs[2][1] = matmul(aa->getPbc().getInvBox(),Vector(0,0,+1));
     296          41 :     vals[2] = Tools::pbc(d[2]);
     297             :   } else {
     298      311681 :     derivs[0][0] = -invvalue*distance;
     299      311681 :     derivs[0][1] = invvalue*distance;
     300      311681 :     setBoxDerivativesNoPbc( pos, derivs, virial );
     301      311681 :     vals[0] = value;
     302             :   }
     303      406099 : }
     304             : 
     305             : }
     306             : }
     307             : 
     308             : 
     309             : 

Generated by: LCOV version 1.16