LCOV - code coverage report
Current view: top level - bias - ABMD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 77 79 97.5 %
Date: 2026-11-05 10:19:04 Functions: 3 4 75.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             : #include "Bias.h"
      23             : #include "tools/Random.h"
      24             : #include "core/ActionRegister.h"
      25             : #include <ctime>
      26             : 
      27             : namespace PLMD {
      28             : namespace bias {
      29             : 
      30             : //+PLUMEDOC BIAS ABMD
      31             : /*
      32             : Adds a ratchet-and-pawl like restraint on one or more variables.
      33             : 
      34             : This action can be used to evolve a system towards a target value in
      35             : CV space using an harmonic potential that moves with the thermal fluctuations of the CV.
      36             : This method was introduced in the papers cited below.  In it the biasing potential in this
      37             : method is as follows:
      38             : 
      39             : $$
      40             : V(\rho(t)) = \left \{ \begin{array}{ll} \frac{K}{2}\left(\rho(t)-\rho_m(t)\right)^2, &\rho(t)>\rho_m(t)\\
      41             :               0, & \rho(t)\le\rho_m(t), \end{array} \right .
      42             : $$
      43             : 
      44             : where
      45             : 
      46             : $$
      47             : \rho(t)=\left(CV(t)-TO\right)^2
      48             : $$
      49             : 
      50             : and
      51             : 
      52             : $$
      53             : \rho_m(t)=\min_{0\le\tau\le t}\rho(\tau)+\eta(t)
      54             : $$.
      55             : 
      56             : The method is based on the introduction of a biasing potential which is zero when
      57             : the system is moving towards the desired arrival point and which damps the
      58             : fluctuations when the system attempts to move in the opposite direction. As in the
      59             : case of the ratchet and pawl system, propelled by thermal motion of the solvent
      60             : molecules, the biasing potential does not exert work on the system. $\eta(t)$ is
      61             : an additional white noise acting on the minimum position of the bias.
      62             : 
      63             : ## Examples
      64             : 
      65             : The following input sets up two biases, one on the distance between atoms 3 and 5
      66             : and another on the distance between atoms 2 and 4. The two target values are defined
      67             : using TO and the two strength using KAPPA. The total energy of the bias is printed.
      68             : 
      69             : ```plumed
      70             : DISTANCE ATOMS=3,5 LABEL=d1
      71             : DISTANCE ATOMS=2,4 LABEL=d2
      72             : ABMD ARG=d1,d2 TO=1.0,1.5 KAPPA=5.0,5.0 LABEL=abmd
      73             : PRINT ARG=abmd.bias,abmd.d1_min,abmd.d2_min
      74             : ```
      75             : 
      76             : */
      77             : //+ENDPLUMEDOC
      78             : 
      79             : class ABMD : public Bias {
      80             :   std::vector<double> to;
      81             :   std::vector<double> min;
      82             :   std::vector<double> kappa;
      83             :   std::vector<double> temp;
      84             :   std::vector<int> seed;
      85             :   std::vector<Random> random;
      86             : public:
      87             :   explicit ABMD(const ActionOptions&);
      88             :   void calculate() override;
      89             :   static void registerKeywords(Keywords& keys);
      90             : };
      91             : 
      92             : PLUMED_REGISTER_ACTION(ABMD,"ABMD")
      93             : 
      94           7 : void ABMD::registerKeywords(Keywords& keys) {
      95           7 :   Bias::registerKeywords(keys);
      96           7 :   keys.add("compulsory","TO","The array of target values");
      97           7 :   keys.add("compulsory","KAPPA","The array of force constants.");
      98           7 :   keys.add("optional","MIN","Array of starting values for the bias (set rho_m(t), otherwise it is set using the current value of ARG)");
      99           7 :   keys.add("optional","NOISE","Array of white noise intensities (add a temperature to the ABMD)");
     100           7 :   keys.add("optional","SEED","Array of seeds for the white noise (add a temperature to the ABMD)");
     101          14 :   keys.addOutputComponent("force2","default","scalar","the instantaneous value of the squared force due to this bias potential");
     102          14 :   keys.addOutputComponent("_min","default","scalar","one or multiple instances of this quantity can be referenced elsewhere in the input file. "
     103             :                           " These quantities will be named with the arguments of the bias followed by "
     104             :                           "the character string _min. These quantities tell the user the minimum value assumed by rho_m(t).");
     105           7 :   keys.addDOI("10.1063/1.478259");
     106           7 :   keys.addDOI("10.1016/j.bpj.2010.01.047");
     107           7 :   keys.addDOI("10.1063/1.3523345");
     108           7 : }
     109             : 
     110           3 : ABMD::ABMD(const ActionOptions&ao):
     111             :   PLUMED_BIAS_INIT(ao),
     112           6 :   to(getNumberOfArguments(),0.0),
     113           3 :   min(getNumberOfArguments(),-1.0),
     114           3 :   kappa(getNumberOfArguments(),0.0),
     115           3 :   temp(getNumberOfArguments(),0.0),
     116           3 :   seed(getNumberOfArguments(),std::time(0)),
     117           6 :   random(getNumberOfArguments()) {
     118             :   // Note : parseVector will check that number of arguments is correct
     119           3 :   parseVector("KAPPA",kappa);
     120           6 :   parseVector("MIN",min);
     121           3 :   if(min.size()==0) {
     122           2 :     min.assign(getNumberOfArguments(),-1.0);
     123             :   }
     124           3 :   if(min.size()!=getNumberOfArguments()) {
     125           0 :     error("MIN array should have the same size as ARG array");
     126             :   }
     127             :   // optional keywords that are not given leave an empty vector: restore the defaults
     128             :   // (the code below read temp[i] and seed[i] out of bounds without NOISE or SEED)
     129           6 :   parseVector("NOISE",temp);
     130           3 :   if(temp.size()==0) {
     131           1 :     temp.assign(getNumberOfArguments(),0.0);
     132             :   }
     133           6 :   parseVector("SEED",seed);
     134           3 :   if(seed.size()==0) {
     135           1 :     seed.assign(getNumberOfArguments(),std::time(0));
     136             :   }
     137           3 :   parseVector("TO",to);
     138           3 :   checkRead();
     139             : 
     140           3 :   log.printf("  min");
     141           6 :   for(unsigned i=0; i<min.size(); i++) {
     142           3 :     log.printf(" %f",min[i]);
     143             :   }
     144           3 :   log.printf("\n");
     145           3 :   log.printf("  to");
     146           6 :   for(unsigned i=0; i<to.size(); i++) {
     147           3 :     log.printf(" %f",to[i]);
     148             :   }
     149           3 :   log.printf("\n");
     150           3 :   log.printf("  with force constant");
     151           6 :   for(unsigned i=0; i<kappa.size(); i++) {
     152           3 :     log.printf(" %f",kappa[i]);
     153             :   }
     154           3 :   log.printf("\n");
     155             : 
     156           6 :   for(unsigned i=0; i<getNumberOfArguments(); i++) {
     157           3 :     std::string str_min=getPntrToArgument(i)->getName()+"_min";
     158           3 :     addComponent(str_min);
     159           3 :     componentIsNotPeriodic(str_min);
     160           3 :     if(min[i]!=-1.0) {
     161           1 :       getPntrToComponent(str_min)->set(min[i]);
     162             :     }
     163             :   }
     164           6 :   for(unsigned i=0; i<getNumberOfArguments(); i++) {
     165           3 :     random[i].setSeed(-seed[i]);
     166             :   }
     167           6 :   addComponent("force2");
     168           3 :   componentIsNotPeriodic("force2");
     169           3 : }
     170             : 
     171             : 
     172          68 : void ABMD::calculate() {
     173             :   double ene=0.0;
     174             :   double totf2=0.0;
     175         136 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     176          68 :     const double cv=difference(i,to[i],getArgument(i));
     177          68 :     const double cv2=cv*cv;
     178          68 :     const double k=kappa[i];
     179             :     double noise=0.;
     180          68 :     double diff=temp[i];
     181          68 :     if(diff>0) {
     182           5 :       noise = 2.*random[i].Gaussian()*diff;
     183           5 :       if(cv2<=diff) {
     184             :         diff=0.;
     185           0 :         temp[i]=0.;
     186             :       }
     187             :     }
     188             : 
     189             :     // min < 0 means that the variable has not been used in the input file, so the current position of the CV is used
     190             :     // cv2 < min means that the collective variable is nearer to the target value than at any other previous time so
     191             :     // min is set to the CV value
     192          68 :     if(min[i]<0.||cv2<min[i]) {
     193          10 :       min[i] = cv2;
     194          10 :       setOutputForce(i,0.0);
     195             :     } else {
     196             :       // otherwise a noise is added to the minimum value
     197          58 :       min[i] += noise;
     198          58 :       const double f = -2.*k*(cv2-min[i])*cv;
     199          58 :       setOutputForce(i,f);
     200          58 :       ene += 0.5*k*(cv2-min[i])*(cv2-min[i]);
     201          58 :       totf2+=f*f;
     202             :     }
     203          68 :     getPntrToComponent(i+1)->set(min[i]);
     204             :   }
     205          68 :   setBias(ene);
     206          68 :   getPntrToComponent("force2")->set(totf2);
     207          68 : }
     208             : 
     209             : }
     210             : }
     211             : 
     212             : 

Generated by: LCOV version 1.16