LCOV - code coverage report
Current view: top level - bias - LWalls.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 69 70 98.6 %
Date: 2026-11-12 10:48:31 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-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 "core/ActionRegister.h"
      24             : 
      25             : namespace PLMD {
      26             : namespace bias {
      27             : 
      28             : //+PLUMEDOC BIAS LOWER_WALLS
      29             : /*
      30             : Defines a wall for the value of one or more collective variables,
      31             :  which limits the region of the phase space accessible during the simulation.
      32             : 
      33             : The restraining potential starts acting on the system when the value of the CV is greater
      34             : (in the case of UPPER_WALLS) or lower (in the case of LOWER_WALLS) than a certain limit \f$a_i\f$ (AT)
      35             : minus an offset \f$o_i\f$ (OFFSET).
      36             : The expression for the bias due to the wall is given by:
      37             : 
      38             : for UPPER_WALLS:
      39             : \f$
      40             :   \sum_i {k_i}((x_i-a_i+o_i)/s_i)^e_i
      41             : \f$
      42             : 
      43             : for LOWER_WALLS:
      44             : \f$
      45             :   \sum_i {k_i}|(x_i-a_i-o_i)/s_i|^e_i
      46             : \f$
      47             : 
      48             : \f$k_i\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s_i\f$ (EPS) a rescaling factor and
      49             : \f$e_i\f$ (EXP) the exponent determining the power law. By default: EXP = 2, EPS = 1.0, OFFSET = 0.
      50             : 
      51             : 
      52             : \par Examples
      53             : 
      54             : The following input tells plumed to add both a lower and an upper walls on the distance
      55             : between atoms 3 and 5 and the distance between atoms 2 and 4. The lower and upper limits
      56             : are defined at different values. The strength of the walls is the same for the four cases.
      57             : It also tells plumed to print the energy of the walls.
      58             : \plumedfile
      59             : DISTANCE ATOMS=3,5 LABEL=d1
      60             : DISTANCE ATOMS=2,4 LABEL=d2
      61             : UPPER_WALLS ARG=d1,d2 AT=1.0,1.5 KAPPA=150.0,150.0 EXP=2,2 EPS=1,1 OFFSET=0,0 LABEL=uwall
      62             : LOWER_WALLS ARG=d1,d2 AT=0.0,1.0 KAPPA=150.0,150.0 EXP=2,2 EPS=1,1 OFFSET=0,0 LABEL=lwall
      63             : PRINT ARG=uwall.bias,lwall.bias
      64             : \endplumedfile
      65             : (See also \ref DISTANCE and \ref PRINT).
      66             : 
      67             : 
      68             : \par Periodic arguments
      69             : 
      70             : If an argument is periodic (e.g. a \ref TORSION), the wall acts on the value of the argument in its periodic domain
      71             : and periodic boundary conditions are __not__ applied to the difference \f$x_i-a_i\f$. The value of AT must thus be within the
      72             : periodic domain of the argument. This is the case both when the arguments are scalars and when they are vectors.
      73             : The following input restrains a torsion within the interval \f$[-2,2]\f$:
      74             : \plumedfile
      75             : t: TORSION ATOMS=1,2,3,4
      76             : uwall: UPPER_WALLS ARG=t AT=2.0 KAPPA=150.0
      77             : lwall: LOWER_WALLS ARG=t AT=-2.0 KAPPA=150.0
      78             : PRINT ARG=t,uwall.bias,lwall.bias
      79             : \endplumedfile
      80             : 
      81             : Notice that the bias is discontinuous at the boundary of the periodic domain (here at \f$\pm\pi\f$). You should thus make sure that
      82             : the walls keep the argument far from this boundary, e.g. by using both an upper and a lower wall as in the input above.
      83             : 
      84             : Versions of PLUMED before 2.9.7 applied periodic boundary conditions to the difference \f$x_i-a_i\f$. With that choice, each wall acts on half of the
      85             : periodic domain, and the region left free by an upper and a lower wall is smaller than the one between AT values
      86             : (see \issue{658}).
      87             : 
      88             : */
      89             : //+ENDPLUMEDOC
      90             : 
      91             : //+PLUMEDOC BIAS LOWER_WALLS_SCALAR
      92             : /*
      93             : Defines a wall for the value of one or more collective variables,
      94             :  which limits the region of the phase space accessible during the simulation.
      95             : 
      96             : \par Examples
      97             : 
      98             : */
      99             : //+ENDPLUMEDOC
     100             : 
     101             : class LWalls : public Bias {
     102             :   std::vector<double> at;
     103             :   std::vector<double> kappa;
     104             :   std::vector<double> exp;
     105             :   std::vector<double> eps;
     106             :   std::vector<double> offset;
     107             : public:
     108             :   explicit LWalls(const ActionOptions&);
     109             :   void calculate() override;
     110             :   static void registerKeywords(Keywords& keys);
     111             : };
     112             : 
     113             : PLUMED_REGISTER_ACTION(LWalls,"LOWER_WALLS_SCALAR")
     114             : 
     115          20 : void LWalls::registerKeywords(Keywords& keys) {
     116          20 :   Bias::registerKeywords(keys);
     117          20 :   keys.setDisplayName("LOWER_WALLS");
     118          20 :   keys.use("ARG");
     119          40 :   keys.add("hidden","NO_ACTION_LOG","suppresses printing from action on the log");
     120          40 :   keys.add("compulsory","AT","the positions of the wall. The a_i in the expression for a wall.");
     121          40 :   keys.add("compulsory","KAPPA","the force constant for the wall.  The k_i in the expression for a wall.");
     122          40 :   keys.add("compulsory","OFFSET","0.0","the offset for the start of the wall.  The o_i in the expression for a wall.");
     123          40 :   keys.add("compulsory","EXP","2.0","the powers for the walls.  The e_i in the expression for a wall.");
     124          40 :   keys.add("compulsory","EPS","1.0","the values for s_i in the expression for a wall");
     125          40 :   keys.addOutputComponent("force2","default","the instantaneous value of the squared force due to this bias potential");
     126          20 : }
     127             : 
     128           8 : LWalls::LWalls(const ActionOptions&ao):
     129             :   PLUMED_BIAS_INIT(ao),
     130          16 :   at(getNumberOfArguments(),0),
     131           8 :   kappa(getNumberOfArguments(),0.0),
     132           8 :   exp(getNumberOfArguments(),2.0),
     133           8 :   eps(getNumberOfArguments(),1.0),
     134          16 :   offset(getNumberOfArguments(),0.0) {
     135             :   // Note sizes of these vectors are automatically checked by parseVector :-)
     136           8 :   parseVector("OFFSET",offset);
     137           8 :   parseVector("EPS",eps);
     138           8 :   parseVector("EXP",exp);
     139           8 :   parseVector("KAPPA",kappa);
     140           8 :   parseVector("AT",at);
     141           8 :   checkRead();
     142             : 
     143           8 :   log.printf("  at");
     144          18 :   for(unsigned i=0; i<at.size(); i++) {
     145          10 :     log.printf(" %f",at[i]);
     146             :   }
     147           8 :   log.printf("\n");
     148           8 :   log.printf("  with an offset");
     149          18 :   for(unsigned i=0; i<offset.size(); i++) {
     150          10 :     log.printf(" %f",offset[i]);
     151             :   }
     152           8 :   log.printf("\n");
     153           8 :   log.printf("  with force constant");
     154          18 :   for(unsigned i=0; i<kappa.size(); i++) {
     155          10 :     log.printf(" %f",kappa[i]);
     156             :   }
     157           8 :   log.printf("\n");
     158           8 :   log.printf("  and exponent");
     159          18 :   for(unsigned i=0; i<exp.size(); i++) {
     160          10 :     log.printf(" %f",exp[i]);
     161             :   }
     162           8 :   log.printf("\n");
     163           8 :   log.printf("  rescaled");
     164          18 :   for(unsigned i=0; i<eps.size(); i++) {
     165          10 :     log.printf(" %f",eps[i]);
     166             :   }
     167           8 :   log.printf("\n");
     168             : 
     169             :   // The wall acts on the value of the argument in its domain, without periodic images
     170             :   // (see https://github.com/plumed/plumed2/issues/658).
     171          18 :   for(unsigned i=0; i<getNumberOfArguments(); i++) {
     172             :     Value* arg=getPntrToArgument(i);
     173          10 :     if( arg->isPeriodic() ) {
     174             :       double min, max;
     175           4 :       arg->getDomain( min, max );
     176           4 :       if( at[i]<min || at[i]>max ) {
     177           0 :         error("the position of the wall (AT) for periodic argument " + arg->getName() + " should be within its periodic domain");
     178             :       }
     179           4 :       log.printf("  WARNING: argument %s is periodic. The wall acts on its value in the domain [%f,%f]\n"
     180             :                  "    without periodic images, so the bias is discontinuous at the boundary of the domain.\n"
     181             :                  "    Make sure that the walls keep the argument far from it (e.g. use both an upper and a lower wall).\n",
     182             :                  arg->getName().c_str(), min, max );
     183             :     }
     184             :   }
     185             : 
     186          16 :   addComponent("force2");
     187           8 :   componentIsNotPeriodic("force2");
     188           8 : }
     189             : 
     190         117 : void LWalls::calculate() {
     191             :   double ene = 0.0;
     192             :   double totf2 = 0.0;
     193         298 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     194             :     double f = 0.0;
     195             :     // no periodic boundary conditions here, see the documentation and issue #658
     196         181 :     const double cv=getArgument(i)-at[i];
     197         181 :     const double off=offset[i];
     198         181 :     const double epsilon=eps[i];
     199         181 :     const double lscale = (cv-off)/epsilon;
     200         181 :     if( lscale < 0.) {
     201          76 :       const double k=kappa[i];
     202          76 :       const double exponent=exp[i];
     203          76 :       double power = std::pow( -lscale, exponent );
     204          76 :       f = -( k / epsilon ) * exponent * power / lscale;
     205          76 :       ene += k * power;
     206          76 :       totf2 += f * f;
     207             :     }
     208         181 :     setOutputForce(i,f);
     209             :   }
     210         117 :   setBias(ene);
     211         117 :   getPntrToComponent("force2")->set(totf2);
     212         117 : }
     213             : 
     214             : }
     215             : }

Generated by: LCOV version 1.16