LCOV - code coverage report
Current view: top level - bias - Walls.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 79 89 88.8 %
Date: 2026-11-12 10:48:31 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2020 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 "core/ActionShortcut.h"
      23             : #include "core/ActionWithArguments.h"
      24             : #include "core/PlumedMain.h"
      25             : #include "core/ActionSet.h"
      26             : #include "core/ActionRegister.h"
      27             : #include "tools/Tools.h"
      28             : 
      29             : namespace PLMD {
      30             : namespace bias {
      31             : 
      32             : class Walls : public ActionShortcut {
      33             : public:
      34             :   explicit Walls(const ActionOptions&);
      35             :   static void registerKeywords(Keywords& keys);
      36             : };
      37             : 
      38             : PLUMED_REGISTER_ACTION(Walls,"UPPER_WALLS")
      39             : PLUMED_REGISTER_ACTION(Walls,"LOWER_WALLS")
      40             : 
      41          70 : void Walls::registerKeywords(Keywords& keys) {
      42          70 :   ActionShortcut::registerKeywords(keys);
      43         140 :   keys.add("numbered","ARG","the arguments on which the bias is acting");
      44         140 :   keys.add("compulsory","AT","the positions of the wall. The a_i in the expression for a wall.");
      45         140 :   keys.add("compulsory","KAPPA","the force constant for the wall.  The k_i in the expression for a wall.");
      46         140 :   keys.add("compulsory","OFFSET","0.0","the offset for the start of the wall.  The o_i in the expression for a wall.");
      47         140 :   keys.add("compulsory","EXP","2.0","the powers for the walls.  The e_i in the expression for a wall.");
      48         140 :   keys.add("compulsory","EPS","1.0","the values for s_i in the expression for a wall");
      49         140 :   keys.add("hidden","STRIDE","the frequency with which the forces due to the bias should be calculated.  This can be used to correctly set up multistep algorithms");
      50         140 :   keys.addOutputComponent("bias","default","the instantaneous value of the bias potential");
      51         140 :   keys.addOutputComponent("force2","default","the instantaneous value of the squared force due to this bias potential");
      52          70 :   keys.addActionNameSuffix("_SCALAR");
      53          70 :   keys.needsAction("COMBINE");
      54          70 :   keys.needsAction("CUSTOM");
      55          70 :   keys.needsAction("SUM");
      56          70 :   keys.needsAction("COMBINE");
      57          70 :   keys.needsAction("BIASVALUE");
      58          70 : }
      59             : 
      60          29 : Walls::Walls(const ActionOptions&ao):
      61             :   Action(ao),
      62          29 :   ActionShortcut(ao) {
      63             :   // Read the arguments
      64             :   std::vector<std::string> args;
      65          58 :   parseVector("ARG",args);
      66          29 :   if( args.size()==0 ) {
      67           0 :     error("found no input arguments");
      68             :   }
      69          29 :   std::string allargs=args[0];
      70          33 :   for(unsigned i=1; i<args.size(); ++i) {
      71           8 :     allargs += "," + args[i];
      72             :   }
      73             :   std::vector<Value*> vals;
      74          29 :   ActionWithArguments::interpretArgumentList( args, plumed.getActionSet(), this, vals );
      75          29 :   if( vals.size()==0 ) {
      76           0 :     error("found no input arguments");
      77             :   }
      78             : 
      79             :   // Find the rank
      80          29 :   unsigned rank=vals[0]->getRank();
      81          62 :   for(unsigned i=0; i<vals.size(); ++i) {
      82          33 :     if( vals[i]->getRank()>0 && vals[i]->hasDerivatives() ) {
      83           0 :       error("argument should not be function on grid");
      84             :     }
      85          33 :     if( vals[i]->getRank()!=rank ) {
      86           0 :       error("all arguments should have same rank");
      87             :     }
      88             :   }
      89          29 :   if( rank==0 ) {
      90          25 :     if( getName()=="UPPER_WALLS") {
      91          34 :       readInputLine( getShortcutLabel() + ": UPPER_WALLS_SCALAR ARG=" + allargs + " " + convertInputLineToString() );
      92           8 :     } else if( getName()=="LOWER_WALLS") {
      93          16 :       readInputLine( getShortcutLabel() + ": LOWER_WALLS_SCALAR ARG=" + allargs + " " + convertInputLineToString() );
      94             :     } else {
      95           0 :       plumed_merror( getName() + " is not valid");
      96             :     }
      97             :     return;
      98             :   }
      99             : 
     100             :   // Note : the sizes of these vectors are checked automatically by parseVector
     101           4 :   std::vector<std::string> kappa(args.size());
     102           8 :   parseVector("KAPPA",kappa);
     103           4 :   std::vector<std::string> offset(kappa.size());
     104           8 :   parseVector("OFFSET",offset);
     105           4 :   std::vector<std::string> eps(kappa.size());
     106           8 :   parseVector("EPS",eps);
     107           4 :   std::vector<std::string> exp(kappa.size());
     108           8 :   parseVector("EXP",exp);
     109           4 :   std::vector<std::string> at(kappa.size());
     110           8 :   parseVector("AT",at);
     111             : 
     112             :   std::string biasinp, forceinp;
     113           8 :   for(unsigned i=0; i<args.size(); ++i) {
     114             :     std::string argn;
     115           4 :     std::size_t dot=args[i].find_first_of(".");
     116           4 :     if(dot!=std::string::npos) {
     117           0 :       argn = args[i].substr(0,dot) + "_" + args[i].substr(dot+1);
     118             :     } else {
     119             :       argn = args[i];
     120             :     }
     121             :     // For periodic arguments the wall acts on the value of the argument in its domain, without periodic images
     122             :     // (see https://github.com/plumed/plumed2/issues/658).  COMBINE would apply PBCs to the difference, so CUSTOM is used instead.
     123             :     std::vector<Value*> myvals;
     124           4 :     ActionWithArguments::interpretArgumentList( std::vector<std::string>(1,args[i]), plumed.getActionSet(), this, myvals );
     125             :     bool periodic=false;
     126           8 :     for(unsigned j=0; j<myvals.size(); ++j) {
     127           4 :       if( myvals[j]->isPeriodic() ) {
     128             :         periodic=true;
     129             :         double min, max, atval;
     130           2 :         myvals[j]->getDomain( min, max );
     131           2 :         if( !Tools::convertNoexcept( at[i], atval ) ) {
     132           0 :           error("could not convert " + at[i] + " into a real number");
     133             :         }
     134           2 :         if( atval<min || atval>max ) {
     135           0 :           error("the position of the wall (AT) for periodic argument " + myvals[j]->getName() + " should be within its periodic domain");
     136             :         }
     137           2 :         log.printf("  WARNING: argument %s is periodic. The wall acts on its value in the domain [%f,%f]\n"
     138             :                    "    without periodic images, so the bias is discontinuous at the boundary of the domain.\n"
     139             :                    "    Make sure that the walls keep the argument far from it (e.g. use both an upper and a lower wall).\n",
     140           2 :                    myvals[j]->getName().c_str(), min, max );
     141             :       }
     142             :     }
     143           4 :     if( periodic ) {
     144           4 :       readInputLine( getShortcutLabel() + "_cv_" + argn + ": CUSTOM PERIODIC=NO FUNC=x-(" + at[i] + ") ARG=" + args[i] );
     145             :     } else {
     146           4 :       readInputLine( getShortcutLabel() + "_cv_" + argn + ": COMBINE PERIODIC=NO ARG=" + args[i] + " PARAMETERS=" + at[i] );
     147             :     }
     148           4 :     if( getName()=="UPPER_WALLS" ) {
     149           6 :       readInputLine( getShortcutLabel() + "_scale_" + argn + ": CUSTOM PERIODIC=NO FUNC=(x+" + offset[i] +")/" + eps[i] + " ARG=" + getShortcutLabel() + "_cv_" + argn );
     150           6 :       readInputLine( getShortcutLabel() + "_pow_" + argn + ": CUSTOM PERIODIC=NO FUNC=step(x)*x^" + exp[i] + " ARG=" + getShortcutLabel() + "_scale_" + argn );
     151           1 :     } else if( getName()=="LOWER_WALLS" ) {
     152           2 :       readInputLine( getShortcutLabel() + "_scale_" + argn + ": CUSTOM PERIODIC=NO FUNC=(x-" + offset[i] +")/" + eps[i] + " ARG=" + getShortcutLabel() + "_cv_" + argn );
     153           2 :       readInputLine( getShortcutLabel() + "_pow_" + argn + ": CUSTOM PERIODIC=NO FUNC=step(-x)*(-x)^" + exp[i] + " ARG=" + getShortcutLabel() + "_scale_" + argn );
     154             :     }
     155           8 :     readInputLine( getShortcutLabel() + "_v_wall_" + argn + ": CUSTOM PERIODIC=NO FUNC=" + kappa[i] +"*x" + " ARG=" + getShortcutLabel() + "_pow_" + argn );
     156           8 :     readInputLine( getShortcutLabel() + "_wall_" + argn + ": SUM ARG=" + getShortcutLabel() + "_v_wall_" + argn + " PERIODIC=NO");
     157          12 :     readInputLine( getShortcutLabel() + "_force_" + argn + ": CUSTOM PERIODIC=NO FUNC=" + kappa[i] + "*" + exp[i] + "*x/(y*" + eps[i] + ") " +
     158          12 :                    "ARG=" + getShortcutLabel() + "_pow_" + argn + "," + getShortcutLabel() + "_scale_" + argn );
     159           8 :     readInputLine( getShortcutLabel() + "_v_force2_" + argn + ": CUSTOM PERIODIC=NO FUNC=x*x ARG=" + getShortcutLabel() + "_force_" + argn );
     160           8 :     readInputLine( getShortcutLabel() + "_force2_" + argn + ": SUM ARG=" + getShortcutLabel() + "_v_force2_" + argn + " PERIODIC=NO");
     161           4 :     if(i==0) {
     162           8 :       biasinp = " ARG=" + getShortcutLabel() + "_wall_" + argn;
     163           8 :       forceinp = " ARG=" + getShortcutLabel() + "_force2_" + argn;
     164             :     } else {
     165           0 :       biasinp += "," + getShortcutLabel() + "_wall_" + argn;
     166           0 :       forceinp += "," + getShortcutLabel() + "_force2_" + argn;
     167             :     }
     168             :   }
     169           8 :   readInputLine( getShortcutLabel() + "_bias: COMBINE PERIODIC=NO " + biasinp );
     170           8 :   readInputLine( "BIASVALUE ARG=" + getShortcutLabel() + "_bias" );
     171           8 :   readInputLine( getShortcutLabel() + "_force2: COMBINE PERIODIC=NO " + forceinp  );
     172          33 : }
     173             : 
     174             : }
     175             : }

Generated by: LCOV version 1.16