Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2015-2018 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 : #include "core/ActionSet.h"
25 : #include "tools/Grid.h"
26 : #include "core/PlumedMain.h"
27 : #include "core/Atoms.h"
28 : #include "tools/Exception.h"
29 : #include "tools/Random.h"
30 : #include <string>
31 : #include <cstring>
32 : #include "tools/File.h"
33 : #include "time.h"
34 : #include <iostream>
35 : #include <limits>
36 :
37 : #define DP2CUTOFF 6.25
38 :
39 : using namespace std;
40 :
41 :
42 : namespace PLMD {
43 : namespace bias {
44 :
45 : //+PLUMEDOC BIAS PBMETAD
46 : /*
47 : Used to performed Parallel Bias MetaDynamics.
48 :
49 : This action activate Parallel Bias MetaDynamics (PBMetaD) \cite pbmetad, a version of MetaDynamics \cite metad in which
50 : multiple low-dimensional bias potentials are applied in parallel.
51 : In the current implementation, these have the form of mono-dimensional MetaDynamics bias
52 : potentials:
53 :
54 : \f[
55 : {V(s_1,t), ..., V(s_N,t)}
56 : \f]
57 :
58 : where:
59 :
60 : \f[
61 : V(s_i,t) = \sum_{ k \tau < t} W_i(k \tau)
62 : \exp\left(
63 : - \frac{(s_i-s_i^{(0)}(k \tau))^2}{2\sigma_i^2}
64 : \right).
65 : \f]
66 :
67 : To ensure the convergence of each mono-dimensional bias potential to the corresponding free energy,
68 : at each deposition step the Gaussian heights are multiplied by the so-called conditional term:
69 :
70 : \f[
71 : W_i(k \tau)=W_0 \frac{\exp\left(
72 : - \frac{V(s_i,k \tau)}{k_B T}
73 : \right)}{\sum_{i=1}^N
74 : \exp\left(
75 : - \frac{V(s_i,k \tau)}{k_B T}
76 : \right)}
77 : \f]
78 :
79 : where \f$W_0\f$ is the initial Gaussian height.
80 :
81 : The PBMetaD bias potential is defined by:
82 :
83 : \f[
84 : V_{PB}(\vec{s},t) = -k_B T \log{\sum_{i=1}^N
85 : \exp\left(
86 : - \frac{V(s_i,t)}{k_B T}
87 : \right)}.
88 : \f]
89 :
90 :
91 : Information on the Gaussian functions that build each bias potential are printed to
92 : multiple HILLS files, which
93 : are used both to restart the calculation and to reconstruct the mono-dimensional
94 : free energies as a function of the corresponding CVs.
95 : These can be reconstructed using the \ref sum_hills utility because the final bias is given
96 : by:
97 :
98 : \f[
99 : V(s_i) = -F(s_i)
100 : \f]
101 :
102 : Currently, only a subset of the \ref METAD options are available in PBMetaD.
103 :
104 : The bias potentials can be stored on a grid to increase performances of long PBMetaD simulations.
105 : You should
106 : provide either the number of bins for every collective variable (GRID_BIN) or
107 : the desired grid spacing (GRID_SPACING). In case you provide both PLUMED will use
108 : the most conservative choice (highest number of bins) for each dimension.
109 : In case you do not provide any information about bin size (neither GRID_BIN nor GRID_SPACING)
110 : and if Gaussian width is fixed PLUMED will use 1/5 of the Gaussian width as grid spacing.
111 : This default choice should be reasonable for most applications.
112 :
113 : Another option that is available is well-tempered metadynamics \cite Barducci:2008. In this
114 : variant of PBMetaD the heights of the Gaussian hills are rescaled at each step by the
115 : additional well-tempered metadynamics term.
116 : This ensures that each bias converges more smoothly. It should be noted that, in the case of well-tempered metadynamics, in
117 : the output printed the Gaussian height is re-scaled using the bias factor.
118 : Also notice that with well-tempered metadynamics the HILLS files do not contain the bias,
119 : but the negative of the free-energy estimate. This choice has the advantage that
120 : one can restart a simulation using a different value for the \f$\Delta T\f$. The applied bias will be scaled accordingly.
121 :
122 : With the keyword INTERVAL one changes the metadynamics algorithm setting the bias force equal to zero
123 : outside boundary \cite baftizadeh2012protein. If, for example, metadynamics is performed on a CV s and one is interested only
124 : to the free energy for s > sw, the history dependent potential is still updated according to the above
125 : equations but the metadynamics force is set to zero for s < sw. Notice that Gaussians are added also
126 : if s < sw, as the tails of these Gaussians influence VG in the relevant region s > sw. In this way, the
127 : force on the system in the region s > sw comes from both metadynamics and the force field, in the region
128 : s < sw only from the latter. This approach allows obtaining a history-dependent bias potential VG that
129 : fluctuates around a stable estimator, equal to the negative of the free energy far enough from the
130 : boundaries. Note that:
131 : - It works only for one-dimensional biases;
132 : - It works both with and without GRID;
133 : - The interval limit sw in a region where the free energy derivative is not large;
134 : - If in the region outside the limit sw the system has a free energy minimum, the INTERVAL keyword should
135 : be used together with a \ref UPPER_WALLS or \ref LOWER_WALLS at sw.
136 :
137 : Multiple walkers \cite multiplewalkers can also be used, in the MPI implementation only. See below the examples.
138 :
139 : \par Examples
140 :
141 : The following input is for PBMetaD calculation using as
142 : collective variables the distance between atoms 3 and 5
143 : and the distance between atoms 2 and 4. The value of the CVs and
144 : the PBMetaD bias potential are written to the COLVAR file every 100 steps.
145 : \verbatim
146 : DISTANCE ATOMS=3,5 LABEL=d1
147 : DISTANCE ATOMS=2,4 LABEL=d2
148 : PBMETAD ARG=d1,d2 SIGMA=0.2,0.2 HEIGHT=0.3 PACE=500 LABEL=pb FILE=HILLS_d1,HILLS_d2
149 : PRINT ARG=d1,d2,pb.bias STRIDE=100 FILE=COLVAR
150 : \endverbatim
151 : (See also \ref DISTANCE and \ref PRINT).
152 :
153 : \par
154 : If you use well-tempered metadynamics, you should specify a single biasfactor and initial
155 : Gaussian height.
156 : \verbatim
157 : DISTANCE ATOMS=3,5 LABEL=d1
158 : DISTANCE ATOMS=2,4 LABEL=d2
159 : PBMETAD ...
160 : ARG=d1,d2 SIGMA=0.2,0.2 HEIGHT=0.3
161 : PACE=500 BIASFACTOR=8 LABEL=pb
162 : FILE=HILLS_d1,HILLS_d2
163 : ... PBMETAD
164 : PRINT ARG=d1,d2,pb.bias STRIDE=100 FILE=COLVAR
165 : \endverbatim
166 :
167 : \par
168 : Only the MPI version of multiple-walkers is currently implemented.
169 : \verbatim
170 : DISTANCE ATOMS=3,5 LABEL=d1
171 : DISTANCE ATOMS=2,4 LABEL=d2
172 : PBMETAD ...
173 : ARG=d1,d2 SIGMA=0.2,0.2 HEIGHT=0.3
174 : PACE=500 BIASFACTOR=8 LABEL=pb
175 : FILE=HILLS_d1,HILLS_d2
176 : MULTIPLE_WALKERS
177 : ... PBMETAD
178 : PRINT ARG=d1,d2,pb.bias STRIDE=100 FILE=COLVAR
179 : \endverbatim
180 :
181 : */
182 : //+ENDPLUMEDOC
183 :
184 : class PBMetaD : public Bias {
185 :
186 : private:
187 1068 : struct Gaussian {
188 : vector<double> center;
189 : vector<double> sigma;
190 : double height;
191 192 : Gaussian(const vector<double> & center,const vector<double> & sigma, double height):
192 192 : center(center),sigma(sigma),height(height) {}
193 : };
194 : vector<double> sigma0_;
195 : vector< vector<Gaussian> > hills_;
196 : vector<OFile*> hillsOfiles_;
197 : vector<OFile*> gridfiles_;
198 : vector<Grid*> BiasGrids_;
199 : bool grid_;
200 : double height0_;
201 : double biasf_;
202 : double kbt_;
203 : int stride_;
204 : int wgridstride_;
205 : bool welltemp_;
206 : bool multiple_w;
207 : unsigned nw_;
208 : unsigned mw_;
209 : vector<double> uppI_;
210 : vector<double> lowI_;
211 : vector<bool> doInt_;
212 : bool isFirstStep;
213 :
214 : void readGaussians(unsigned iarg, IFile*);
215 : bool readChunkOfGaussians(unsigned iarg, IFile *ifile, unsigned n);
216 : void writeGaussian(unsigned iarg, const Gaussian&, OFile*);
217 : void addGaussian(unsigned iarg, const Gaussian&);
218 : double getBiasAndDerivatives(unsigned iarg, const vector<double>&, double* der=NULL);
219 : double evaluateGaussian(unsigned iarg, const vector<double>&, const Gaussian&,double* der=NULL);
220 : vector<unsigned> getGaussianSupport(unsigned iarg, const Gaussian&);
221 : bool scanOneHill(unsigned iarg, IFile *ifile, vector<Value> &v, vector<double> ¢er, vector<double> &sigma, double &height);
222 : std::string fmt;
223 :
224 : public:
225 : explicit PBMetaD(const ActionOptions&);
226 : ~PBMetaD();
227 : void calculate();
228 : void update();
229 : static void registerKeywords(Keywords& keys);
230 : };
231 :
232 2529 : PLUMED_REGISTER_ACTION(PBMetaD,"PBMETAD")
233 :
234 7 : void PBMetaD::registerKeywords(Keywords& keys) {
235 7 : Bias::registerKeywords(keys);
236 7 : keys.use("ARG");
237 7 : keys.add("compulsory","SIGMA","the widths of the Gaussian hills");
238 7 : keys.add("compulsory","PACE","the frequency for hill addition, one for all biases");
239 7 : keys.add("optional","FILE","files in which the lists of added hills are stored");
240 7 : keys.add("optional","HEIGHT","the height of the Gaussian hills, one for all biases. Compulsory unless TAU, TEMP and BIASFACTOR are given");
241 7 : keys.add("optional","FMT","specify format for HILLS files (useful for decrease the number of digits in regtests)");
242 7 : keys.add("optional","BIASFACTOR","use well tempered metadynamics with this biasfactor, one for all biases. Please note you must also specify temp");
243 7 : keys.add("optional","TEMP","the system temperature - this is only needed if you are doing well-tempered metadynamics");
244 7 : keys.add("optional","TAU","in well tempered metadynamics, sets height to (kb*DeltaT*pace*timestep)/tau");
245 7 : keys.add("optional","GRID_RFILES", "read grid for the bias");
246 7 : keys.add("optional","GRID_WFILES", "dump grid for the bias");
247 7 : keys.add("optional","GRID_WSTRIDE", "frequency for dumping the grid");
248 7 : keys.add("optional","GRID_MIN","the lower bounds for the grid");
249 7 : keys.add("optional","GRID_MAX","the upper bounds for the grid");
250 7 : keys.add("optional","GRID_BIN","the number of bins for the grid");
251 7 : keys.add("optional","GRID_SPACING","the approximate grid spacing (to be used as an alternative or together with GRID_BIN)");
252 7 : keys.addFlag("GRID_SPARSE",false,"use a sparse grid to store hills");
253 7 : keys.addFlag("GRID_NOSPLINE",false,"don't use spline interpolation with grids");
254 7 : keys.add("optional","INTERVAL_MIN","monodimensional lower limits, outside the limits the system will not feel the biasing force.");
255 7 : keys.add("optional","INTERVAL_MAX","monodimensional upper limits, outside the limits the system will not feel the biasing force.");
256 7 : keys.addFlag("MULTIPLE_WALKERS",false,"Switch on MPI version of multiple walkers");
257 7 : keys.use("RESTART");
258 7 : keys.use("UPDATE_FROM");
259 7 : keys.use("UPDATE_UNTIL");
260 7 : }
261 :
262 24 : PBMetaD::~PBMetaD() {
263 6 : for(unsigned i=0; i<BiasGrids_.size(); ++i) delete BiasGrids_[i];
264 18 : for(unsigned i=0; i<hillsOfiles_.size(); ++i) {
265 12 : hillsOfiles_[i]->close();
266 12 : delete hillsOfiles_[i];
267 : }
268 6 : if(wgridstride_ > 0) {
269 3 : for(unsigned i=0; i<gridfiles_.size(); ++i) {
270 2 : gridfiles_[i]->close();
271 2 : delete gridfiles_[i];
272 : }
273 : }
274 18 : }
275 :
276 6 : PBMetaD::PBMetaD(const ActionOptions& ao):
277 : PLUMED_BIAS_INIT(ao),
278 6 : grid_(false), height0_(std::numeric_limits<double>::max()),
279 : biasf_(1.0), kbt_(0.0), stride_(0), wgridstride_(0), welltemp_(false),
280 12 : multiple_w(false), isFirstStep(true)
281 : {
282 :
283 6 : parse("FMT",fmt);
284 :
285 : // parse the sigma
286 6 : parseVector("SIGMA",sigma0_);
287 6 : if( sigma0_.size()!=getNumberOfArguments() ) error("number of arguments does not match number of SIGMA parameters");
288 :
289 : // note: HEIGHT is not compulsory, since one could use the TAU keyword, see below
290 6 : parse("HEIGHT",height0_);
291 6 : parse("PACE",stride_);
292 6 : if(stride_<=0) error("frequency for hill addition is nonsensical");
293 :
294 6 : vector<string> hillsfname;
295 6 : parseVector("FILE",hillsfname);
296 6 : if(hillsfname.size()==0) {
297 0 : for(unsigned i=0; i<getNumberOfArguments(); i++) hillsfname.push_back("HILLS."+getPntrToArgument(i)->getName());
298 : }
299 6 : if( hillsfname.size()!=getNumberOfArguments() ) {
300 0 : error("number of FILE arguments does not match number of HILLS files");
301 : }
302 :
303 6 : parse("BIASFACTOR",biasf_);
304 6 : if( biasf_<1.0 ) error("well tempered bias factor is nonsensical");
305 6 : double temp=0.0;
306 6 : parse("TEMP",temp);
307 6 : if(temp>0.0) kbt_=plumed.getAtoms().getKBoltzmann()*temp;
308 0 : else kbt_=plumed.getAtoms().getKbT();
309 6 : if(biasf_>1.0) {
310 5 : if(kbt_==0.0) error("Unless the MD engine passes the temperature to plumed, with well-tempered metad you must specify it using TEMP");
311 5 : welltemp_=true;
312 : }
313 6 : double tau=0.0;
314 6 : parse("TAU",tau);
315 6 : if(tau==0.0) {
316 6 : if(height0_==std::numeric_limits<double>::max()) error("At least one between HEIGHT and TAU should be specified");
317 : // if tau is not set, we compute it here from the other input parameters
318 6 : if(welltemp_) tau=(kbt_*(biasf_-1.0))/height0_*getTimeStep()*stride_;
319 : } else {
320 0 : if(!welltemp_)error("TAU only makes sense in well-tempered metadynamics");
321 0 : if(height0_!=std::numeric_limits<double>::max()) error("At most one between HEIGHT and TAU should be specified");
322 0 : height0_=(kbt_*(biasf_-1.0))/tau*getTimeStep()*stride_;
323 : }
324 :
325 : // MPI version
326 6 : parseFlag("MULTIPLE_WALKERS",multiple_w);
327 :
328 : // Grid file
329 12 : vector<string> gridfilenames_;
330 6 : parseVector("GRID_WFILES",gridfilenames_);
331 6 : parse("GRID_WSTRIDE",wgridstride_);
332 6 : if (wgridstride_ == 0 && gridfilenames_.size() > 0) {
333 0 : error("frequency with which to output grid not specified use GRID_WSTRIDE");
334 : }
335 6 : if(gridfilenames_.size() > 0 && hillsfname.size() > 0 && gridfilenames_.size() != hillsfname.size())
336 0 : error("number of GRID_WFILES arguments does not match number of HILLS files");
337 :
338 : // Read grid
339 12 : vector<string> gridreadfilenames_;
340 6 : parseVector("GRID_RFILES",gridreadfilenames_);
341 :
342 : // Grid Stuff
343 12 : vector<std::string> gmin(getNumberOfArguments());
344 6 : parseVector("GRID_MIN",gmin);
345 6 : if(gmin.size()!=getNumberOfArguments() && gmin.size()!=0) error("not enough values for GRID_MIN");
346 12 : vector<std::string> gmax(getNumberOfArguments());
347 6 : parseVector("GRID_MAX",gmax);
348 6 : if(gmax.size()!=getNumberOfArguments() && gmax.size()!=0) error("not enough values for GRID_MAX");
349 12 : vector<unsigned> gbin(getNumberOfArguments());
350 12 : vector<double> gspacing;
351 6 : parseVector("GRID_BIN",gbin);
352 6 : if(gbin.size()!=getNumberOfArguments() && gbin.size()!=0) error("not enough values for GRID_BIN");
353 6 : parseVector("GRID_SPACING",gspacing);
354 6 : if(gspacing.size()!=getNumberOfArguments() && gspacing.size()!=0) error("not enough values for GRID_SPACING");
355 6 : if(gmin.size()!=gmax.size()) error("GRID_MAX and GRID_MIN should be either present or absent");
356 6 : if(gspacing.size()!=0 && gmin.size()==0) error("If GRID_SPACING is present also GRID_MIN should be present");
357 6 : if(gbin.size()!=0 && gmin.size()==0) error("If GRID_SPACING is present also GRID_MIN should be present");
358 6 : if(gmin.size()!=0) {
359 1 : if(gbin.size()==0 && gspacing.size()==0) {
360 1 : log<<" Binsize not specified, 1/10 of sigma will be be used\n";
361 1 : plumed_assert(sigma0_.size()==getNumberOfArguments());
362 1 : gspacing.resize(getNumberOfArguments());
363 1 : for(unsigned i=0; i<gspacing.size(); i++) gspacing[i]=0.1*sigma0_[i];
364 0 : } else if(gspacing.size()!=0 && gbin.size()==0) {
365 0 : log<<" The number of bins will be estimated from GRID_SPACING\n";
366 0 : } else if(gspacing.size()!=0 && gbin.size()!=0) {
367 0 : log<<" You specified both GRID_BIN and GRID_SPACING\n";
368 0 : log<<" The more conservative (highest) number of bins will be used for each variable\n";
369 : }
370 1 : if(gbin.size()==0) gbin.assign(getNumberOfArguments(),1);
371 3 : if(gspacing.size()!=0) for(unsigned i=0; i<getNumberOfArguments(); i++) {
372 : double a,b;
373 2 : Tools::convert(gmin[i],a);
374 2 : Tools::convert(gmax[i],b);
375 2 : unsigned n=((b-a)/gspacing[i])+1;
376 2 : if(gbin[i]<n) gbin[i]=n;
377 : }
378 : }
379 6 : bool sparsegrid=false;
380 6 : parseFlag("GRID_SPARSE",sparsegrid);
381 6 : bool nospline=false;
382 6 : parseFlag("GRID_NOSPLINE",nospline);
383 6 : bool spline=!nospline;
384 6 : if(gbin.size()>0) {grid_=true;}
385 6 : if(!grid_&&gridfilenames_.size() > 0) error("To write a grid you need first to define it!");
386 6 : if(!grid_&&gridreadfilenames_.size() > 0) error("To read a grid you need first to define it!");
387 :
388 6 : doInt_.resize(getNumberOfArguments(),false);
389 : // Interval keyword
390 6 : parseVector("INTERVAL_MIN",lowI_);
391 6 : parseVector("INTERVAL_MAX",uppI_);
392 : // various checks
393 6 : if(lowI_.size()!=uppI_.size()) error("both a lower and an upper limits must be provided with INTERVAL");
394 6 : if(lowI_.size()!=0 && lowI_.size()!=getNumberOfArguments()) error("check number of argument of INTERVAL");
395 6 : for(unsigned i=0; i<lowI_.size(); ++i) {
396 0 : if(uppI_[i]<lowI_[i]) error("The Upper limit must be greater than the Lower limit!");
397 0 : if(getPntrToArgument(i)->isPeriodic()) warning("INTERVAL is not used for periodic variables");
398 0 : else doInt_[i]=true;
399 : }
400 :
401 6 : checkRead();
402 :
403 6 : log.printf(" Gaussian width ");
404 6 : for(unsigned i=0; i<sigma0_.size(); ++i) log.printf(" %f",sigma0_[i]);
405 6 : log.printf(" Gaussian height %f\n",height0_);
406 6 : log.printf(" Gaussian deposition pace %d\n",stride_);
407 :
408 6 : log.printf(" Gaussian files ");
409 6 : for(unsigned i=0; i<hillsfname.size(); ++i) log.printf("%s ",hillsfname[i].c_str());
410 6 : log.printf("\n");
411 6 : if(welltemp_) {
412 5 : log.printf(" Well-Tempered Bias Factor %f\n",biasf_);
413 5 : log.printf(" Hills relaxation time (tau) %f\n",tau);
414 5 : log.printf(" KbT %f\n",kbt_);
415 : }
416 6 : if(multiple_w) log.printf(" Multiple walkers active using MPI communnication\n");
417 18 : for(unsigned i=0; i<doInt_.size(); i++) {
418 12 : if(doInt_[i]) log.printf(" Upper and Lower limits boundaries for the bias of CV %u are activated\n", i);
419 : }
420 6 : if(grid_) {
421 1 : log.printf(" Grid min");
422 1 : for(unsigned i=0; i<gmin.size(); ++i) log.printf(" %s",gmin[i].c_str() );
423 1 : log.printf("\n");
424 1 : log.printf(" Grid max");
425 1 : for(unsigned i=0; i<gmax.size(); ++i) log.printf(" %s",gmax[i].c_str() );
426 1 : log.printf("\n");
427 1 : log.printf(" Grid bin");
428 1 : for(unsigned i=0; i<gbin.size(); ++i) log.printf(" %u",gbin[i]);
429 1 : log.printf("\n");
430 1 : if(spline) {log.printf(" Grid uses spline interpolation\n");}
431 1 : if(sparsegrid) {log.printf(" Grid uses sparse grid\n");}
432 1 : if(wgridstride_>0) {
433 3 : for(unsigned i=0; i<gridfilenames_.size(); ++i) {
434 2 : log.printf(" Grid is written on file %s with stride %d\n",gridfilenames_[i].c_str(),wgridstride_);
435 : }
436 : }
437 1 : if(gridreadfilenames_.size()>0) {
438 0 : for(unsigned i=0; i<gridreadfilenames_.size(); ++i) {
439 0 : log.printf(" Reading bias from grid in file %s \n",gridreadfilenames_[i].c_str());
440 : }
441 : }
442 : }
443 :
444 : // initializing vector of hills
445 6 : hills_.resize(getNumberOfArguments());
446 :
447 : // restart from external grid
448 6 : bool restartedFromGrid=false;
449 :
450 : // initializing and checking grid
451 6 : if(grid_) {
452 : // check for mesh and sigma size
453 3 : for(unsigned i=0; i<getNumberOfArguments(); i++) {
454 : double a,b;
455 2 : Tools::convert(gmin[i],a);
456 2 : Tools::convert(gmax[i],b);
457 2 : double mesh=(b-a)/((double)gbin[i]);
458 2 : if(mesh>0.5*sigma0_[i]) log<<" WARNING: Using a METAD with a Grid Spacing larger than half of the Gaussians width can produce artifacts\n";
459 : }
460 1 : std::string funcl=getLabel() + ".bias";
461 3 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
462 2 : std::vector<Value*> args(1);
463 2 : args[0] = getPntrToArgument(i);
464 4 : vector<std::string> gmin_t(1);
465 4 : vector<std::string> gmax_t(1);
466 4 : vector<unsigned> gbin_t(1);
467 2 : gmin_t[0] = gmin[i];
468 2 : gmax_t[0] = gmax[i];
469 2 : gbin_t[0] = gbin[i];
470 : Grid* BiasGrid_;
471 : // Read grid from file
472 2 : if(gridreadfilenames_.size()>0) {
473 0 : IFile gridfile;
474 0 : gridfile.link(*this);
475 0 : if(gridfile.FileExist(gridreadfilenames_[i])) {
476 0 : gridfile.open(gridreadfilenames_[i]);
477 : } else {
478 0 : error("The GRID file you want to read: " + gridreadfilenames_[i] + ", cannot be found!");
479 : }
480 0 : string funcl = getLabel() + ".bias";
481 0 : BiasGrid_ = Grid::create(funcl, args, gridfile, gmin_t, gmax_t, gbin_t, sparsegrid, spline, true);
482 0 : gridfile.close();
483 0 : if(BiasGrid_->getDimension() != args.size()) {
484 0 : error("mismatch between dimensionality of input grid and number of arguments");
485 : }
486 0 : if(getPntrToArgument(i)->isPeriodic() != BiasGrid_->getIsPeriodic()[0]) {
487 0 : error("periodicity mismatch between arguments and input bias");
488 : }
489 0 : log.printf(" Restarting from %s:",gridreadfilenames_[i].c_str());
490 0 : if(getRestart()) restartedFromGrid=true;
491 : } else {
492 2 : if(!sparsegrid) {BiasGrid_=new Grid(funcl,args,gmin_t,gmax_t,gbin_t,spline,true);}
493 0 : else {BiasGrid_=new SparseGrid(funcl,args,gmin_t,gmax_t,gbin_t,spline,true);}
494 2 : std::vector<std::string> actualmin=BiasGrid_->getMin();
495 4 : std::vector<std::string> actualmax=BiasGrid_->getMax();
496 2 : if(gmin_t[0]!=actualmin[0]) log<<" WARNING: GRID_MIN["<<i<<"] has been adjusted to "<<actualmin[0]<<" to fit periodicity\n";
497 4 : if(gmax_t[0]!=actualmax[0]) log<<" WARNING: GRID_MAX["<<i<<"] has been adjusted to "<<actualmax[0]<<" to fit periodicity\n";
498 : }
499 2 : BiasGrids_.push_back(BiasGrid_);
500 3 : }
501 : }
502 :
503 : // read Gaussians if restarting
504 6 : if (!restartedFromGrid) {
505 18 : for(unsigned i=0; i<hillsfname.size(); ++i) {
506 12 : IFile *ifile = new IFile();
507 12 : ifile->link(*this);
508 12 : if(ifile->FileExist(hillsfname[i])) {
509 0 : ifile->open(hillsfname[i]);
510 0 : if(getRestart()) {
511 0 : log.printf(" Restarting from %s:",hillsfname[i].c_str());
512 0 : readGaussians(i, ifile);
513 : }
514 0 : ifile->reset(false);
515 0 : ifile->close();
516 0 : delete ifile;
517 : }
518 : }
519 : }
520 :
521 6 : comm.Barrier();
522 : // this barrier is needed when using walkers_mpi
523 : // to be sure that all files have been read before
524 : // backing them up
525 : // it should not be used when walkers_mpi is false otherwise
526 : // it would introduce troubles when using replicas without METAD
527 : // (e.g. in bias exchange with a neutral replica)
528 : // see issue #168 on github
529 6 : if(multiple_w) {
530 4 : if(comm.Get_rank()==0) {
531 2 : multi_sim_comm.Barrier();
532 2 : nw_ = multi_sim_comm.Get_size();
533 2 : mw_ = multi_sim_comm.Get_rank();
534 : }
535 4 : comm.Bcast(nw_,0);
536 4 : comm.Bcast(mw_,0);
537 : }
538 :
539 : // open hills files for writing
540 18 : for(unsigned i=0; i<hillsfname.size(); ++i) {
541 12 : OFile *ofile = new OFile();
542 12 : ofile->link(*this);
543 12 : string hillsfname_tmp = hillsfname[i];
544 : // if multiple walkers, only rank 0 will write to file
545 12 : if(multiple_w) {
546 8 : int r=0;
547 8 : if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank();
548 8 : comm.Bcast(r,0);
549 8 : if(r>0) hillsfname_tmp="/dev/null";
550 8 : ofile->enforceSuffix("");
551 : }
552 12 : ofile->open(hillsfname_tmp);
553 12 : if(fmt.length()>0) ofile->fmtField(fmt);
554 12 : ofile->addConstantField("multivariate");
555 12 : if(doInt_[i]) {
556 0 : ofile->addConstantField("lower_int").printField("lower_int",lowI_[i]);
557 0 : ofile->addConstantField("upper_int").printField("upper_int",uppI_[i]);
558 : }
559 12 : ofile->setHeavyFlush();
560 : // output periodicities of variables
561 12 : ofile->setupPrintValue( getPntrToArgument(i) );
562 : // push back
563 12 : hillsOfiles_.push_back(ofile);
564 12 : }
565 :
566 : // Dump grid to files
567 6 : if(wgridstride_ > 0) {
568 3 : for(unsigned i = 0; i < gridfilenames_.size(); ++i) {
569 2 : OFile *ofile = new OFile();
570 2 : ofile->link(*this);
571 2 : string gridfname_tmp = gridfilenames_[i];
572 2 : if(multiple_w) {
573 0 : int r = 0;
574 0 : if(comm.Get_rank() == 0) {
575 0 : r = multi_sim_comm.Get_rank();
576 : }
577 0 : comm.Bcast(r, 0);
578 0 : if(r>0) {
579 0 : gridfname_tmp = "/dev/null";
580 : }
581 0 : ofile->enforceSuffix("");
582 : }
583 2 : ofile->open(gridfname_tmp);
584 2 : ofile->setHeavyFlush();
585 2 : gridfiles_.push_back(ofile);
586 2 : }
587 : }
588 :
589 6 : log<<" Bibliography "<<plumed.cite("Pfaendtner and Bonomi. J. Chem. Theory Comput. 11, 5062 (2015)");
590 6 : if(doInt_[0]) log<<plumed.cite(
591 0 : "Baftizadeh, Cossio, Pietrucci, and Laio, Curr. Phys. Chem. 2, 79 (2012)");
592 6 : if(multiple_w) log<<plumed.cite(
593 4 : "Raiteri, Laio, Gervasio, Micheletti, and Parrinello, J. Phys. Chem. B 110, 3533 (2006)");
594 12 : log<<"\n";
595 6 : }
596 :
597 0 : void PBMetaD::readGaussians(unsigned iarg, IFile *ifile) {
598 0 : vector<double> center(1);
599 0 : vector<double> sigma(1);
600 : double height;
601 0 : int nhills=0;
602 :
603 0 : std::vector<Value> tmpvalues;
604 0 : tmpvalues.push_back( Value( this, getPntrToArgument(iarg)->getName(), false ) );
605 :
606 0 : while(scanOneHill(iarg,ifile,tmpvalues,center,sigma,height)) {
607 : ;
608 0 : nhills++;
609 0 : if(welltemp_) {height*=(biasf_-1.0)/biasf_;}
610 0 : addGaussian(iarg, Gaussian(center,sigma,height));
611 : }
612 0 : log.printf(" %d Gaussians read\n",nhills);
613 0 : }
614 :
615 0 : bool PBMetaD::readChunkOfGaussians(unsigned iarg, IFile *ifile, unsigned n) {
616 0 : vector<double> center(1);
617 0 : vector<double> sigma(1);
618 : double height;
619 0 : unsigned nhills=0;
620 0 : std::vector<Value> tmpvalues;
621 0 : tmpvalues.push_back( Value( this, getPntrToArgument(iarg)->getName(), false ) );
622 :
623 0 : while(scanOneHill(iarg,ifile,tmpvalues,center,sigma,height)) {
624 : ;
625 0 : if(welltemp_) {height*=(biasf_-1.0)/biasf_;}
626 0 : addGaussian(iarg, Gaussian(center,sigma,height));
627 0 : if(nhills==n) {
628 0 : log.printf(" %u Gaussians read\n",nhills);
629 0 : return true;
630 : }
631 0 : nhills++;
632 : }
633 0 : log.printf(" %u Gaussians read\n",nhills);
634 0 : return false;
635 : }
636 :
637 192 : void PBMetaD::writeGaussian(unsigned iarg, const Gaussian& hill, OFile *ofile) {
638 192 : ofile->printField("time",getTimeStep()*getStep());
639 192 : ofile->printField(getPntrToArgument(iarg),hill.center[0]);
640 192 : ofile->printField("multivariate","false");
641 192 : ofile->printField("sigma_"+getPntrToArgument(iarg)->getName(),hill.sigma[0]);
642 192 : double height=hill.height;
643 192 : if(welltemp_) {height *= biasf_/(biasf_-1.0);}
644 192 : ofile->printField("height",height);
645 192 : ofile->printField("biasf",biasf_);
646 192 : ofile->printField();
647 192 : }
648 :
649 192 : void PBMetaD::addGaussian(unsigned iarg, const Gaussian& hill) {
650 192 : if(!grid_) {hills_[iarg].push_back(hill);}
651 : else {
652 8 : vector<unsigned> nneighb=getGaussianSupport(iarg, hill);
653 16 : vector<Grid::index_t> neighbors=BiasGrids_[iarg]->getNeighbors(hill.center,nneighb);
654 16 : vector<double> der(1);
655 16 : vector<double> xx(1);
656 8 : if(comm.Get_size()==1) {
657 592 : for(unsigned i=0; i<neighbors.size(); ++i) {
658 584 : Grid::index_t ineigh=neighbors[i];
659 584 : der[0]=0.0;
660 584 : BiasGrids_[iarg]->getPoint(ineigh,xx);
661 584 : double bias=evaluateGaussian(iarg,xx,hill,&der[0]);
662 584 : BiasGrids_[iarg]->addValueAndDerivatives(ineigh,bias,der);
663 : }
664 : } else {
665 0 : unsigned stride=comm.Get_size();
666 0 : unsigned rank=comm.Get_rank();
667 0 : vector<double> allder(neighbors.size(),0.0);
668 0 : vector<double> allbias(neighbors.size(),0.0);
669 0 : for(unsigned i=rank; i<neighbors.size(); i+=stride) {
670 0 : Grid::index_t ineigh=neighbors[i];
671 0 : BiasGrids_[iarg]->getPoint(ineigh,xx);
672 0 : allbias[i]=evaluateGaussian(iarg,xx,hill,&allder[i]);
673 : }
674 0 : comm.Sum(allbias);
675 0 : comm.Sum(allder);
676 0 : for(unsigned i=0; i<neighbors.size(); ++i) {
677 0 : Grid::index_t ineigh=neighbors[i];
678 0 : der[0]=allder[i];
679 0 : BiasGrids_[iarg]->addValueAndDerivatives(ineigh,allbias[i],der);
680 0 : }
681 8 : }
682 : }
683 192 : }
684 :
685 8 : vector<unsigned> PBMetaD::getGaussianSupport(unsigned iarg, const Gaussian& hill) {
686 8 : vector<unsigned> nneigh;
687 8 : const double cutoff=sqrt(2.0*DP2CUTOFF)*hill.sigma[0];
688 8 : if(doInt_[iarg]) {
689 0 : if(hill.center[0]+cutoff > uppI_[iarg] || hill.center[0]-cutoff < lowI_[iarg]) {
690 : // in this case, we updated the entire grid to avoid problems
691 0 : return BiasGrids_[iarg]->getNbin();
692 : } else {
693 0 : nneigh.push_back( static_cast<unsigned>(ceil(cutoff/BiasGrids_[iarg]->getDx()[0])));
694 0 : return nneigh;
695 : }
696 : }
697 :
698 8 : nneigh.push_back( static_cast<unsigned>(ceil(cutoff/BiasGrids_[iarg]->getDx()[0])) );
699 :
700 8 : return nneigh;
701 : }
702 :
703 220 : double PBMetaD::getBiasAndDerivatives(unsigned iarg, const vector<double>& cv, double* der)
704 : {
705 220 : double bias=0.0;
706 220 : if(!grid_) {
707 202 : unsigned stride=comm.Get_size();
708 202 : unsigned rank=comm.Get_rank();
709 1106 : for(unsigned i=rank; i<hills_[iarg].size(); i+=stride) {
710 904 : bias += evaluateGaussian(iarg,cv,hills_[iarg][i],der);
711 : }
712 202 : comm.Sum(bias);
713 202 : if(der) comm.Sum(der,1);
714 : } else {
715 18 : if(der) {
716 10 : vector<double> vder(1);
717 10 : bias = BiasGrids_[iarg]->getValueAndDerivatives(cv,vder);
718 10 : der[0] = vder[0];
719 : } else {
720 8 : bias = BiasGrids_[iarg]->getValue(cv);
721 : }
722 : }
723 :
724 220 : return bias;
725 : }
726 :
727 1488 : double PBMetaD::evaluateGaussian(unsigned iarg, const vector<double>& cv, const Gaussian& hill, double* der)
728 : {
729 1488 : double bias=0.0;
730 : // I use a pointer here because cv is const (and should be const)
731 : // but when using doInt it is easier to locally replace cv[0] with
732 : // the upper/lower limit in case it is out of range
733 1488 : const double *pcv=NULL;
734 : double tmpcv[1]; // tmp array with cv (to be used with doInt_)
735 1488 : tmpcv[0]=cv[0];
736 1488 : bool isOutOfInt = false;
737 1488 : if(doInt_[iarg]) {
738 0 : if(cv[0]<lowI_[iarg]) { tmpcv[0]=lowI_[iarg]; isOutOfInt = true; }
739 0 : else if(cv[0]>uppI_[iarg]) { tmpcv[0]=uppI_[iarg]; isOutOfInt = true; }
740 : }
741 1488 : pcv=&(tmpcv[0]);
742 1488 : double dp = difference(iarg, hill.center[0],pcv[0]) / hill.sigma[0];
743 1488 : double dp2 = 0.5 * dp * dp;
744 1488 : if(dp2<DP2CUTOFF) {
745 1472 : bias = hill.height*exp(-dp2);
746 1472 : if(der &&!isOutOfInt) {
747 1020 : der[0] += -bias * dp / hill.sigma[0];
748 : }
749 : }
750 1488 : return bias;
751 : }
752 :
753 58 : void PBMetaD::calculate()
754 : {
755 58 : vector<double> cv(1);
756 : double der[1];
757 116 : vector<double> bias(getNumberOfArguments());
758 116 : vector<double> deriv(getNumberOfArguments());
759 :
760 58 : double ncv = (double) getNumberOfArguments();
761 58 : double bmin = 1.0e+19;
762 174 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
763 116 : cv[0] = getArgument(i);
764 116 : der[0] = 0.0;
765 116 : bias[i] = getBiasAndDerivatives(i, cv, der);
766 116 : deriv[i] = der[0];
767 116 : if(bias[i] < bmin) bmin = bias[i];
768 : }
769 58 : double ene = 0.;
770 174 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
771 116 : ene += exp((-bias[i]+bmin)/kbt_);
772 : }
773 :
774 : // set Forces
775 174 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
776 116 : const double f = - exp((-bias[i]+bmin)/kbt_) / (ene) * deriv[i];
777 116 : setOutputForce(i, f);
778 : }
779 :
780 : // set bias
781 58 : ene = -kbt_ * (std::log(ene) - std::log(ncv)) + bmin;
782 116 : setBias(ene);
783 58 : }
784 :
785 58 : void PBMetaD::update()
786 : {
787 : // adding hills criteria
788 : bool nowAddAHill;
789 58 : if(getStep()%stride_==0 && !isFirstStep ) {nowAddAHill=true;} else {nowAddAHill=false; isFirstStep=false;}
790 :
791 58 : if(nowAddAHill) {
792 : // get all CVs value
793 52 : vector<double> cv(getNumberOfArguments());
794 52 : for(unsigned i=0; i<getNumberOfArguments(); ++i) cv[i] = getArgument(i);
795 : // get all biases and heights
796 104 : vector<double> bias(getNumberOfArguments());
797 104 : vector<double> height(getNumberOfArguments());
798 104 : vector<double> cv_tmp(1);
799 104 : vector<double> sigma_tmp(1);
800 52 : double bmin = 1.0e+19;
801 156 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
802 104 : cv_tmp[0] = cv[i];
803 104 : bias[i] = getBiasAndDerivatives(i, cv_tmp);
804 104 : if(bias[i] < bmin) bmin = bias[i];
805 : }
806 52 : double norm = 0.0;
807 : // calculate heights and norm
808 156 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
809 104 : double h = exp((-bias[i]+bmin)/kbt_);
810 104 : norm += h;
811 104 : height[i] = h;
812 : }
813 : // normalize and apply welltemp correction
814 156 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
815 104 : height[i] *= height0_ / norm;
816 104 : if(welltemp_) height[i] *= exp(-bias[i]/(kbt_*(biasf_-1.0)));
817 : }
818 :
819 : // Multiple walkers: share hills and add them all
820 52 : if(multiple_w) {
821 : // Allocate arrays to store all walkers hills
822 44 : std::vector<double> all_cv(nw_*cv.size(), 0.0);
823 88 : std::vector<double> all_height(nw_*height.size(), 0.0);
824 44 : if(comm.Get_rank()==0) {
825 : // fill in value
826 66 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
827 44 : unsigned j = mw_ * getNumberOfArguments() + i;
828 44 : all_cv[j] = cv[i];
829 44 : all_height[j] = height[i];
830 : }
831 : // Communicate (only root)
832 22 : multi_sim_comm.Sum(&all_cv[0], all_cv.size());
833 22 : multi_sim_comm.Sum(&all_height[0], all_height.size());
834 : }
835 : // Share info with group members
836 44 : comm.Sum(&all_cv[0], all_cv.size());
837 44 : comm.Sum(&all_height[0], all_height.size());
838 : // now add hills one by one
839 132 : for(unsigned j=0; j<nw_; ++j) {
840 264 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
841 176 : cv_tmp[0] = all_cv[j*cv.size()+i];
842 176 : sigma_tmp[0] = sigma0_[i];
843 : // new Gaussian
844 176 : Gaussian newhill = Gaussian(cv_tmp, sigma_tmp, all_height[j*cv.size()+i]);
845 176 : addGaussian(i, newhill);
846 : // print on HILLS file
847 176 : writeGaussian(i, newhill, hillsOfiles_[i]);
848 176 : }
849 44 : }
850 : // just add your own hills
851 : } else {
852 24 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
853 16 : cv_tmp[0] = cv[i];
854 16 : sigma_tmp[0] = sigma0_[i];
855 : // new Gaussian
856 16 : Gaussian newhill = Gaussian(cv_tmp, sigma_tmp, height[i]);
857 16 : addGaussian(i, newhill);
858 : // print on HILLS file
859 16 : writeGaussian(i, newhill, hillsOfiles_[i]);
860 16 : }
861 52 : }
862 : }
863 : // write grid files
864 58 : if(wgridstride_>0 && (getStep()%wgridstride_==0 || getCPT())) {
865 5 : int r = 0;
866 5 : if(multiple_w) {
867 0 : if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank();
868 0 : comm.Bcast(r,0);
869 : }
870 5 : if(r==0) {
871 15 : for(unsigned i=0; i<gridfiles_.size(); ++i) {
872 10 : gridfiles_[i]->rewind();
873 10 : BiasGrids_[i]->writeToFile(*gridfiles_[i]);
874 10 : gridfiles_[i]->flush();
875 : }
876 : }
877 : }
878 58 : }
879 :
880 : /// takes a pointer to the file and a template string with values v and gives back the next center, sigma and height
881 0 : bool PBMetaD::scanOneHill(unsigned iarg, IFile *ifile, vector<Value> &tmpvalues, vector<double> ¢er, vector<double> &sigma, double &height) {
882 : double dummy;
883 :
884 0 : if(ifile->scanField("time",dummy)) {
885 0 : ifile->scanField( &tmpvalues[0] );
886 0 : if( tmpvalues[0].isPeriodic() && ! getPntrToArgument(iarg)->isPeriodic() ) {
887 0 : error("in hills file periodicity for variable " + tmpvalues[0].getName() + " does not match periodicity in input");
888 0 : } else if( tmpvalues[0].isPeriodic() ) {
889 0 : std::string imin, imax; tmpvalues[0].getDomain( imin, imax );
890 0 : std::string rmin, rmax; getPntrToArgument(iarg)->getDomain( rmin, rmax );
891 0 : if( imin!=rmin || imax!=rmax ) {
892 0 : error("in hills file periodicity for variable " + tmpvalues[0].getName() + " does not match periodicity in input");
893 0 : }
894 : }
895 0 : center[0]=tmpvalues[0].get();
896 : // scan for multivariate label: record the actual file position so to eventually rewind
897 0 : std::string sss;
898 0 : ifile->scanField("multivariate",sss);
899 0 : ifile->scanField("sigma_"+getPntrToArgument(iarg)->getName(),sigma[0]);
900 0 : ifile->scanField("height",height);
901 0 : ifile->scanField("biasf",dummy);
902 0 : if(ifile->FieldExist("clock")) ifile->scanField("clock",dummy);
903 0 : if(ifile->FieldExist("lower_int")) ifile->scanField("lower_int",dummy);
904 0 : if(ifile->FieldExist("upper_int")) ifile->scanField("upper_int",dummy);
905 0 : ifile->scanField();
906 0 : return true;
907 : } else {
908 0 : return false;
909 : };
910 : }
911 :
912 : }
913 2523 : }
914 :
|