LCOV - code coverage report
Current view: top level - drr - DynamicReferenceRestraining.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 403 444 90.8 %
Date: 2024-10-11 08:09:47 Functions: 11 12 91.7 %

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

Generated by: LCOV version 1.15