LCOV - code coverage report
Current view: top level - drr - DynamicReferenceRestraining.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 412 451 91.4 %
Date: 2024-10-18 13:59:31 Functions: 8 9 88.9 %

          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/PlumedMain.h"
      22             : #include "DRR.h"
      23             : #include "tools/Random.h"
      24             : #include "tools/Tools.h"
      25             : #include "colvar_UIestimator.h"
      26             : 
      27             : #include <boost/archive/binary_iarchive.hpp>
      28             : #include <boost/archive/binary_oarchive.hpp>
      29             : #include <boost/serialization/vector.hpp>
      30             : #include <cmath>
      31             : #include <fstream>
      32             : #include <iomanip>
      33             : #include <iostream>
      34             : #include <limits>
      35             : #include <random>
      36             : #include <string>
      37             : 
      38             : using namespace PLMD;
      39             : using namespace bias;
      40             : using namespace std;
      41             : 
      42             : namespace PLMD {
      43             : namespace drr {
      44             : 
      45             : //+PLUMEDOC EABFMOD_BIAS DRR
      46             : /*
      47             : Used to performed extended-system adaptive biasing force(eABF)
      48             : 
      49             : This method was introduced in \cite Lelievre2007.  It is used
      50             :  on one or more collective variables. This method is also
      51             :  called dynamic reference restraining(DRR) \cite Zheng2012 . A detailed description
      52             :  of this module can be found at \cite Chen2018 .
      53             : 
      54             : For each collective variable \f$\xi_i\f$, a fictitious variable \f$\lambda_i\f$
      55             : is attached through a spring. The fictitious variable \f$\lambda_i\f$ undergoes
      56             : overdamped Langevin dynamics just like \ref EXTENDED_LAGRANGIAN. The ABF
      57             : algorithm applies bias force on \f$\lambda_i\f$. The bias force acts on
      58             : \f$\lambda_i\f$ is the negative average spring force on \f$\lambda_i\f$, which
      59             : enhances the sampling of \f$\lambda_i\f$.
      60             : 
      61             : \f[
      62             : F_{bias}(\lambda_i)=k(\lambda_i-\langle\xi_i\rangle_{\lambda_i})
      63             : \f]
      64             : 
      65             : If spring force constant k is large enough, then \f$\xi_i\f$ synchronizes with
      66             : \f$\lambda_i\f$. The naive(ABF) estimator is just the negative
      67             : average spring force of \f$\lambda_i\f$.
      68             : 
      69             : The naive(ABF) estimator is biased. There are unbiased estimators such as
      70             : CZAR(Corrected z-averaged restraint) \cite Lesage2016 and UI(Umbrella
      71             : Integration).
      72             : The CZAR estimates the gradients as:
      73             : 
      74             : \f[
      75             : \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)
      76             : \f]
      77             : 
      78             : The UI estimates the gradients as:
      79             : \f[
      80             : 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)}
      81             : \f]
      82             : 
      83             : The code performing UI(colvar_UIestimator.h) is contributed by Haohao Fu \cite Fu2016 .
      84             : It may be slow. I only change the Boltzmann constant and output
      85             : precision in it. For new version and issues, please see:
      86             : https://github.com/fhh2626/colvars
      87             : 
      88             : 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. The additional .zcount and .zgrad files contain the number of samples of \f$\boldsymbol{\xi}\f$, and the negative of \f$\boldsymbol{\xi}\f$-averaged spring forces, respectively, which are mainly for inspecting and debugging purpose. To get PMF, the abf_integrate(https://github.com/Colvars/colvars/tree/master/colvartools) is useful for numerically integrating the .czar.grad file.
      89             : 
      90             : \par Examples
      91             : 
      92             : The following input tells plumed to perform a eABF/DRR simulation on two
      93             : torsional angles.
      94             : \plumedfile
      95             : phi: TORSION ATOMS=5,7,9,15
      96             : psi: TORSION ATOMS=7,9,15,17
      97             : 
      98             : DRR ...
      99             : LABEL=eabf
     100             : ARG=phi,psi
     101             : FULLSAMPLES=500
     102             : GRID_MIN=-pi,-pi
     103             : GRID_MAX=pi,pi
     104             : GRID_BIN=180,180
     105             : FRICTION=8.0,8.0
     106             : TAU=0.5,0.5
     107             : OUTPUTFREQ=50000
     108             : HISTORYFREQ=500000
     109             : ... DRR
     110             : 
     111             : # monitor the two variables, their fictitious variables and applied forces.
     112             : PRINT STRIDE=10 ARG=phi,psi,eabf.phi_fict,eabf.psi_fict,eabf.phi_biasforce,eabf.psi_biasforce FILE=COLVAR
     113             : \endplumedfile
     114             : 
     115             : The following input tells plumed to perform a eABF/DRR simulation on the
     116             : distance of atom 10 and 92. The distance is restraint by \ref LOWER_WALLS and
     117             : \ref UPPER_WALLS.
     118             : \plumedfile
     119             : dist1: DISTANCE ATOMS=10,92
     120             : 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
     121             : uwall: UPPER_WALLS ARG=eabf_winall.dist1_fict AT=3.2 KAPPA=418.4
     122             : lwall: LOWER_WALLS ARG=eabf_winall.dist1_fict AT=1.2 KAPPA=418.4
     123             : PRINT STRIDE=10 ARG=dist1,eabf_winall.dist1_fict,eabf_winall.dist1_biasforce FILE=COLVAR
     124             : \endplumedfile
     125             : 
     126             : It's also possible to run extended generalized adaptive biasing force (egABF) described in \cite Zhao2017 .
     127             : An egABF example:
     128             : \plumedfile
     129             : phi: TORSION ATOMS=5,7,9,15
     130             : psi: TORSION ATOMS=7,9,15,17
     131             : 
     132             : DRR ...
     133             : LABEL=gabf_phi
     134             : ARG=phi
     135             : FULLSAMPLES=500
     136             : GRID_MIN=-pi
     137             : GRID_MAX=pi
     138             : GRID_BIN=180
     139             : FRICTION=8.0
     140             : TAU=0.5
     141             : OUTPUTFREQ=50000
     142             : HISTORYFREQ=500000
     143             : ... DRR
     144             : 
     145             : DRR ...
     146             : LABEL=gabf_psi
     147             : ARG=psi
     148             : FULLSAMPLES=500
     149             : GRID_MIN=-pi
     150             : GRID_MAX=pi
     151             : GRID_BIN=180
     152             : FRICTION=8.0
     153             : TAU=0.5
     154             : OUTPUTFREQ=50000
     155             : HISTORYFREQ=500000
     156             : ... DRR
     157             : 
     158             : DRR ...
     159             : LABEL=gabf_2d
     160             : ARG=phi,psi
     161             : EXTERNAL_FORCE=gabf_phi.phi_springforce,gabf_psi.psi_springforce
     162             : EXTERNAL_FICT=gabf_phi.phi_fictNoPBC,gabf_psi.psi_fictNoPBC
     163             : GRID_MIN=-pi,-pi
     164             : GRID_MAX=pi,pi
     165             : GRID_BIN=180,180
     166             : NOBIAS
     167             : OUTPUTFREQ=50000
     168             : HISTORYFREQ=500000
     169             : ... DRR
     170             : 
     171             : PRINT STRIDE=10 ARG=phi,psi FILE=COLVAR
     172             : \endplumedfile
     173             : 
     174             :  */
     175             : //+ENDPLUMEDOC
     176             : 
     177             : using std::vector;
     178             : using std::string;
     179             : 
     180             : class DynamicReferenceRestraining : public Bias {
     181             : private:
     182             :   bool firsttime;
     183             :   bool nobias;
     184             :   vector<double> fictNoPBC;
     185             :   vector<double> real;
     186             :   vector<double> springlength; // spring lengths
     187             :   vector<double> fict;         // coordinates of extended variables
     188             :   vector<double> vfict;        // velocities of extended variables
     189             :   vector<double> vfict_laststep;
     190             :   vector<double> ffict; // forces exerted on extended variables
     191             :   vector<double> fbias; // bias forces from eABF
     192             :   vector<double> kappa;
     193             :   vector<double> tau;
     194             :   vector<double> friction;
     195             :   vector<double> etemp;
     196             :   vector<double> ffict_measured;
     197             :   vector<double> force_external;
     198             :   vector<double> fict_external;
     199             :   vector<Value *> biasforceValue;
     200             :   vector<Value *> springforceValue;
     201             :   vector<Value *> fictValue;
     202             :   vector<Value *> vfictValue;
     203             :   vector<Value *> fictNoPBCValue;
     204             :   vector<Value *> externalForceValue;
     205             :   vector<Value *> externalFictValue;
     206             :   vector<double> c1;
     207             :   vector<double> c2;
     208             :   vector<double> mass;
     209             :   vector<DRRAxis> delim;
     210             :   string outputname;
     211             :   string cptname;
     212             :   string outputprefix;
     213             :   string fmt_;
     214             :   const size_t ndims;
     215             :   double dt;
     216             :   double kbt;
     217             :   double outputfreq;
     218             :   double historyfreq;
     219             :   bool isRestart;
     220             :   bool useCZARestimator;
     221             :   bool useUIestimator;
     222             :   bool mergeHistoryFiles;
     223             :   bool textoutput;
     224             :   bool withExternalForce;
     225             :   bool withExternalFict;
     226             :   vector<unsigned> reflectingWall;
     227             :   ABF ABFGrid;
     228             :   CZAR CZARestimator;
     229             :   double fullsamples;
     230             :   vector<double> maxFactors;
     231             :   UIestimator::UIestimator eabf_UI;
     232             :   Random rand;
     233             : 
     234             : public:
     235             :   explicit DynamicReferenceRestraining(const ActionOptions &);
     236             :   void calculate();
     237             :   void update();
     238             :   void save(const string &filename, long long int step);
     239             :   void load(const string &filename);
     240             :   void backupFile(const string &filename);
     241             :   static void registerKeywords(Keywords &keys);
     242             :   bool is_file_exist(const char *fileName);
     243             : };
     244             : 
     245             : PLUMED_REGISTER_ACTION(DynamicReferenceRestraining, "DRR")
     246             : 
     247          14 : void DynamicReferenceRestraining::registerKeywords(Keywords &keys) {
     248          14 :   Bias::registerKeywords(keys);
     249          28 :   keys.add("optional", "KAPPA", "specifies that the restraint is harmonic and "
     250             :            "what the values of the force constants on "
     251             :            "each of the variables are (default to "
     252             :            "k_BT/(GRID_SPACING)^2)");
     253          28 :   keys.add("compulsory", "TAU", "0.5", "specifies relaxation time on each of "
     254             :            "variables are, similar to "
     255             :            "extended Time Constant in Colvars");
     256          28 :   keys.add("compulsory", "FRICTION", "8.0",
     257             :            "add a friction to the variable, similar to extended Langevin Damping "
     258             :            "in Colvars");
     259          28 :   keys.add("compulsory", "GRID_MIN", "the lower bounds for the grid (GRID_BIN "
     260             :            "or GRID_SPACING should be specified)");
     261          28 :   keys.add("compulsory", "GRID_MAX", "the upper bounds for the grid (GRID_BIN "
     262             :            "or GRID_SPACING should be specified)");
     263          28 :   keys.add("compulsory", "REFLECTINGWALL", "0", "whether add reflecting walls "
     264             :            "for each CV at GRID_MIN and GRID_MAX. Setting non-zero values will "
     265             :            "enable this feature");
     266          28 :   keys.add("optional", "GRID_BIN", "the number of bins for the grid");
     267          28 :   keys.add("optional", "GRID_SPACING", "the approximate grid spacing (to be "
     268             :            "used as an alternative or together "
     269             :            "with GRID_BIN)");
     270          28 :   keys.add("optional", "ZGRID_MIN", "the lower bounds for the grid (ZGRID_BIN"
     271             :            " or ZGRID_SPACING should be specified)");
     272          28 :   keys.add("optional", "ZGRID_MAX", "the upper bounds for the grid (ZGRID_BIN"
     273             :            " or ZGRID_SPACING should be specified)");
     274          28 :   keys.add("optional", "ZGRID_BIN", "the number of bins for the grid");
     275          28 :   keys.add("optional", "ZGRID_SPACING", "the approximate grid spacing (to be "
     276             :            "used as an alternative or together "
     277             :            "with ZGRID_BIN)");
     278          28 :   keys.add("optional", "EXTERNAL_FORCE", "use forces from other action instead"
     279             :            " of internal spring force, this disable the extended system!");
     280          28 :   keys.add("optional", "EXTERNAL_FICT", "position of external fictitious "
     281             :            "particles, useful for UIESTIMATOR");
     282          28 :   keys.add("compulsory", "FULLSAMPLES", "500",
     283             :            "number of samples in a bin prior to application of the ABF");
     284          28 :   keys.add("compulsory", "MAXFACTOR", "1.0",
     285             :            "maximum scaling factor of biasing force");
     286          28 :   keys.add("compulsory", "OUTPUTFREQ", "write results to a file every N steps");
     287          28 :   keys.add("optional", "HISTORYFREQ", "save history to a file every N steps");
     288          28 :   keys.addFlag("NOCZAR", false, "disable the CZAR estimator");
     289          28 :   keys.addFlag("UI", false,
     290             :                "enable the umbrella integration estimator");
     291          28 :   keys.add("optional", "UIRESTARTPREFIX",
     292             :            "specify the restart files for umbrella integration");
     293          28 :   keys.add("optional", "OUTPUTPREFIX",
     294             :            "specify the output prefix (default to the label name)");
     295          28 :   keys.add("optional", "TEMP", "the system temperature - needed when FRICTION "
     296             :            "is present. If not provided will be taken from "
     297             :            "MD code (if available)");
     298          28 :   keys.add(
     299             :     "optional", "EXTTEMP",
     300             :     "the temperature of extended variables (default to system temperature)");
     301          28 :   keys.add("optional", "DRR_RFILE",
     302             :            "specifies the restart file (.drrstate file)");
     303          28 :   keys.addFlag("NOBIAS", false, "DO NOT apply bias forces.");
     304          28 :   keys.addFlag("TEXTOUTPUT", false, "use text output for grad and count files "
     305             :                "instead of boost::serialization binary "
     306             :                "output");
     307          28 :   keys.addFlag("MERGEHISTORYFILES", false, "output all historic results "
     308             :                "to a single file rather than multiple .drrstate files. "
     309             :                "This option is effective only when textOutput is on.");
     310          28 :   keys.add("optional","FMT","specify format for outfiles files (useful for decrease the number of digits in regtests)");
     311          28 :   keys.addOutputComponent(
     312             :     "_fict", "default",
     313             :     "one or multiple instances of this quantity can be referenced "
     314             :     "elsewhere in the input file. "
     315             :     "These quantities will named with the arguments of the bias followed by "
     316             :     "the character string _tilde. It is possible to add forces on these "
     317             :     "variable.");
     318          28 :   keys.addOutputComponent(
     319             :     "_vfict", "default",
     320             :     "one or multiple instances of this quantity can be referenced "
     321             :     "elsewhere in the input file. "
     322             :     "These quantities will named with the arguments of the bias followed by "
     323             :     "the character string _tilde. It is NOT possible to add forces on these "
     324             :     "variable.");
     325          28 :   keys.addOutputComponent(
     326             :     "_biasforce", "default",
     327             :     "The bias force from eABF/DRR of the fictitious particle.");
     328          28 :   keys.addOutputComponent("_springforce", "default", "Spring force between real CVs and extended CVs");
     329          28 :   keys.addOutputComponent("_fictNoPBC", "default",
     330             :                           "the positions of fictitious particles (without PBC).");
     331          14 : }
     332             : 
     333          12 : DynamicReferenceRestraining::DynamicReferenceRestraining(
     334          12 :   const ActionOptions &ao)
     335          12 :   : PLUMED_BIAS_INIT(ao), firsttime(true), nobias(false),
     336          12 :     fictNoPBC(getNumberOfArguments(), 0.0), real(getNumberOfArguments(), 0.0),
     337          12 :     springlength(getNumberOfArguments(), 0.0),
     338          12 :     fict(getNumberOfArguments(), 0.0), vfict(getNumberOfArguments(), 0.0),
     339          12 :     vfict_laststep(getNumberOfArguments(), 0.0),
     340          12 :     ffict(getNumberOfArguments(), 0.0), fbias(getNumberOfArguments(), 0.0),
     341          12 :     kappa(getNumberOfArguments(), 0.0), tau(getNumberOfArguments(), 0.0),
     342          12 :     friction(getNumberOfArguments(), 0.0), etemp(getNumberOfArguments(), 0.0),
     343          12 :     ffict_measured(getNumberOfArguments(), 0.0),
     344          12 :     biasforceValue(getNumberOfArguments(), NULL),
     345          12 :     springforceValue(getNumberOfArguments(), NULL),
     346          12 :     fictValue(getNumberOfArguments(), NULL),
     347          12 :     vfictValue(getNumberOfArguments(), NULL),
     348          12 :     fictNoPBCValue(getNumberOfArguments(), NULL),
     349          12 :     externalForceValue(getNumberOfArguments(), NULL),
     350          12 :     externalFictValue(getNumberOfArguments(), NULL),
     351          12 :     c1(getNumberOfArguments(), 0.0),
     352          12 :     c2(getNumberOfArguments(), 0.0), mass(getNumberOfArguments(), 0.0),
     353          12 :     delim(getNumberOfArguments()), outputname(""), cptname(""),
     354          12 :     outputprefix(""), fmt_("%.9f"), ndims(getNumberOfArguments()), dt(0.0), kbt(0.0),
     355          12 :     outputfreq(0.0), historyfreq(-1.0), isRestart(false),
     356          12 :     useCZARestimator(true), useUIestimator(false), mergeHistoryFiles(false),
     357          12 :     textoutput(false), withExternalForce(false), withExternalFict(false),
     358          12 :     reflectingWall(getNumberOfArguments(), 0),
     359          36 :     maxFactors(getNumberOfArguments(), 1.0)
     360             : {
     361          12 :   log << "eABF/DRR: You now are using the extended adaptive biasing "
     362             :       "force(eABF) method."
     363          12 :       << '\n';
     364          12 :   log << "eABF/DRR: Some people also refer to it as dynamic reference "
     365             :       "restraining(DRR) method."
     366          12 :       << '\n';
     367          12 :   log << "eABF/DRR: Currently the CZAR and naive(ABF on extended variables) "
     368             :       "estimator is enabled by default."
     369          12 :       << '\n';
     370          12 :   log << "eABF/DRR: For reasons of performance, the umbrella integration "
     371             :       "estimator is not enabled by default."
     372          12 :       << '\n';
     373          12 :   log << "eABF/DRR: This method is originally implemented in "
     374             :       "colvars(https://github.com/colvars/colvars)."
     375          12 :       << '\n';
     376          12 :   log << "eABF/DRR: The code in plumed is heavily modified from "
     377             :       "ExtendedLagrangian.cpp and doesn't implemented all variants of "
     378             :       "eABF/DRR."
     379          12 :       << '\n';
     380          12 :   log << "eABF/DRR: The thermostat used here may be different from Colvars."
     381          12 :       << '\n';
     382          12 :   log << "eABF/DRR: To integrate the gradients file, you can use abf_integrate "
     383             :       "from https://github.com/colvars/colvars/tree/master/colvartools."
     384          12 :       << '\n';
     385          12 :   log << "eABF/DRR: Please read relevant articles and use this biasing "
     386             :       "method carefully!"
     387          12 :       << '\n';
     388          12 :   parseFlag("NOBIAS", nobias);
     389          12 :   parseFlag("UI", useUIestimator);
     390          12 :   bool noCZAR = false;
     391          12 :   parseFlag("NOCZAR", noCZAR);
     392             : //   noCZAR == false ? useCZARestimator = true : useCZARestimator = false;
     393          12 :   parseFlag("TEXTOUTPUT", textoutput);
     394          12 :   parseFlag("MERGEHISTORYFILES", mergeHistoryFiles);
     395          12 :   parseVector("TAU", tau);
     396          12 :   parseVector("FRICTION", friction);
     397          12 :   parseVector("EXTTEMP", etemp);
     398          12 :   parseVector("KAPPA", kappa);
     399          12 :   parseVector("REFLECTINGWALL", reflectingWall);
     400          12 :   parse("FULLSAMPLES", fullsamples);
     401          12 :   parseVector("MAXFACTOR", maxFactors);
     402          12 :   parse("OUTPUTFREQ", outputfreq);
     403          12 :   parse("HISTORYFREQ", historyfreq);
     404          24 :   parse("OUTPUTPREFIX", outputprefix);
     405             :   string restart_prefix;
     406          24 :   parse("DRR_RFILE", restart_prefix);
     407             :   string uirprefix;
     408          12 :   parse("UIRESTARTPREFIX", uirprefix);
     409          12 :   parseArgumentList("EXTERNAL_FORCE", externalForceValue);
     410          12 :   parseArgumentList("EXTERNAL_FICT", externalFictValue);
     411          24 :   parse("FMT",fmt_);
     412          12 :   if (externalForceValue.empty()) {
     413          11 :     withExternalForce = false;
     414           1 :   } else if (externalForceValue.size() != ndims) {
     415           0 :     error("eABF/DRR: Number of forces doesn't match ARGS!");
     416             :   } else {
     417           1 :     withExternalForce = true;
     418             :   }
     419          12 :   if (withExternalForce && useUIestimator) {
     420           1 :     if (externalFictValue.empty()) {
     421           0 :       error("eABF/DRR: No external fictitious particles specified. UI estimator needs it.");
     422           1 :     } else if(externalFictValue.size() != ndims) {
     423           0 :       error("eABF/DRR: Number of fictitious particles doesn't match ARGS!");
     424             :     } else {
     425           1 :       withExternalFict = true;
     426             :     }
     427             :   }
     428          12 :   kbt = getkBT();
     429          12 :   if (kbt <= std::numeric_limits<double>::epsilon()) {
     430           0 :     error("eABF/DRR: It seems the MD engine does not setup the temperature correctly for PLUMED."
     431             :           "Please set it by the TEMP keyword manually.");
     432             :   }
     433          12 :   if (fullsamples < 0.5) {
     434           0 :     fullsamples = 500.0;
     435           0 :     log << "eABF/DRR: The fullsamples parametre is not set. Set it to "
     436             :         "500(default)."
     437           0 :         << '\n';
     438             :   }
     439          12 :   if (getRestart()) {
     440           1 :     if (restart_prefix.length() != 0) {
     441           1 :       isRestart = true;
     442           1 :       firsttime = false;
     443           1 :       load(restart_prefix);
     444             :     } else {
     445           0 :       log << "eABF/DRR: You don't specify the file for restarting." << '\n';
     446           0 :       log << "eABF/DRR: So I assume you are splitting windows." << '\n';
     447           0 :       isRestart = false;
     448           0 :       firsttime = true;
     449             :     }
     450             :   }
     451             : 
     452          12 :   vector<string> gmin(ndims);
     453          12 :   vector<string> zgmin(ndims);
     454          12 :   parseVector("GRID_MIN", gmin);
     455          24 :   parseVector("ZGRID_MIN", zgmin);
     456          12 :   if (gmin.size() != ndims)
     457           0 :     error("eABF/DRR: not enough values for GRID_MIN");
     458          12 :   if (zgmin.size() != ndims) {
     459          33 :     log << "eABF/DRR: You didn't specify ZGRID_MIN. " << '\n'
     460          11 :         << "eABF/DRR: The GRID_MIN will be used instead.";
     461          11 :     zgmin = gmin;
     462             :   }
     463          12 :   vector<string> gmax(ndims);
     464          12 :   vector<string> zgmax(ndims);
     465          12 :   parseVector("GRID_MAX", gmax);
     466          24 :   parseVector("ZGRID_MAX", zgmax);
     467          12 :   if (gmax.size() != ndims)
     468           0 :     error("eABF/DRR: not enough values for GRID_MAX");
     469          12 :   if (zgmax.size() != ndims) {
     470          33 :     log << "eABF/DRR: You didn't specify ZGRID_MAX. " << '\n'
     471          11 :         << "eABF/DRR: The GRID_MAX will be used instead.";
     472          11 :     zgmax = gmax;
     473             :   }
     474          12 :   vector<unsigned> gbin(ndims);
     475          12 :   vector<unsigned> zgbin(ndims);
     476          12 :   vector<double> gspacing(ndims);
     477          12 :   vector<double> zgspacing(ndims);
     478          12 :   parseVector("GRID_BIN", gbin);
     479          12 :   parseVector("ZGRID_BIN", zgbin);
     480          12 :   parseVector("GRID_SPACING", gspacing);
     481          24 :   parseVector("ZGRID_SPACING", zgspacing);
     482          12 :   if (gbin.size() != ndims) {
     483           3 :     log << "eABF/DRR: You didn't specify GRID_BIN. Trying to use GRID_SPACING "
     484             :         "instead."
     485           3 :         << '\n';
     486           3 :     if (gspacing.size() != ndims) {
     487           0 :       error("eABF/DRR: not enough values for GRID_BIN");
     488             :     } else {
     489           3 :       gbin.resize(ndims);
     490           6 :       for (size_t i = 0; i < ndims; ++i) {
     491             :         double l, h;
     492           3 :         PLMD::Tools::convert(gmin[i], l);
     493           3 :         PLMD::Tools::convert(gmax[i], h);
     494           3 :         gbin[i] = std::nearbyint((h - l) / gspacing[i]);
     495           3 :         gspacing[i] = (h - l) / gbin[i];
     496           3 :         log << "GRID_BIN[" << i << "] is " << gbin[i] << '\n';
     497             :       }
     498             :     }
     499             :   }
     500          12 :   if (zgbin.size() != ndims) {
     501          11 :     log << "eABF/DRR: You didn't specify ZGRID_BIN. Trying to use ZGRID_SPACING instead." << '\n';
     502          11 :     if (zgspacing.size() != ndims) {
     503          11 :       log << "eABF/DRR: You didn't specify ZGRID_SPACING. Trying to use GRID_SPACING or GRID_BIN instead." << '\n';
     504          11 :       zgbin = gbin;
     505          11 :       zgspacing = gspacing;
     506             :     } else {
     507           0 :       zgbin.resize(ndims);
     508           0 :       for (size_t i = 0; i < ndims; ++i) {
     509             :         double l, h;
     510           0 :         PLMD::Tools::convert(zgmin[i], l);
     511           0 :         PLMD::Tools::convert(zgmax[i], h);
     512           0 :         zgbin[i] = std::nearbyint((h - l) / zgspacing[i]);
     513           0 :         zgspacing[i] = (h - l) / zgbin[i];
     514           0 :         log << "ZGRID_BIN[" << i << "] is " << zgbin[i] << '\n';
     515             :       }
     516             :     }
     517             :   }
     518          12 :   checkRead();
     519             : 
     520             :   // Set up kbt for extended system
     521          12 :   log << "eABF/DRR: The fullsamples is " << fullsamples << '\n';
     522          12 :   log << "eABF/DRR: The kbt(real system) is " << kbt << '\n';
     523          12 :   dt = getTimeStep() * getStride();
     524          12 :   log << "eABF/DRR: timestep = " << getTimeStep() << " ps with stride = " << getStride() << " steps\n";
     525          12 :   vector<double> ekbt(ndims, 0.0);
     526          12 :   if (etemp.size() != ndims) {
     527          12 :     etemp.assign(ndims, kbt / getKBoltzmann());
     528             :   }
     529          12 :   if (tau.size() != ndims) {
     530           0 :     tau.assign(ndims, 0.5);
     531             :   }
     532          12 :   if (friction.size() != ndims) {
     533           0 :     friction.assign(ndims, 8.0);
     534             :   }
     535          12 :   if (maxFactors.size() != ndims) {
     536           0 :     maxFactors.assign(ndims, 1.0);
     537             :   }
     538          31 :   for (size_t i = 0; i < ndims; ++i) {
     539          19 :     log << "eABF/DRR: The maximum scaling factor [" << i << "] is " << maxFactors[i] << '\n';
     540          19 :     if (maxFactors[i] > 1.0) {
     541           0 :       log << "eABF/DRR: Warning! The maximum scaling factor larger than 1.0 is not recommended!" << '\n';
     542             :     }
     543             :   }
     544          31 :   for (size_t i = 0; i < ndims; ++i) {
     545          19 :     ekbt[i] = etemp[i] * getKBoltzmann();
     546          19 :     log << "eABF/DRR: The kbt(extended system) of [" << i << "] is " << ekbt[i]
     547          19 :         << '\n';
     548          19 :     log << "eABF/DRR: relaxation time tau [" << i << "] is " << tau[i] << '\n';
     549          19 :     log << "eABF/DRR: Extended variable [" << i << "] has friction: " << friction[i] << '\n';
     550             :   }
     551             : 
     552             :   // Set up the force grid
     553          12 :   vector<DRRAxis> zdelim(ndims);
     554          31 :   for (size_t i = 0; i < ndims; ++i) {
     555          19 :     log << "eABF/DRR: The " << i << " dimensional grid minimum is " << gmin[i]
     556          19 :         << '\n';
     557          19 :     log << "eABF/DRR: The " << i << " dimensional grid maximum is " << gmax[i]
     558          19 :         << '\n';
     559          19 :     log << "eABF/DRR: The " << i << " dimensional grid has " << gbin[i]
     560          19 :         << " bins" << '\n';
     561          19 :     log << "eABF/DRR: The " << i << " dimensional zgrid minimum is " << zgmin[i]
     562          19 :         << '\n';
     563          19 :     log << "eABF/DRR: The " << i << " dimensional zgrid maximum is " << zgmax[i]
     564          19 :         << '\n';
     565          19 :     log << "eABF/DRR: The " << i << " dimensional zgrid has " << zgbin[i]
     566          19 :         << " bins" << '\n';
     567             :     double l, h;
     568          19 :     PLMD::Tools::convert(gmin[i], l);
     569          19 :     PLMD::Tools::convert(gmax[i], h);
     570          19 :     delim[i].set(l, h, gbin[i]);
     571             :     double zl,zh;
     572          19 :     PLMD::Tools::convert(zgmin[i], zl);
     573          19 :     PLMD::Tools::convert(zgmax[i], zh);
     574          19 :     zdelim[i].set(zl, zh, zgbin[i]);
     575             :   }
     576          12 :   if (kappa.size() != ndims) {
     577           9 :     kappa.resize(ndims, 0.0);
     578          25 :     for (size_t i = 0; i < ndims; ++i) {
     579          16 :       if (kappa[i] <= 0) {
     580          16 :         log << "eABF/DRR: The spring force constant kappa[" << i
     581          16 :             << "] is not set." << '\n';
     582          16 :         kappa[i] = ekbt[i] / (delim[i].getWidth() * delim[i].getWidth());
     583          16 :         log << "eABF/DRR: set kappa[" << i
     584          16 :             << "] according to bin width(ekbt/(binWidth^2))." << '\n';
     585             :       }
     586          16 :       log << "eABF/DRR: The spring force constant kappa[" << i << "] is "
     587          16 :           << std::fixed << std::setprecision(10) << kappa[i] << '\n';
     588             :     }
     589             :   } else {
     590           3 :     log << "eABF/DRR: The kappa have been set manually." << '\n';
     591           6 :     for (size_t i = 0; i < ndims; ++i) {
     592           3 :       log << "eABF/DRR: The spring force constant kappa[" << i << "] is "
     593           3 :           << std::fixed << std::setprecision(10) << kappa[i] << '\n';
     594             :     }
     595             :   }
     596             : 
     597          31 :   for (size_t i = 0; i < ndims; ++i) {
     598          19 :     mass[i] = kappa[i] * tau[i] * tau[i] / (4 * pi * pi);
     599          19 :     log << "eABF/DRR: Fictitious mass[" << i << "] is " << mass[i] << '\n';
     600          19 :     c1[i] = exp(-0.5 * friction[i] * dt);
     601          19 :     c2[i] = sqrt(ekbt[i] * (1.0 - c1[i] * c1[i]) / mass[i]);
     602             :   }
     603             : 
     604          31 :   for (size_t i = 0; i < ndims; ++i) {
     605             :     // Position output
     606          19 :     string comp = getPntrToArgument(i)->getName() + "_fict";
     607          38 :     addComponentWithDerivatives(comp);
     608          19 :     if (getPntrToArgument(i)->isPeriodic()) {
     609             :       string a, b;
     610             :       double c, d;
     611          16 :       getPntrToArgument(i)->getDomain(a, b);
     612          16 :       getPntrToArgument(i)->getDomain(c, d);
     613          16 :       componentIsPeriodic(comp, a, b);
     614          16 :       delim[i].setPeriodicity(c, d);
     615             :       zdelim[i].setPeriodicity(c, d);
     616             :     } else
     617           3 :       componentIsNotPeriodic(comp);
     618          19 :     fictValue[i] = getPntrToComponent(comp);
     619             :     // Velocity output
     620          38 :     comp = getPntrToArgument(i)->getName() + "_vfict";
     621          19 :     addComponent(comp);
     622          19 :     componentIsNotPeriodic(comp);
     623          19 :     vfictValue[i] = getPntrToComponent(comp);
     624             :     // Bias force from eABF/DRR output
     625          38 :     comp = getPntrToArgument(i)->getName() + "_biasforce";
     626          19 :     addComponent(comp);
     627          19 :     componentIsNotPeriodic(comp);
     628          19 :     biasforceValue[i] = getPntrToComponent(comp);
     629             :     // Spring force output, useful for perform egABF and other analysis
     630          38 :     comp = getPntrToArgument(i)->getName() + "_springforce";
     631          19 :     addComponent(comp);
     632          19 :     componentIsNotPeriodic(comp);
     633          19 :     springforceValue[i] = getPntrToComponent(comp);
     634             :     // Position output, no pbc-aware
     635          38 :     comp = getPntrToArgument(i)->getName() + "_fictNoPBC";
     636          19 :     addComponent(comp);
     637          19 :     componentIsNotPeriodic(comp);
     638          19 :     fictNoPBCValue[i] = getPntrToComponent(comp);
     639             :   }
     640             : 
     641          12 :   if (outputprefix.length() == 0) {
     642           0 :     outputprefix = getLabel();
     643             :   }
     644             :   // Support multiple replica
     645          12 :   string replica_suffix = plumed.getSuffix();
     646          12 :   if (replica_suffix.empty() == false) {
     647           4 :     outputprefix = outputprefix + replica_suffix;
     648             :   }
     649          12 :   outputname = outputprefix + ".drrstate";
     650          12 :   cptname = outputprefix + ".cpt.drrstate";
     651             : 
     652          12 :   if (!isRestart) {
     653             :     // If you want to use on-the-fly text output for CZAR and naive estimator,
     654             :     // you should turn it to true first!
     655          11 :     ABFGrid = ABF(delim, ".abf", fullsamples, maxFactors, textoutput);
     656             :     // Just initialize it even useCZARestimator is off.
     657          22 :     CZARestimator = CZAR(zdelim, ".czar", kbt, textoutput);
     658          11 :     log << "eABF/DRR: The init function of the grid is finished." << '\n';
     659             :   } else {
     660             :     // ABF Parametres are not saved in binary files
     661             :     // So manully set them up
     662           1 :     ABFGrid.setParameters(fullsamples, maxFactors);
     663             :   }
     664          12 :   if (useCZARestimator) {
     665          12 :     log << "eABF/DRR: Using corrected z-average restraint estimator of gradients" << '\n';
     666          24 :     log << "  Bibliography " << plumed.cite("Lesage, Lelièvre, Stoltz and Hénin, "
     667          24 :                                             "J. Phys. Chem. B 3676, 121 (2017)");
     668          12 :     log << plumed.cite("Darve and Pohorille, J. Chem. Phys. 9169, 115 (2001)") << '\n';
     669             :   }
     670          12 :   if (useUIestimator) {
     671           9 :     log << "eABF/DRR: Using umbrella integration(Zheng and Yang's) estimator "
     672             :         "of gradients."
     673           9 :         << '\n';
     674           9 :     log << "eABF/DRR: The UI estimator code is contributed by Haohao Fu."
     675           9 :         << '\n';
     676          18 :     log << "  Bibliography " << plumed.cite(
     677          18 :           "Fu, Shao, Chipot and Cai, J. Chem. Theory Comput. 3506, 12 (2016)");
     678          18 :     log << plumed.cite("Zheng and Yang, J. Chem. Theory Comput. 810, 8 (2012)");
     679           9 :     log << plumed.cite("Darve and Pohorille, J. Chem. Phys. 9169, 115 (2001)") << '\n';
     680           9 :     vector<double> lowerboundary(zdelim.size(), 0);
     681           9 :     vector<double> upperboundary(zdelim.size(), 0);
     682           9 :     vector<double> width(zdelim.size(), 0);
     683          24 :     for (size_t i = 0; i < zdelim.size(); ++i) {
     684          15 :       lowerboundary[i] = zdelim[i].getMin();
     685          15 :       upperboundary[i] = zdelim[i].getMax();
     686          15 :       width[i] = zdelim[i].getWidth();
     687             :     }
     688             :     vector<string> input_filename;
     689             :     bool uirestart = false;
     690           9 :     if (isRestart && (uirprefix.length() != 0)) {
     691           1 :       input_filename.push_back(uirprefix);
     692             :       uirestart = true;
     693             :     }
     694           9 :     if (isRestart && (uirprefix.length() == 0)) {
     695           0 :       input_filename.push_back(outputprefix);
     696             :     }
     697           9 :     eabf_UI = UIestimator::UIestimator(
     698           9 :                 lowerboundary, upperboundary, width, kappa, outputprefix, int(outputfreq),
     699          18 :                 uirestart, input_filename, kbt / getKBoltzmann());
     700           9 :   }
     701          24 : }
     702             : 
     703         123 : void DynamicReferenceRestraining::calculate() {
     704         123 :   if (firsttime) {
     705          28 :     for (size_t i = 0; i < ndims; ++i) {
     706          17 :       fict[i] = getArgument(i);
     707          17 :       if(reflectingWall[i] && (fict[i]>=delim[i].getMax() || fict[i]<=delim[i].getMin())) {
     708           0 :         error("eABF/DRR: initial position not in the range of [gmin, gmax]!");
     709             :       }
     710             :     }
     711          11 :     firsttime = false;
     712             :   }
     713         123 :   if (withExternalForce == false) {
     714             :     double ene = 0.0;
     715         294 :     for (size_t i = 0; i < ndims; ++i) {
     716         183 :       real[i] = getArgument(i);
     717         183 :       springlength[i] = difference(i, fict[i], real[i]);
     718         183 :       fictNoPBC[i] = real[i] - springlength[i];
     719         183 :       double f = -kappa[i] * springlength[i];
     720         183 :       ffict_measured[i] = -f;
     721         183 :       ene += 0.5 * kappa[i] * springlength[i] * springlength[i];
     722         183 :       setOutputForce(i, f);
     723         183 :       ffict[i] = -f;
     724         183 :       fict[i] = fictValue[i]->bringBackInPbc(fict[i]);
     725         183 :       fictValue[i]->set(fict[i]);
     726         183 :       vfictValue[i]->set(vfict_laststep[i]);
     727         183 :       springforceValue[i]->set(ffict_measured[i]);
     728         183 :       fictNoPBCValue[i]->set(fictNoPBC[i]);
     729             :     }
     730         111 :     setBias(ene);
     731         111 :     ABFGrid.getbias(fict, ffict_measured, fbias);
     732             :   } else {
     733          36 :     for (size_t i = 0; i < ndims; ++i) {
     734          24 :       real[i] = getArgument(i);
     735          24 :       ffict_measured[i] = externalForceValue[i]->get();
     736          24 :       if (withExternalFict) {
     737          24 :         fictNoPBC[i] = externalFictValue[i]->get();
     738             :       }
     739          24 :       springforceValue[i]->set(ffict_measured[i]);
     740          24 :       fictNoPBCValue[i]->set(fictNoPBC[i]);
     741             :     }
     742          12 :     ABFGrid.getbias(real, ffict_measured, fbias);
     743          12 :     if (!nobias) {
     744           0 :       for (size_t i = 0; i < ndims; ++i) {
     745           0 :         setOutputForce(i, fbias[i]);
     746             :       }
     747             :     }
     748             :   }
     749         123 : }
     750             : 
     751         123 : void DynamicReferenceRestraining::update() {
     752         123 :   const long long int step_now = getStep();
     753         123 :   if (step_now != 0) {
     754         111 :     if ((step_now % int(outputfreq)) == 0) {
     755          15 :       save(outputname, step_now);
     756          15 :       if (textoutput) {
     757          10 :         ABFGrid.writeAll(outputprefix, fmt_);
     758          10 :         if (useCZARestimator) {
     759          10 :           CZARestimator.writeAll(outputprefix, fmt_);
     760          10 :           CZARestimator.writeZCountZGrad(outputprefix);
     761             :         }
     762             :       }
     763             :     }
     764         111 :     if (historyfreq > 0 && (step_now % int(historyfreq)) == 0) {
     765           4 :       if (textoutput) {
     766             :         const string filename =
     767           4 :           outputprefix + ".another.drrstate";
     768           4 :         save(filename, step_now);
     769             :         const string textfilename =
     770           4 :           mergeHistoryFiles ? (outputprefix + ".hist") : (outputprefix + "." + std::to_string(step_now));
     771           4 :         ABFGrid.writeAll(textfilename, fmt_, mergeHistoryFiles);
     772           4 :         if (useCZARestimator) {
     773           4 :           CZARestimator.writeAll(textfilename, fmt_, mergeHistoryFiles);
     774           4 :           CZARestimator.writeZCountZGrad(textfilename, mergeHistoryFiles);
     775             :         }
     776             :       } else {
     777             :         const string filename =
     778           0 :           outputprefix + "." + std::to_string(step_now) + ".drrstate";
     779           0 :         save(filename, step_now);
     780             :       }
     781             :     }
     782         111 :     if (getCPT()) {
     783           0 :       log << "eABF/DRR: The MD engine is writing checkpoint so we also write a "
     784             :           "DRR state file at step: "
     785           0 :           << step_now << ".\n";
     786           0 :       save(cptname, step_now);
     787             :     }
     788             :   }
     789         123 :   if (withExternalForce == false) {
     790         294 :     for (size_t i = 0; i < ndims; ++i) {
     791         183 :       real[i] = getArgument(i);
     792         183 :       springlength[i] = difference(i, fict[i], real[i]);
     793         183 :       ffict_measured[i] = kappa[i] * springlength[i];
     794             :     }
     795         111 :     ABFGrid.store_force(fict, ffict_measured);
     796             :   } else {
     797          36 :     for (size_t i = 0; i < ndims; ++i) {
     798          24 :       real[i] = getArgument(i);
     799          24 :       ffict_measured[i] = externalForceValue[i]->get();
     800             :     }
     801          12 :     ABFGrid.store_force(real, ffict_measured);
     802             :   }
     803         123 :   if (useCZARestimator) {
     804         123 :     CZARestimator.store(real, ffict_measured);
     805             :   }
     806         123 :   if (useUIestimator) {
     807          87 :     eabf_UI.update_output_filename(outputprefix);
     808         174 :     eabf_UI.update(int(step_now), real, fictNoPBC);
     809             :   }
     810         123 :   if (withExternalForce == false) {
     811         294 :     for (size_t i = 0; i < ndims; ++i) {
     812             :       // consider additional forces on the fictitious particle
     813             :       // (e.g. MetaD stuff)
     814         183 :       ffict[i] += fictValue[i]->getForce();
     815         183 :       if (!nobias) {
     816         183 :         ffict[i] += fbias[i];
     817             :       }
     818         183 :       biasforceValue[i]->set(fbias[i]);
     819             :       // update velocity (half step)
     820         183 :       vfict[i] += ffict[i] * 0.5 * dt / mass[i];
     821             :       // thermostat (half step)
     822         183 :       vfict[i] = c1[i] * vfict[i] + c2[i] * rand.Gaussian();
     823             :       // save full step velocity to be dumped at next step
     824         183 :       vfict_laststep[i] = vfict[i];
     825             :       // thermostat (half step)
     826         183 :       vfict[i] = c1[i] * vfict[i] + c2[i] * rand.Gaussian();
     827             :       // update velocity (half step)
     828         183 :       vfict[i] += ffict[i] * 0.5 * dt / mass[i];
     829             :       // update position (full step)
     830         183 :       fict[i] += vfict[i] * dt;
     831             :       // reflecting boundary
     832         183 :       if (reflectingWall[i]) {
     833          24 :         if (fict[i]<delim[i].getMin()) {
     834           1 :           fict[i]=delim[i].getMin()+(delim[i].getMin()-fict[i]);
     835           1 :           vfict[i]*=-1.0;
     836          23 :         } else if (fict[i]>delim[i].getMax()) {
     837           0 :           fict[i]=delim[i].getMax()-(fict[i]-delim[i].getMax());
     838           0 :           vfict[i]*=-1.0;
     839             :         }
     840             :       }
     841             :     }
     842             :   }
     843         123 : }
     844             : 
     845          19 : void DynamicReferenceRestraining::save(const string &filename,
     846             :                                        long long int step) {
     847          19 :   std::ofstream out;
     848          19 :   out.open(filename.c_str(), std::ios::binary);
     849          19 :   boost::archive::binary_oarchive oa(out);
     850          19 :   oa << step << fict << vfict << vfict_laststep << ffict << ABFGrid
     851          19 :      << CZARestimator;
     852          19 :   out.close();
     853          19 : }
     854             : 
     855           1 : void DynamicReferenceRestraining::load(const string &rfile_prefix) {
     856           1 :   string replica_suffix = plumed.getSuffix();
     857             :   string filename;
     858           1 :   if (replica_suffix.empty() == true) {
     859           2 :     filename = rfile_prefix + ".drrstate";
     860             :   } else {
     861           0 :     filename = rfile_prefix + "." + replica_suffix + ".drrstate";
     862             :   }
     863           1 :   std::ifstream in;
     864             :   long long int step;
     865           1 :   in.open(filename.c_str(), std::ios::binary);
     866           1 :   log << "eABF/DRR: Read restart file: " << filename << '\n';
     867           1 :   boost::archive::binary_iarchive ia(in);
     868           1 :   ia >> step >> fict >> vfict >> vfict_laststep >> ffict >> ABFGrid >>
     869           1 :      CZARestimator;
     870           1 :   in.close();
     871           1 :   log << "eABF/DRR: Restart at step: " << step << '\n';
     872           1 :   backupFile(filename);
     873           2 : }
     874             : 
     875           1 : void DynamicReferenceRestraining::backupFile(const string &filename) {
     876             :   bool isSuccess = false;
     877             :   long int i = 0;
     878           2 :   while (!isSuccess) {
     879             :     // If libstdc++ support C++17 we can simplify following code.
     880           2 :     const string bckname = "bck." + filename + "." + std::to_string(i);
     881           1 :     if (is_file_exist(bckname.c_str())) {
     882           0 :       ++i;
     883             :     } else {
     884           1 :       log << "eABF/DRR: Backup original restart file to " << bckname << '\n';
     885           1 :       std::ifstream src(filename.c_str(), std::ios::binary);
     886           1 :       std::ofstream dst(bckname.c_str(), std::ios::binary);
     887           1 :       dst << src.rdbuf();
     888           1 :       src.close();
     889           1 :       dst.close();
     890             :       isSuccess = true;
     891           1 :     }
     892             :   }
     893           1 : }
     894             : 
     895             : // Copy from
     896             : // stackoverflow(https://stackoverflow.com/questions/12774207/fastest-way-to-check-if-a-file-exist-using-standard-c-c11-c)
     897           1 : bool DynamicReferenceRestraining::is_file_exist(const char *fileName) {
     898           1 :   std::ifstream infile(fileName);
     899           1 :   return infile.good();
     900           1 : }
     901             : }
     902             : }
     903             : 
     904             : #endif

Generated by: LCOV version 1.16