2525namespace PLMD {
2626namespace bias {
2727
28+ // +PLUMEDOC BIAS UPPER_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+ If the inputs to the arguments are scalars the restraining potential starts acting on the system when the value of the CV is greater
34+ than a certain limit $a_i$ (AT) minus an offset $o_i$ (OFFSET). The expression for the bias due to the wall is given by:
35+
36+ $$
37+ \sum_i {k_i}((x_i-a_i+o_i)/s_i)^e_i
38+ $$
39+
40+ In this expression $k_i$ (KAPPA) is an energy constant in internal unit of the code, $s_i$ (EPS) a rescaling factor and
41+ $e_i$ (EXP) the exponent determining the power law. By default: EXP = 2, EPS = 1.0, OFFSET = 0.
42+
43+ The following input tells plumed to add both a lower and an upper walls on the distance
44+ between atoms 3 and 5 and the distance between atoms 2 and 4. The lower and upper limits
45+ are defined at different values. The strength of the walls is the same for the four cases.
46+ It also tells plumed to print the energy of the walls.
47+
48+ ```plumed
49+ d1: DISTANCE ATOMS=3,5
50+ d2: DISTANCE ATOMS=2,4
51+ uwall: UPPER_WALLS ARG=d1,d2 AT=1.0,1.5 KAPPA=150.0,150.0 EXP=2,2 EPS=1,1 OFFSET=0,0
52+ lwall: LOWER_WALLS ARG=d1,d2 AT=0.0,1.0 KAPPA=150.0,150.0 EXP=2,2 EPS=1,1 OFFSET=0,0
53+ PRINT ARG=uwall.bias,lwall.bias
54+ ```
55+
56+ Alternatively, if the input to this action is a vector as in the example shown below:
57+
58+ ```plumed
59+ d1: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6
60+ uwall: UPPER_WALLS ARG=d1 AT=1.0 KAPPA=150.0 EXP=2 EPS=1 OFFSET=0
61+ PRINT ARG=uwall.bias
62+ ```
63+
64+ The bias that acts is given by the following expression:
65+
66+ $$
67+ \sum_i \sum_j {k_i}((x_{ij}-a_i+o_i)/s_i)^e_i
68+ $$
69+
70+ The sum over $i$ here is runs over the two arguments, while the sum over $j$ runs over the three components of the input vectors.
71+ Notice, that regardless of whether the input is a scalar, vector or matrix the number of $k_i$, $a_i$, $o_i$, $e_i$ and $s_i$ values must be
72+ equal to the number of arguments to the action.
73+
74+ */
75+ // +ENDPLUMEDOC
76+
2877// +PLUMEDOC BIAS LOWER_WALLS
2978/*
3079Defines a wall for the value of one or more collective variables,
@@ -74,23 +123,58 @@ equal to the number of arguments to the action.
74123*/
75124// +ENDPLUMEDOC
76125
77- class LWalls : public Bias {
126+ enum class WallType {UPPER ,LOWER };
127+
128+ template <WallType W>
129+ class WallsScalar : public Bias {
78130 std::vector<double > at;
79131 std::vector<double > kappa;
80132 std::vector<double > exp;
81133 std::vector<double > eps;
82134 std::vector<double > offset;
135+ static constexpr auto force2=" force2" ;
136+ inline double walloff (double cv, double off) {
137+ if constexpr (W==WallType::UPPER ) {
138+ return cv+off;
139+ } else {
140+ return cv-off;
141+ }
142+ }
143+ inline double wallpow (double scale, double exponent) {
144+ if constexpr (W==WallType::UPPER ) {
145+ return std::pow (scale,exponent);
146+ } else {
147+ return std::pow (-scale,exponent);
148+ }
149+ }
150+ inline bool check (double scale) {
151+ if constexpr (W==WallType::UPPER ) {
152+ return scale > 0.0 ;
153+ } else {
154+ return scale < 0.0 ;
155+ }
156+ }
83157public:
84- explicit LWalls (const ActionOptions&);
158+ explicit WallsScalar (const ActionOptions&);
85159 void calculate () override ;
86160 static void registerKeywords (Keywords& keys);
87161};
88162
163+ using UWalls = WallsScalar<WallType::UPPER >;
164+ PLUMED_REGISTER_ACTION (UWalls," UPPER_WALLS_SCALAR" )
165+
166+ using LWalls = WallsScalar<WallType::LOWER >;
89167PLUMED_REGISTER_ACTION (LWalls," LOWER_WALLS_SCALAR" )
90168
91- void LWalls::registerKeywords (Keywords& keys) {
169+ template <WallType W>
170+ void WallsScalar<W>::registerKeywords(Keywords& keys) {
92171 Bias::registerKeywords (keys);
93- keys.setDisplayName (" LOWER_WALLS" );
172+ if constexpr (W==WallType::UPPER ) {
173+ keys.setDisplayName (" UPPER_WALLS" );
174+ } else {
175+ keys.setDisplayName (" LOWER_WALLS" );
176+ }
177+
94178 keys.add (" hidden" ," NO_ACTION_LOG" ," suppresses printing from action on the log" );
95179 keys.add (" compulsory" ," AT" ," the positions of the wall. The a_i in the expression for a wall." );
96180 keys.add (" compulsory" ," KAPPA" ," the force constant for the wall. The k_i in the expression for a wall." );
@@ -100,7 +184,8 @@ void LWalls::registerKeywords(Keywords& keys) {
100184 keys.addOutputComponent (" force2" ," default" ," scalar" ," the instantaneous value of the squared force due to this bias potential" );
101185}
102186
103- LWalls::LWalls (const ActionOptions&ao):
187+ template <WallType W>
188+ WallsScalar<W>::WallsScalar(const ActionOptions&ao):
104189 PLUMED_BIAS_INIT (ao),
105190 at(getNumberOfArguments(),0),
106191 kappa(getNumberOfArguments(),0.0),
@@ -141,31 +226,34 @@ LWalls::LWalls(const ActionOptions&ao):
141226 }
142227 log.printf (" \n " );
143228
144- addComponent (" force2" );
145- componentIsNotPeriodic (" force2" );
229+ addComponent (force2);
230+ componentIsNotPeriodic (force2);
146231}
147232
148- void LWalls::calculate () {
233+
234+
235+ template <WallType W>
236+ void WallsScalar<W>::calculate() {
149237 double ene = 0.0 ;
150238 double totf2 = 0.0 ;
151239 for (unsigned i=0 ; i<getNumberOfArguments (); ++i) {
152240 double f = 0.0 ;
153241 const double cv=difference (i,at[i],getArgument (i));
154242 const double off=offset[i];
155243 const double epsilon=eps[i];
156- const double lscale = (cv- off)/epsilon;
157- if ( lscale < 0 . ) {
244+ const double scale = walloff (cv, off)/epsilon;
245+ if ( check (scale) ) {
158246 const double k=kappa[i];
159247 const double exponent=exp[i];
160- double power = std::pow ( -lscale , exponent );
161- f = -( k / epsilon ) * exponent * power / lscale ;
248+ double power = wallpow ( scale , exponent );
249+ f = -( k / epsilon ) * exponent * power / scale ;
162250 ene += k * power;
163251 totf2 += f * f;
164252 }
165253 setOutputForce (i,f);
166254 }
167255 setBias (ene);
168- getPntrToComponent (" force2" )->set (totf2);
256+ getPntrToComponent (force2)->set (totf2);
169257}
170258
171259}
0 commit comments