Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2017 of Haochuan Chen (excluding colvar_UIestimator.h)
3 : Copyright (c) 2017 of Haohao Fu (colvar_UIestimator.h)
4 :
5 : This program is free software: you can redistribute it and/or modify
6 : it under the terms of the GNU Lesser General Public License as published
7 : by the Free Software Foundation, either version 3 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU Lesser General Public License for more details.
14 :
15 : You should have received a copy of the GNU Lesser General Public License
16 : along with this program. If not, see <http://www.gnu.org/licenses/>.
17 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
18 : #ifdef __PLUMED_HAS_BOOST_SERIALIZATION
19 : #include "core/ActionRegister.h"
20 : #include "bias/Bias.h"
21 : #include "core/Atoms.h"
22 : #include "core/PlumedMain.h"
23 : #include "DRR.h"
24 : #include "tools/Random.h"
25 : #include "tools/Tools.h"
26 : #include "colvar_UIestimator.h"
27 :
28 : #include <boost/archive/binary_iarchive.hpp>
29 : #include <boost/archive/binary_oarchive.hpp>
30 : #include <boost/serialization/vector.hpp>
31 : #include <cmath>
32 : #include <fstream>
33 : #include <iomanip>
34 : #include <iostream>
35 : #include <limits>
36 : #include <random>
37 : #include <string>
38 :
39 : using namespace PLMD;
40 : using namespace bias;
41 : using namespace std;
42 :
43 : namespace PLMD {
44 : namespace drr {
45 :
46 : //+PLUMEDOC EABFMOD_BIAS DRR
47 : /*
48 : Used to performed extended-system adaptive biasing force(eABF) \cite Lelievre2007 method
49 : on one or more collective variables. This method is also
50 : called dynamic reference restraining(DRR) \cite Zheng2012 .
51 :
52 : For each collective variable \f$\xi_i\f$, a fictitious variable \f$\lambda_i\f$
53 : is attached through a spring. The fictitious variable \f$\lambda_i\f$ undergoes
54 : overdamped langevin dynamics jusk like \ref EXTENDED_LAGRANGIAN. The ABF
55 : algorithm applies bias force on \f$\lambda_i\f$. The bias force acts on
56 : \f$\lambda_i\f$ is the negative average spring force on \f$\lambda_i\f$, which
57 : enhances the sampling of \f$\lambda_i\f$.
58 :
59 : \f[
60 : F_{bias}(\lambda_i)=k(\lambda_i-\langle\xi_i\rangle_{\lambda_i})
61 : \f]
62 :
63 : If spring force constant k is large enough, then \f$\xi_i\f$ synchronizes with
64 : \f$\lambda_i\f$. The naive(ABF) estimator is just the negative
65 : average spring force of \f$\lambda_i\f$.
66 :
67 : The naive(ABF) estimator is biased. There are unbiased estimators such as
68 : CZAR(Corrected z-averaged restraint) \cite Lesage2016 and UI(Umbrella
69 : Integration).
70 : The CZAR estimates the gradients as:
71 :
72 : \f[
73 : \frac{\partial{A}}{\partial{\xi_i}}\left({\xi}\right)=-\frac{1}{\beta}\frac{\partial\ln\tilde{\rho}\left(\xi\right)}{\partial{\xi_i}}+k\left(\langle\lambda_i\rangle_\xi-\xi_i\right)
74 : \f]
75 :
76 : The UI estimates the gradients as:
77 : \f[
78 : A'(\xi^*)=\frac{{\sum_\lambda}N\left(\xi^*,\lambda\right)\left[\frac{\xi^*-\langle\xi\rangle_\lambda}{\beta\sigma_\lambda^2}-k(\xi^*-\lambda)\right]}{{\sum_\lambda}N\left(\xi^*,\lambda\right)}
79 : \f]
80 :
81 : The code performing UI(colvar_UIestimator.h) is contributed by Haohao Fu \cite Fu2016 .
82 : It may be slow. I only change the boltzmann constant and output
83 : precision in it. For new version and issues, please see:
84 : https://github.com/fhh2626/colvars
85 :
86 : After running eABF/DRR, the \ref drr_tool utility can be used to extract the gradients and counts files from .drrstate. Naive(ABF) estimator's result is in .abf.grad and .abf.count files and CZAR estimator's result is in .czar.grad and .czar.count files. To get PMF, the abf_integrate(https://github.com/Colvars/colvars/tree/master/colvartools) is useful.
87 :
88 : \par Examples
89 :
90 : The following input tells plumed to perform a eABF/DRR simulation on two
91 : torsional angles.
92 : \plumedfile
93 : phi: TORSION ATOMS=5,7,9,15
94 : psi: TORSION ATOMS=7,9,15,17
95 :
96 : DRR ...
97 : LABEL=eabf
98 : ARG=phi,psi
99 : FULLSAMPLES=500
100 : GRID_MIN=-pi,-pi
101 : GRID_MAX=pi,pi
102 : GRID_BIN=180,180
103 : FRICTION=8.0,8.0
104 : TAU=0.5,0.5
105 : OUTPUTFREQ=50000
106 : HISTORYFREQ=500000
107 : ... DRR
108 :
109 : # monitor the two variables, their fictitious variables and applied forces.
110 : PRINT STRIDE=10 ARG=phi,psi,eabf.phi_fict,eabf.psi_fict,eabf.phi_biasforce,eabf.psi_biasforce FILE=COLVAR
111 : \endplumedfile
112 :
113 : The following input tells plumed to perform a eABF/DRR simulation on the
114 : distance of atom 10 and 92. The distance is restraint by \ref LOWER_WALLS and
115 : \ref UPPER_WALLS.
116 : \plumedfile
117 : dist1: DISTANCE ATOMS=10,92
118 : eabf_winall: DRR ARG=dist1 FULLSAMPLES=2000 GRID_MIN=1.20 GRID_MAX=3.20 GRID_BIN=200 FRICTION=8.0 TAU=0.5 OUTPUTFREQ=5000 HISTORYFREQ=500000
119 : uwall: UPPER_WALLS ARG=eabf_winall.dist1_fict AT=3.2 KAPPA=418.4
120 : lwall: LOWER_WALLS ARG=eabf_winall.dist1_fict AT=1.2 KAPPA=418.4
121 : PRINT STRIDE=10 ARG=dist1,eabf_winall.dist1_fict,eabf_winall.dist1_biasforce FILE=COLVAR
122 : \endplumedfile
123 :
124 : */
125 : //+ENDPLUMEDOC
126 :
127 : using std::vector;
128 : using std::string;
129 :
130 8 : class DynamicReferenceRestraining : public Bias {
131 : private:
132 : bool firsttime;
133 : bool nobias;
134 : vector<double> fictNoPBC;
135 : vector<double> real;
136 : vector<double> springlength; // spring lengths
137 : vector<double> fict; // coordinates of extended variables
138 : vector<double> vfict; // velocities of extended variables
139 : vector<double> vfict_laststep;
140 : vector<double> ffict; // forces exerted on extended variables
141 : vector<double> fbias; // bias forces from eABF
142 : vector<double> kappa;
143 : vector<double> tau;
144 : vector<double> friction;
145 : vector<double> etemp;
146 : vector<double> ffict_measured;
147 : vector<Value *> biasforceValue;
148 : vector<Value *> fictValue;
149 : vector<Value *> vfictValue;
150 : vector<double> c1;
151 : vector<double> c2;
152 : vector<double> mass;
153 : vector<DRRAxis> delim;
154 : string outputname;
155 : string cptname;
156 : string outputprefix;
157 : const size_t ndims;
158 : double dt;
159 : double kbt;
160 : double outputfreq;
161 : double historyfreq;
162 : bool isRestart;
163 : bool useCZARestimator;
164 : bool useUIestimator;
165 : bool textoutput;
166 : ABF ABFGrid;
167 : CZAR CZARestimator;
168 : double fullsamples;
169 : UIestimator::UIestimator eabf_UI;
170 : Random rand;
171 :
172 : public:
173 : explicit DynamicReferenceRestraining(const ActionOptions &);
174 : void calculate();
175 : void update();
176 : void save(const string &filename, long long int step);
177 : void load(const string &filename);
178 : void backupFile(const string &filename);
179 : static void registerKeywords(Keywords &keys);
180 : bool is_file_exist(const char *fileName);
181 : };
182 :
183 4825 : PLUMED_REGISTER_ACTION(DynamicReferenceRestraining, "DRR")
184 :
185 5 : void DynamicReferenceRestraining::registerKeywords(Keywords &keys) {
186 5 : Bias::registerKeywords(keys);
187 5 : keys.use("ARG");
188 : keys.add("optional", "KAPPA", "specifies that the restraint is harmonic and "
189 : "what the values of the force constants on "
190 : "each of the variables are (default to "
191 5 : "kbt/(GRID_SPACING)^2)");
192 : keys.add("compulsory", "TAU", "0.5", "specifies relaxation time on each of "
193 : "variables are, similar to "
194 5 : "extendedTimeConstant in Colvars");
195 : keys.add("compulsory", "FRICTION", "8.0",
196 : "add a friction to the variable, similar to extendedLangevinDamping "
197 5 : "in Colvars");
198 : keys.add("compulsory", "GRID_MIN", "the lower bounds for the grid (GRID_BIN "
199 5 : "or GRID_SPACING should be specified)");
200 : keys.add("compulsory", "GRID_MAX", "the upper bounds for the grid (GRID_BIN "
201 5 : "or GRID_SPACING should be specified)");
202 5 : keys.add("optional", "GRID_BIN", "the number of bins for the grid");
203 : keys.add("optional", "GRID_SPACING", "the approximate grid spacing (to be "
204 : "used as an alternative or together "
205 5 : "with GRID_BIN)");
206 : keys.add("compulsory", "FULLSAMPLES", "500",
207 5 : "number of samples in a bin prior to application of the ABF");
208 5 : keys.add("compulsory", "OUTPUTFREQ", "write results to a file every N steps");
209 5 : keys.add("optional", "HISTORYFREQ", "save history to a file every N steps");
210 5 : keys.addFlag("NOCZAR", false, "disable the CZAR estimator");
211 : keys.addFlag("UI", false,
212 5 : "enable the umbrella integration estimator");
213 : keys.add("optional", "UIRESTARTPREFIX",
214 5 : "specify the restart files for umbrella integration");
215 : keys.add("optional", "OUTPUTPREFIX",
216 5 : "specify the output prefix (default to the label name)");
217 : keys.add("optional", "TEMP", "the system temperature - needed when FRICTION "
218 : "is present. If not provided will be taken from "
219 5 : "MD code (if available)");
220 : keys.add(
221 : "optional", "EXTTEMP",
222 5 : "the temperature of extended variables (default to system temperature)");
223 : keys.add("optional", "DRR_RFILE",
224 5 : "specifies the restart file (.drrstate file)");
225 5 : keys.addFlag("NOBIAS", false, "DO NOT apply bias forces.");
226 : keys.addFlag("TEXTOUTPUT", false, "use text output for grad and count files "
227 : "instead of boost::serialization binary "
228 5 : "output");
229 5 : componentsAreNotOptional(keys);
230 : keys.addOutputComponent(
231 : "_fict", "default",
232 : "one or multiple instances of this quantity will be refereceable "
233 : "elsewhere in the input file. "
234 : "These quantities will named with the arguments of the bias followed by "
235 : "the character string _tilde. It is possible to add forces on these "
236 5 : "variable.");
237 : keys.addOutputComponent(
238 : "_vfict", "default",
239 : "one or multiple instances of this quantity will be refereceable "
240 : "elsewhere in the input file. "
241 : "These quantities will named with the arguments of the bias followed by "
242 : "the character string _tilde. It is NOT possible to add forces on these "
243 5 : "variable.");
244 : keys.addOutputComponent(
245 : "_biasforce", "default",
246 5 : "The bias force from eABF/DRR of the fictitious particle.");
247 5 : }
248 :
249 4 : DynamicReferenceRestraining::DynamicReferenceRestraining(
250 : const ActionOptions &ao)
251 : : PLUMED_BIAS_INIT(ao), firsttime(true), nobias(false),
252 8 : fictNoPBC(getNumberOfArguments(), 0.0), real(getNumberOfArguments(), 0.0),
253 4 : springlength(getNumberOfArguments(), 0.0),
254 8 : fict(getNumberOfArguments(), 0.0), vfict(getNumberOfArguments(), 0.0),
255 4 : vfict_laststep(getNumberOfArguments(), 0.0),
256 8 : ffict(getNumberOfArguments(), 0.0), fbias(getNumberOfArguments(), 0.0),
257 8 : kappa(getNumberOfArguments(), 0.0), tau(getNumberOfArguments(), 0.0),
258 8 : friction(getNumberOfArguments(), 0.0), etemp(getNumberOfArguments(), 0.0),
259 4 : ffict_measured(getNumberOfArguments(), 0.0),
260 4 : biasforceValue(getNumberOfArguments(), NULL),
261 4 : fictValue(getNumberOfArguments(), NULL),
262 8 : vfictValue(getNumberOfArguments(), NULL), c1(getNumberOfArguments(), 0.0),
263 8 : c2(getNumberOfArguments(), 0.0), mass(getNumberOfArguments(), 0.0),
264 4 : delim(getNumberOfArguments()), outputname(""), cptname(""),
265 4 : outputprefix(""), ndims(getNumberOfArguments()), dt(0.0), kbt(0.0),
266 : outputfreq(0.0), historyfreq(-1.0), isRestart(false),
267 88 : useCZARestimator(true), useUIestimator(false), textoutput(false)
268 : {
269 : log << "eABF/DRR: You now are using the extended adaptive biasing "
270 4 : "force(eABF) method."
271 8 : << '\n';
272 : log << "eABF/DRR: Some people also refer to it as dynamic reference "
273 4 : "restraining(DRR) method."
274 8 : << '\n';
275 : log << "eABF/DRR: Currently the CZAR and naive(ABF on extended variables) "
276 4 : "estimator is enabled by default."
277 8 : << '\n';
278 : log << "eABF/DRR: For reasons of performance, the umbrella integration "
279 4 : "estimator is not enabled by default."
280 8 : << '\n';
281 : log << "eABF/DRR: This method is originally implemented in "
282 4 : "colvars(https://github.com/colvars/colvars)."
283 8 : << '\n';
284 : log << "eABF/DRR: This code in plumed is heavily modified from "
285 : "ExtendedLagrangian.cpp and doesn't implemented all variants of "
286 4 : "eABF/DRR."
287 8 : << '\n';
288 4 : log << "eABF/DRR: The thermostat using here maybe different from colvars."
289 8 : << '\n';
290 : log << "eABF/DRR: To integrate the gradients file, you can use abf_integrate "
291 4 : "from https://github.com/colvars/colvars/tree/master/colvartools."
292 8 : << '\n';
293 : log << "eABF/DRR: Please reading relevant articles and using this bias "
294 4 : "method carefully!"
295 8 : << '\n';
296 4 : parseFlag("NOBIAS", nobias);
297 4 : parseFlag("UI", useUIestimator);
298 4 : bool noCZAR = false;
299 4 : parseFlag("NOCZAR", noCZAR);
300 4 : noCZAR == false ? useCZARestimator = true : useCZARestimator = false;
301 4 : parseFlag("TEXTOUTPUT", textoutput);
302 4 : parseVector("TAU", tau);
303 4 : parseVector("FRICTION", friction);
304 4 : parseVector("EXTTEMP", etemp);
305 4 : parseVector("KAPPA", kappa);
306 4 : double temp = -1.0;
307 4 : parse("TEMP", temp);
308 4 : parse("FULLSAMPLES", fullsamples);
309 4 : parse("OUTPUTFREQ", outputfreq);
310 4 : parse("HISTORYFREQ", historyfreq);
311 4 : parse("OUTPUTPREFIX", outputprefix);
312 4 : string restartfilename;
313 4 : parse("DRR_RFILE", restartfilename);
314 8 : string uirprefix;
315 4 : parse("UIRESTARTPREFIX", uirprefix);
316 4 : if (temp >= 0.0)
317 4 : kbt = plumed.getAtoms().getKBoltzmann() * temp;
318 : else
319 0 : kbt = plumed.getAtoms().getKbT();
320 4 : if (fullsamples < 0.5) {
321 0 : fullsamples = 500.0;
322 : log << "eABF/DRR: The fullsamples parametre is not set. Set it to "
323 0 : "500(default)."
324 0 : << '\n';
325 : }
326 4 : if (getRestart()) {
327 1 : if (restartfilename.length() != 0) {
328 1 : isRestart = true;
329 1 : firsttime = false;
330 1 : load(restartfilename);
331 : } else {
332 0 : log << "eABF/DRR: You don't specify the file for restarting." << '\n';
333 0 : log << "eABF/DRR: So I assume you are splitting windows." << '\n';
334 0 : isRestart = false;
335 0 : firsttime = true;
336 : }
337 : }
338 :
339 8 : vector<string> gmin(ndims);
340 4 : parseVector("GRID_MIN", gmin);
341 4 : if (gmin.size() != ndims)
342 0 : error("eABF/DRR: not enough values for GRID_MIN");
343 8 : vector<string> gmax(ndims);
344 4 : parseVector("GRID_MAX", gmax);
345 4 : if (gmax.size() != ndims)
346 0 : error("eABF/DRR: not enough values for GRID_MAX");
347 8 : vector<unsigned> gbin(ndims);
348 8 : vector<double> gspacing(ndims);
349 4 : parseVector("GRID_BIN", gbin);
350 4 : parseVector("GRID_SPACING", gspacing);
351 4 : if (gbin.size() != ndims) {
352 : log << "eABF/DRR: You didn't specify GRID_BIN. Trying to use GRID_SPACING "
353 2 : "instead."
354 4 : << '\n';
355 2 : if (gspacing.size() != ndims) {
356 0 : error("eABF/DRR: not enough values for GRID_BIN");
357 : } else {
358 2 : gbin.resize(ndims);
359 4 : for (size_t i = 0; i < ndims; ++i) {
360 : double l, h;
361 2 : PLMD::Tools::convert(gmin[i], l);
362 2 : PLMD::Tools::convert(gmax[i], h);
363 2 : gbin[i] = std::nearbyint((h - l) / gspacing[i]);
364 2 : gspacing[i] = (h - l) / gbin[i];
365 2 : log << "GRID_BIN[" << i << "] is " << gbin[i] << '\n';
366 : }
367 : }
368 : }
369 4 : checkRead();
370 :
371 : // Set up kbt for extended system
372 4 : log << "eABF/DRR: The fullsamples is " << fullsamples << '\n';
373 4 : log << "eABF/DRR: The kbt(real system) is " << kbt << '\n';
374 4 : dt = getTimeStep();
375 8 : vector<double> ekbt(ndims, 0.0);
376 4 : if (etemp.size() != ndims) {
377 4 : etemp.assign(ndims, kbt / plumed.getAtoms().getKBoltzmann());
378 : }
379 4 : if (tau.size() != ndims) {
380 0 : tau.assign(ndims, 0.5);
381 : }
382 4 : if (friction.size() != ndims) {
383 0 : friction.assign(ndims, 8.0);
384 : }
385 10 : for (size_t i = 0; i < ndims; ++i) {
386 6 : ekbt[i] = etemp[i] * plumed.getAtoms().getKBoltzmann();
387 6 : log << "eABF/DRR: The kbt(extended system) of [" << i << "] is " << ekbt[i]
388 12 : << '\n';
389 6 : log << "eABF/DRR: relaxation time tau [" << i << "] is " << tau[i] << '\n';
390 6 : log << "eABF/DRR: Extended variable [" << i << "] has friction: " << friction[i] << '\n';
391 : }
392 :
393 : // Set up the force grid
394 10 : for (size_t i = 0; i < ndims; ++i) {
395 6 : log << "eABF/DRR: The " << i << " dimensional grid minimum is " << gmin[i]
396 12 : << '\n';
397 6 : log << "eABF/DRR: The " << i << " dimensional grid maximum is " << gmax[i]
398 12 : << '\n';
399 6 : log << "eABF/DRR: The " << i << " dimensional grid has " << gbin[i]
400 12 : << " bins" << '\n';
401 : double l, h;
402 6 : PLMD::Tools::convert(gmin[i], l);
403 6 : PLMD::Tools::convert(gmax[i], h);
404 6 : delim[i].set(l, h, gbin[i]);
405 : }
406 4 : if (kappa.size() != ndims) {
407 2 : kappa.resize(ndims, 0.0);
408 6 : for (size_t i = 0; i < ndims; ++i) {
409 4 : if (kappa[i] <= 0) {
410 4 : log << "eABF/DRR: The spring force constant kappa[" << i
411 8 : << "] is not set." << '\n';
412 4 : kappa[i] = ekbt[i] / (delim[i].getWidth() * delim[i].getWidth());
413 4 : log << "eABF/DRR: set kappa[" << i
414 8 : << "] according to bin width(ekbt/(binWidth^2))." << '\n';
415 : }
416 4 : log << "eABF/DRR: The spring force constant kappa[" << i << "] is "
417 8 : << std::fixed << std::setprecision(10) << kappa[i] << '\n';
418 : }
419 : } else {
420 2 : log << "eABF/DRR: The kappa have been set manually." << '\n';
421 4 : for (size_t i = 0; i < ndims; ++i) {
422 2 : log << "eABF/DRR: The spring force constant kappa[" << i << "] is "
423 4 : << std::fixed << std::setprecision(10) << kappa[i] << '\n';
424 : }
425 : }
426 :
427 10 : for (size_t i = 0; i < ndims; ++i) {
428 6 : mass[i] = kappa[i] * tau[i] * tau[i] / (4 * pi * pi);
429 6 : log << "eABF/DRR: Fictitious mass[" << i << "] is " << mass[i] << '\n';
430 6 : c1[i] = exp(-0.5 * friction[i] * dt);
431 6 : c2[i] = sqrt(ekbt[i] * (1.0 - c1[i] * c1[i]) / mass[i]);
432 : }
433 :
434 10 : for (size_t i = 0; i < ndims; ++i) {
435 : // Position output
436 6 : string comp = getPntrToArgument(i)->getName() + "_fict";
437 6 : addComponentWithDerivatives(comp);
438 6 : if (getPntrToArgument(i)->isPeriodic()) {
439 8 : string a, b;
440 : double c, d;
441 4 : getPntrToArgument(i)->getDomain(a, b);
442 4 : getPntrToArgument(i)->getDomain(c, d);
443 4 : componentIsPeriodic(comp, a, b);
444 8 : delim[i].setPeriodicity(c, d);
445 : } else
446 2 : componentIsNotPeriodic(comp);
447 6 : fictValue[i] = getPntrToComponent(comp);
448 : // Velocity output
449 6 : comp = getPntrToArgument(i)->getName() + "_vfict";
450 6 : addComponent(comp);
451 6 : componentIsNotPeriodic(comp);
452 6 : vfictValue[i] = getPntrToComponent(comp);
453 : // Bias force from eABF/DRR output
454 6 : comp = getPntrToArgument(i)->getName() + "_biasforce";
455 6 : addComponent(comp);
456 6 : componentIsNotPeriodic(comp);
457 6 : biasforceValue[i] = getPntrToComponent(comp);
458 6 : }
459 :
460 4 : if (outputprefix.length() == 0)
461 4 : outputprefix = getLabel();
462 4 : outputname = outputprefix + ".drrstate";
463 4 : cptname = outputprefix + ".cpt.drrstate";
464 :
465 4 : if (!isRestart) {
466 : // If you want to use on-the-fly text output for CZAR and naive estimator,
467 : // you should turn it to true first!
468 3 : ABFGrid = ABF(delim, ".abf", textoutput);
469 : // Just initialize it even useCZARestimator is off.
470 3 : CZARestimator = CZAR(delim, ".czar", kbt, textoutput);
471 3 : log << "eABF/DRR: The init function of the grid is finished." << '\n';
472 : }
473 4 : if (useCZARestimator) {
474 3 : log << "eABF/DRR: Using corrected z-average restraint estimator of gradients" << '\n';
475 3 : log << " Bibliography " << plumed.cite("Lesage, Lelièvre, Stoltz and Hénin, "
476 6 : "J. Phys. Chem. B 3676, 121 (2017)");
477 3 : log << plumed.cite("Darve and Pohorille, J. Chem. Phys. 9169, 115 (2001)") << '\n';
478 : }
479 4 : if (useUIestimator) {
480 : log << "eABF/DRR: Using umbrella integration(Zheng and Yang's) estimator "
481 4 : "of gradients."
482 8 : << '\n';
483 4 : log << "eABF/DRR: The UI estimator code is contributed by Haohao Fu."
484 8 : << '\n';
485 4 : log << " Bibliography " << plumed.cite(
486 8 : "Fu, Shao, Chipot and Cai, J. Chem. Theory Comput. 3506, 12 (2016)");
487 4 : log << plumed.cite("Zheng and Yang, J. Chem. Theory Comput. 810, 8 (2012)");
488 4 : log << plumed.cite("Darve and Pohorille, J. Chem. Phys. 9169, 115 (2001)") << '\n';
489 4 : vector<double> lowerboundary(delim.size(), 0);
490 8 : vector<double> upperboundary(delim.size(), 0);
491 8 : vector<double> width(delim.size(), 0);
492 10 : for (size_t i = 0; i < delim.size(); ++i) {
493 6 : lowerboundary[i] = delim[i].getMin();
494 6 : upperboundary[i] = delim[i].getMax();
495 6 : width[i] = delim[i].getWidth();
496 : }
497 8 : vector<string> input_filename;
498 4 : bool uirestart = false;
499 4 : if (isRestart && (uirprefix.length() != 0)) {
500 1 : input_filename.push_back(uirprefix);
501 1 : uirestart = true;
502 : }
503 4 : if (isRestart && (uirprefix.length() == 0)) {
504 0 : input_filename.push_back(getLabel());
505 : }
506 16 : eabf_UI = UIestimator::UIestimator(
507 4 : lowerboundary, upperboundary, width, kappa, getLabel(), int(outputfreq),
508 12 : uirestart, input_filename, kbt / plumed.getAtoms().getKBoltzmann());
509 4 : }
510 4 : }
511 :
512 34 : void DynamicReferenceRestraining::calculate() {
513 34 : long long int step_now = getStep();
514 34 : if (firsttime) {
515 7 : for (size_t i = 0; i < ndims; ++i) {
516 4 : fict[i] = getArgument(i);
517 : }
518 3 : firsttime = false;
519 : }
520 34 : if (step_now != 0) {
521 30 : if ((step_now % int(outputfreq)) == 0) {
522 6 : save(outputname, step_now);
523 6 : if (textoutput) {
524 4 : ABFGrid.writeAll(outputprefix);
525 4 : if (useCZARestimator) {
526 2 : CZARestimator.writeAll(outputprefix);
527 : }
528 : }
529 : }
530 30 : if (historyfreq > 0 && (step_now % int(historyfreq)) == 0) {
531 : const string filename =
532 0 : outputprefix + "." + std::to_string(step_now) + ".drrstate";
533 0 : save(filename, step_now);
534 0 : if (textoutput) {
535 : const string textfilename =
536 0 : outputprefix + "." + std::to_string(step_now);
537 0 : ABFGrid.writeAll(textfilename);
538 0 : if (useCZARestimator) {
539 0 : CZARestimator.writeAll(textfilename);
540 0 : }
541 0 : }
542 : }
543 30 : if (getCPT()) {
544 : log << "eABF/DRR: The MD engine is writing checkpoint so we also write a "
545 0 : "DRR state file at step: "
546 0 : << step_now << ".\n";
547 0 : save(cptname, step_now);
548 : }
549 : }
550 34 : double ene = 0.0;
551 92 : for (size_t i = 0; i < ndims; ++i) {
552 58 : real[i] = getArgument(i);
553 58 : springlength[i] = difference(i, fict[i], real[i]);
554 58 : fictNoPBC[i] = real[i] - springlength[i];
555 58 : double f = -kappa[i] * springlength[i];
556 58 : ffict_measured[i] = -f;
557 58 : ene += 0.5 * kappa[i] * springlength[i] * springlength[i];
558 58 : setOutputForce(i, f);
559 58 : ffict[i] = -f;
560 58 : fict[i] = fictValue[i]->bringBackInPbc(fict[i]);
561 58 : fictValue[i]->set(fict[i]);
562 58 : vfictValue[i]->set(vfict_laststep[i]);
563 : }
564 34 : setBias(ene);
565 34 : ABFGrid.store_getbias(fict, ffict_measured, fbias, fullsamples);
566 34 : if (useCZARestimator) {
567 29 : CZARestimator.store(real, ffict_measured);
568 : }
569 34 : if (useUIestimator) {
570 34 : eabf_UI.update_output_filename(outputprefix);
571 34 : eabf_UI.update(int(step_now), real, fictNoPBC);
572 : }
573 34 : }
574 :
575 34 : void DynamicReferenceRestraining::update() {
576 92 : for (size_t i = 0; i < ndims; ++i) {
577 : // consider additional forces on the fictitious particle
578 : // (e.g. MetaD stuff)
579 58 : ffict[i] += fictValue[i]->getForce();
580 58 : if (!nobias) {
581 58 : ffict[i] += fbias[i];
582 : }
583 58 : biasforceValue[i]->set(fbias[i]);
584 : // update velocity (half step)
585 58 : vfict[i] += ffict[i] * 0.5 * dt / mass[i];
586 : // thermostat (half step)
587 58 : vfict[i] = c1[i] * vfict[i] + c2[i] * rand.Gaussian();
588 : // save full step velocity to be dumped at next step
589 58 : vfict_laststep[i] = vfict[i];
590 : // thermostat (half step)
591 58 : vfict[i] = c1[i] * vfict[i] + c2[i] * rand.Gaussian();
592 : // update velocity (half step)
593 58 : vfict[i] += ffict[i] * 0.5 * dt / mass[i];
594 : // update position (full step)
595 58 : fict[i] += vfict[i] * dt;
596 : }
597 34 : }
598 :
599 6 : void DynamicReferenceRestraining::save(const string &filename,
600 : long long int step) {
601 6 : std::ofstream out;
602 6 : out.open(filename.c_str(), std::ios::binary);
603 12 : boost::archive::binary_oarchive oa(out);
604 6 : oa << step << fict << vfict << vfict_laststep << ffict << ABFGrid
605 12 : << CZARestimator;
606 12 : out.close();
607 6 : }
608 :
609 1 : void DynamicReferenceRestraining::load(const string &filename) {
610 1 : std::ifstream in;
611 : long long int step;
612 1 : in.open(filename.c_str(), std::ios::binary);
613 1 : log << "eABF/DRR: Read restart file: " << filename << '\n';
614 2 : boost::archive::binary_iarchive ia(in);
615 1 : ia >> step >> fict >> vfict >> vfict_laststep >> ffict >> ABFGrid >>
616 2 : CZARestimator;
617 1 : in.close();
618 1 : log << "eABF/DRR: Restart at step: " << step << '\n';
619 2 : backupFile(filename);
620 1 : }
621 :
622 1 : void DynamicReferenceRestraining::backupFile(const string &filename) {
623 1 : bool isSuccess = false;
624 1 : long int i = 0;
625 3 : while (!isSuccess) {
626 : // If libstdc++ support C++17 we can simplify following code.
627 1 : const string bckname = "bck." + filename + "." + std::to_string(i);
628 1 : if (is_file_exist(bckname.c_str())) {
629 0 : ++i;
630 : } else {
631 1 : log << "eABF/DRR: Backup original restart file to " << bckname << '\n';
632 1 : std::ifstream src(filename.c_str(), std::ios::binary);
633 2 : std::ofstream dst(bckname.c_str(), std::ios::binary);
634 1 : dst << src.rdbuf();
635 1 : src.close();
636 1 : dst.close();
637 2 : isSuccess = true;
638 : }
639 1 : }
640 1 : }
641 :
642 : // Copy from
643 : // stackoverflow(https://stackoverflow.com/questions/12774207/fastest-way-to-check-if-a-file-exist-using-standard-c-c11-c)
644 1 : bool DynamicReferenceRestraining::is_file_exist(const char *fileName) {
645 1 : std::ifstream infile(fileName);
646 1 : return infile.good();
647 : }
648 : }
649 4821 : }
650 :
651 : #endif
|