LCOV - code coverage report
Current view: top level - logmfd - LogMFD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 325 370 87.8 %
Date: 2024-10-18 14:00:25 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : Copyright (c) 2019
       3             : National Institute of Advanced Industrial Science and Technology (AIST), Japan.
       4             : This file contains module for LogMFD method proposed by Tetsuya Morishita(AIST).
       5             : 
       6             : The LogMFD module is free software: you can redistribute it and/or modify
       7             : it under the terms of the GNU Lesser General Public License as published by
       8             : the Free Software Foundation, either version 3 of the License, or
       9             : (at your option) any later version.
      10             : 
      11             : The LogMFD module is distributed in the hope that it will be useful,
      12             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : GNU Lesser General Public License for more details.
      15             : 
      16             : You should have received a copy of the GNU Lesser General Public License
      17             : along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      18             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      19             : 
      20             : //+PLUMEDOC LOGMFDMOD_BIAS LOGMFD
      21             : /*
      22             : Used to perform LogMFD, LogPD, and TAMD/d-AFED.
      23             : 
      24             : \section LogMFD LogMFD
      25             : 
      26             : Consider a physical system of \f$N_q\f$ particles, for which the Hamiltonian is given as
      27             : 
      28             : \f[
      29             :   {H_{\rm MD}}\left( {\bf{\Gamma}} \right) = \sum\limits_{j = 1}^{{N_q}} {\frac{{{\bf{p}}_j^2}}{{2{m_j}}}}  + \Phi \left( {\bf{q}} \right)
      30             : \f]
      31             : 
      32             : where \f${\bf q}_j\f$, \f${\bf p}_j\f$ (\f$\bf{\Gamma}={\bf q},{\bf p}\f$), and \f$m_j\f$ are the position, momentum, and mass of particle \f$j\f$ respectively,
      33             : and \f$\Phi\f$ is the potential energy function for \f${\bf q}\f$.
      34             : The free energy \f$F({\bf X})\f$ as a function of a set of \f$N\f$ collective variables (CVs) is given as
      35             : 
      36             : \f{eqnarray*}{
      37             :   F\left( {{\bf X}} \right) &=&  - {k_B}T\log \int {\exp \left[ { - \beta {H_{\rm MD}}} \right]\prod\limits_{i = 1}^N {\delta \left( {{s_i}\left( {{\bf q}} \right) - {X_i}} \right)} d{\bf{\Gamma }}} \\
      38             :   &\simeq&  - {k_B}T\log \int {\exp \left[ { - \beta \left\{ {{H_{\rm MD}} + \sum\limits_i^N {\frac{{{K_i}}}{2}{{\left( {{s_i}\left( {{\bf q}} \right) - {X_i}} \right)}^2}} } \right\}} \right]} d{\bf{\Gamma }}
      39             : \f}
      40             : 
      41             : where \f$\bf{s}\f$ are the CVs, \f$k_B\f$ is Boltzmann constant, \f$\beta=1/k_BT\f$,
      42             : and \f$K_i\f$ is the spring constant which is large enough to invoke
      43             : 
      44             : \f[
      45             :  \delta \left( x \right) = \lim_{k \to \infty } \sqrt {\beta k/2\pi} \exp \left( -\beta kx^2/2 \right)
      46             : \f]
      47             : 
      48             : In mean-force dynamics, \f${\bf X}\f$ are treated as fictitious dynamical variables, which are associated with the following Hamiltonian,
      49             : 
      50             : \f[
      51             :  {H_{\rm log}} = \sum\limits_{i = 1}^N {\frac{{P_{{X_i}}^2}}{{2{M_i}}} + \Psi \left( {{\bf X}} \right)}
      52             : \f]
      53             : 
      54             : where \f${P_{{X_i}}}\f$  and \f$M_i\f$ are the momentum and mass of \f$X_i\f$, respectively, and \f$\Psi\f$ is the potential function for \f${\bf X}\f$.
      55             : We assume that \f$\Psi\f$ is a functional of \f$F({\bf X})\f$; \f$Ψ[F({\bf X})]\f$. The simplest form of \f$\Psi\f$ is \f$\Psi = F({\bf X})\f$,
      56             : which corresponds to TAMD/d-AFED \cite AbramsJ2008, \cite Maragliano2006 (or the extended Lagrangian dynamics in the limit of the adiabatic decoupling between \f$\bf{q}\f$ and \f${\bf X}\f$).
      57             :  In the case of LogMFD, the following form of \f$\Psi\f$ is introduced \cite MorishitaLogMFD;
      58             : 
      59             : 
      60             : \f[
      61             :   {\Psi _{\rm log}}\left( {{\bf X}} \right) = \gamma \log \left[ {\alpha F\left( {{\bf X}} \right) + 1} \right]
      62             : \f]
      63             : 
      64             : where \f$\alpha\f$ (ALPHA) and \f$\gamma\f$ (GAMMA) are positive parameters. The logarithmic form of \f$\Psi_{\rm log}\f$ ensures the dynamics of \f${\bf X}\f$ on a much smoother energy surface [i.e., \f$\Psi_{\rm log}({\bf X})\f$] than \f$F({\bf X})\f$, thus enhancing the sampling in the \f${\bf X}\f$-space. The parameters \f$\alpha\f$ and \f$\gamma\f$ determine the degree of flatness of \f$\Psi_{\rm log}\f$, but adjusting only \f$\alpha\f$ is normally sufficient to have a relatively flat surface (with keeping the relation \f$\gamma=1/\alpha\f$).
      65             : 
      66             : The equation of motion for \f$X_i\f$ in LogMFD (no thermostat) is
      67             : 
      68             : \f[
      69             :  {M_i}{\ddot X_i} =  - \left( {\frac{{\alpha \gamma }}{{\alpha F + 1}}} \right)\frac{{\partial F}}{{\partial {X_i}}}
      70             : \f]
      71             : 
      72             : where \f$-\partial F/\partial X_i\f$  is evaluated as a canonical average under the condition that \f${\bf X}\f$ is fixed;
      73             : 
      74             : \f{eqnarray*}{
      75             :  - \frac{{\partial F}}{{\partial {X_i}}} &\simeq& \frac{1}{Z}\int {{K_i}\left( {{s_i}\left( {{\bf q}} \right) - {X_i}} \right)\exp \left[ { - \beta \left\{ {{H_{\rm MD}} + \sum\limits_i^N {\frac{{{K_i}}}{2}{{\left( {{s_i}\left( {{\bf q}} \right) - {X_i}} \right)}^2}} } \right\}} \right]} d{\bf{\Gamma }}\\
      76             :  &\equiv& {\left\langle {{K_i}\left( {{s_i}\left( {{\bf q}} \right) - {X_i}} \right)} \right\rangle _{{\bf X}}}
      77             : \f}
      78             : 
      79             : where
      80             : 
      81             : \f[
      82             :  Z = \int {\exp \left[ { - \beta \left\{ {{H_{\rm MD}} + \sum\limits_i^N {\frac{{{K_i}}}{2}{{\left( {{s_i}\left( {{\bf q}} \right) - {X_i}} \right)}^2}} } \right\}} \right]} d{\bf{\Gamma }}
      83             : \f]
      84             : 
      85             : The mean-force (MF) is practically evaluated by performing a shot-time canonical MD run of \f$N_m\f$ steps each time \f${\bf X}\f$ is updated according to the equation of motion for \f${\bf X}\f$.
      86             : 
      87             : If the canonical average for the MF is effectively converged, the dynamical variables \f${\bf q}\f$ and \f${\bf X}\f$ are decoupled and they evolve adiabatically, which can be exploited for the on-the-fly evaluation of \f$F({\bf X})\f$. I.e., \f$H_{\rm log}\f$ should be a constant of motion in this case, thus \f$F({\bf X})\f$ can be evaluated each time \f${\bf X}\f$ is updated as
      88             : 
      89             : 
      90             : \f[
      91             :  F\left( {{{\bf X}}\left( t \right)} \right) = \frac{1}{\alpha} \left[
      92             :   \exp \frac{1}{\gamma} \left\{ \left( H_{\rm log} - \sum_i \frac{P_{X_i}^2}{2M_i} \right) \right\} - 1 \right]
      93             : \f]
      94             : 
      95             : 
      96             : This means that \f$F({\bf X})\f$ can be constructed without post processing (on-the-fly free energy reconstruction). Note that the on-the-fly free energy reconstruction is also possible in TAMD/d-AFED if the Hamiltonian-like conserved quantity is available (e.g., the Nose-Hoover type dynamics).
      97             : 
      98             : 
      99             : 
     100             : \section LogPD LogPD
     101             : 
     102             : 
     103             : The accuracy in the MF is critical to the on-the-fly free energy reconstruction. To improve the evaluation of the MF, parallel-dynamics (PD) is incorporated into LogMFD, leading to logarithmic parallel-dynamics (LogPD) \cite MorishitaLogPD.
     104             : 
     105             : 
     106             : In PD, the MF is evaluated by a non-equilibrium path-ensemble based on the Crooks-Jarzynski non-equilibrium work relation. To this end, multiple replicas of the MD system which run in parallel are introduced. The CVs [\f${\bf s}({\bf q})\f$] in each replica is restrained to the same value of \f${\bf X}(t)\f$. A canonical MD run with \f$N_m\f$ steps is performed in each replica, then the MF on \f$X_i\f$ is evaluated using the MD trajectories from all replicas.
     107             : The MF is practically calculated as
     108             : 
     109             : 
     110             : \f[
     111             :  - \frac{{\partial F}}{{\partial {X_i}}} = \sum\limits_{k = 1}^{{N_r}} {{W_k}} \sum\limits_{n = 1}^{{N_m}} {\frac{1}{{{N_m}}}{K_i}\left[ {{s_i}\left( {{{\bf q}}_n^k} \right) - {X_i}} \right]}
     112             : \f]
     113             : 
     114             : 
     115             : 
     116             : where \f${\bf q}^k_n\f$  indicates the \f${\bf q}\f$-configuration at time step \f$n\f$ in the \f$N_m\f$-step shot-time MD run in the \f$k\f$th replica among \f$N_r\f$ replicas. \f$W_k\f$ is given as
     117             : 
     118             : \f[
     119             :  {W_k} = \frac{{{e^{ - \beta {w_k}\left( t \right)}}}}{{\sum\limits_{k=1}^{{N_r}} {{e^{ - \beta {w_k}\left( t \right)}}} }}
     120             : \f]
     121             : 
     122             : 
     123             : where
     124             : 
     125             : 
     126             : \f[
     127             :  {w_k}\left( t \right) = \int\limits_{{X_0}}^{X\left( t \right)} {\sum\limits_{i=1}^N {\frac{{\partial H_{\rm MD}^k}}{{\partial {X_i}}}d{X_i}} }
     128             : \f]
     129             : 
     130             : \f[
     131             :  H_{\rm MD}^k\left( {{\bf{\Gamma }},{{\bf X}}} \right) = {H_{\rm MD}}\left( {{{\bf{\Gamma }}^k}} \right) + \sum\limits_{i = 1}^N {\frac{{{K_i}}}{2}{{\left( {s_i^k - {X_i}} \right)}^2}}
     132             : \f]
     133             : 
     134             : and \f$s^k_i\f$ is the \f$i\f$th CV in the \f$k\f$th replica.
     135             : 
     136             : \f$W_k\f$ comes from the Crooks-Jarzynski non-equilibrium work relation by which we can evaluate an equilibrium ensemble average from a set of non-equilibrium trajectories. Note that, to avoid possible numerical errors in the exponential function, the following form of \f$W_k\f$ is instead used in PLUMED,
     137             : 
     138             : \f[
     139             :  {W_k}\left( t \right) = \frac{{\exp \left[ { - \beta \left\{ {{w_k}\left( t \right) - {w_{\min }}\left( t \right)} \right\}} \right]}}{{\sum\nolimits_k {\exp \left[ { - \beta \left\{ {{w_k}\left( t \right) - {w_{\min }}\left( t \right)} \right\}} \right]} }}
     140             : \f]
     141             : 
     142             : where
     143             : 
     144             : \f[
     145             :  {w_{\min }}\left( t \right) = {\rm Min}_k\left[ {{w_k}\left( t \right)} \right]
     146             : \f]
     147             : 
     148             : 
     149             : With the MF evaluated using the PD approach, free energy profiles can be reconstructed more efficiently (requiring less elapsed computing time) in LogPD than with a single MD system in LogMFD. In the case that there exist more than one stable state separated by high energy barriers in the hidden subspace orthogonal to the CV-subspace, LogPD is particularly of use to incorporate all the contributions from such hidden states with appropriate weights (in the limit \f$N_r\to\infty\f$ ).
     150             : 
     151             : Note that LogPD calculations should always be initiated with an equilibrium \f${\bf q}\f$-configuration in each replica, because the Crooks-Jarzynski non-equilibrium work relation is invoked. Also note that LogPD is currently available only with Gromacs, while LogMFD can be performed with LAMMPS, Gromacs, Quantum Espresso, NAMD, and so on.
     152             : 
     153             : \section Thermostat Using LogMFD/PD with a thermostat
     154             : 
     155             : Introducing a thermostat on \f${\bf X}\f$ is often recommended in LogMFD/PD to maintain the adiabatic decoupling between \f${\bf q}\f$ and \f${\bf X}\f$. In the framework of the LogMFD approach, the Nose-Hoover type thermostat and the Gaussian isokinetic (velocity scaling) thermostat can be used to control the kinetic energy of \f${\bf X}\f$.
     156             : 
     157             : \subsection Nose-Hoover Nose-Hoover LogMFD/PD
     158             : 
     159             : The equation of motion for \f$X_i\f$ coupled to a Nose-Hoover thermostat variable \f$\eta\f$ (single heat bath) is
     160             : 
     161             : \f[
     162             :  {M_i}{\ddot X_i} =  - \left( {\frac{{\alpha \gamma }}{{\alpha F + 1}}} \right)\frac{{\partial F}}{{\partial {X_i}}} - {M_i}{\dot X_i}\dot \eta
     163             : \f]
     164             : 
     165             : The equation of motion for \f$\eta\f$ is
     166             : 
     167             : \f[
     168             :  Q\ddot \eta  = \sum\limits_{i = 1}^N {\frac{{P_{{X_i}}^2}}{{{M_i}}} - N{k_B}T}
     169             : \f]
     170             : 
     171             : where \f$N\f$ is the number of the CVs. Since the following pseudo-Hamiltonian is a constant of motion in Nose-Hoover LogMFD/PD,
     172             : 
     173             : \f[
     174             :  H_{\rm log}^{\rm NH} = \sum\limits_{i = 1}^N {\frac{{P_{{X_i}}^2}}{{2{M_i}}} + \gamma \log \left[ {\alpha F\left( {{\bf X}} \right) + 1} \right] + \frac{1}{2}Q{{\dot \eta }^2} + N{k_B}T\eta}
     175             : \f]
     176             : 
     177             : \f$F({\bf X}(t))\f$ is obtained at each MFD step as
     178             : 
     179             : \f[
     180             :  F\left( {{{\bf X}}\left( t \right)} \right) = \frac{1}{\alpha }\left[ {\exp \left\{ {{{ \frac{1}{\gamma} \left( {H_{\rm log}^{\rm NH} - \sum_i {\frac{{P_{{X_i}}^2}}{{2{M_i}}}}  - \frac{1}{2}Q{{\dot \eta }^2} - N{k_B}T\eta} \right)}  }} \right\} - 1} \right]
     181             : \f]
     182             : 
     183             : 
     184             : 
     185             : \subsection VS Velocity scaling LogMFD/PD
     186             : 
     187             : The velocity scaling algorithm (which is equivalent to the Gaussian isokinetic dynamics in the limit \f$\Delta t\to 0\f$) can also be employed to control the velocity of \f${\bf X}\f$, \f$\bf{V}_x\f$.
     188             : 
     189             : The following algorithm is introduced to perform isokinetic LogMFD calculations \cite MorishitaVsLogMFD;
     190             : 
     191             : \f{eqnarray*}{
     192             : {V_{{X_i}}}\left( {{t_{n + 1}}} \right)
     193             : &=&
     194             :  V_{X_i}^\prime \left( {{t_n}} \right) + \Delta t \left[
     195             :   { - \left( {\frac{{\alpha \gamma }}{{\alpha F\left( {{t_n}} \right) + 1}}} \right)
     196             :   \frac{{\partial F\left( {{t_n}} \right)}}{{\partial {X_i}}}}
     197             :  \right]\\
     198             : S\left( {{t_{n + 1}}} \right)
     199             : &=&
     200             :  \sqrt {\frac{{N{k_B}T}}{{\sum\limits_i {{M_i}V_{{X_i}}^2\left( {{t_{n + 1}}} \right)} }}} \\
     201             : {V_{{X_i}}}^\prime \left( {{t_{n + 1}}} \right)
     202             : &=&
     203             : S\left( {{t_{n + 1}}} \right){V_{{X_i}}}\left( {{t_{n + 1}}} \right)\\
     204             : {X_i}\left( {{t_{n + 1}}} \right)
     205             : &=&
     206             : {X_i}\left( {{t_n}} \right) + \Delta t V_{X_i}^\prime \left( {{t_{n + 1}}} \right)\\
     207             : {\Psi_{\rm log}}\left( {{t_{n + 1}}} \right)
     208             : &=&
     209             : N{k_B}T\log S\left( {{t_{n + 1}}} \right) + {\Psi_{\rm log}}\left( {{t_n}} \right)\\
     210             : F\left( {{t_{n + 1}}} \right)
     211             : &=&
     212             : \frac{1}{\alpha} \left[
     213             :   \exp \left\{ \Psi_{\rm log} \left( t_{n+1} \right) / \gamma \right\} - 1
     214             : \right]
     215             : \f}
     216             : 
     217             : Note that \f$V_{X_i}^\prime\left( {{t_0}} \right)\f$ is assumed to be initially given, which meets the following relation,
     218             : 
     219             : \f[
     220             :   \sum\limits_{i = 1}^N M_i V_{X_i}^{\prime 2} \left( t_0 \right)  = N{k_B}{T}
     221             : \f]
     222             : 
     223             : It should be stressed that, in the same way as in the NVE and Nose-Hoover LogMFD/PD, \f$F({\bf X}(t))\f$ can be evaluated at each MFD step (on-the-fly free energy reconstruction) in Velocity Scaling LogMFD/PD.
     224             : 
     225             : 
     226             : \par Examples
     227             : \section Examples Examples
     228             : 
     229             : \subsection Example-LoGMFD Example of LogMFD
     230             : 
     231             : The following input file tells plumed to restrain collective variables
     232             : to the fictitious dynamical variables in LogMFD/PD.
     233             : 
     234             : plumed.dat
     235             : \plumedfile
     236             : UNITS TIME=fs LENGTH=1.0 ENERGY=kcal/mol MASS=1.0 CHARGE=1.0
     237             : phi: TORSION ATOMS=5,7,9,15
     238             : psi: TORSION ATOMS=7,9,15,17
     239             : 
     240             : # LogMFD
     241             : LOGMFD ...
     242             : LABEL=logmfd
     243             : ARG=phi,psi
     244             : KAPPA=1000.0,1000.0
     245             : DELTA_T=1.0
     246             : INTERVAL=200
     247             : TEMP=300.0
     248             : FLOG=2.0
     249             : MFICT=5000000,5000000
     250             : VFICT=3.5e-4,3.5e-4
     251             : ALPHA=4.0
     252             : THERMOSTAT=NVE
     253             : FICT_MAX=3.15,3.15
     254             : FICT_MIN=-3.15,-3.15
     255             : ... LOGMFD
     256             : \endplumedfile
     257             : 
     258             : To submit this simulation with Gromacs, use the following command line
     259             : to execute a LogMFD run with Gromacs-MD.
     260             : Here topol.tpr is the input file
     261             : which contains atomic coordinates and Gromacs parameters.
     262             : 
     263             : \verbatim
     264             : gmx_mpi mdrun -s topol.tpr -plumed
     265             : \endverbatim
     266             : 
     267             : This command will output files named logmfd.out and replica.out.
     268             : 
     269             : The output file logmfd.out records free energy and all fictitious dynamical variables at every MFD step.
     270             : 
     271             : logmfd.out
     272             : 
     273             : \verbatim
     274             : # LogMFD
     275             : # CVs : phi psi
     276             : # Mass for CV particles : 5000000.000000 5000000.000000
     277             : # Mass for thermostat   :   11923.224809
     278             : # 1:iter_mfd, 2:Flog, 3:2*Ekin/gkb[K], 4:eta, 5:Veta,
     279             : # 6:phi_fict(t), 7:phi_vfict(t), 8:phi_force(t),
     280             : # 9:psi_fict(t), 10:psi_vfict(t), 11:psi_force(t),
     281             :        0       2.000000     308.221983       0.000000       0.000000      -2.442363       0.000350       5.522717       2.426650       0.000350       7.443177
     282             :        1       1.995466     308.475775       0.000000       0.000000      -2.442013       0.000350      -4.406246       2.427000       0.000350      11.531345
     283             :        2       1.992970     308.615664       0.000000       0.000000      -2.441663       0.000350      -3.346513       2.427350       0.000350      15.763196
     284             :        3       1.988619     308.859946       0.000000       0.000000      -2.441313       0.000350       6.463092       2.427701       0.000351       6.975422
     285             : ...
     286             : \endverbatim
     287             : 
     288             : The output file replica.out records all collective variables at every MFD step.
     289             : 
     290             : replica.out
     291             : 
     292             : \verbatim
     293             :  Replica No. 0 of 1.
     294             : # 1:iter_mfd, 2:work, 3:weight,
     295             : # 4:phi(q)
     296             : # 5:psi(q)
     297             :        0    0.000000e+00     1.000000e+00       -2.436841       2.434093
     298             :        1   -4.539972e-03     1.000000e+00       -2.446420       2.438531
     299             :        2   -7.038516e-03     1.000000e+00       -2.445010       2.443114
     300             :        3   -1.139672e-02     1.000000e+00       -2.434850       2.434677
     301             : ...
     302             : \endverbatim
     303             : 
     304             : \subsection Example-LogPD Example of LogPD
     305             : 
     306             : Use the following command line to execute a LogPD run using two MD replicas (note that only Gromacs is currently available for LogPD).
     307             : Here 0/topol.tpr and 1/topol.tpr are the input files,
     308             : each containing the atomic coordinates for the corresponding replica and Gromacs parameters. All the directories, 0/ and 1/, should contain the same plumed.dat.
     309             : 
     310             : \verbatim
     311             : mpirun -np 2 gmx_mpi mdrun -s topol -plumed -multidir 0 1
     312             : \endverbatim
     313             : 
     314             : This command will output files named logmfd.out in 0/, and replica.out.0 and replica.out.1 in 0/ and 1/, respectively.
     315             : 
     316             : The output file logmfd.out records free energy and all fictitious dynamical variables at every MFD step.
     317             : 
     318             : logmfd.out
     319             : 
     320             : \verbatim
     321             : # LogPD, replica parallel of LogMFD
     322             : # number of replica : 2
     323             : # CVs : phi psi
     324             : # Mass for CV particles : 5000000.000000 5000000.000000
     325             : # Mass for thermostat   :   11923.224809
     326             : # 1:iter_mfd, 2:Flog, 3:2*Ekin/gkb[K], 4:eta, 5:Veta,
     327             : # 6:phi_fict(t), 7:phi_vfict(t), 8:phi_force(t),
     328             : # 9:psi_fict(t), 10:psi_vfict(t), 11:psi_force(t),
     329             :        0       2.000000     308.221983       0.000000       0.000000      -2.417903       0.000350       4.930899       2.451475       0.000350      -3.122024
     330             :        1       1.999367     308.257404       0.000000       0.000000      -2.417552       0.000350       0.851133       2.451825       0.000350      -1.552718
     331             :        2       1.999612     308.243683       0.000000       0.000000      -2.417202       0.000350      -1.588175       2.452175       0.000350       1.601274
     332             :        3       1.999608     308.243922       0.000000       0.000000      -2.416852       0.000350       4.267745       2.452525       0.000350      -4.565621
     333             : ...
     334             : \endverbatim
     335             : 
     336             : 
     337             : The output file replica.out.0 records all collective variables and the Jarzynski weight of replica No.0 at every MFD step.
     338             : 
     339             : replica.out.0
     340             : 
     341             : \verbatim
     342             : # Replica No. 0 of 2.
     343             : # 1:iter_mfd, 2:work, 3:weight,
     344             : # 4:phi(q)
     345             : # 5:psi(q)
     346             :        0    0.000000e+00     5.000000e-01       -2.412607       2.446191
     347             :        1   -4.649101e-06     4.994723e-01       -2.421403       2.451318
     348             :        2    1.520985e-03     4.983996e-01       -2.420269       2.455049
     349             :        3    1.588855e-03     4.983392e-01       -2.411081       2.447394
     350             : ...
     351             : \endverbatim
     352             : 
     353             : The output file replica.out.1 records all collective variables and the Jarzynski weight of replica No.1 at every MFD step.
     354             : 
     355             : replica.out.1
     356             : 
     357             : \verbatim
     358             : # Replica No. 1 of 2.
     359             : # 1:iter_mfd, 2:work, 3:weight,
     360             : # 4:phi(q)
     361             : # 5:psi(q)
     362             :        0    0.000000e+00     5.000000e-01       -2.413336       2.450516
     363             :        1   -1.263077e-03     5.005277e-01       -2.412009       2.449229
     364             :        2   -2.295444e-03     5.016004e-01       -2.417322       2.452512
     365             :        3   -2.371507e-03     5.016608e-01       -2.414078       2.448521
     366             : ...
     367             : \endverbatim
     368             : 
     369             : */
     370             : //+ENDPLUMEDOC
     371             : 
     372             : #include "bias/Bias.h"
     373             : #include "core/ActionRegister.h"
     374             : #include "tools/Communicator.h"
     375             : 
     376             : #include <iostream>
     377             : 
     378             : using namespace std;
     379             : using namespace PLMD;
     380             : using namespace bias;
     381             : 
     382             : namespace PLMD {
     383             : namespace logmfd {
     384             : /**
     385             :    \brief class for LogMFD parameters, variables and subroutines.
     386             :  */
     387             : class LogMFD : public Bias {
     388             :   bool firsttime;               ///< flag that indicates first MFD step or not.
     389             :   int    step_initial;          ///< initial MD step.
     390             :   int    interval;              ///< input parameter, period of MD steps when fictitious dynamical variables are evolved.
     391             :   double delta_t;               ///< input parameter, one time step of MFD when fictitious dynamical variables are evolved.
     392             :   string thermostat;            ///< input parameter, type of thermostat for canonical dyanamics.
     393             :   double kbt;                   ///< k_B*temperature
     394             :   double kbtpd;                   ///< k_B*temperature for PD
     395             : 
     396             :   int    TAMD;                  ///< input parameter, perform TAMD instead of LogMFD.
     397             :   double alpha;                 ///< input parameter, alpha parameter for LogMFD.
     398             :   double gamma;                 ///< input parameter, gamma parameter for LogMFD.
     399             :   std::vector<double> kappa;    ///< input parameter, strength of the harmonic restraining potential.
     400             : 
     401             :   std::vector<double> fict_max; ///< input parameter, maximum of each fictitous dynamical variable.
     402             :   std::vector<double> fict_min; ///< input parameter, minimum of each fictitous dynamical variable.
     403             : 
     404             : 
     405             :   std::vector<double>  fict;    ///< current values of each fictitous dynamical variable.
     406             :   std::vector<double> vfict;    ///< current velocity of each fictitous dynamical variable.
     407             :   std::vector<double> mfict;    ///< mass of each fictitous dynamical variable.
     408             : 
     409             :   double xeta;                  ///< current eta variable of thermostat.
     410             :   double veta;                  ///< current velocity of eta variable of thermostat.
     411             :   double meta;                  ///< mass of eta variable of thermostat.
     412             : 
     413             :   double phivs;                 ///< potential used in VS method
     414             :   double work;                  ///< current works done by fictitious dynamical variables in this replica.
     415             :   double weight;                ///< current weight of this replica.
     416             :   double flog;                  ///< current free energy
     417             :   double hlog;                  ///< value invariant
     418             : 
     419             :   struct {
     420             :     std::vector<double>  fict;
     421             :     std::vector<double> vfict;
     422             :     std::vector<double> ffict;
     423             :     double xeta;
     424             :     double veta;
     425             :     double phivs;
     426             :     double work;
     427             :     double weight;
     428             :   } backup;
     429             : 
     430             :   std::vector<double> ffict;    ///< current force of each fictitous dynamical variable.
     431             :   std::vector<double> fict_ave; ///< averaged values of each collective variable.
     432             : 
     433             :   std::vector<Value*>  fictValue; ///< pointers to fictitious dynamical variables
     434             :   std::vector<Value*> vfictValue; ///< pointers to velocity of fictitious dynamical variables
     435             : 
     436             : public:
     437             :   static void registerKeywords(Keywords& keys);
     438             : 
     439             :   explicit LogMFD(const ActionOptions&);
     440             :   void calculate();
     441             :   void update();
     442             :   void updateNVE();
     443             :   void updateNVT();
     444             :   void updateVS();
     445             :   void updateWork();
     446             :   void calcMeanForce();
     447             :   double calcEkin();
     448             :   double calcFlog();
     449             :   double calcClog();
     450             : 
     451             : private:
     452             :   double sgn( double x ) {
     453          55 :     return x>0.0 ? 1.0 : x<0.0 ? -1.0 : 0.0;
     454             :   }
     455             : };
     456             : 
     457             : PLUMED_REGISTER_ACTION(LogMFD,"LOGMFD")
     458             : 
     459             : /**
     460             :    \brief instruction of parameters for Plumed manual.
     461             : */
     462           5 : void LogMFD::registerKeywords(Keywords& keys) {
     463           5 :   Bias::registerKeywords(keys);
     464           5 :   keys.use("ARG");
     465          10 :   keys.add("compulsory","INTERVAL",
     466             :            "Period of MD steps (N_m) to update fictitious dynamical variables." );
     467          10 :   keys.add("compulsory","DELTA_T",
     468             :            "Time step for the fictitious dynamical variables (DELTA_T=1 often works)." );
     469          10 :   keys.add("compulsory","THERMOSTAT",
     470             :            "Type of thermostat for the fictitious dynamical variables. NVE, NVT, VS are available." );
     471          10 :   keys.add("optional","TEMP",
     472             :            "Target temperature for the fictitious dynamical variables in LogMFD/PD. "
     473             :            "It is recommended to set TEMP to be the same as "
     474             :            "the temperature of the MD system in any thermostated LogMFD/PD run. "
     475             :            "If not provided, it will be taken from the temperature of the MD system (Gromacs only)." );
     476             : 
     477          10 :   keys.add("optional","TAMD",
     478             :            "When TAMD=1, TAMD/d-AFED calculations can be performed instead of LogMFD. Otherwise, the LogMFD protocol is switched on (default)." );
     479             : 
     480          10 :   keys.add("optional","ALPHA",
     481             :            "Alpha parameter for LogMFD. "
     482             :            "If not provided or provided as 0, it will be taken as 1/gamma. "
     483             :            "If gamma is also not provided, Alpha is set as 4, which is a sensible value when the unit of kcal/mol is used." );
     484          10 :   keys.add("optional","GAMMA",
     485             :            "Gamma parameter for LogMFD. "
     486             :            "If not provided or provided as 0, it will be taken as 1/alpha. "
     487             :            "If alpha is also not provided, Gamma is set as 0.25, which is a sensible value when the unit of kcal/mol is used." );
     488          10 :   keys.add("compulsory","KAPPA",
     489             :            "Spring constant of the harmonic restraining potential." );
     490             : 
     491          10 :   keys.add("compulsory","FICT_MAX",
     492             :            "Maximum values reachable for the fictitious dynamical variables. The variables will elastically bounce back at the boundary (mirror boundary)." );
     493          10 :   keys.add("compulsory","FICT_MIN",
     494             :            "Minimum values reachable for the fictitious dynamical variables. The variables will elastically bounce back at the boundary (mirror boundary)." );
     495             : 
     496          10 :   keys.add("optional","FICT",
     497             :            "The initial values of the fictitious dynamical variables. "
     498             :            "If not provided, they are set equal to their corresponding CVs for the initial atomic configuration." );
     499          10 :   keys.add("optional","VFICT",
     500             :            "The initial velocities of the fictitious dynamical variables. "
     501             :            "If not provided, they will be taken as 0. "
     502             :            "If THERMOSTAT=VS, they are instead automatically adjusted according to TEMP. "  );
     503          10 :   keys.add("optional","MFICT",
     504             :            "Masses of each fictitious dynamical variable. "
     505             :            "If not provided, they will be taken as 10000." );
     506             : 
     507          10 :   keys.add("optional","XETA",
     508             :            "The initial eta variable of the Nose-Hoover thermostat "
     509             :            "for the fictitious dynamical variables. "
     510             :            "If not provided, it will be taken as 0." );
     511          10 :   keys.add("optional","VETA",
     512             :            "The initial velocity of eta variable. "
     513             :            "If not provided, it will be taken as 0." );
     514          10 :   keys.add("optional","META",
     515             :            "Mass of eta variable. "
     516             :            "If not provided, it will be taken as N*kb*T*100*100." );
     517             : 
     518          10 :   keys.add("compulsory","FLOG",
     519             :            "The initial free energy value in the LogMFD/PD run."
     520             :            "The origin of the free energy profile is adjusted by FLOG to "
     521             :            "realize F({X}(t)) > 0 at any X(t), "
     522             :            "resulting in enhanced barrier-crossing. "
     523             :            "(The value of H_log is automatically "
     524             :            "set according to FLOG). "
     525             :            "In fact, F({X}(t)) is correctly "
     526             :            "estimated in PLUMED even when F({X}(t)) < 0 in "
     527             :            "the LogMFD/PD run." );
     528             : 
     529          10 :   keys.add("optional","WORK",
     530             :            "The initial value of the work done by fictitious dynamical "
     531             :            "variables in each replica. "
     532             :            "If not provided, it will be taken as 0.");
     533             : 
     534          10 :   keys.add("optional","TEMPPD",
     535             :            "Temperature of the Boltzmann factor in the Jarzynski weight in LogPD (Gromacs only). "
     536             :            "TEMPPD should be the same as the "
     537             :            "temperature of the MD system, while TEMP may be (in principle) different from it. "
     538             :            "If not provided, TEMPPD is set to be the same value as TEMP." );
     539             : 
     540          10 :   keys.addOutputComponent("_fict","default",
     541             :                           "For example, the fictitious collective variable for LogMFD is specified as "
     542             :                           "ARG=dist12 and LABEL=logmfd in LOGMFD section in Plumed input file, "
     543             :                           "the associated fictitious dynamical variable can be specified as "
     544             :                           "PRINT ARG=dist12,logmfd.dist12_fict FILE=COLVAR");
     545          10 :   keys.addOutputComponent("_vfict","default",
     546             :                           "For example, the fictitious collective variable for LogMFD is specified as "
     547             :                           "ARG=dist12 and LABEL=logmfd in LOGMFD section in Plumed input file, the "
     548             :                           "velocity of the associated fictitious dynamical variable can be specified as "
     549             :                           "PRINT ARG=dist12,logmfd.dist12_vfict FILE=COLVAR");
     550           5 : }
     551             : 
     552             : 
     553             : /**
     554             :    \brief constructor of LogMFD class
     555             :    \details This constructor initializes all parameters and variables,
     556             :    reads input file and set value of parameters and initial value of variables,
     557             :    and writes messages as Plumed log.
     558             : */
     559           3 : LogMFD::LogMFD( const ActionOptions& ao ):
     560             :   PLUMED_BIAS_INIT(ao),
     561           3 :   firsttime(true),
     562           3 :   step_initial(0),
     563           3 :   interval(10),
     564           3 :   delta_t(1.0),
     565           6 :   thermostat("NVE"),
     566           3 :   kbt(-1.0),
     567           3 :   kbtpd(-1.0),
     568           3 :   TAMD(0),
     569           3 :   alpha(0.0),
     570           3 :   gamma(0.0),
     571           3 :   kappa(getNumberOfArguments(),0.0),
     572           3 :   fict_max(getNumberOfArguments(),0.0),
     573           3 :   fict_min(getNumberOfArguments(),0.0),
     574           3 :   fict (getNumberOfArguments(),-999.0), // -999 means no initial values given in plumed.dat
     575           3 :   vfict(getNumberOfArguments(),0.0),
     576           3 :   mfict(getNumberOfArguments(),10000.0),
     577           3 :   xeta(0.0),
     578           3 :   veta(0.0),
     579           3 :   meta(0.0),
     580           3 :   flog(0.0),
     581           3 :   hlog(0.0),
     582           3 :   phivs(0.0),
     583           3 :   work(0.0),
     584           3 :   weight(0.0),
     585           3 :   ffict(getNumberOfArguments(),0.0),
     586           3 :   fict_ave(getNumberOfArguments(),0.0),
     587           3 :   fictValue(getNumberOfArguments(),NULL),
     588           9 :   vfictValue(getNumberOfArguments(),NULL)
     589             : {
     590           3 :   backup.fict.resize(getNumberOfArguments(),0.0);
     591           3 :   backup.vfict.resize(getNumberOfArguments(),0.0);
     592           3 :   backup.ffict.resize(getNumberOfArguments(),0.0);
     593           3 :   backup.xeta = 0.0;
     594           3 :   backup.veta = 0.0;
     595           3 :   backup.phivs = 0.0;
     596           3 :   backup.work = 0.0;
     597           3 :   backup.weight = 0.0;
     598             : 
     599           3 :   parse("INTERVAL",interval);
     600           3 :   parse("DELTA_T",delta_t);
     601           3 :   parse("THERMOSTAT",thermostat);
     602           3 :   kbt = getkBT(); // read as temperature
     603           3 :   parse("TEMPPD",kbtpd); // read as temperature
     604             : 
     605           3 :   parse("TAMD",TAMD);
     606           3 :   parse("ALPHA",alpha);
     607           3 :   parse("GAMMA",gamma);
     608           3 :   parseVector("KAPPA",kappa);
     609             : 
     610           3 :   parseVector("FICT_MAX",fict_max);
     611           3 :   parseVector("FICT_MIN",fict_min);
     612             : 
     613           3 :   parseVector("FICT",fict);
     614           3 :   parseVector("VFICT",vfict);
     615           3 :   parseVector("MFICT",mfict);
     616             : 
     617           3 :   parse("XETA",xeta);
     618           3 :   parse("VETA",veta);
     619           3 :   parse("META",meta);
     620             : 
     621           3 :   parse("FLOG",flog);
     622             : 
     623             :   // read initial value of work for each replica of LogPD
     624           3 :   if( multi_sim_comm.Get_size()>1 ) {
     625           0 :     vector<double> vwork(multi_sim_comm.Get_size(),0.0);
     626           0 :     parseVector("WORK",vwork);
     627             :     // initial work of this replica
     628           0 :     work = vwork[multi_sim_comm.Get_rank()];
     629             :   }
     630             :   else {
     631           3 :     work = 0.0;
     632             :   }
     633             : 
     634           3 :   if( kbtpd>=0.0 ) {
     635           0 :     kbtpd *= getKBoltzmann();
     636             :   }
     637             :   else {
     638           3 :     kbtpd = kbt;
     639             :   }
     640             : 
     641           3 :   if( meta == 0.0 ) {
     642           2 :     const double nkt = getNumberOfArguments()*kbt;
     643           2 :     meta = nkt*100.0*100.0;
     644             :   }
     645             : 
     646           3 :   if(alpha == 0.0 && gamma == 0.0) {
     647           0 :     alpha = 4.0;
     648           0 :     gamma = 1 / alpha;
     649             :   }
     650           3 :   else if(alpha != 0.0 && gamma == 0.0) {
     651           3 :     gamma = 1 / alpha;
     652             :   }
     653           0 :   else if(alpha == 0.0 && gamma != 0.0) {
     654           0 :     alpha = 1 / gamma;
     655             :   }
     656             : 
     657           3 :   checkRead();
     658             : 
     659             :   // output messaages to Plumed's log file
     660           3 :   if( multi_sim_comm.Get_size()>1 ) {
     661           0 :     if( TAMD ) {
     662           0 :       log.printf("TAMD-PD, replica parallel of TAMD, no logarithmic flattening.\n");
     663             :     }
     664             :     else {
     665           0 :       log.printf("LogPD, replica parallel of LogMFD.\n");
     666             :     }
     667           0 :     log.printf("number of replica : %d.\n", multi_sim_comm.Get_size() );
     668             :   }
     669             :   else {
     670           3 :     if( TAMD ) {
     671           0 :       log.printf("TAMD, no logarithmic flattening.\n");
     672             :     }
     673             :     else {
     674           3 :       log.printf("LogMFD, logarithmic flattening.\n");
     675             :     }
     676             :   }
     677             : 
     678           3 :   log.printf("  with harmonic force constant      ");
     679           6 :   for(unsigned i=0; i<kappa.size(); i++) log.printf(" %f",kappa[i]);
     680           3 :   log.printf("\n");
     681             : 
     682           3 :   log.printf("  with interval of cv(ideal) update ");
     683           3 :   log.printf(" %d", interval);
     684           3 :   log.printf("\n");
     685             : 
     686           3 :   log.printf("  with time step of cv(ideal) update ");
     687           3 :   log.printf(" %f", delta_t);
     688           3 :   log.printf("\n");
     689             : 
     690           3 :   if( !TAMD ) {
     691           3 :     log.printf("  with alpha, gamma                 ");
     692           3 :     log.printf(" %f %f", alpha, gamma);
     693           3 :     log.printf("\n");
     694             :   }
     695             : 
     696           3 :   log.printf("  with Thermostat for cv(ideal)     ");
     697           3 :   log.printf(" %s", thermostat.c_str());
     698           3 :   log.printf("\n");
     699             : 
     700           3 :   log.printf("  with initial free energy          ");
     701           3 :   log.printf(" %f", flog);
     702           3 :   log.printf("\n");
     703             : 
     704           3 :   log.printf("  with mass of cv(ideal)");
     705           6 :   for(unsigned i=0; i<mfict.size(); i++) log.printf(" %f", mfict[i]);
     706           3 :   log.printf("\n");
     707             : 
     708           3 :   log.printf("  with initial value of cv(ideal)");
     709           6 :   for(unsigned i=0; i<fict.size(); i++) log.printf(" %f", fict[i]);
     710           3 :   log.printf("\n");
     711             : 
     712           3 :   log.printf("  with initial velocity of cv(ideal)");
     713           6 :   for(unsigned i=0; i<vfict.size(); i++) log.printf(" %f", vfict[i]);
     714           3 :   log.printf("\n");
     715             : 
     716           3 :   log.printf("  with maximum value of cv(ideal)    ");
     717           6 :   for(unsigned i=0; i<fict_max.size(); i++) log.printf(" %f",fict_max[i]);
     718           3 :   log.printf("\n");
     719             : 
     720           3 :   log.printf("  with minimum value of cv(ideal)    ");
     721           6 :   for(unsigned i=0; i<fict_min.size(); i++) log.printf(" %f",fict_min[i]);
     722           3 :   log.printf("\n");
     723             : 
     724           3 :   log.printf("  and kbt                           ");
     725           3 :   log.printf(" %f\n",kbt);
     726           3 :   log.printf(" kbt for PD %f\n",kbtpd);
     727             : 
     728             :   // setup Value* variables
     729           6 :   for(unsigned i=0; i<getNumberOfArguments(); i++) {
     730           3 :     std::string comp = getPntrToArgument(i)->getName()+"_fict";
     731           6 :     addComponentWithDerivatives(comp);
     732             : 
     733           3 :     if(getPntrToArgument(i)->isPeriodic()) {
     734             :       std::string a,b;
     735           0 :       getPntrToArgument(i)->getDomain(a,b);
     736           0 :       componentIsPeriodic(comp,a,b);
     737             :     }
     738             :     else {
     739           3 :       componentIsNotPeriodic(comp);
     740             :     }
     741           3 :     fictValue[i] = getPntrToComponent(comp);
     742             : 
     743           6 :     comp = getPntrToArgument(i)->getName()+"_vfict";
     744           3 :     addComponent(comp);
     745             : 
     746           3 :     componentIsNotPeriodic(comp);
     747           3 :     vfictValue[i] = getPntrToComponent(comp);
     748             :   }
     749           3 : }
     750             : 
     751             : /**
     752             :    \brief calculate forces for fictitious variables at every MD steps.
     753             :    \details This function calculates initial values of fictitious variables
     754             :    and write header messages to LogMFD log files at the first MFD step,
     755             :    calculates restraining fources comes from difference between the fictitious variable
     756             :    and collective variable at every MD steps.
     757             : */
     758        1500 : void LogMFD::calculate() {
     759        1500 :   if( firsttime ) {
     760           3 :     firsttime = false;
     761             : 
     762           3 :     step_initial = getStep();
     763             : 
     764             :     // set initial values of fictitious variables if they were not specified.
     765           6 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     766           3 :       if( fict[i] != -999.0 ) continue; // -999 means no initial values given in plumed.dat
     767             : 
     768             :       // use the collective variables as the initial of the fictitious variable.
     769           0 :       fict[i] = getArgument(i);
     770             : 
     771             :       // average values of fictitious variables by all replica.
     772           0 :       if( multi_sim_comm.Get_size()>1 ) {
     773           0 :         multi_sim_comm.Sum(fict[i]);
     774           0 :         fict[i] /= multi_sim_comm.Get_size();
     775             :       }
     776             :     }
     777             : 
     778             :     // initialize accumulation value to zero
     779           6 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     780           3 :       fict_ave[i] = 0.0;
     781             :     }
     782             : 
     783             :     // calculate invariant for NVE
     784           3 :     if(thermostat == "NVE") {
     785             :       // kinetic energy
     786           1 :       const double ekin = calcEkin();
     787             :       // potential energy
     788           1 :       const double pot = TAMD ? flog : sgn(flog)*gamma * std::log1p( alpha*fabs(flog) );
     789             :       // invariant
     790           1 :       hlog = pot + ekin;
     791             :     }
     792           2 :     else if(thermostat == "NVT") {
     793           1 :       const double nkt = getNumberOfArguments()*kbt;
     794             :       // kinetic energy
     795           1 :       const double ekin = calcEkin();
     796             :       // bath energy
     797           1 :       const double ekin_bath = 0.5*veta*veta*meta + xeta*nkt;
     798             :       // potential energy
     799           1 :       const double pot = TAMD ? flog : sgn(flog)*gamma * std::log1p( alpha*fabs(flog) );
     800             :       // invariant
     801           1 :       hlog = pot + ekin + ekin_bath;
     802             :     }
     803           1 :     else if(thermostat == "VS") {
     804             :       // kinetic energy
     805           1 :       const double ekin = calcEkin();
     806           1 :       if( ekin == 0.0 ) { // this means VFICT is not given.
     807             :         // initial velocities
     808           2 :         for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     809           1 :           vfict[i] = sqrt(kbt/mfict[i]);
     810             :         }
     811             :       }
     812             :       else {
     813           0 :         const double nkt = getNumberOfArguments()*kbt;
     814           0 :         const double svs = sqrt(nkt/ekin/2);
     815           0 :         for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     816           0 :           vfict[i] *= svs; // scale velocities
     817             :         }
     818             :       }
     819             :       // initial VS potential
     820           1 :       phivs = TAMD ? flog : sgn(flog)* gamma*std::log1p( alpha*fabs(flog) );
     821             : 
     822             :       // invariant
     823           1 :       hlog = 0.0;
     824             :     }
     825             : 
     826           3 :     weight = 1.0; // for replica parallel
     827             : 
     828             :     // open LogMFD's log file
     829           3 :     if( multi_sim_comm.Get_rank()==0 && comm.Get_rank()==0 ) {
     830           3 :       FILE *outlog = std::fopen("logmfd.out", "w");
     831             : 
     832             :       // output messages to LogMFD's log file
     833           3 :       if( multi_sim_comm.Get_size()>1 ) {
     834             :         fprintf(outlog, "# LogPD, replica parallel of LogMFD\n");
     835           0 :         fprintf(outlog, "# number of replica : %d\n", multi_sim_comm.Get_size() );
     836             :       }
     837             :       else {
     838             :         fprintf(outlog, "# LogMFD\n");
     839             :       }
     840             : 
     841             :       fprintf(outlog, "# CVs :");
     842           6 :       for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     843             :         fprintf(outlog, " %s",  getPntrToArgument(i)->getName().c_str() );
     844             :       }
     845             :       fprintf(outlog, "\n");
     846             : 
     847             :       fprintf(outlog, "# Mass for CV particles :");
     848           6 :       for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     849           3 :         fprintf(outlog, "%15.6f", mfict[i]);
     850             :       }
     851             :       fprintf(outlog, "\n");
     852             : 
     853             :       fprintf(outlog, "# Mass for thermostat   :");
     854           3 :       fprintf(outlog, "%15.6f", meta);
     855             :       fprintf(outlog, "\n");
     856             :       fprintf(outlog, "# 1:iter_mfd, 2:Flog, 3:2*Ekin/gkb[K], 4:eta, 5:Veta,\n");
     857             : 
     858           6 :       for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     859           3 :         fprintf(outlog, "# %u:%s_fict(t), %u:%s_vfict(t), %u:%s_force(t),\n",
     860             :                 6+i*3, getPntrToArgument(i)->getName().c_str(),
     861             :                 7+i*3, getPntrToArgument(i)->getName().c_str(),
     862           3 :                 8+i*3, getPntrToArgument(i)->getName().c_str() );
     863             :       }
     864           3 :       fclose(outlog);
     865             :     }
     866             : 
     867           3 :     if( comm.Get_rank()==0 ) {
     868             :       // the number of replica is added to file name to distingwish replica.
     869           3 :       FILE *outlog2 = fopen("replica.out", "w");
     870           6 :       fprintf(outlog2, "# Replica No. %d of %d.\n",
     871           3 :               multi_sim_comm.Get_rank(), multi_sim_comm.Get_size() );
     872             : 
     873             :       fprintf(outlog2, "# 1:iter_mfd, 2:work, 3:weight,\n");
     874           6 :       for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     875           3 :         fprintf(outlog2, "# %u:%s(q)\n",
     876             :                 4+i, getPntrToArgument(i)->getName().c_str() );
     877             :       }
     878           3 :       fclose(outlog2);
     879             :     }
     880             : 
     881             :     // output messages to Plumed's log file
     882             :     //    log.printf("LOGMFD thermostat parameters Xeta Veta Meta");
     883             :     //    log.printf(" %f %f %f", xeta, veta, meta);
     884             :     //    log.printf("\n");
     885             :     //    log.printf("# 1:iter_mfd, 2:Flog, 3:2*Ekin/gkb[K], 4:eta, 5:Veta,");
     886             :     //    log.printf("# 6:X1(t), 7:V1(t), 8:F1(t), 9:X2(t), 10:V2(t), 11:F2(t), ...");
     887             : 
     888             :   } // firsttime
     889             : 
     890             :   // calculate force for fictitious variable
     891             :   double ene=0.0;
     892        3000 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     893             :     // difference between fictitious variable and collective variable.
     894        1500 :     const double diff = difference(i,fict[i],getArgument(i));
     895             :     // restraining force.
     896        1500 :     const double f = -kappa[i]*diff;
     897        1500 :     setOutputForce(i,f);
     898             : 
     899             :     // restraining energy.
     900        1500 :     ene += 0.5*kappa[i]*diff*diff;
     901             : 
     902             :     // accumulate force, later it will be averaged.
     903        1500 :     ffict[i] += -f;
     904             : 
     905             :     // accumulate varience of collective variable, later it will be averaged.
     906        1500 :     fict_ave[i] += diff;
     907             :   }
     908             : 
     909        1500 :   setBias(ene);
     910        3000 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     911             :     // correct fict so that it is inside [min:max].
     912        1500 :     double tmp = fict[i];
     913        1500 :     fict[i] = fictValue[i]->bringBackInPbc(fict[i]);
     914        1500 :     fictValue[i]->set(fict[i]);
     915        1500 :     vfictValue[i]->set(vfict[i]);
     916             :   }
     917        1500 : } // calculate
     918             : 
     919             : /**
     920             :    \brief update fictitious variables.
     921             :    \details This function manages evolution of fictitious variables.
     922             :    This function calculates mean force, updates fictitious variables by one MFD step,
     923             :    bounces back variables, updates free energy, and record logs.
     924             : */
     925        1500 : void LogMFD::update() {
     926        1500 :   if( (getStep()-step_initial)%interval != interval-1 ) return;
     927             : 
     928          30 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     929          15 :     backup.fict[i]  =  fict[i];
     930          15 :     backup.vfict[i] = vfict[i];
     931             :   }
     932          15 :   backup.xeta = xeta;
     933          15 :   backup.veta = veta;
     934          15 :   backup.phivs = phivs;
     935          15 :   backup.work = work;
     936          15 :   backup.weight = weight;
     937             : 
     938             :   // calc mean force for fictitious variables
     939          15 :   calcMeanForce();
     940             : 
     941             :   // record log for fictitious variables
     942          15 :   if( multi_sim_comm.Get_rank()==0 && comm.Get_rank()==0 ) {
     943          15 :     const double ekin = calcEkin();
     944          15 :     const double temp = 2.0*ekin/getNumberOfArguments()/getKBoltzmann();
     945             : 
     946          15 :     FILE *outlog = std::fopen("logmfd.out", "a");
     947          15 :     fprintf(outlog, "%*d", 8, (int)(getStep()-step_initial)/interval);
     948          15 :     fprintf(outlog, "%15.6f", flog);
     949             :     fprintf(outlog, "%15.6f", temp);
     950          15 :     fprintf(outlog, "%15.6f", xeta);
     951          15 :     fprintf(outlog, "%15.6f", veta);
     952          30 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     953          15 :       fprintf(outlog, "%15.6f", fict[i]);
     954          15 :       fprintf(outlog, "%15.6f", vfict[i]);
     955          15 :       fprintf(outlog, "%15.6f", ffict[i]);
     956             :     }
     957             :     fprintf(outlog," \n");
     958          15 :     fclose(outlog);
     959             :   }
     960             : 
     961             :   // record log for collective variables
     962          15 :   if( comm.Get_rank()==0 ) {
     963             :     // the number of replica is added to file name to distingwish replica.
     964          15 :     FILE *outlog2 = fopen("replica.out", "a");
     965          15 :     fprintf(outlog2, "%*d", 8, (int)(getStep()-step_initial)/interval);
     966          15 :     fprintf(outlog2, "%16.6e ", work);
     967          15 :     fprintf(outlog2, "%16.6e ", weight);
     968          30 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     969          15 :       fprintf(outlog2, "%15.6f", fict_ave[i]);
     970             :     }
     971             :     fprintf(outlog2," \n");
     972          15 :     fclose(outlog2);
     973             :   }
     974             : 
     975             :   // update fictitious variables
     976          15 :   if(thermostat == "NVE") {
     977           5 :     updateNVE();
     978             :   }
     979          10 :   else if(thermostat == "NVT") {
     980           5 :     updateNVT();
     981             :   }
     982           5 :   else if(thermostat == "VS") {
     983           5 :     updateVS();
     984             :   }
     985             : 
     986             :   // update work done by fictitious dynamical variables
     987          15 :   updateWork();
     988             : 
     989             :   // check boundary
     990             :   bool reject = false;
     991          30 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     992          15 :     if( fict[i] < fict_min[i] || fict_max[i] < fict[i] ) {
     993             :       reject = true;
     994           0 :       backup.vfict[i] *= -1.0;
     995             :     }
     996             :   }
     997          15 :   if( reject ) {
     998           0 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     999           0 :       fict[i] = backup.fict[i];
    1000           0 :       vfict[i] = backup.vfict[i];
    1001             :     }
    1002           0 :     xeta = backup.xeta;
    1003           0 :     veta = backup.veta;
    1004           0 :     phivs = backup.phivs;
    1005           0 :     work = backup.work;
    1006           0 :     weight = backup.weight;
    1007             :   }
    1008             : 
    1009             :   // update free energy
    1010          15 :   flog = calcFlog();
    1011             : 
    1012             :   // reset mean force
    1013          30 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1014          15 :     ffict[i] = 0.0;
    1015          15 :     fict_ave[i] = 0.0;
    1016             :   }
    1017             : 
    1018             : } // update
    1019             : 
    1020             : /**
    1021             :    \brief update fictitious variables by NVE mechanics.
    1022             :    \details This function updates ficitious variables by one NVE-MFD step using mean forces
    1023             :    and flattening coefficient and free energy.
    1024             :  */
    1025           5 : void LogMFD::updateNVE() {
    1026           5 :   const double dt = delta_t;
    1027             : 
    1028             :   // get latest free energy and flattening coefficient
    1029           5 :   flog = calcFlog();
    1030           5 :   const double clog = calcClog();
    1031             : 
    1032             :   // update all ficitious variables by one MFD step
    1033          10 :   for( unsigned i=0; i<getNumberOfArguments(); ++i ) {
    1034             :     // update velocity (full step)
    1035           5 :     vfict[i]+=clog*ffict[i]*dt/mfict[i];
    1036             :     // update position (full step)
    1037           5 :     fict[i]+=vfict[i]*dt;
    1038             :   }
    1039           5 : } // updateNVE
    1040             : 
    1041             : /**
    1042             :    \brief update fictitious variables by NVT mechanics.
    1043             :    \details This function updates ficitious variables by one NVT-MFD step using mean forces
    1044             :    and flattening coefficient and free energy.
    1045             :  */
    1046           5 : void LogMFD::updateNVT() {
    1047           5 :   const double dt = delta_t;
    1048           5 :   const double nkt = getNumberOfArguments()*kbt;
    1049             : 
    1050             :   // backup vfict
    1051          10 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1052           5 :     backup.vfict[i] = vfict[i];
    1053             :   }
    1054             : 
    1055             :   const int niter=5;
    1056          30 :   for(unsigned j=0; j<niter; ++j) {
    1057             :     // get latest free energy and flattening coefficient
    1058          25 :     flog = calcFlog();
    1059          25 :     const double clog = calcClog();
    1060             : 
    1061             :     // restore vfict from backup.vfict
    1062          50 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1063          25 :       vfict[i] = backup.vfict[i];
    1064             :     }
    1065             : 
    1066             :     // evolve vfict from backup.vfict by dt/2
    1067          50 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1068          25 :       vfict[i] *= exp(-0.25*dt*veta);
    1069          25 :       vfict[i] += 0.5*dt*clog*ffict[i]/mfict[i];
    1070          25 :       vfict[i] *= exp(-0.25*dt*veta);
    1071             :     }
    1072             :   }
    1073             : 
    1074             :   // get latest free energy and flattening coefficient
    1075           5 :   flog = calcFlog();
    1076           5 :   const double clog = calcClog();
    1077             : 
    1078             :   // evolve vfict by dt/2, and evolve fict by dt
    1079          10 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1080           5 :     vfict[i] *= exp(-0.25*dt*veta);
    1081           5 :     vfict[i] += 0.5*dt*clog*ffict[i]/mfict[i];
    1082           5 :     vfict[i] *= exp(-0.25*dt*veta);
    1083           5 :     fict[i]  += dt*vfict[i];
    1084             :   }
    1085             : 
    1086             :   // evolve xeta and veta by dt
    1087           5 :   xeta += 0.5*dt*veta;
    1088           5 :   const double ekin = calcEkin();
    1089           5 :   veta += dt*(2.0*ekin-nkt)/meta;
    1090           5 :   xeta += 0.5*dt*veta;
    1091           5 : } // updateNVT
    1092             : 
    1093             : /**
    1094             :    \brief update fictitious variables by VS mechanics.
    1095             :    \details This function updates ficitious variables by one VS-MFD step using mean forces
    1096             :    and flattening coefficient and free energy.
    1097             :  */
    1098           5 : void LogMFD::updateVS() {
    1099           5 :   const double dt = delta_t;
    1100           5 :   const double nkt = getNumberOfArguments()*kbt;
    1101             : 
    1102             :   // get latest free energy and flattening coefficient
    1103           5 :   flog = calcFlog();
    1104           5 :   const double clog = calcClog();
    1105             : 
    1106          10 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1107             :     // update velocity (full step)
    1108           5 :     vfict[i] += clog*ffict[i]*dt/mfict[i];
    1109             :   }
    1110             : 
    1111           5 :   const double ekin = calcEkin();
    1112           5 :   const double svs = sqrt(nkt/ekin/2);
    1113             : 
    1114          10 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1115             :     // update position (full step)
    1116           5 :     vfict[i] *= svs;
    1117           5 :     fict[i] += vfict[i]*dt;
    1118             :   }
    1119             : 
    1120             :   // evolve VS potential
    1121           5 :   phivs += nkt*std::log(svs);
    1122           5 : } // updateVS
    1123             : 
    1124             : /**
    1125             :    \brief update work done by fictious variables.
    1126             :    \details This function updates work done by ficitious variables.
    1127             :  */
    1128          15 : void LogMFD::updateWork() {
    1129             :   // accumulate work, it was initialized as 0.0
    1130          30 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1131          15 :     work -= backup.ffict[i] * vfict[i] * delta_t;
    1132             :   }
    1133          15 : } // updateWork
    1134             : 
    1135             : /**
    1136             :    \brief calculate mean force for fictitious variables.
    1137             :    \details This function calculates mean forces by averaging forces accumulated during one MFD step,
    1138             :    update work variables done by fictitious variables by one MFD step,
    1139             :    calculate weight variable of this replica for LogPD.
    1140             : */
    1141          15 : void LogMFD::calcMeanForce() {
    1142             :   // cale temporal mean force for each CV
    1143          30 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1144          15 :     ffict[i] /= interval;
    1145             :     // backup force of replica
    1146          15 :     backup.ffict[i] = ffict[i];
    1147             :     // average of diff (getArgument(i)-fict[i])
    1148          15 :     fict_ave[i] /= interval;
    1149             :     // average of getArgument(i)
    1150          15 :     fict_ave[i] += fict[i];
    1151             : 
    1152             :     // correct fict_ave so that it is inside [min:max].
    1153          15 :     fict_ave[i] = fictValue[i]->bringBackInPbc(fict_ave[i]);
    1154             :   }
    1155             : 
    1156             :   // for replica parallel
    1157          15 :   if( multi_sim_comm.Get_size()>1 ) {
    1158             :     // find the minimum work among all replicas
    1159           0 :     double work_min = work;
    1160           0 :     multi_sim_comm.Min(work_min);
    1161             : 
    1162             :     // weight of this replica.
    1163             :     // here, work is reduced by work_min to avoid all exp(-work/kbt)s disconverge
    1164           0 :     if( kbtpd == 0.0 ) {
    1165           0 :       weight = work==work_min ? 1.0 : 0.0;
    1166             :     }
    1167             :     else {
    1168           0 :       weight = exp(-(work-work_min)/kbtpd);
    1169             :     }
    1170             : 
    1171             :     // normalize the weight
    1172           0 :     double sum_weight = weight;
    1173           0 :     multi_sim_comm.Sum(sum_weight);
    1174           0 :     weight /= sum_weight;
    1175             : 
    1176             :     // weighting force of this replica
    1177           0 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1178           0 :       ffict[i] *= weight;
    1179             :     }
    1180             : 
    1181             :     // averaged mean forces of all replica.
    1182           0 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1183           0 :       multi_sim_comm.Sum(ffict[i]);
    1184             :     }
    1185             :     // now, mean force is obtained.
    1186             :   }
    1187          15 : } // calcMeanForce
    1188             : 
    1189             : /**
    1190             :    \brief calculate kinetic energy of fictitious variables.
    1191             :    \retval kinetic energy.
    1192             :    \details This function calculates sum of kinetic energy of all fictitious variables.
    1193             :  */
    1194          83 : double LogMFD::calcEkin() {
    1195             :   double ekin=0.0;
    1196         166 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1197          83 :     ekin += mfict[i]*vfict[i]*vfict[i]*0.5;
    1198             :   }
    1199          83 :   return ekin;
    1200             : } // calcEkin
    1201             : 
    1202             : /**
    1203             :    \brief calculate free energy of fictitious variables.
    1204             :    \retval free energy.
    1205             :    \details This function calculates free energy by using invariant of canonical mechanics.
    1206             :  */
    1207          55 : double LogMFD::calcFlog() {
    1208          55 :   const double nkt = getNumberOfArguments()*kbt;
    1209          55 :   const double ekin = calcEkin();
    1210             :   double pot;
    1211             : 
    1212          55 :   if (thermostat == "NVE") {
    1213          10 :     pot = hlog - ekin;
    1214             :   }
    1215          45 :   else if (thermostat == "NVT") {
    1216          35 :     const double ekin_bath = 0.5*veta*veta*meta+xeta*nkt;
    1217          35 :     pot = hlog - ekin - ekin_bath;
    1218             :   }
    1219          10 :   else if (thermostat == "VS") {
    1220          10 :     pot = phivs;
    1221             :   }
    1222             :   else {
    1223             :     pot = 0.0; // never occurs
    1224             :   }
    1225             : 
    1226         110 :   return TAMD ? pot : sgn(pot)*expm1(fabs(pot)/gamma)/alpha;
    1227             : } // calcFlog
    1228             : 
    1229             : /**
    1230             :    \brief calculate coefficient for flattening.
    1231             :    \retval flattering coefficient.
    1232             :    \details This function returns 1.0 for TAMD, flattening coefficient for LogMFD.
    1233             :  */
    1234          40 : double LogMFD::calcClog() {
    1235          40 :   return TAMD ? 1.0 : alpha*gamma/(alpha*fabs(flog)+1.0);
    1236             : } // calcClog
    1237             : 
    1238             : } // logmfd
    1239             : } // PLMD

Generated by: LCOV version 1.16