LCOV - code coverage report
Current view: top level - drr - DynamicReferenceRestraining.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 275 301 91.4 %
Date: 2020-11-18 11:20:57 Functions: 15 16 93.8 %

          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          16 : 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        6456 : PLUMED_REGISTER_ACTION(DynamicReferenceRestraining, "DRR")
     184             : 
     185           5 : void DynamicReferenceRestraining::registerKeywords(Keywords &keys) {
     186           5 :   Bias::registerKeywords(keys);
     187          10 :   keys.use("ARG");
     188          20 :   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             :            "kbt/(GRID_SPACING)^2)");
     192          25 :   keys.add("compulsory", "TAU", "0.5", "specifies relaxation time on each of "
     193             :            "variables are, similar to "
     194             :            "extendedTimeConstant in Colvars");
     195          25 :   keys.add("compulsory", "FRICTION", "8.0",
     196             :            "add a friction to the variable, similar to extendedLangevinDamping "
     197             :            "in Colvars");
     198          20 :   keys.add("compulsory", "GRID_MIN", "the lower bounds for the grid (GRID_BIN "
     199             :            "or GRID_SPACING should be specified)");
     200          20 :   keys.add("compulsory", "GRID_MAX", "the upper bounds for the grid (GRID_BIN "
     201             :            "or GRID_SPACING should be specified)");
     202          20 :   keys.add("optional", "GRID_BIN", "the number of bins for the grid");
     203          20 :   keys.add("optional", "GRID_SPACING", "the approximate grid spacing (to be "
     204             :            "used as an alternative or together "
     205             :            "with GRID_BIN)");
     206          25 :   keys.add("compulsory", "FULLSAMPLES", "500",
     207             :            "number of samples in a bin prior to application of the ABF");
     208          20 :   keys.add("compulsory", "OUTPUTFREQ", "write results to a file every N steps");
     209          20 :   keys.add("optional", "HISTORYFREQ", "save history to a file every N steps");
     210          15 :   keys.addFlag("NOCZAR", false, "disable the CZAR estimator");
     211          15 :   keys.addFlag("UI", false,
     212             :                "enable the umbrella integration estimator");
     213          20 :   keys.add("optional", "UIRESTARTPREFIX",
     214             :            "specify the restart files for umbrella integration");
     215          20 :   keys.add("optional", "OUTPUTPREFIX",
     216             :            "specify the output prefix (default to the label name)");
     217          20 :   keys.add("optional", "TEMP", "the system temperature - needed when FRICTION "
     218             :            "is present. If not provided will be taken from "
     219             :            "MD code (if available)");
     220          20 :   keys.add(
     221             :     "optional", "EXTTEMP",
     222             :     "the temperature of extended variables (default to system temperature)");
     223          20 :   keys.add("optional", "DRR_RFILE",
     224             :            "specifies the restart file (.drrstate file)");
     225          15 :   keys.addFlag("NOBIAS", false, "DO NOT apply bias forces.");
     226          15 :   keys.addFlag("TEXTOUTPUT", false, "use text output for grad and count files "
     227             :                "instead of boost::serialization binary "
     228             :                "output");
     229           5 :   componentsAreNotOptional(keys);
     230          20 :   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             :     "variable.");
     237          20 :   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             :     "variable.");
     244          20 :   keys.addOutputComponent(
     245             :     "_biasforce", "default",
     246             :     "The bias force from eABF/DRR of the fictitious particle.");
     247           5 : }
     248             : 
     249           4 : DynamicReferenceRestraining::DynamicReferenceRestraining(
     250           4 :   const ActionOptions &ao)
     251             :   : PLUMED_BIAS_INIT(ao), firsttime(true), nobias(false),
     252             :     fictNoPBC(getNumberOfArguments(), 0.0), real(getNumberOfArguments(), 0.0),
     253             :     springlength(getNumberOfArguments(), 0.0),
     254             :     fict(getNumberOfArguments(), 0.0), vfict(getNumberOfArguments(), 0.0),
     255             :     vfict_laststep(getNumberOfArguments(), 0.0),
     256             :     ffict(getNumberOfArguments(), 0.0), fbias(getNumberOfArguments(), 0.0),
     257             :     kappa(getNumberOfArguments(), 0.0), tau(getNumberOfArguments(), 0.0),
     258             :     friction(getNumberOfArguments(), 0.0), etemp(getNumberOfArguments(), 0.0),
     259             :     ffict_measured(getNumberOfArguments(), 0.0),
     260             :     biasforceValue(getNumberOfArguments(), NULL),
     261             :     fictValue(getNumberOfArguments(), NULL),
     262             :     vfictValue(getNumberOfArguments(), NULL), c1(getNumberOfArguments(), 0.0),
     263             :     c2(getNumberOfArguments(), 0.0), mass(getNumberOfArguments(), 0.0),
     264             :     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          92 :     useCZARestimator(true), useUIestimator(false), textoutput(false)
     268             : {
     269           4 :   log << "eABF/DRR: You now are using the extended adaptive biasing "
     270             :       "force(eABF) method."
     271           4 :       << '\n';
     272           4 :   log << "eABF/DRR: Some people also refer to it as dynamic reference "
     273             :       "restraining(DRR) method."
     274           4 :       << '\n';
     275           4 :   log << "eABF/DRR: Currently the CZAR and naive(ABF on extended variables) "
     276             :       "estimator is enabled by default."
     277           4 :       << '\n';
     278           4 :   log << "eABF/DRR: For reasons of performance, the umbrella integration "
     279             :       "estimator is not enabled by default."
     280           4 :       << '\n';
     281           4 :   log << "eABF/DRR: This method is originally implemented in "
     282             :       "colvars(https://github.com/colvars/colvars)."
     283           4 :       << '\n';
     284           4 :   log << "eABF/DRR: This code in plumed is heavily modified from "
     285             :       "ExtendedLagrangian.cpp and doesn't implemented all variants of "
     286             :       "eABF/DRR."
     287           4 :       << '\n';
     288           4 :   log << "eABF/DRR: The thermostat using here maybe different from colvars."
     289           4 :       << '\n';
     290           4 :   log << "eABF/DRR: To integrate the gradients file, you can use abf_integrate "
     291             :       "from https://github.com/colvars/colvars/tree/master/colvartools."
     292           4 :       << '\n';
     293           4 :   log << "eABF/DRR: Please reading relevant articles and using this bias "
     294             :       "method carefully!"
     295           4 :       << '\n';
     296           8 :   parseFlag("NOBIAS", nobias);
     297           8 :   parseFlag("UI", useUIestimator);
     298           4 :   bool noCZAR = false;
     299           8 :   parseFlag("NOCZAR", noCZAR);
     300           4 :   noCZAR == false ? useCZARestimator = true : useCZARestimator = false;
     301           8 :   parseFlag("TEXTOUTPUT", textoutput);
     302           8 :   parseVector("TAU", tau);
     303           8 :   parseVector("FRICTION", friction);
     304           8 :   parseVector("EXTTEMP", etemp);
     305           8 :   parseVector("KAPPA", kappa);
     306           4 :   double temp = -1.0;
     307           8 :   parse("TEMP", temp);
     308           8 :   parse("FULLSAMPLES", fullsamples);
     309           8 :   parse("OUTPUTFREQ", outputfreq);
     310           8 :   parse("HISTORYFREQ", historyfreq);
     311           8 :   parse("OUTPUTPREFIX", outputprefix);
     312             :   string restartfilename;
     313           8 :   parse("DRR_RFILE", restartfilename);
     314             :   string uirprefix;
     315           8 :   parse("UIRESTARTPREFIX", uirprefix);
     316           4 :   if (temp >= 0.0)
     317           8 :     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           0 :     log << "eABF/DRR: The fullsamples parametre is not set. Set it to "
     323             :         "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           8 :   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           8 :   parseVector("GRID_MAX", gmax);
     345           4 :   if (gmax.size() != ndims)
     346           0 :     error("eABF/DRR: not enough values for GRID_MAX");
     347           4 :   vector<unsigned> gbin(ndims);
     348           4 :   vector<double> gspacing(ndims);
     349           8 :   parseVector("GRID_BIN", gbin);
     350           8 :   parseVector("GRID_SPACING", gspacing);
     351           4 :   if (gbin.size() != ndims) {
     352           2 :     log << "eABF/DRR: You didn't specify GRID_BIN. Trying to use GRID_SPACING "
     353             :         "instead."
     354           2 :         << '\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           4 :         PLMD::Tools::convert(gmax[i], h);
     363           6 :         gbin[i] = std::nearbyint((h - l) / gspacing[i]);
     364           6 :         gspacing[i] = (h - l) / gbin[i];
     365           4 :         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           4 :   vector<double> ekbt(ndims, 0.0);
     376           4 :   if (etemp.size() != ndims) {
     377          12 :     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          18 :     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          12 :     log << "eABF/DRR: relaxation time tau [" << i << "] is " << tau[i] << '\n';
     390          12 :     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          12 :     PLMD::Tools::convert(gmin[i], l);
     403          12 :     PLMD::Tools::convert(gmax[i], h);
     404          12 :     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           4 :             << "] is not set." << '\n';
     412          16 :         kappa[i] = ekbt[i] / (delim[i].getWidth() * delim[i].getWidth());
     413           4 :         log << "eABF/DRR: set kappa[" << i
     414           4 :             << "] 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          18 :     mass[i] = kappa[i] * tau[i] * tau[i] / (4 * pi * pi);
     429          12 :     log << "eABF/DRR: Fictitious mass[" << i << "] is " << mass[i] << '\n';
     430          18 :     c1[i] = exp(-0.5 * friction[i] * dt);
     431          30 :     c2[i] = sqrt(ekbt[i] * (1.0 - c1[i] * c1[i]) / mass[i]);
     432             :   }
     433             : 
     434          16 :   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             :       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           4 :       delim[i].setPeriodicity(c, d);
     445             :     } else
     446           2 :       componentIsNotPeriodic(comp);
     447           6 :     fictValue[i] = getPntrToComponent(comp);
     448             :     // Velocity output
     449          12 :     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          12 :     comp = getPntrToArgument(i)->getName() + "_biasforce";
     455           6 :     addComponent(comp);
     456           6 :     componentIsNotPeriodic(comp);
     457           6 :     biasforceValue[i] = getPntrToComponent(comp);
     458             :   }
     459             : 
     460           4 :   if (outputprefix.length() == 0)
     461           0 :     outputprefix = getLabel();
     462           8 :   outputname = outputprefix + ".drrstate";
     463           8 :   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           9 :     ABFGrid = ABF(delim, ".abf", textoutput);
     469             :     // Just initialize it even useCZARestimator is off.
     470           9 :     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          12 :     log << "  Bibliography " << plumed.cite("Lesage, Lelièvre, Stoltz and Hénin, "
     476           3 :                                             "J. Phys. Chem. B 3676, 121 (2017)");
     477           9 :     log << plumed.cite("Darve and Pohorille, J. Chem. Phys. 9169, 115 (2001)") << '\n';
     478             :   }
     479           4 :   if (useUIestimator) {
     480           4 :     log << "eABF/DRR: Using umbrella integration(Zheng and Yang's) estimator "
     481             :         "of gradients."
     482           4 :         << '\n';
     483           4 :     log << "eABF/DRR: The UI estimator code is contributed by Haohao Fu."
     484           4 :         << '\n';
     485          16 :     log << "  Bibliography " << plumed.cite(
     486           4 :           "Fu, Shao, Chipot and Cai, J. Chem. Theory Comput. 3506, 12 (2016)");
     487          12 :     log << plumed.cite("Zheng and Yang, J. Chem. Theory Comput. 810, 8 (2012)");
     488          12 :     log << plumed.cite("Darve and Pohorille, J. Chem. Phys. 9169, 115 (2001)") << '\n';
     489           8 :     vector<double> lowerboundary(delim.size(), 0);
     490           8 :     vector<double> upperboundary(delim.size(), 0);
     491           8 :     vector<double> width(delim.size(), 0);
     492          16 :     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           4 :     vector<string> input_filename;
     498             :     bool uirestart = false;
     499           5 :     if (isRestart && (uirprefix.length() != 0)) {
     500           1 :       input_filename.push_back(uirprefix);
     501             :       uirestart = true;
     502             :     }
     503           5 :     if (isRestart && (uirprefix.length() == 0)) {
     504           0 :       input_filename.push_back(getLabel());
     505             :     }
     506          12 :     eabf_UI = UIestimator::UIestimator(
     507           4 :                 lowerboundary, upperboundary, width, kappa, getLabel(), int(outputfreq),
     508           8 :                 uirestart, input_filename, kbt / plumed.getAtoms().getKBoltzmann());
     509             :   }
     510           4 : }
     511             : 
     512          34 : void DynamicReferenceRestraining::calculate() {
     513          34 :   long long int step_now = getStep();
     514          34 :   if (firsttime) {
     515          11 :     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             :         }
     541             :       }
     542             :     }
     543          30 :     if (getCPT()) {
     544           0 :       log << "eABF/DRR: The MD engine is writing checkpoint so we also write a "
     545             :           "DRR state file at step: "
     546           0 :           << step_now << ".\n";
     547           0 :       save(cptname, step_now);
     548             :     }
     549             :   }
     550             :   double ene = 0.0;
     551         150 :   for (size_t i = 0; i < ndims; ++i) {
     552          58 :     real[i] = getArgument(i);
     553         174 :     springlength[i] = difference(i, fict[i], real[i]);
     554         174 :     fictNoPBC[i] = real[i] - springlength[i];
     555         116 :     double f = -kappa[i] * springlength[i];
     556          58 :     ffict_measured[i] = -f;
     557         116 :     ene += 0.5 * kappa[i] * springlength[i] * springlength[i];
     558             :     setOutputForce(i, f);
     559          58 :     ffict[i] = -f;
     560         174 :     fict[i] = fictValue[i]->bringBackInPbc(fict[i]);
     561         116 :     fictValue[i]->set(fict[i]);
     562         116 :     vfictValue[i]->set(vfict_laststep[i]);
     563             :   }
     564             :   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         102 :     eabf_UI.update(int(step_now), real, fictNoPBC);
     572             :   }
     573          34 : }
     574             : 
     575          34 : void DynamicReferenceRestraining::update() {
     576         150 :   for (size_t i = 0; i < ndims; ++i) {
     577             :     // consider additional forces on the fictitious particle
     578             :     // (e.g. MetaD stuff)
     579         116 :     ffict[i] += fictValue[i]->getForce();
     580          58 :     if (!nobias) {
     581         116 :       ffict[i] += fbias[i];
     582             :     }
     583         116 :     biasforceValue[i]->set(fbias[i]);
     584             :     // update velocity (half step)
     585         174 :     vfict[i] += ffict[i] * 0.5 * dt / mass[i];
     586             :     // thermostat (half step)
     587         232 :     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         232 :     vfict[i] = c1[i] * vfict[i] + c2[i] * rand.Gaussian();
     592             :     // update velocity (half step)
     593         174 :     vfict[i] += ffict[i] * 0.5 * dt / mass[i];
     594             :     // update position (full step)
     595         116 :     fict[i] += vfict[i] * dt;
     596             :   }
     597          34 : }
     598             : 
     599           6 : void DynamicReferenceRestraining::save(const string &filename,
     600             :                                        long long int step) {
     601          12 :   std::ofstream out;
     602           6 :   out.open(filename.c_str(), std::ios::binary);
     603             :   boost::archive::binary_oarchive oa(out);
     604          30 :   oa << step << fict << vfict << vfict_laststep << ffict << ABFGrid
     605           6 :      << CZARestimator;
     606           6 :   out.close();
     607           6 : }
     608             : 
     609           1 : void DynamicReferenceRestraining::load(const string &filename) {
     610           2 :   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             :   boost::archive::binary_iarchive ia(in);
     615           5 :   ia >> step >> fict >> vfict >> vfict_laststep >> ffict >> ABFGrid >>
     616           1 :      CZARestimator;
     617           1 :   in.close();
     618           1 :   log << "eABF/DRR: Restart at step: " << step << '\n';
     619           1 :   backupFile(filename);
     620           1 : }
     621             : 
     622           1 : void DynamicReferenceRestraining::backupFile(const string &filename) {
     623             :   bool isSuccess = false;
     624             :   long int i = 0;
     625           3 :   while (!isSuccess) {
     626             :     // If libstdc++ support C++17 we can simplify following code.
     627           4 :     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           2 :       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             :       isSuccess = true;
     638             :     }
     639             :   }
     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           2 :   std::ifstream infile(fileName);
     646           1 :   return infile.good();
     647             : }
     648             : }
     649        4839 : }
     650             : 
     651             : #endif

Generated by: LCOV version 1.13