LCOV - code coverage report
Current view: top level - drr - DynamicReferenceRestraining.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 403 442 91.2 %
Date: 2024-10-18 14:00:25 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          14 :   keys.use("ARG");
     250          28 :   keys.add("optional", "KAPPA", "specifies that the restraint is harmonic and "
     251             :            "what the values of the force constants on "
     252             :            "each of the variables are (default to "
     253             :            "k_BT/(GRID_SPACING)^2)");
     254          28 :   keys.add("compulsory", "TAU", "0.5", "specifies relaxation time on each of "
     255             :            "variables are, similar to "
     256             :            "extended Time Constant in Colvars");
     257          28 :   keys.add("compulsory", "FRICTION", "8.0",
     258             :            "add a friction to the variable, similar to extended Langevin Damping "
     259             :            "in Colvars");
     260          28 :   keys.add("compulsory", "GRID_MIN", "the lower bounds for the grid (GRID_BIN "
     261             :            "or GRID_SPACING should be specified)");
     262          28 :   keys.add("compulsory", "GRID_MAX", "the upper bounds for the grid (GRID_BIN "
     263             :            "or GRID_SPACING should be specified)");
     264          28 :   keys.add("compulsory", "REFLECTINGWALL", "0", "whether add reflecting walls "
     265             :            "for each CV at GRID_MIN and GRID_MAX. Setting non-zero values will "
     266             :            "enable this feature");
     267          28 :   keys.add("optional", "GRID_BIN", "the number of bins for the grid");
     268          28 :   keys.add("optional", "GRID_SPACING", "the approximate grid spacing (to be "
     269             :            "used as an alternative or together "
     270             :            "with GRID_BIN)");
     271          28 :   keys.add("optional", "ZGRID_MIN", "the lower bounds for the grid (ZGRID_BIN"
     272             :            " or ZGRID_SPACING should be specified)");
     273          28 :   keys.add("optional", "ZGRID_MAX", "the upper bounds for the grid (ZGRID_BIN"
     274             :            " or ZGRID_SPACING should be specified)");
     275          28 :   keys.add("optional", "ZGRID_BIN", "the number of bins for the grid");
     276          28 :   keys.add("optional", "ZGRID_SPACING", "the approximate grid spacing (to be "
     277             :            "used as an alternative or together "
     278             :            "with ZGRID_BIN)");
     279          28 :   keys.add("optional", "EXTERNAL_FORCE", "use forces from other action instead"
     280             :            " of internal spring force, this disable the extended system!");
     281          28 :   keys.add("optional", "EXTERNAL_FICT", "position of external fictitious "
     282             :            "particles, useful for UIESTIMATOR");
     283          28 :   keys.add("compulsory", "FULLSAMPLES", "500",
     284             :            "number of samples in a bin prior to application of the ABF");
     285          28 :   keys.add("compulsory", "MAXFACTOR", "1.0",
     286             :            "maximum scaling factor of biasing force");
     287          28 :   keys.add("compulsory", "OUTPUTFREQ", "write results to a file every N steps");
     288          28 :   keys.add("optional", "HISTORYFREQ", "save history to a file every N steps");
     289          28 :   keys.addFlag("NOCZAR", false, "disable the CZAR estimator");
     290          28 :   keys.addFlag("UI", false,
     291             :                "enable the umbrella integration estimator");
     292          28 :   keys.add("optional", "UIRESTARTPREFIX",
     293             :            "specify the restart files for umbrella integration");
     294          28 :   keys.add("optional", "OUTPUTPREFIX",
     295             :            "specify the output prefix (default to the label name)");
     296          28 :   keys.add("optional", "TEMP", "the system temperature - needed when FRICTION "
     297             :            "is present. If not provided will be taken from "
     298             :            "MD code (if available)");
     299          28 :   keys.add(
     300             :     "optional", "EXTTEMP",
     301             :     "the temperature of extended variables (default to system temperature)");
     302          28 :   keys.add("optional", "DRR_RFILE",
     303             :            "specifies the restart file (.drrstate file)");
     304          28 :   keys.addFlag("NOBIAS", false, "DO NOT apply bias forces.");
     305          28 :   keys.addFlag("TEXTOUTPUT", false, "use text output for grad and count files "
     306             :                "instead of boost::serialization binary "
     307             :                "output");
     308          28 :   keys.addFlag("MERGEHISTORYFILES", false, "output all historic results "
     309             :                "to a single file rather than multiple .drrstate files. "
     310             :                "This option is effective only when textOutput is on.");
     311          28 :   keys.add("optional","FMT","specify format for outfiles files (useful for decrease the number of digits in regtests)");
     312          28 :   keys.addOutputComponent(
     313             :     "_fict", "default",
     314             :     "one or multiple instances of this quantity can be referenced "
     315             :     "elsewhere in the input file. "
     316             :     "These quantities will named with the arguments of the bias followed by "
     317             :     "the character string _tilde. It is possible to add forces on these "
     318             :     "variable.");
     319          28 :   keys.addOutputComponent(
     320             :     "_vfict", "default",
     321             :     "one or multiple instances of this quantity can be referenced "
     322             :     "elsewhere in the input file. "
     323             :     "These quantities will named with the arguments of the bias followed by "
     324             :     "the character string _tilde. It is NOT possible to add forces on these "
     325             :     "variable.");
     326          28 :   keys.addOutputComponent(
     327             :     "_biasforce", "default",
     328             :     "The bias force from eABF/DRR of the fictitious particle.");
     329          28 :   keys.addOutputComponent("_springforce", "default", "Spring force between real CVs and extended CVs");
     330          28 :   keys.addOutputComponent("_fictNoPBC", "default",
     331             :                           "the positions of fictitious particles (without PBC).");
     332          14 : }
     333             : 
     334          12 : DynamicReferenceRestraining::DynamicReferenceRestraining(
     335          12 :   const ActionOptions &ao)
     336          12 :   : PLUMED_BIAS_INIT(ao), firsttime(true), nobias(false),
     337          12 :     fictNoPBC(getNumberOfArguments(), 0.0), real(getNumberOfArguments(), 0.0),
     338          12 :     springlength(getNumberOfArguments(), 0.0),
     339          12 :     fict(getNumberOfArguments(), 0.0), vfict(getNumberOfArguments(), 0.0),
     340          12 :     vfict_laststep(getNumberOfArguments(), 0.0),
     341          12 :     ffict(getNumberOfArguments(), 0.0), fbias(getNumberOfArguments(), 0.0),
     342          12 :     kappa(getNumberOfArguments(), 0.0), tau(getNumberOfArguments(), 0.0),
     343          12 :     friction(getNumberOfArguments(), 0.0), etemp(getNumberOfArguments(), 0.0),
     344          12 :     ffict_measured(getNumberOfArguments(), 0.0),
     345          12 :     biasforceValue(getNumberOfArguments(), NULL),
     346          12 :     springforceValue(getNumberOfArguments(), NULL),
     347          12 :     fictValue(getNumberOfArguments(), NULL),
     348          12 :     vfictValue(getNumberOfArguments(), NULL),
     349          12 :     fictNoPBCValue(getNumberOfArguments(), NULL),
     350          12 :     externalForceValue(getNumberOfArguments(), NULL),
     351          12 :     externalFictValue(getNumberOfArguments(), NULL),
     352          12 :     c1(getNumberOfArguments(), 0.0),
     353          12 :     c2(getNumberOfArguments(), 0.0), mass(getNumberOfArguments(), 0.0),
     354          12 :     delim(getNumberOfArguments()), outputname(""), cptname(""),
     355          12 :     outputprefix(""), fmt_("%.9f"), ndims(getNumberOfArguments()), dt(0.0), kbt(0.0),
     356          12 :     outputfreq(0.0), historyfreq(-1.0), isRestart(false),
     357          12 :     useCZARestimator(true), useUIestimator(false), mergeHistoryFiles(false),
     358          12 :     textoutput(false), withExternalForce(false), withExternalFict(false),
     359          12 :     reflectingWall(getNumberOfArguments(), 0),
     360          36 :     maxFactors(getNumberOfArguments(), 1.0)
     361             : {
     362          12 :   log << "eABF/DRR: You now are using the extended adaptive biasing "
     363             :       "force(eABF) method."
     364          12 :       << '\n';
     365          12 :   log << "eABF/DRR: Some people also refer to it as dynamic reference "
     366             :       "restraining(DRR) method."
     367          12 :       << '\n';
     368          12 :   log << "eABF/DRR: Currently the CZAR and naive(ABF on extended variables) "
     369             :       "estimator is enabled by default."
     370          12 :       << '\n';
     371          12 :   log << "eABF/DRR: For reasons of performance, the umbrella integration "
     372             :       "estimator is not enabled by default."
     373          12 :       << '\n';
     374          12 :   log << "eABF/DRR: This method is originally implemented in "
     375             :       "colvars(https://github.com/colvars/colvars)."
     376          12 :       << '\n';
     377          12 :   log << "eABF/DRR: The code in plumed is heavily modified from "
     378             :       "ExtendedLagrangian.cpp and doesn't implemented all variants of "
     379             :       "eABF/DRR."
     380          12 :       << '\n';
     381          12 :   log << "eABF/DRR: The thermostat used here may be different from Colvars."
     382          12 :       << '\n';
     383          12 :   log << "eABF/DRR: To integrate the gradients file, you can use abf_integrate "
     384             :       "from https://github.com/colvars/colvars/tree/master/colvartools."
     385          12 :       << '\n';
     386          12 :   log << "eABF/DRR: Please read relevant articles and use this biasing "
     387             :       "method carefully!"
     388          12 :       << '\n';
     389          12 :   parseFlag("NOBIAS", nobias);
     390          12 :   parseFlag("UI", useUIestimator);
     391          12 :   bool noCZAR = false;
     392          12 :   parseFlag("NOCZAR", noCZAR);
     393             : //   noCZAR == false ? useCZARestimator = true : useCZARestimator = false;
     394          12 :   parseFlag("TEXTOUTPUT", textoutput);
     395          12 :   parseFlag("MERGEHISTORYFILES", mergeHistoryFiles);
     396          12 :   parseVector("TAU", tau);
     397          12 :   parseVector("FRICTION", friction);
     398          12 :   parseVector("EXTTEMP", etemp);
     399          12 :   parseVector("KAPPA", kappa);
     400          12 :   parseVector("REFLECTINGWALL", reflectingWall);
     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          12 :   parseArgumentList("EXTERNAL_FICT", externalFictValue);
     412          24 :   parse("FMT",fmt_);
     413          12 :   if (externalForceValue.empty()) {
     414          11 :     withExternalForce = false;
     415           1 :   } else if (externalForceValue.size() != ndims) {
     416           0 :     error("eABF/DRR: Number of forces doesn't match ARGS!");
     417             :   } else {
     418           1 :     withExternalForce = true;
     419             :   }
     420          12 :   if (withExternalForce && useUIestimator) {
     421           1 :     if (externalFictValue.empty()) {
     422           0 :       error("eABF/DRR: No external fictitious particles specified. UI estimator needs it.");
     423           1 :     } else if(externalFictValue.size() != ndims) {
     424           0 :       error("eABF/DRR: Number of fictitious particles doesn't match ARGS!");
     425             :     } else {
     426           1 :       withExternalFict = true;
     427             :     }
     428             :   }
     429          12 :   kbt = getkBT();
     430          12 :   if (kbt <= std::numeric_limits<double>::epsilon()) {
     431           0 :     error("eABF/DRR: It seems the MD engine does not setup the temperature correctly for PLUMED."
     432             :           "Please set it by the TEMP keyword manually.");
     433             :   }
     434          12 :   if (fullsamples < 0.5) {
     435           0 :     fullsamples = 500.0;
     436           0 :     log << "eABF/DRR: The fullsamples parametre is not set. Set it to "
     437             :         "500(default)."
     438           0 :         << '\n';
     439             :   }
     440          12 :   if (getRestart()) {
     441           1 :     if (restart_prefix.length() != 0) {
     442           1 :       isRestart = true;
     443           1 :       firsttime = false;
     444           1 :       load(restart_prefix);
     445             :     } else {
     446           0 :       log << "eABF/DRR: You don't specify the file for restarting." << '\n';
     447           0 :       log << "eABF/DRR: So I assume you are splitting windows." << '\n';
     448           0 :       isRestart = false;
     449           0 :       firsttime = true;
     450             :     }
     451             :   }
     452             : 
     453          12 :   vector<string> gmin(ndims);
     454          12 :   vector<string> zgmin(ndims);
     455          12 :   parseVector("GRID_MIN", gmin);
     456          24 :   parseVector("ZGRID_MIN", zgmin);
     457          12 :   if (gmin.size() != ndims)
     458           0 :     error("eABF/DRR: not enough values for GRID_MIN");
     459          12 :   if (zgmin.size() != ndims) {
     460          33 :     log << "eABF/DRR: You didn't specify ZGRID_MIN. " << '\n'
     461          11 :         << "eABF/DRR: The GRID_MIN will be used instead.";
     462          11 :     zgmin = gmin;
     463             :   }
     464          12 :   vector<string> gmax(ndims);
     465          12 :   vector<string> zgmax(ndims);
     466          12 :   parseVector("GRID_MAX", gmax);
     467          24 :   parseVector("ZGRID_MAX", zgmax);
     468          12 :   if (gmax.size() != ndims)
     469           0 :     error("eABF/DRR: not enough values for GRID_MAX");
     470          12 :   if (zgmax.size() != ndims) {
     471          33 :     log << "eABF/DRR: You didn't specify ZGRID_MAX. " << '\n'
     472          11 :         << "eABF/DRR: The GRID_MAX will be used instead.";
     473          11 :     zgmax = gmax;
     474             :   }
     475          12 :   vector<unsigned> gbin(ndims);
     476          12 :   vector<unsigned> zgbin(ndims);
     477          12 :   vector<double> gspacing(ndims);
     478          12 :   vector<double> zgspacing(ndims);
     479          12 :   parseVector("GRID_BIN", gbin);
     480          12 :   parseVector("ZGRID_BIN", zgbin);
     481          12 :   parseVector("GRID_SPACING", gspacing);
     482          24 :   parseVector("ZGRID_SPACING", zgspacing);
     483          12 :   if (gbin.size() != ndims) {
     484           3 :     log << "eABF/DRR: You didn't specify GRID_BIN. Trying to use GRID_SPACING "
     485             :         "instead."
     486           3 :         << '\n';
     487           3 :     if (gspacing.size() != ndims) {
     488           0 :       error("eABF/DRR: not enough values for GRID_BIN");
     489             :     } else {
     490           3 :       gbin.resize(ndims);
     491           6 :       for (size_t i = 0; i < ndims; ++i) {
     492             :         double l, h;
     493           3 :         PLMD::Tools::convert(gmin[i], l);
     494           3 :         PLMD::Tools::convert(gmax[i], h);
     495           3 :         gbin[i] = std::nearbyint((h - l) / gspacing[i]);
     496           3 :         gspacing[i] = (h - l) / gbin[i];
     497           3 :         log << "GRID_BIN[" << i << "] is " << gbin[i] << '\n';
     498             :       }
     499             :     }
     500             :   }
     501          12 :   if (zgbin.size() != ndims) {
     502          11 :     log << "eABF/DRR: You didn't specify ZGRID_BIN. Trying to use ZGRID_SPACING instead." << '\n';
     503          11 :     if (zgspacing.size() != ndims) {
     504          11 :       log << "eABF/DRR: You didn't specify ZGRID_SPACING. Trying to use GRID_SPACING or GRID_BIN instead." << '\n';
     505          11 :       zgbin = gbin;
     506          11 :       zgspacing = gspacing;
     507             :     } else {
     508           0 :       zgbin.resize(ndims);
     509           0 :       for (size_t i = 0; i < ndims; ++i) {
     510             :         double l, h;
     511           0 :         PLMD::Tools::convert(zgmin[i], l);
     512           0 :         PLMD::Tools::convert(zgmax[i], h);
     513           0 :         zgbin[i] = std::nearbyint((h - l) / zgspacing[i]);
     514           0 :         zgspacing[i] = (h - l) / zgbin[i];
     515           0 :         log << "ZGRID_BIN[" << i << "] is " << zgbin[i] << '\n';
     516             :       }
     517             :     }
     518             :   }
     519          12 :   checkRead();
     520             : 
     521             :   // Set up kbt for extended system
     522          12 :   log << "eABF/DRR: The fullsamples is " << fullsamples << '\n';
     523          12 :   log << "eABF/DRR: The kbt(real system) is " << kbt << '\n';
     524          12 :   dt = getTimeStep() * getStride();
     525          12 :   log << "eABF/DRR: timestep = " << getTimeStep() << " ps with stride = " << getStride() << " steps\n";
     526          12 :   vector<double> ekbt(ndims, 0.0);
     527          12 :   if (etemp.size() != ndims) {
     528          12 :     etemp.assign(ndims, kbt / getKBoltzmann());
     529             :   }
     530          12 :   if (tau.size() != ndims) {
     531           0 :     tau.assign(ndims, 0.5);
     532             :   }
     533          12 :   if (friction.size() != ndims) {
     534           0 :     friction.assign(ndims, 8.0);
     535             :   }
     536          12 :   if (maxFactors.size() != ndims) {
     537           0 :     maxFactors.assign(ndims, 1.0);
     538             :   }
     539          31 :   for (size_t i = 0; i < ndims; ++i) {
     540          19 :     log << "eABF/DRR: The maximum scaling factor [" << i << "] is " << maxFactors[i] << '\n';
     541          19 :     if (maxFactors[i] > 1.0) {
     542           0 :       log << "eABF/DRR: Warning! The maximum scaling factor larger than 1.0 is not recommended!" << '\n';
     543             :     }
     544             :   }
     545          31 :   for (size_t i = 0; i < ndims; ++i) {
     546          19 :     ekbt[i] = etemp[i] * getKBoltzmann();
     547          19 :     log << "eABF/DRR: The kbt(extended system) of [" << i << "] is " << ekbt[i]
     548          19 :         << '\n';
     549          19 :     log << "eABF/DRR: relaxation time tau [" << i << "] is " << tau[i] << '\n';
     550          19 :     log << "eABF/DRR: Extended variable [" << i << "] has friction: " << friction[i] << '\n';
     551             :   }
     552             : 
     553             :   // Set up the force grid
     554          12 :   vector<DRRAxis> zdelim(ndims);
     555          31 :   for (size_t i = 0; i < ndims; ++i) {
     556          19 :     log << "eABF/DRR: The " << i << " dimensional grid minimum is " << gmin[i]
     557          19 :         << '\n';
     558          19 :     log << "eABF/DRR: The " << i << " dimensional grid maximum is " << gmax[i]
     559          19 :         << '\n';
     560          19 :     log << "eABF/DRR: The " << i << " dimensional grid has " << gbin[i]
     561          19 :         << " bins" << '\n';
     562          19 :     log << "eABF/DRR: The " << i << " dimensional zgrid minimum is " << zgmin[i]
     563          19 :         << '\n';
     564          19 :     log << "eABF/DRR: The " << i << " dimensional zgrid maximum is " << zgmax[i]
     565          19 :         << '\n';
     566          19 :     log << "eABF/DRR: The " << i << " dimensional zgrid has " << zgbin[i]
     567          19 :         << " bins" << '\n';
     568             :     double l, h;
     569          19 :     PLMD::Tools::convert(gmin[i], l);
     570          19 :     PLMD::Tools::convert(gmax[i], h);
     571          19 :     delim[i].set(l, h, gbin[i]);
     572             :     double zl,zh;
     573          19 :     PLMD::Tools::convert(zgmin[i], zl);
     574          19 :     PLMD::Tools::convert(zgmax[i], zh);
     575          19 :     zdelim[i].set(zl, zh, zgbin[i]);
     576             :   }
     577          12 :   if (kappa.size() != ndims) {
     578           9 :     kappa.resize(ndims, 0.0);
     579          25 :     for (size_t i = 0; i < ndims; ++i) {
     580          16 :       if (kappa[i] <= 0) {
     581          16 :         log << "eABF/DRR: The spring force constant kappa[" << i
     582          16 :             << "] is not set." << '\n';
     583          16 :         kappa[i] = ekbt[i] / (delim[i].getWidth() * delim[i].getWidth());
     584          16 :         log << "eABF/DRR: set kappa[" << i
     585          16 :             << "] according to bin width(ekbt/(binWidth^2))." << '\n';
     586             :       }
     587          16 :       log << "eABF/DRR: The spring force constant kappa[" << i << "] is "
     588          16 :           << std::fixed << std::setprecision(10) << kappa[i] << '\n';
     589             :     }
     590             :   } else {
     591           3 :     log << "eABF/DRR: The kappa have been set manually." << '\n';
     592           6 :     for (size_t i = 0; i < ndims; ++i) {
     593           3 :       log << "eABF/DRR: The spring force constant kappa[" << i << "] is "
     594           3 :           << std::fixed << std::setprecision(10) << kappa[i] << '\n';
     595             :     }
     596             :   }
     597             : 
     598          31 :   for (size_t i = 0; i < ndims; ++i) {
     599          19 :     mass[i] = kappa[i] * tau[i] * tau[i] / (4 * pi * pi);
     600          19 :     log << "eABF/DRR: Fictitious mass[" << i << "] is " << mass[i] << '\n';
     601          19 :     c1[i] = exp(-0.5 * friction[i] * dt);
     602          19 :     c2[i] = sqrt(ekbt[i] * (1.0 - c1[i] * c1[i]) / mass[i]);
     603             :   }
     604             : 
     605          31 :   for (size_t i = 0; i < ndims; ++i) {
     606             :     // Position output
     607          19 :     string comp = getPntrToArgument(i)->getName() + "_fict";
     608          38 :     addComponentWithDerivatives(comp);
     609          19 :     if (getPntrToArgument(i)->isPeriodic()) {
     610             :       string a, b;
     611             :       double c, d;
     612          16 :       getPntrToArgument(i)->getDomain(a, b);
     613          16 :       getPntrToArgument(i)->getDomain(c, d);
     614          16 :       componentIsPeriodic(comp, a, b);
     615          16 :       delim[i].setPeriodicity(c, d);
     616             :       zdelim[i].setPeriodicity(c, d);
     617             :     } else
     618           3 :       componentIsNotPeriodic(comp);
     619          19 :     fictValue[i] = getPntrToComponent(comp);
     620             :     // Velocity output
     621          38 :     comp = getPntrToArgument(i)->getName() + "_vfict";
     622          19 :     addComponent(comp);
     623          19 :     componentIsNotPeriodic(comp);
     624          19 :     vfictValue[i] = getPntrToComponent(comp);
     625             :     // Bias force from eABF/DRR output
     626          38 :     comp = getPntrToArgument(i)->getName() + "_biasforce";
     627          19 :     addComponent(comp);
     628          19 :     componentIsNotPeriodic(comp);
     629          19 :     biasforceValue[i] = getPntrToComponent(comp);
     630             :     // Spring force output, useful for perform egABF and other analysis
     631          38 :     comp = getPntrToArgument(i)->getName() + "_springforce";
     632          19 :     addComponent(comp);
     633          19 :     componentIsNotPeriodic(comp);
     634          19 :     springforceValue[i] = getPntrToComponent(comp);
     635             :     // Position output, no pbc-aware
     636          38 :     comp = getPntrToArgument(i)->getName() + "_fictNoPBC";
     637          19 :     addComponent(comp);
     638          19 :     componentIsNotPeriodic(comp);
     639          19 :     fictNoPBCValue[i] = getPntrToComponent(comp);
     640             :   }
     641             : 
     642          12 :   if (outputprefix.length() == 0) {
     643           0 :     outputprefix = getLabel();
     644             :   }
     645             :   // Support multiple replica
     646          12 :   string replica_suffix = plumed.getSuffix();
     647          12 :   if (replica_suffix.empty() == false) {
     648           4 :     outputprefix = outputprefix + replica_suffix;
     649             :   }
     650          12 :   outputname = outputprefix + ".drrstate";
     651          12 :   cptname = outputprefix + ".cpt.drrstate";
     652             : 
     653          12 :   if (!isRestart) {
     654             :     // If you want to use on-the-fly text output for CZAR and naive estimator,
     655             :     // you should turn it to true first!
     656          11 :     ABFGrid = ABF(delim, ".abf", fullsamples, maxFactors, textoutput);
     657             :     // Just initialize it even useCZARestimator is off.
     658          22 :     CZARestimator = CZAR(zdelim, ".czar", kbt, textoutput);
     659          11 :     log << "eABF/DRR: The init function of the grid is finished." << '\n';
     660             :   } else {
     661             :     // ABF Parametres are not saved in binary files
     662             :     // So manully set them up
     663           1 :     ABFGrid.setParameters(fullsamples, maxFactors);
     664             :   }
     665          12 :   if (useCZARestimator) {
     666          12 :     log << "eABF/DRR: Using corrected z-average restraint estimator of gradients" << '\n';
     667          24 :     log << "  Bibliography " << plumed.cite("Lesage, Lelièvre, Stoltz and Hénin, "
     668          24 :                                             "J. Phys. Chem. B 3676, 121 (2017)");
     669          12 :     log << plumed.cite("Darve and Pohorille, J. Chem. Phys. 9169, 115 (2001)") << '\n';
     670             :   }
     671          12 :   if (useUIestimator) {
     672           9 :     log << "eABF/DRR: Using umbrella integration(Zheng and Yang's) estimator "
     673             :         "of gradients."
     674           9 :         << '\n';
     675           9 :     log << "eABF/DRR: The UI estimator code is contributed by Haohao Fu."
     676           9 :         << '\n';
     677          18 :     log << "  Bibliography " << plumed.cite(
     678          18 :           "Fu, Shao, Chipot and Cai, J. Chem. Theory Comput. 3506, 12 (2016)");
     679          18 :     log << plumed.cite("Zheng and Yang, J. Chem. Theory Comput. 810, 8 (2012)");
     680           9 :     log << plumed.cite("Darve and Pohorille, J. Chem. Phys. 9169, 115 (2001)") << '\n';
     681           9 :     vector<double> lowerboundary(zdelim.size(), 0);
     682           9 :     vector<double> upperboundary(zdelim.size(), 0);
     683           9 :     vector<double> width(zdelim.size(), 0);
     684          24 :     for (size_t i = 0; i < zdelim.size(); ++i) {
     685          15 :       lowerboundary[i] = zdelim[i].getMin();
     686          15 :       upperboundary[i] = zdelim[i].getMax();
     687          15 :       width[i] = zdelim[i].getWidth();
     688             :     }
     689             :     vector<string> input_filename;
     690             :     bool uirestart = false;
     691           9 :     if (isRestart && (uirprefix.length() != 0)) {
     692           1 :       input_filename.push_back(uirprefix);
     693             :       uirestart = true;
     694             :     }
     695           9 :     if (isRestart && (uirprefix.length() == 0)) {
     696           0 :       input_filename.push_back(outputprefix);
     697             :     }
     698           9 :     eabf_UI = UIestimator::UIestimator(
     699           9 :                 lowerboundary, upperboundary, width, kappa, outputprefix, int(outputfreq),
     700          18 :                 uirestart, input_filename, kbt / getKBoltzmann());
     701           9 :   }
     702          24 : }
     703             : 
     704         123 : void DynamicReferenceRestraining::calculate() {
     705         123 :   long long int step_now = getStep();
     706         123 :   if (firsttime) {
     707          28 :     for (size_t i = 0; i < ndims; ++i) {
     708          17 :       fict[i] = getArgument(i);
     709          17 :       if(reflectingWall[i] && (fict[i]>=delim[i].getMax() || fict[i]<=delim[i].getMin())) {
     710           0 :         error("eABF/DRR: initial position not in the range of [gmin, gmax]!");
     711             :       }
     712             :     }
     713          11 :     firsttime = false;
     714             :   }
     715         123 :   if (step_now != 0) {
     716         111 :     if ((step_now % int(outputfreq)) == 0) {
     717          15 :       save(outputname, step_now);
     718          15 :       if (textoutput) {
     719          10 :         ABFGrid.writeAll(outputprefix, fmt_);
     720          10 :         if (useCZARestimator) {
     721          10 :           CZARestimator.writeAll(outputprefix, fmt_);
     722          10 :           CZARestimator.writeZCountZGrad(outputprefix);
     723             :         }
     724             :       }
     725             :     }
     726         111 :     if (historyfreq > 0 && (step_now % int(historyfreq)) == 0) {
     727           4 :       if (textoutput) {
     728             :         const string filename =
     729           4 :           outputprefix + ".another.drrstate";
     730           4 :         save(filename, step_now);
     731             :         const string textfilename =
     732           4 :           mergeHistoryFiles ? (outputprefix + ".hist") : (outputprefix + "." + std::to_string(step_now));
     733           4 :         ABFGrid.writeAll(textfilename, fmt_, mergeHistoryFiles);
     734           4 :         if (useCZARestimator) {
     735           4 :           CZARestimator.writeAll(textfilename, fmt_, mergeHistoryFiles);
     736           4 :           CZARestimator.writeZCountZGrad(textfilename, mergeHistoryFiles);
     737             :         }
     738             :       } else {
     739             :         const string filename =
     740           0 :           outputprefix + "." + std::to_string(step_now) + ".drrstate";
     741           0 :         save(filename, step_now);
     742             :       }
     743             :     }
     744         111 :     if (getCPT()) {
     745           0 :       log << "eABF/DRR: The MD engine is writing checkpoint so we also write a "
     746             :           "DRR state file at step: "
     747           0 :           << step_now << ".\n";
     748           0 :       save(cptname, step_now);
     749             :     }
     750             :   }
     751         123 :   if (withExternalForce == false) {
     752             :     double ene = 0.0;
     753         294 :     for (size_t i = 0; i < ndims; ++i) {
     754         183 :       real[i] = getArgument(i);
     755         183 :       springlength[i] = difference(i, fict[i], real[i]);
     756         183 :       fictNoPBC[i] = real[i] - springlength[i];
     757         183 :       double f = -kappa[i] * springlength[i];
     758         183 :       ffict_measured[i] = -f;
     759         183 :       ene += 0.5 * kappa[i] * springlength[i] * springlength[i];
     760         183 :       setOutputForce(i, f);
     761         183 :       ffict[i] = -f;
     762         183 :       fict[i] = fictValue[i]->bringBackInPbc(fict[i]);
     763         183 :       fictValue[i]->set(fict[i]);
     764         183 :       vfictValue[i]->set(vfict_laststep[i]);
     765         183 :       springforceValue[i]->set(ffict_measured[i]);
     766         183 :       fictNoPBCValue[i]->set(fictNoPBC[i]);
     767             :     }
     768         111 :     setBias(ene);
     769         111 :     ABFGrid.store_getbias(fict, ffict_measured, fbias);
     770             :   } else {
     771          36 :     for (size_t i = 0; i < ndims; ++i) {
     772          24 :       real[i] = getArgument(i);
     773          24 :       ffict_measured[i] = externalForceValue[i]->get();
     774          24 :       if (withExternalFict) {
     775          24 :         fictNoPBC[i] = externalFictValue[i]->get();
     776             :       }
     777          24 :       springforceValue[i]->set(ffict_measured[i]);
     778          24 :       fictNoPBCValue[i]->set(fictNoPBC[i]);
     779             :     }
     780          12 :     ABFGrid.store_getbias(real, ffict_measured, fbias);
     781          12 :     if (!nobias) {
     782           0 :       for (size_t i = 0; i < ndims; ++i) {
     783           0 :         setOutputForce(i, fbias[i]);
     784             :       }
     785             :     }
     786             :   }
     787         123 :   if (useCZARestimator) {
     788         123 :     CZARestimator.store(real, ffict_measured);
     789             :   }
     790         123 :   if (useUIestimator) {
     791          87 :     eabf_UI.update_output_filename(outputprefix);
     792         174 :     eabf_UI.update(int(step_now), real, fictNoPBC);
     793             :   }
     794         123 : }
     795             : 
     796         123 : void DynamicReferenceRestraining::update() {
     797         123 :   if (withExternalForce == false) {
     798         294 :     for (size_t i = 0; i < ndims; ++i) {
     799             :       // consider additional forces on the fictitious particle
     800             :       // (e.g. MetaD stuff)
     801         183 :       ffict[i] += fictValue[i]->getForce();
     802         183 :       if (!nobias) {
     803         183 :         ffict[i] += fbias[i];
     804             :       }
     805         183 :       biasforceValue[i]->set(fbias[i]);
     806             :       // update velocity (half step)
     807         183 :       vfict[i] += ffict[i] * 0.5 * dt / mass[i];
     808             :       // thermostat (half step)
     809         183 :       vfict[i] = c1[i] * vfict[i] + c2[i] * rand.Gaussian();
     810             :       // save full step velocity to be dumped at next step
     811         183 :       vfict_laststep[i] = vfict[i];
     812             :       // thermostat (half step)
     813         183 :       vfict[i] = c1[i] * vfict[i] + c2[i] * rand.Gaussian();
     814             :       // update velocity (half step)
     815         183 :       vfict[i] += ffict[i] * 0.5 * dt / mass[i];
     816             :       // update position (full step)
     817         183 :       fict[i] += vfict[i] * dt;
     818             :       // reflecting boundary
     819         183 :       if (reflectingWall[i]) {
     820          24 :         if (fict[i]<delim[i].getMin()) {
     821           1 :           fict[i]=delim[i].getMin()+(delim[i].getMin()-fict[i]);
     822           1 :           vfict[i]*=-1.0;
     823          23 :         } else if (fict[i]>delim[i].getMax()) {
     824           0 :           fict[i]=delim[i].getMax()-(fict[i]-delim[i].getMax());
     825           0 :           vfict[i]*=-1.0;
     826             :         }
     827             :       }
     828             :     }
     829             :   }
     830         123 : }
     831             : 
     832          19 : void DynamicReferenceRestraining::save(const string &filename,
     833             :                                        long long int step) {
     834          19 :   std::ofstream out;
     835          19 :   out.open(filename.c_str(), std::ios::binary);
     836          19 :   boost::archive::binary_oarchive oa(out);
     837          19 :   oa << step << fict << vfict << vfict_laststep << ffict << ABFGrid
     838          19 :      << CZARestimator;
     839          19 :   out.close();
     840          19 : }
     841             : 
     842           1 : void DynamicReferenceRestraining::load(const string &rfile_prefix) {
     843           1 :   string replica_suffix = plumed.getSuffix();
     844             :   string filename;
     845           1 :   if (replica_suffix.empty() == true) {
     846           2 :     filename = rfile_prefix + ".drrstate";
     847             :   } else {
     848           0 :     filename = rfile_prefix + "." + replica_suffix + ".drrstate";
     849             :   }
     850           1 :   std::ifstream in;
     851             :   long long int step;
     852           1 :   in.open(filename.c_str(), std::ios::binary);
     853           1 :   log << "eABF/DRR: Read restart file: " << filename << '\n';
     854           1 :   boost::archive::binary_iarchive ia(in);
     855           1 :   ia >> step >> fict >> vfict >> vfict_laststep >> ffict >> ABFGrid >>
     856           1 :      CZARestimator;
     857           1 :   in.close();
     858           1 :   log << "eABF/DRR: Restart at step: " << step << '\n';
     859           1 :   backupFile(filename);
     860           2 : }
     861             : 
     862           1 : void DynamicReferenceRestraining::backupFile(const string &filename) {
     863             :   bool isSuccess = false;
     864             :   long int i = 0;
     865           2 :   while (!isSuccess) {
     866             :     // If libstdc++ support C++17 we can simplify following code.
     867           2 :     const string bckname = "bck." + filename + "." + std::to_string(i);
     868           1 :     if (is_file_exist(bckname.c_str())) {
     869           0 :       ++i;
     870             :     } else {
     871           1 :       log << "eABF/DRR: Backup original restart file to " << bckname << '\n';
     872           1 :       std::ifstream src(filename.c_str(), std::ios::binary);
     873           1 :       std::ofstream dst(bckname.c_str(), std::ios::binary);
     874           1 :       dst << src.rdbuf();
     875           1 :       src.close();
     876           1 :       dst.close();
     877             :       isSuccess = true;
     878           1 :     }
     879             :   }
     880           1 : }
     881             : 
     882             : // Copy from
     883             : // stackoverflow(https://stackoverflow.com/questions/12774207/fastest-way-to-check-if-a-file-exist-using-standard-c-c11-c)
     884           1 : bool DynamicReferenceRestraining::is_file_exist(const char *fileName) {
     885           1 :   std::ifstream infile(fileName);
     886           1 :   return infile.good();
     887           1 : }
     888             : }
     889             : }
     890             : 
     891             : #endif

Generated by: LCOV version 1.16