LCOV - code coverage report
Current view: top level - logmfd - LogMFD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 275 311 88.4 %
Date: 2021-11-18 15:22:58 Functions: 18 19 94.7 %

          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=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 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, reconstructing free energy profiles can be performed more efficiently (requiring less elapsed computing time) in LogPD than with a single MD system in LogMFD. In the case that there exists 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, and NAMD.
     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) &=& V_{X_i}^\prime \left( {{t_n}} \right) + \Delta t\left[ { - \left( {\frac{{\alpha \gamma }}{{\alpha F\left( {{t_n}} \right) + 1}}} \right)\frac{{\partial F\left( {{t_n}} \right)}}{{\partial {X_i}}}} \right]\\
     193             : S\left( {{t_{n + 1}}} \right) &=& \sqrt {\frac{{N{k_B}T}}{{\sum\limits_i {{M_i}V_{{X_i}}^2\left( {{t_{n + 1}}} \right)} }}} \\
     194             : {V_{{X_i}}}^\prime \left( {{t_{n + 1}}} \right) &=& S\left( {{t_{n + 1}}} \right){V_{{X_i}}}\left( {{t_{n + 1}}} \right)\\
     195             : {X_i}\left( {{t_{n + 1}}} \right) &=& {X_i}\left( {{t_n}} \right) + \Delta t V_{X_i}^\prime \left( {{t_{n + 1}}} \right)\\
     196             : {\Psi_{\rm log}}\left( {{t_{n + 1}}} \right) &=& N{k_B}T\log S\left( {{t_{n + 1}}} \right) + {\Psi_{\rm log}}\left( {{t_n}} \right)\\
     197             : F\left( {{t_{n + 1}}} \right) &=& \frac{1}{\alpha} \left[
     198             :     \exp \left\{ \Psi_{\rm log} \left( t_{n+1} \right) / \gamma \right\} - 1 \right]
     199             : \f}
     200             : 
     201             : Note that \f$V_{X_i}^\prime\left( {{t_0}} \right)\f$ is assumed to be initially given, which meets the following relation,
     202             : 
     203             : \f[
     204             :   \sum\limits_{i = 1}^N M_i V_{X_i}^{\prime 2} \left( t_0 \right)  = N{k_B}{T}
     205             : \f]
     206             : 
     207             : 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.
     208             : 
     209             : 
     210             : \par Examples
     211             : \section Examples Examples
     212             : 
     213             : \subsection Example-LoGMFD Example of LogMFD
     214             : 
     215             : The following input file tells plumed to restrain collective variables
     216             : to the fictitious dynamical variables in LogMFD/PD.
     217             : 
     218             : plumed.dat
     219             : \plumedfile
     220             : UNITS TIME=fs LENGTH=1.0 ENERGY=kcal/mol MASS=1.0 CHARGE=1.0
     221             : phi: TORSION ATOMS=5,7,9,15
     222             : psi: TORSION ATOMS=7,9,15,17
     223             : 
     224             : # LogMFD
     225             : LOGMFD ...
     226             : LABEL=logmfd
     227             : ARG=phi,psi
     228             : KAPPA=100.0,100.0
     229             : DELTA_T=0.5
     230             : INTERVAL=500
     231             : TEMP=300.0
     232             : FLOG=5.0
     233             : MFICT=5000000.0,5000000.0
     234             : # FICT=0.8,0.8
     235             : VFICT=3.5e-4,3.5e-4
     236             : ALPHA=4.0
     237             : THERMOSTAT=NVE
     238             : VETA=0.0
     239             : META=20000.0
     240             : FICT_MAX=3.1,3.1
     241             : FICT_MIN=-3.1,-3.1
     242             : ... LOGMFD
     243             : \endplumedfile
     244             : 
     245             : To submit this simulation with Gromacs, use the following command line
     246             : to execute a LogMFD run with Gromacs-MD.
     247             : Here TOPO/topol0.tpr is an input file
     248             : which contains atomic coordinates and Gromacs parameters.
     249             : 
     250             : \verbatim
     251             : gmx_mpi mdrun -s TOPO/topol0.tpr -plumed
     252             : \endverbatim
     253             : 
     254             : This command will output files named logmfd.out and replica.out.
     255             : 
     256             : The output file logmfd.out records free energy and all fictitious dynamical variables at every MFD step.
     257             : 
     258             : logmfd.out
     259             : 
     260             : \verbatim
     261             : # LogMFD
     262             : # CVs : phi psi
     263             : # Mass for CV particles : 5000000.000000000 5000000.000000000
     264             : # Mass for thermostat   :   20000.000000000
     265             : # 1:iter_md, 2:Flog, 3:2*Ekin/gkb[K], 4:eta, 5:Veta,
     266             : # 6:phi_fict(t), 7:phi_vfict(t), 8:phi_force(t),
     267             : # 9:psi_fict(t), 10:psi_vfict(t), 11:psi_force(t),
     268             :        1       4.99918574     308.24149708       0.00000000       0.00000000      -2.85605938       0.00035002       5.19074544       2.79216364       0.00035000      -0.53762989
     269             :        2       4.99836196     308.26124159       0.00000000       0.00000000      -2.85588436       0.00035005       4.71247605       2.79233863       0.00035000      -0.00532474
     270             :        3       4.99743572     308.28344595       0.00000000       0.00000000      -2.85570932       0.00035007       5.34358230       2.79251363       0.00035000      -0.05119816
     271             : ...
     272             : \endverbatim
     273             : 
     274             : The output file replica.out records all collective variables at every MFD step.
     275             : 
     276             : replica.out
     277             : 
     278             : \verbatim
     279             : # Replica No. 0 of 1.
     280             : # 1:iter_md, 2:work, 3:weight,
     281             : # 4:phi(q)
     282             : # 5:psi(q)
     283             :        1   -8.142952e-04     1.000000e+00       -2.80432694       2.78661234
     284             :        2   -1.638105e-03     1.000000e+00       -2.80893462       2.79211039
     285             :        3   -2.564398e-03     1.000000e+00       -2.80244854       2.79182665
     286             : ...
     287             : \endverbatim
     288             : 
     289             : \subsection Example-LogPD Example of LogPD
     290             : 
     291             : Use the following command line to execute a LogPD run using two MD replicas (note that only Gromacs is currently available for LogPD).
     292             : Here TOPO/topol0.tpr and TOPO/topol1.tpr are input files
     293             : which contain atomic coordinates of each replica and Gromacs parameters.
     294             : 
     295             : \verbatim
     296             : mpirun -np 2 gmx_mpi mdrun -s TOPO/topol -plumed -multi 2
     297             : \endverbatim
     298             : 
     299             : This command will output files named logmfd.out, replica.out.0 and replica.out.1.
     300             : 
     301             : The output file logmfd.out records free energy and all fictitious dynamical variables at every MFD step.
     302             : 
     303             : logmfd.out
     304             : 
     305             : \verbatim
     306             : # LogPD, replica parallel of LogMFD
     307             : # number of replica : 2
     308             : # CVs : phi psi
     309             : # Mass for CV particles : 5000000.000000000 5000000.000000000
     310             : # Mass for thermostat   :   20000.000000000
     311             : # 1:iter_md, 2:Flog, 3:2*Ekin/gkb[K], 4:eta, 5:Veta,
     312             : # 6:phi_fict(t), 7:phi_vfict(t), 8:phi_force(t),
     313             : # 9:psi_fict(t), 10:psi_vfict(t), 11:psi_force(t),
     314             :        1       5.00224715     308.16814691       0.00000000       0.00000000      -0.95937173       0.00034994     -12.91277494       0.78923967       0.00035000       0.07353010
     315             :        2       5.00476934     308.10774854       0.00000000       0.00000000      -0.95919679       0.00034989     -11.20093553       0.78941467       0.00034999      -3.21098229
     316             :        3       5.00702463     308.05376594       0.00000000       0.00000000      -0.95902187       0.00034983     -10.81712171       0.78958965       0.00034998      -2.07196718
     317             : ...
     318             : \endverbatim
     319             : 
     320             : 
     321             : The output file replica.out.0 records all collective variables of replica No.0 at every MFD step.
     322             : 
     323             : replica.out.0
     324             : 
     325             : \verbatim
     326             : # Replica No. 0 of 2.
     327             : # 1:iter_md, 2:work, 3:weight,
     328             : # 4:phi(q)
     329             : # 5:psi(q)
     330             :        1    1.843110e-03     5.003389e-01       -1.10929125       0.83348865
     331             :        2    3.466179e-03     5.010942e-01       -1.05020764       0.78731283
     332             :        3    4.927870e-03     5.017619e-01       -1.04968867       0.79635198
     333             : ...
     334             : \endverbatim
     335             : 
     336             : The output file replica.out.1 records all collective variables of replica No.1 at every MFD step.
     337             : 
     338             : replica.out.1
     339             : 
     340             : \verbatim
     341             : # Replica No. 1 of 2.
     342             : # 1:iter_md, 2:work, 3:weight,
     343             : # 4:phi(q)
     344             : # 5:psi(q)
     345             :        1    2.651173e-03     4.996611e-01       -1.06802968       0.74605205
     346             :        2    6.075530e-03     4.989058e-01       -1.09264741       0.72681448
     347             :        3    9.129358e-03     4.982381e-01       -1.08517238       0.74084241
     348             : ...
     349             : \endverbatim
     350             : 
     351             : */
     352             : //+ENDPLUMEDOC
     353             : 
     354             : #include "bias/Bias.h"
     355             : #include "core/ActionRegister.h"
     356             : #include "core/Atoms.h"
     357             : #include "core/PlumedMain.h"
     358             : 
     359             : #include <iostream>
     360             : 
     361             : using namespace std;
     362             : using namespace PLMD;
     363             : using namespace bias;
     364             : 
     365             : namespace PLMD {
     366             : namespace logmfd {
     367             : /**
     368             :    \brief class for LogMFD parameters, variables and subroutines.
     369             :  */
     370           9 : class LogMFD : public Bias {
     371             :   bool firsttime;               ///< flag that indicates first MFD step or not.
     372             :   int    interval;              ///< input parameter, period of MD steps when fictitious dynamical variables are evolved.
     373             :   double delta_t;               ///< input parameter, one time step of MFD when fictitious dynamical variables are evolved.
     374             :   string thermostat;            ///< input parameter, type of thermostat for canonical dyanamics.
     375             :   double kbt;                   ///< k_B*temerature
     376             : 
     377             :   int    TAMD;                  ///< input parameter, perform TAMD instead of LogMFD.
     378             :   double alpha;                 ///< input parameter, alpha parameter for LogMFD.
     379             :   double gamma;                 ///< input parameter, gamma parameter for LogMFD.
     380             :   std::vector<double> kappa;    ///< input parameter, strength of the harmonic restraining potential.
     381             : 
     382             :   std::vector<double> fict_max; ///< input parameter, maximum of each fictitous dynamical variable.
     383             :   std::vector<double> fict_min; ///< input parameter, minimum of each fictitous dynamical variable.
     384             : 
     385             :   std::vector<double>  fict;    ///< current values of each fictitous dynamical variable.
     386             :   std::vector<double> vfict;    ///< current velocity of each fictitous dynamical variable.
     387             :   std::vector<double> mfict;    ///< mass of each fictitous dynamical variable.
     388             : 
     389             :   double xeta;                  ///< current eta variable of thermostat.
     390             :   double veta;                  ///< current velocity of eta variable of thermostat.
     391             :   double meta;                  ///< mass of eta variable of thermostat.
     392             : 
     393             :   double flog;                  ///< current free energy
     394             : 
     395             :   double hlog;                  ///< value invariant
     396             :   double phivs;                 ///< potential used in VS method
     397             :   double work;                  ///< current works done by fictitious dynamical variables in this replica.
     398             :   double weight;                ///< current weight of this replica.
     399             : 
     400             :   std::vector<double> ffict;    ///< current force of each fictitous dynamical variable.
     401             :   std::vector<double> fict_ave; ///< averaged values of each collective variable.
     402             : 
     403             :   std::vector<Value*>  fictValue; ///< pointers to fictitious dynamical variables
     404             :   std::vector<Value*> vfictValue; ///< pointers to velocity of fictitious dynamical variables
     405             : 
     406             : public:
     407             :   static void registerKeywords(Keywords& keys);
     408             : 
     409             :   explicit LogMFD(const ActionOptions&);
     410             :   void calculate();
     411             :   void update();
     412             :   void updateNVE();
     413             :   void updateNVT();
     414             :   void updateVS();
     415             :   void calcMeanForce();
     416             :   double calcEkin();
     417             :   double calcFlog();
     418             :   double calcClog();
     419             : 
     420             : private:
     421             :   double sgn( double x ) {
     422          58 :     return x>0.0 ? 1.0 : x<0.0 ? -1.0 : 0.0;
     423             :   }
     424             : };
     425             : 
     426        7362 : PLUMED_REGISTER_ACTION(LogMFD,"LOGMFD")
     427             : 
     428             : /**
     429             :    \brief instruction of parameters for Plumed manual.
     430             : */
     431           4 : void LogMFD::registerKeywords(Keywords& keys) {
     432           4 :   Bias::registerKeywords(keys);
     433           8 :   keys.use("ARG");
     434          16 :   keys.add("compulsory","INTERVAL",
     435             :            "Period of MD steps (\\f$N_m\\f$) to update fictitious dynamical variables." );
     436          16 :   keys.add("compulsory","DELTA_T",
     437             :            "Time step for the fictitious dynamical variables (MFD step)." );
     438          16 :   keys.add("compulsory","THERMOSTAT",
     439             :            "Type of thermostat for the fictitious dynamical variables. NVE, NVT, VS are available." );
     440          16 :   keys.add("optional","TEMP",
     441             :            "Temperature of the fictitious dynamical variables in LogMFD/PD thermostat. "
     442             :            "If not provided or provided as 0, it will be taken from the temperature of the MD system." );
     443             : 
     444          16 :   keys.add("optional","TAMD",
     445             :            "When TAMD=1, TAMD/d-AFED calculations can be performed instead of LogMFD. Otherwise, the LogMFD protocol is switched on (default)." );
     446             : 
     447          16 :   keys.add("optional","ALPHA",
     448             :            "Alpha parameter for LogMFD. "
     449             :            "If not provided or provided as 0, it will be taken as 1/gamma. "
     450             :            "If gamma is also not provided, Alpha is set as 4, which is a sensible value when the unit of kcal/mol is used." );
     451          16 :   keys.add("optional","GAMMA",
     452             :            "Gamma parameter for LogMFD. "
     453             :            "If not provided or provided as 0, it will be taken as 1/alpha. "
     454             :            "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." );
     455          16 :   keys.add("compulsory","KAPPA",
     456             :            "Spring constant of the harmonic restraining potential for the fictitious dynamical variables." );
     457             : 
     458          16 :   keys.add("compulsory","FICT_MAX",
     459             :            "Maximum values reachable for the fictitious dynamical variables. The variables will elastically bounce back at the boundary (mirror boundary)." );
     460          16 :   keys.add("compulsory","FICT_MIN",
     461             :            "Minimum values reachable for the fictitious dynamical variables. The variables will elastically bounce back at the boundary (mirror boundary)." );
     462             : 
     463          16 :   keys.add("optional","FICT",
     464             :            "The initial values of the fictitious dynamical variables. "
     465             :            "If not provided, they are set equal to their corresponding CVs for the initial atomic configuration." );
     466          16 :   keys.add("optional","VFICT",
     467             :            "The initial velocities of the fictitious dynamical variables. "
     468             :            "If not provided, they will be taken as 0." );
     469          16 :   keys.add("optional","MFICT",
     470             :            "Masses of each fictitious dynamical variable. "
     471             :            "If not provided, they will be taken as 10000." );
     472             : 
     473          16 :   keys.add("optional","XETA",
     474             :            "The initial eta variable of the Nose-Hoover thermostat "
     475             :            "for the fictitious dynamical variables. "
     476             :            "If not provided, it will be taken as 0." );
     477          16 :   keys.add("optional","VETA",
     478             :            "The initial velocity of eta variable. "
     479             :            "If not provided, it will be taken as 0." );
     480          16 :   keys.add("optional","META",
     481             :            "Mass of eta variable. "
     482             :            "If not provided, it will be taken as \\f$N*kb*T*100*100\\f$." );
     483             : 
     484          16 :   keys.add("compulsory","FLOG",
     485             :            "The initial free energy value in the LogMFD/PD run."
     486             :            "The origin of the free energy profile is adjusted by FLOG to "
     487             :            "realize \\f$F({\\bf X}(t)) > 0\\f$ at any \\f${\\bf X}(t)\\f$, "
     488             :            "resulting in enhanced barrier-crossing. "
     489             :            "(The value of \\f$H_{\\rm log}\\f$ is automatically "
     490             :            "set according to FLOG).");
     491             : 
     492          16 :   keys.add("optional","WORK",
     493             :            "The initial value of the work done by fictitious dynamical "
     494             :            "variables in each replica. "
     495             :            "If not provided, it will be taken as 0.");
     496             : 
     497           4 :   componentsAreNotOptional(keys);
     498          16 :   keys.addOutputComponent("_fict","default",
     499             :                           "For example, the fictitious collective variable for LogMFD is specified as "
     500             :                           "ARG=dist12 and LABEL=logmfd in LOGMFD section in Plumed input file, "
     501             :                           "the associated fictitious dynamical variable can be specified as "
     502             :                           "PRINT ARG=dist12,logmfd.dist12_fict FILE=COLVAR");
     503          16 :   keys.addOutputComponent("_vfict","default",
     504             :                           "For example, the fictitious collective variable for LogMFD is specified as "
     505             :                           "ARG=dist12 and LABEL=logmfd in LOGMFD section in Plumed input file, the "
     506             :                           "velocity of the associated fictitious dynamical variable can be specified as "
     507             :                           "PRINT ARG=dist12,logmfd.dist12_vfict FILE=COLVAR");
     508           4 : }
     509             : 
     510             : 
     511             : /**
     512             :    \brief constructor of LogMFD class
     513             :    \details This constructor initializes all parameters and variables,
     514             :    reads input file and set value of parameters and initial value of variables,
     515             :    and writes messages as Plumed log.
     516             : */
     517           3 : LogMFD::LogMFD( const ActionOptions& ao ):
     518             :   PLUMED_BIAS_INIT(ao),
     519             :   firsttime(true),
     520             :   interval(10),
     521             :   delta_t(1.0),
     522             :   thermostat("NVE"),
     523             :   kbt(-1.0),
     524             :   TAMD(0),
     525             :   alpha(0.0),
     526             :   gamma(0.0),
     527             :   kappa(getNumberOfArguments(),0.0),
     528             :   fict_max(getNumberOfArguments(),0.0),
     529             :   fict_min(getNumberOfArguments(),0.0),
     530             :   fict (getNumberOfArguments(),0.0),
     531             :   vfict(getNumberOfArguments(),0.0),
     532             :   mfict(getNumberOfArguments(),10000.0),
     533             :   xeta(0.0),
     534             :   veta(0.0),
     535             :   meta(0.0),
     536             :   flog(0.0),
     537             :   hlog(0.0),
     538             :   phivs(0.0),
     539             :   work(0.0),
     540             :   weight(0.0),
     541             :   ffict(getNumberOfArguments(),0.0),
     542             :   fict_ave(getNumberOfArguments(),0.0),
     543             :   fictValue(getNumberOfArguments(),NULL),
     544          33 :   vfictValue(getNumberOfArguments(),NULL)
     545             : {
     546           6 :   parse("INTERVAL",interval);
     547           6 :   parse("DELTA_T",delta_t);
     548           6 :   parse("THERMOSTAT",thermostat);
     549           6 :   parse("TEMP",kbt); // read as temperature
     550             : 
     551           6 :   parse("TAMD",TAMD);
     552           6 :   parse("ALPHA",alpha);
     553           6 :   parse("GAMMA",gamma);
     554           6 :   parseVector("KAPPA",kappa);
     555             : 
     556           6 :   parseVector("FICT_MAX",fict_max);
     557           6 :   parseVector("FICT_MIN",fict_min);
     558             : 
     559           6 :   parseVector("FICT",fict);
     560           6 :   parseVector("VFICT",vfict);
     561           6 :   parseVector("MFICT",mfict);
     562             : 
     563           6 :   parse("XETA",xeta);
     564           6 :   parse("VETA",veta);
     565           6 :   parse("META",meta);
     566             : 
     567           6 :   parse("FLOG",flog);
     568             : 
     569             :   // read initial value of work for each replica of LogPD
     570           3 :   if( multi_sim_comm.Get_size()>1 ) {
     571           0 :     vector<double> vwork(multi_sim_comm.Get_size(),0.0);
     572           0 :     parseVector("WORK",vwork);
     573             :     // initial work of this replica
     574           0 :     work = vwork[multi_sim_comm.Get_rank()];
     575             :   }
     576             :   else {
     577           3 :     work = 0.0;
     578             :   }
     579             : 
     580           3 :   if( kbt>=0.0 ) {
     581           6 :     kbt *= plumed.getAtoms().getKBoltzmann();
     582             :   }
     583             :   else {
     584           0 :     kbt = plumed.getAtoms().getKbT();
     585             :   }
     586             : 
     587           3 :   if( meta == 0.0 ) {
     588           2 :     const double nkt = getNumberOfArguments()*kbt;
     589           2 :     meta = nkt*100.0*100.0;
     590             :   }
     591             : 
     592           3 :   if(alpha == 0.0 && gamma == 0.0) {
     593           0 :     alpha = 4.0;
     594           0 :     gamma = 1 / alpha;
     595             :   }
     596           3 :   else if(alpha != 0.0 && gamma == 0.0) {
     597           3 :     gamma = 1 / alpha;
     598             :   }
     599           0 :   else if(alpha == 0.0 && gamma != 0.0) {
     600           0 :     alpha = 1 / gamma;
     601             :   }
     602             : 
     603           3 :   checkRead();
     604             : 
     605             :   // output messaages to Plumed's log file
     606           3 :   if( multi_sim_comm.Get_size()>1 ) {
     607           0 :     if( TAMD ) {
     608           0 :       log.printf("TAMD-PD, replica parallel of TAMD, no logarithmic flattening.\n");
     609             :     }
     610             :     else {
     611           0 :       log.printf("LogPD, replica parallel of LogMFD.\n");
     612             :     }
     613           0 :     log.printf("number of replica : %d.\n", multi_sim_comm.Get_size() );
     614             :   }
     615             :   else {
     616           3 :     if( TAMD ) {
     617           0 :       log.printf("TAMD, no logarithmic flattening.\n");
     618             :     }
     619             :     else {
     620           3 :       log.printf("LogMFD, logarithmic flattening.\n");
     621             :     }
     622             :   }
     623             : 
     624           3 :   log.printf("  with harmonic force constant      ");
     625          15 :   for(unsigned i=0; i<kappa.size(); i++) log.printf(" %f",kappa[i]);
     626           3 :   log.printf("\n");
     627             : 
     628           3 :   log.printf("  with interval of cv(ideal) update ");
     629           3 :   log.printf(" %d", interval);
     630           3 :   log.printf("\n");
     631             : 
     632           3 :   log.printf("  with time step of cv(ideal) update ");
     633           3 :   log.printf(" %f", delta_t);
     634           3 :   log.printf("\n");
     635             : 
     636           3 :   if( !TAMD ) {
     637           3 :     log.printf("  with alpha, gamma                 ");
     638           3 :     log.printf(" %f %f", alpha, gamma);
     639           3 :     log.printf("\n");
     640             :   }
     641             : 
     642           3 :   log.printf("  with Thermostat for cv(ideal)     ");
     643           6 :   log.printf(" %s", thermostat.c_str());
     644           3 :   log.printf("\n");
     645             : 
     646           3 :   log.printf("  with initial free energy          ");
     647           3 :   log.printf(" %f", flog);
     648           3 :   log.printf("\n");
     649             : 
     650           3 :   log.printf("  with mass of cv(ideal)");
     651          15 :   for(unsigned i=0; i<mfict.size(); i++) log.printf(" %f", mfict[i]);
     652           3 :   log.printf("\n");
     653             : 
     654           3 :   log.printf("  with initial value of cv(ideal)");
     655          15 :   for(unsigned i=0; i<fict.size(); i++) log.printf(" %f", fict[i]);
     656           3 :   log.printf("\n");
     657             : 
     658           3 :   log.printf("  with initial velocity of cv(ideal)");
     659          15 :   for(unsigned i=0; i<vfict.size(); i++) log.printf(" %f", vfict[i]);
     660           3 :   log.printf("\n");
     661             : 
     662           3 :   log.printf("  with maximum value of cv(ideal)    ");
     663          15 :   for(unsigned i=0; i<fict_max.size(); i++) log.printf(" %f",fict_max[i]);
     664           3 :   log.printf("\n");
     665             : 
     666           3 :   log.printf("  with minimum value of cv(ideal)    ");
     667          15 :   for(unsigned i=0; i<fict_min.size(); i++) log.printf(" %f",fict_min[i]);
     668           3 :   log.printf("\n");
     669             : 
     670           3 :   log.printf("  and kbt                           ");
     671           3 :   log.printf(" %f",kbt);
     672           3 :   log.printf("\n");
     673             : 
     674             :   // setup Value* variables
     675           9 :   for(unsigned i=0; i<getNumberOfArguments(); i++) {
     676           3 :     std::string comp = getPntrToArgument(i)->getName()+"_fict";
     677           3 :     addComponentWithDerivatives(comp);
     678             : 
     679           3 :     if(getPntrToArgument(i)->isPeriodic()) {
     680             :       std::string a,b;
     681           0 :       getPntrToArgument(i)->getDomain(a,b);
     682           0 :       componentIsPeriodic(comp,a,b);
     683             :     }
     684             :     else {
     685           3 :       componentIsNotPeriodic(comp);
     686             :     }
     687           3 :     fictValue[i] = getPntrToComponent(comp);
     688             : 
     689           6 :     comp = getPntrToArgument(i)->getName()+"_vfict";
     690           3 :     addComponent(comp);
     691             : 
     692           3 :     componentIsNotPeriodic(comp);
     693           3 :     vfictValue[i] = getPntrToComponent(comp);
     694             :   }
     695           3 : }
     696             : 
     697             : /**
     698             :    \brief calculate forces for fictitious variables at every MD steps.
     699             :    \details This function calculates initial values of fictitious variables
     700             :    and write header messages to LogMFD log files at the first MFD step,
     701             :    calculates restraining fources comes from difference between the fictious variable
     702             :    and collective variable at every MD steps.
     703             : */
     704        1500 : void LogMFD::calculate() {
     705        1500 :   if( firsttime ) {
     706           3 :     firsttime = false;
     707             : 
     708             :     // set initial values of fictitious variables if they were not specified.
     709           9 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     710           6 :       if( fict[i] != 0.0 ) continue;
     711             : 
     712             :       // use the collective variables as the initial of the fictitious variable.
     713           0 :       fict[i] = getArgument(i);
     714             : 
     715             :       // average values of fictitious variables by all replica.
     716           0 :       if( multi_sim_comm.Get_size()>1 ) {
     717           0 :         multi_sim_comm.Sum(fict[i]);
     718           0 :         fict[i] /= multi_sim_comm.Get_size();
     719             :       }
     720             :     }
     721             : 
     722             :     // initialize accumulation value to zero
     723           9 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     724           6 :       fict_ave[i] = 0.0;
     725             :     }
     726             : 
     727             :     // calculate invariant for NVE
     728           6 :     if(thermostat == "NVE") {
     729             :       // kinetic energy
     730           1 :       const double ekin = calcEkin();
     731             :       // potential energy
     732           2 :       const double pot = TAMD ? flog : sgn(flog)*gamma * std::log1p( alpha*fabs(flog) );
     733             :       // invariant
     734           1 :       hlog = pot + ekin;
     735             :     }
     736           2 :     else if(thermostat == "NVT") {
     737           1 :       const double nkt = getNumberOfArguments()*kbt;
     738             :       // kinetic energy
     739           1 :       const double ekin = calcEkin();
     740             :       // bath energy
     741           1 :       const double ekin_bath = 0.5*veta*veta*meta + xeta*nkt;
     742             :       // potential energy
     743           2 :       const double pot = TAMD ? flog : sgn(flog)*gamma * std::log1p( alpha*fabs(flog) );
     744             :       // invariant
     745           1 :       hlog = pot + ekin + ekin_bath;
     746             :     }
     747           1 :     else if(thermostat == "VS") {
     748             :       // initial velocities
     749           3 :       for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     750           3 :         vfict[i] = sqrt(kbt/mfict[i]);
     751             :       }
     752             :       // initial VS potential
     753           2 :       phivs = TAMD ? flog : sgn(flog)* gamma*std::log1p( alpha*fabs(flog) );
     754             : 
     755             :       // invariant
     756           1 :       hlog = 0.0;
     757             :     }
     758             : 
     759           3 :     weight = 1.0; // for replica parallel
     760             : 
     761             :     // open LogMFD's log file
     762           3 :     if( multi_sim_comm.Get_rank()==0 && comm.Get_rank()==0 ) {
     763           3 :       FILE *outlog = std::fopen("logmfd.out", "w");
     764             : 
     765             :       // output messages to LogMFD's log file
     766           3 :       if( multi_sim_comm.Get_size()>1 ) {
     767             :         fprintf(outlog, "# LogPD, replica parallel of LogMFD\n");
     768           0 :         fprintf(outlog, "# number of replica : %d\n", multi_sim_comm.Get_size() );
     769             :       }
     770             :       else {
     771             :         fprintf(outlog, "# LogMFD\n");
     772             :       }
     773             : 
     774             :       fprintf(outlog, "# CVs :");
     775           9 :       for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     776             :         fprintf(outlog, " %s",  getPntrToArgument(i)->getName().c_str() );
     777             :       }
     778             :       fprintf(outlog, "\n");
     779             : 
     780             :       fprintf(outlog, "# Mass for CV particles :");
     781           9 :       for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     782           6 :         fprintf(outlog, "%18.9f", mfict[i]);
     783             :       }
     784             :       fprintf(outlog, "\n");
     785             : 
     786             :       fprintf(outlog, "# Mass for thermostat   :");
     787           3 :       fprintf(outlog, "%18.9f", meta);
     788             :       fprintf(outlog, "\n");
     789             :       fprintf(outlog, "# 1:iter_md, 2:Flog, 3:2*Ekin/gkb[K], 4:eta, 5:Veta,\n");
     790             : 
     791           9 :       for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     792           3 :         fprintf(outlog, "# %u:%s_fict(t), %u:%s_vfict(t), %u:%s_force(t),\n",
     793             :                 6+i*3, getPntrToArgument(i)->getName().c_str(),
     794             :                 7+i*3, getPntrToArgument(i)->getName().c_str(),
     795           3 :                 8+i*3, getPntrToArgument(i)->getName().c_str() );
     796             :       }
     797             : 
     798           3 :       fclose(outlog);
     799             :     }
     800             : 
     801           3 :     if( comm.Get_rank()==0 ) {
     802             :       // the number of replica is added to file name to distingwish replica.
     803           3 :       FILE *outlog2 = fopen("replica.out", "w");
     804           9 :       fprintf(outlog2, "# Replica No. %d of %d.\n",
     805           6 :               multi_sim_comm.Get_rank(), multi_sim_comm.Get_size() );
     806             : 
     807             :       fprintf(outlog2, "# 1:iter_md, 2:work, 3:weight,\n");
     808           9 :       for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     809           3 :         fprintf(outlog2, "# %u:%s(q)\n",
     810             :                 4+i, getPntrToArgument(i)->getName().c_str() );
     811             :       }
     812           3 :       fclose(outlog2);
     813             :     }
     814             : 
     815             :     // output messages to Plumed's log file
     816             :     //    log.printf("LOGMFD thermostat parameters Xeta Veta Meta");
     817             :     //    log.printf(" %f %f %f", xeta, veta, meta);
     818             :     //    log.printf("\n");
     819             :     //    log.printf("# 1:iter_md, 2:Flog, 3:2*Ekin/gkb[K], 4:eta, 5:Veta,");
     820             :     //    log.printf("# 6:X1(t), 7:V1(t), 8:F1(t), 9:X2(t), 10:V2(t), 11:F2(t), ...");
     821             : 
     822             :   } // firsttime
     823             : 
     824             :   // calculate force for fictitious variable
     825             :   double ene=0.0;
     826        4500 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     827             :     // difference between fictitious variable and collective variable.
     828        1500 :     const double diff = difference(i,fict[i],getArgument(i));
     829             :     // restraining force.
     830        1500 :     const double f = -kappa[i]*diff;
     831             :     setOutputForce(i,f);
     832             : 
     833             :     // restraining energy.
     834        1500 :     ene += 0.5*kappa[i]*diff*diff;
     835             : 
     836             :     // accumulate force, later it will be averaged.
     837        1500 :     ffict[i] += -f;
     838             : 
     839             :     // accumulate varience of collective variable, later it will be averaged.
     840        1500 :     fict_ave[i] += diff;
     841             :   }
     842             : 
     843             :   setBias(ene);
     844        4500 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     845             :     // correct fict so that it is inside [min:max].
     846        6000 :     fict[i] = fictValue[i]->bringBackInPbc(fict[i]);
     847        3000 :     fictValue[i]->set(fict[i]);
     848        3000 :     vfictValue[i]->set(vfict[i]);
     849             :   }
     850        1500 : } // calculate
     851             : 
     852             : /**
     853             :    \brief update fictitious variables.
     854             :    \details This function manages evolution of fictitious variables.
     855             :    This function calculates mean force, updates fictitious variables by one MFD step,
     856             :    bounces back variables, updates free energy, and record logs.
     857             : */
     858        1500 : void LogMFD::update() {
     859        1500 :   if(getStep() == 0 || getStep()%interval != 0 ) return;
     860             : 
     861             :   // calc mean force for fictitious variables
     862          15 :   calcMeanForce();
     863             : 
     864             :   // update fictitious variables
     865          30 :   if(thermostat == "NVE") {
     866           5 :     updateNVE();
     867             :   }
     868          10 :   else if(thermostat == "NVT") {
     869           5 :     updateNVT();
     870             :   }
     871           5 :   else if(thermostat == "VS") {
     872           5 :     updateVS();
     873             :   }
     874             : 
     875             :   // bounce back variables if they are beyond their min and max.
     876          45 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     877          45 :     if(fict[i] > fict_max[i]) {
     878           0 :       fict[i] = fict_max[i] - (fict[i] - fict_max[i]);
     879           0 :       vfict[i] *= -1.0;
     880             :     }
     881          30 :     if(fict[i] < fict_min[i]) {
     882           0 :       fict[i] = fict_min[i] + (fict_min[i] - fict[i]);
     883           0 :       vfict[i] *= -1.0;
     884             :     }
     885             :   }
     886             : 
     887             :   // update free energy
     888          15 :   flog = calcFlog();
     889             : 
     890             :   // record log for fictitious variables
     891          15 :   if( multi_sim_comm.Get_rank()==0 && comm.Get_rank()==0 ) {
     892          15 :     FILE *outlog = std::fopen("logmfd.out", "a");
     893             : 
     894          15 :     const double ekin = calcEkin();
     895          30 :     const double temp = 2.0*ekin/getNumberOfArguments()/plumed.getAtoms().getKBoltzmann();
     896             : 
     897          15 :     fprintf(outlog, "%*d", 8, (int)getStep()/interval);
     898          15 :     fprintf(outlog, "%17.8f", flog);
     899             :     fprintf(outlog, "%17.8f", temp);
     900          15 :     fprintf(outlog, "%17.8f", xeta);
     901          15 :     fprintf(outlog, "%17.8f", veta);
     902          45 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     903          30 :       fprintf(outlog, "%17.8f", fict[i]);
     904          15 :       fprintf(outlog, "%17.8f", vfict[i]);
     905          15 :       fprintf(outlog, "%17.8f", ffict[i]);
     906             :     }
     907             :     fprintf(outlog," \n");
     908          15 :     fclose(outlog);
     909             :   }
     910             : 
     911             :   // record log for collective variables
     912          15 :   if( comm.Get_rank()==0 ) {
     913             :     // the number of replica is added to file name to distingwish replica.
     914          15 :     FILE *outlog2 = fopen("replica.out", "a");
     915          15 :     fprintf(outlog2, "%*d", 8, (int)getStep()/interval);
     916          15 :     fprintf(outlog2, "%16.6e ", work);
     917          15 :     fprintf(outlog2, "%16.6e ", weight);
     918          45 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     919          30 :       fprintf(outlog2, "%17.8f", fict_ave[i]);
     920             :     }
     921             :     fprintf(outlog2," \n");
     922          15 :     fclose(outlog2);
     923             :   }
     924             : 
     925             :   // reset mean force
     926          45 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     927          30 :     ffict[i] = 0.0;
     928          15 :     fict_ave[i] = 0.0;
     929             :   }
     930             : 
     931             : } // update
     932             : 
     933             : /**
     934             :    \brief update fictitious variables by NVE mechanics.
     935             :    \details This function updates ficitious variables by one NVE-MFD step using mean forces
     936             :    and flattening coefficient and free energy.
     937             :  */
     938           5 : void LogMFD::updateNVE() {
     939           5 :   const double dt = delta_t;
     940             : 
     941             :   // get latest free energy and flattening coefficient
     942           5 :   flog = calcFlog();
     943           5 :   const double clog = calcClog();
     944             : 
     945             :   // update all ficitious variables by one MFD step
     946          15 :   for( unsigned i=0; i<getNumberOfArguments(); ++i ) {
     947             :     // update velocity (full step)
     948          20 :     vfict[i]+=clog*ffict[i]*dt/mfict[i];
     949             :     // update position (full step)
     950          10 :     fict[i]+=vfict[i]*dt;
     951             :   }
     952           5 : } // updateNVE
     953             : 
     954             : /**
     955             :    \brief update fictitious variables by NVT mechanics.
     956             :    \details This function updates ficitious variables by one NVT-MFD step using mean forces
     957             :    and flattening coefficient and free energy.
     958             :  */
     959           5 : void LogMFD::updateNVT() {
     960           5 :   const double dt = delta_t;
     961           5 :   const double nkt = getNumberOfArguments()*kbt;
     962             : 
     963             :   // backup vfict
     964           5 :   std::vector<double> vfict_backup(getNumberOfArguments());
     965          15 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     966          10 :     vfict_backup[i] = vfict[i];
     967             :   }
     968             : 
     969             :   const int niter=5;
     970          55 :   for(unsigned j=0; j<niter; ++j) {
     971             :     // get latest free energy and flattening coefficient
     972          25 :     flog = calcFlog();
     973          25 :     const double clog = calcClog();
     974             : 
     975             :     // restore vfict from vfict_backup
     976          75 :     for(unsigned l=0; l<getNumberOfArguments(); ++l) {
     977          50 :       vfict[l] = vfict_backup[l];
     978             :     }
     979             : 
     980             :     // evolve vfict from vfict_backup by dt/2
     981          75 :     for(unsigned m=0; m<getNumberOfArguments(); ++m) {
     982          50 :       vfict[m] *= exp(-0.25*dt*veta);
     983         100 :       vfict[m] += 0.5*dt*clog*ffict[m]/mfict[m];
     984          50 :       vfict[m] *= exp(-0.25*dt*veta);
     985             :     }
     986             :   }
     987             : 
     988             :   // get latest free energy and flattening coefficient
     989           5 :   flog = calcFlog();
     990           5 :   const double clog = calcClog();
     991             : 
     992             :   // evolve vfict by dt/2, and evolve fict by dt
     993          15 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     994          10 :     vfict[i] *= exp(-0.25*dt*veta);
     995          20 :     vfict[i] += 0.5*dt*clog*ffict[i]/mfict[i];
     996          10 :     vfict[i] *= exp(-0.25*dt*veta);
     997          10 :     fict[i]  += dt*vfict[i];
     998             :   }
     999             : 
    1000             :   // evolve xeta and veta by dt
    1001           5 :   xeta += 0.5*dt*veta;
    1002           5 :   const double ekin = calcEkin();
    1003           5 :   veta += dt*(2.0*ekin-nkt)/meta;
    1004           5 :   xeta += 0.5*dt*veta;
    1005           5 : } // updateNVT
    1006             : 
    1007             : /**
    1008             :    \brief update fictitious variables by VS mechanics.
    1009             :    \details This function updates ficitious variables by one VS-MFD step using mean forces
    1010             :    and flattening coefficient and free energy.
    1011             :  */
    1012           5 : void LogMFD::updateVS() {
    1013           5 :   const double dt = delta_t;
    1014           5 :   const double nkt = getNumberOfArguments()*kbt;
    1015             : 
    1016             :   // get latest free energy and flattening coefficient
    1017           5 :   flog = calcFlog();
    1018           5 :   const double clog = calcClog();
    1019             : 
    1020          15 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1021             :     // update velocity (full step)
    1022          20 :     vfict[i] += clog*ffict[i]*dt/mfict[i];
    1023             :   }
    1024             : 
    1025           5 :   const double ekin = calcEkin();
    1026           5 :   const double svs = sqrt(nkt/ekin/2);
    1027             : 
    1028          15 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1029             :     // update position (full step)
    1030          10 :     vfict[i] *= svs;
    1031          10 :     fict[i] += vfict[i]*dt;
    1032             :   }
    1033             : 
    1034             :   // evolve VS potential
    1035           5 :   phivs += nkt*std::log(svs);
    1036           5 : } // updateVS
    1037             : 
    1038             : /**
    1039             :    \brief calculate mean force for fictitious variables.
    1040             :    \details This function calculates mean forces by averaging forces accumulated during one MFD step,
    1041             :    update work variables done by fictitious variables by one MFD step,
    1042             :    calculate weight variable of this replica for LogPD.
    1043             : */
    1044          15 : void LogMFD::calcMeanForce() {
    1045             :   // cale temporal mean force for each CV
    1046          45 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1047          30 :     ffict[i] /= interval;
    1048             :     // average of diff (getArgument(i)-fict[i])
    1049          15 :     fict_ave[i] /= interval;
    1050             :     // average of getArgument(i)
    1051          30 :     fict_ave[i] += fict[i];
    1052             : 
    1053             :     // correct fict_ave so that it is inside [min:max].
    1054          45 :     fict_ave[i] = fictValue[i]->bringBackInPbc(fict_ave[i]);
    1055             :   }
    1056             : 
    1057             :   // accumulate work, it was initialized as 0.0
    1058          45 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1059          45 :     work -= ffict[i] * vfict[i] * delta_t; // modified sign
    1060             :   }
    1061             : 
    1062             :   // for replica parallel
    1063          15 :   if( multi_sim_comm.Get_size()>1 ) {
    1064             :     // find the minimum work among all replicas
    1065           0 :     double work_min = work;
    1066           0 :     multi_sim_comm.Min(work_min);
    1067             : 
    1068             :     // weight of this replica.
    1069             :     // here, work is reduced by work_min to avoid all exp(-work/kbt)s disconverge
    1070           0 :     if( kbt == 0.0 ) {
    1071           0 :       weight = work==work_min ? 1.0 : 0.0;
    1072             :     }
    1073             :     else {
    1074           0 :       weight = exp(-(work-work_min)/kbt);
    1075             :     }
    1076             : 
    1077             :     // normalize the weight
    1078           0 :     double sum_weight = weight;
    1079           0 :     multi_sim_comm.Sum(sum_weight);
    1080           0 :     weight /= sum_weight;
    1081             : 
    1082             :     // weighting force of this replica
    1083           0 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1084           0 :       ffict[i] *= weight;
    1085             :     }
    1086             : 
    1087             :     // mean forces of all replica.
    1088           0 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1089           0 :       multi_sim_comm.Sum(ffict[i]);
    1090             :     }
    1091             :     // now, mean force is obtained.
    1092             :   }
    1093          15 : } // calcMeanForce
    1094             : 
    1095             : /**
    1096             :    \brief calculate kinetic energy of fictitious variables.
    1097             :    \retval kinetic energy.
    1098             :    \details This function calculates sum of kinetic energy of all fictitious variables.
    1099             :  */
    1100          82 : double LogMFD::calcEkin() {
    1101             :   double ekin=0.0;
    1102         246 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
    1103         246 :     ekin += mfict[i]*vfict[i]*vfict[i]*0.5;
    1104             :   }
    1105          82 :   return ekin;
    1106             : } // calcEkin
    1107             : 
    1108             : /**
    1109             :    \brief calculate free energy of fictitious variables.
    1110             :    \retval free energy.
    1111             :    \details This function calculates free energy by using invariant of canonical mechanics.
    1112             :  */
    1113          55 : double LogMFD::calcFlog() {
    1114          55 :   const double nkt = getNumberOfArguments()*kbt;
    1115          55 :   const double ekin = calcEkin();
    1116             :   double pot;
    1117             : 
    1118         110 :   if (thermostat == "NVE") {
    1119          10 :     pot = hlog - ekin;
    1120             :   }
    1121          45 :   else if (thermostat == "NVT") {
    1122          35 :     const double ekin_bath = 0.5*veta*veta*meta+xeta*nkt;
    1123          35 :     pot = hlog - ekin - ekin_bath;
    1124             :   }
    1125          10 :   else if (thermostat == "VS") {
    1126          10 :     pot = phivs;
    1127             :   }
    1128             :   else {
    1129             :     pot = 0.0; // never occurs
    1130             :   }
    1131             : 
    1132         110 :   return TAMD ? pot : sgn(pot)*expm1(fabs(pot)/gamma)/alpha;
    1133             : } // calcFlog
    1134             : 
    1135             : /**
    1136             :    \brief calculate coefficient for flattening.
    1137             :    \retval flattering coefficient.
    1138             :    \details This function returns 1.0 for TAMD, flattening coefficient for LogMFD.
    1139             :  */
    1140          40 : double LogMFD::calcClog() {
    1141          40 :   return TAMD ? 1.0 : alpha*gamma/(alpha*fabs(flog)+1.0);
    1142             : } // calcClog
    1143             : 
    1144             : } // logmfd
    1145        5517 : } // PLMD

Generated by: LCOV version 1.14