1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2012-2021 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 "ActionRegister.h"
24 
25 
26 using namespace std;
27 
28 
29 namespace PLMD {
30 namespace bias {
31 
32 //+PLUMEDOC BIAS LOWER_WALLS
33 /*
34 Defines a wall for the value of one or more collective variables,
35  which limits the region of the phase space accessible during the simulation.
36 
37 The restraining potential starts acting on the system when the value of the CV is greater
38 (in the case of UPPER_WALLS) or lower (in the case of LOWER_WALLS) than a certain limit \f$a_i\f$ (AT)
39 minus an offset \f$o_i\f$ (OFFSET).
40 The expression for the bias due to the wall is given by:
41 
42 \f$
43   \sum_i {k_i}((x_i-a_i+o_i)/s_i)^e_i
44 \f$
45 
46 \f$k_i\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s_i\f$ (EPS) a rescaling factor and
47 \f$e_i\f$ (EXP) the exponent determining the power law. By default: EXP = 2, EPS = 1.0, OFFSET = 0.
48 
49 
50 \par Examples
51 
52 The following input tells plumed to add both a lower and an upper walls on the distance
53 between atoms 3 and 5 and the distance between atoms 2 and 4. The lower and upper limits
54 are defined at different values. The strength of the walls is the same for the four cases.
55 It also tells plumed to print the energy of the walls.
56 \plumedfile
57 DISTANCE ATOMS=3,5 LABEL=d1
58 DISTANCE ATOMS=2,4 LABEL=d2
59 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
60 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
61 PRINT ARG=uwall.bias,lwall.bias
62 \endplumedfile
63 (See also \ref DISTANCE and \ref PRINT).
64 
65 */
66 //+ENDPLUMEDOC
67 
68 class LWalls : public Bias {
69   std::vector<double> at;
70   std::vector<double> kappa;
71   std::vector<double> exp;
72   std::vector<double> eps;
73   std::vector<double> offset;
74 public:
75   explicit LWalls(const ActionOptions&);
76   void calculate() override;
77   static void registerKeywords(Keywords& keys);
78 };
79 
80 PLUMED_REGISTER_ACTION(LWalls,"LOWER_WALLS")
81 
registerKeywords(Keywords & keys)82 void LWalls::registerKeywords(Keywords& keys) {
83   Bias::registerKeywords(keys);
84   keys.use("ARG");
85   keys.add("compulsory","AT","the positions of the wall. The a_i in the expression for a wall.");
86   keys.add("compulsory","KAPPA","the force constant for the wall.  The k_i in the expression for a wall.");
87   keys.add("compulsory","OFFSET","0.0","the offset for the start of the wall.  The o_i in the expression for a wall.");
88   keys.add("compulsory","EXP","2.0","the powers for the walls.  The e_i in the expression for a wall.");
89   keys.add("compulsory","EPS","1.0","the values for s_i in the expression for a wall");
90   keys.addOutputComponent("force2","default","the instantaneous value of the squared force due to this bias potential");
91 }
92 
LWalls(const ActionOptions & ao)93 LWalls::LWalls(const ActionOptions&ao):
94   PLUMED_BIAS_INIT(ao),
95   at(getNumberOfArguments(),0),
96   kappa(getNumberOfArguments(),0.0),
97   exp(getNumberOfArguments(),2.0),
98   eps(getNumberOfArguments(),1.0),
99   offset(getNumberOfArguments(),0.0)
100 {
101   // Note sizes of these vectors are automatically checked by parseVector :-)
102   parseVector("OFFSET",offset);
103   parseVector("EPS",eps);
104   parseVector("EXP",exp);
105   parseVector("KAPPA",kappa);
106   parseVector("AT",at);
107   checkRead();
108 
109   log.printf("  at");
110   for(unsigned i=0; i<at.size(); i++) log.printf(" %f",at[i]);
111   log.printf("\n");
112   log.printf("  with an offset");
113   for(unsigned i=0; i<offset.size(); i++) log.printf(" %f",offset[i]);
114   log.printf("\n");
115   log.printf("  with force constant");
116   for(unsigned i=0; i<kappa.size(); i++) log.printf(" %f",kappa[i]);
117   log.printf("\n");
118   log.printf("  and exponent");
119   for(unsigned i=0; i<exp.size(); i++) log.printf(" %f",exp[i]);
120   log.printf("\n");
121   log.printf("  rescaled");
122   for(unsigned i=0; i<eps.size(); i++) log.printf(" %f",eps[i]);
123   log.printf("\n");
124 
125   addComponent("force2"); componentIsNotPeriodic("force2");
126 }
127 
calculate()128 void LWalls::calculate() {
129   double ene = 0.0;
130   double totf2 = 0.0;
131   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
132     double f = 0.0;
133     const double cv=difference(i,at[i],getArgument(i));
134     const double off=offset[i];
135     const double epsilon=eps[i];
136     const double lscale = (cv-off)/epsilon;
137     if( lscale < 0.) {
138       const double k=kappa[i];
139       const double exponent=exp[i];
140       double power = pow( lscale, exponent );
141       f = -( k / epsilon ) * exponent * power / lscale;
142       ene += k * power;
143       totf2 += f * f;
144     }
145     setOutputForce(i,f);
146   }
147   setBias(ene);
148   getPntrToComponent("force2")->set(totf2);
149 }
150 
151 }
152 }
153