LCOV - code coverage report
Current view: top level - bias - ReweightTemperaturePressure.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 46 47 97.9 %
Date: 2024-10-11 08:09:47 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2019-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "core/ActionRegister.h"
      23             : #include "core/PlumedMain.h"
      24             : #include "core/Atoms.h"
      25             : #include "ReweightBase.h"
      26             : 
      27             : //+PLUMEDOC REWEIGHTING REWEIGHT_TEMP_PRESS
      28             : /*
      29             : Calculate weights for ensemble averages at temperatures and/or pressures different than those used in your original simulation.
      30             : 
      31             : We can use our knowledge of the probability distribution in the canonical (N\f$\mathcal{V}\f$T) or the isothermal-isobaric ensemble (NPT) to reweight the data
      32             : contained in trajectories and obtain ensemble averages at different temperatures and/or pressures.
      33             : 
      34             : Consider the ensemble average of an observable \f$O(\mathbf{R},\mathcal{V})\f$ that depends on the atomic coordinates \f$\mathbf{R}\f$ and the volume \f$\mathcal{V}\f$.
      35             : This observable is in practice any collective variable (CV) calculated by Plumed.
      36             : The ensemble average of the observable in an ensemble \f$ \xi' \f$  can be calculated from a simulation performed in an ensemble \f$ \xi \f$ using:
      37             : \f[
      38             : \langle O(\mathbf{R},\mathcal{V}) \rangle_{\xi'} = \frac{\langle O(\mathbf{R},\mathcal{V}) w(\mathbf{R},\mathcal{V}) \rangle_{\xi}}
      39             :                                                      {\langle w(\mathbf{R},\mathcal{V}) \rangle_{\xi}}
      40             : \f]
      41             : where \f$\langle \cdot \rangle_{\xi}\f$ and  \f$\langle \cdot \rangle_{\xi'}\f$ are mean values in the simulated and targeted ensemble, respectively, \f$ E(\mathbf{R}) \f$ is the potential energy of the system, and \f$ w (\mathbf{R},\mathcal{V}) \f$ are the appropriate weights to take from \f$ \xi \f$ to \f$ \xi' \f$.
      42             : This action calculates the weights  \f$ w (\mathbf{R},\mathcal{V}) \f$ and handles 4 different cases:
      43             :   1. Change of temperature from T to T' at constant volume. That is to say, from a simulation performed in the N\f$\mathcal{V}\f$T (canonical) ensemble, obtain an ensemble average in the N\f$\mathcal{V}\f$T' ensemble. The weights in this case are  \f$ w(\mathbf{R},\mathcal{V}) = e^{(\beta-\beta')E(\mathbf{R})} \f$ with \f$ \beta \f$ and \f$ \beta' \f$ the inverse temperatures.
      44             :   2. Change of temperature from T to T' at constant pressure. That is to say, from a simulation performed in the NPT (isothermal-isobaric) ensemble, obtain an ensemble average in the NPT' ensemble. The weights in this case are \f$ w(\mathbf{R},\mathcal{V}) = e^{(\beta-\beta')(E(\mathbf{R}) + P\mathcal{V}) } \f$.
      45             :   3. Change of pressure from P to P' at constant temperature. That is to say, from a simulation performed in the NPT (isothermal-isobaric) ensemble, obtain an ensemble average in the NP'T ensemble. The weights in this case are \f$ w(\mathbf{R},\mathcal{V}) = e^{\beta (P - P') \mathcal{V}} \f$.
      46             :   4. Change of temperature and pressure from T,P to T',P'. That is to say, from a simulation performed in the NPT (isothermal-isobaric) ensemble, obtain an ensemble average in the NP'T' ensemble. The weights in this case are \f$ w(\mathbf{R},\mathcal{V}) = e^{(\beta-\beta')E(\mathbf{R}) + (\beta P - \beta' P') \mathcal{V}} \f$.
      47             : 
      48             : These weights can be used in any action that computes ensemble averages.
      49             : For example this action can be used in tandem with \ref HISTOGRAM or \ref AVERAGE.
      50             : 
      51             : 
      52             : The above equation is often impractical since the overlap between the distributions of energy and volume at different temperatures and pressures is only significant for neighboring temperatures and pressures.
      53             : For this reason an unbiased simulation is of little use to reweight at different temperatures and/or pressures.
      54             : A successful approach has been altering the probability of observing a configuration in order to increase this overlap \cite wanglandau.
      55             : This is done through a bias potential \f$ V(\mathbf{s}) \f$ where \f$ \mathbf{s} \f$ is a set of CVs, that often is the energy (and possibly the volume).
      56             : In order to calculate ensemble averages, also the effect of this bias must be taken into account.
      57             : The ensemble average of the observable in the ensemble \f$ \xi' \f$ can be calculated from a biased simulation performed in the ensemble \f$\xi\f$ with bias \f$ V(\mathbf{s}) \f$ using:
      58             : \f[
      59             : \langle O(\mathbf{R},\mathcal{V}) \rangle_{\xi'} = \frac{\langle O(\mathbf{R},\mathcal{V})  w (\mathbf{R},\mathcal{V}) e^{\beta V(\mathbf{s})}  \rangle_{\xi,V}}
      60             :                                                      {\langle w (\mathbf{R},\mathcal{V})  e^{\beta V(\mathbf{s})}  \rangle_{\xi,V}}
      61             : \f]
      62             : where \f$\langle \cdot \rangle_{\xi,V}\f$ is a mean value in the biased ensemble with static bias \f$ V(\mathbf{s}) \f$.
      63             : Therefore in order to reweight the trajectory at different temperatures and/or pressures one must use the weights calculated by this action \f$ w (\mathbf{R},\mathcal{V}) \f$ together with the weights of \ref REWEIGHT_BIAS (see the examples below).
      64             : 
      65             : The bias potential \f$ V(\mathbf{s}) \f$ can be constructed with \ref METAD using \ref ENERGY as a CV \cite mich+04prl.
      66             : More specialized tools are available, for instance using bespoke target distributions such as \ref TD_MULTICANONICAL and \ref TD_MULTITHERMAL_MULTIBARIC \cite Piaggi-PRL-2019 \cite Piaggi-JCP-2019 within \ref VES.
      67             : In the latter algorithms the interval of temperatures and pressures in which the trajectory can be reweighted is chosen explicitly.
      68             : 
      69             : \par Examples
      70             : 
      71             : We consider the 4 cases described above.
      72             : 
      73             : The following input can be used to postprocess a molecular dynamics trajectory of a system of 1000 particles run at 500 K and constant volume using a static bias potential.
      74             : 
      75             : \plumedfile
      76             : energy: READ FILE=COLVAR VALUES=energy  IGNORE_TIME
      77             : distance: READ FILE=COLVAR VALUES=distance  IGNORE_TIME
      78             : mybias: READ FILE=COLVAR VALUES=mybias.bias  IGNORE_TIME
      79             : 
      80             : # Shift energy (to avoid numerical issues)
      81             : renergy: COMBINE ARG=energy PARAMETERS=-13250 PERIODIC=NO
      82             : 
      83             : # Weights
      84             : bias_weights: REWEIGHT_BIAS TEMP=500 ARG=mybias.bias
      85             : temp_press_weights: REWEIGHT_TEMP_PRESS TEMP=500 REWEIGHT_TEMP=300 ENERGY=renergy
      86             : 
      87             : # Ensemble average of the distance at 300 K
      88             : avg_dist: AVERAGE ARG=distance LOGWEIGHTS=bias_weights,temp_press_weights
      89             : 
      90             : PRINT ARG=avg_dist FILE=COLVAR_REWEIGHT STRIDE=1
      91             : \endplumedfile
      92             : 
      93             : Clearly, in performing the analysis above we would read from the potential energy, a distance, and the value of the bias potential from a COLVAR file like the one shown below.  We would then be able
      94             : to calculate the ensemble average of the distance at 300 K.
      95             : 
      96             : \auxfile{COLVAR}
      97             : #! FIELDS time energy volume mybias.bias distance
      98             :  10000.000000 -13133.769283 7.488921 63.740530 0.10293
      99             :  10001.000000 -13200.239722 7.116548 36.691988 0.16253
     100             :  10002.000000 -13165.108850 7.202273 44.408815 0.17625
     101             : \endauxfile
     102             : 
     103             : The next three inputs can be used to postprocess a molecular dynamics trajectory of a system of 1000 particles run at 500 K and 1 bar using a static bias potential.
     104             : 
     105             : We read from a file COLVAR the potential energy, the volume, and the value of the bias potential and calculate the ensemble average of the (particle) density at 300 K and 1 bar (the simulation temperature was 500 K).
     106             : 
     107             : \plumedfile
     108             : energy: READ FILE=COLVAR VALUES=energy  IGNORE_TIME
     109             : volume: READ FILE=COLVAR VALUES=volume  IGNORE_TIME
     110             : mybias: READ FILE=COLVAR VALUES=mybias.bias  IGNORE_TIME
     111             : 
     112             : # Shift energy and volume (to avoid numerical issues)
     113             : rvol: COMBINE ARG=volume PARAMETERS=7.8 PERIODIC=NO
     114             : renergy: COMBINE ARG=energy PARAMETERS=-13250 PERIODIC=NO
     115             : 
     116             : # Weights
     117             : bias_weights: REWEIGHT_BIAS TEMP=500 ARG=mybias.bias
     118             : temp_press_weights: REWEIGHT_TEMP_PRESS TEMP=500 REWEIGHT_TEMP=300 PRESSURE=0.06022140857 ENERGY=renergy VOLUME=rvol
     119             : 
     120             : # Ensemble average of the volume at 300 K
     121             : avg_vol: AVERAGE ARG=volume LOGWEIGHTS=bias_weights,temp_press_weights
     122             : # Ensemble average of the density at 300 K
     123             : avg_density: CUSTOM ARG=avg_vol FUNC=1000/x PERIODIC=NO
     124             : 
     125             : PRINT ARG=avg_density FILE=COLVAR_REWEIGHT STRIDE=1
     126             : \endplumedfile
     127             : 
     128             : In the next example we calculate the ensemble average of the (particle) density at 500 K and 300 MPa (the simulation pressure was 1 bar).
     129             : 
     130             : \plumedfile
     131             : volume: READ FILE=COLVAR VALUES=volume  IGNORE_TIME
     132             : mybias: READ FILE=COLVAR VALUES=mybias.bias  IGNORE_TIME
     133             : 
     134             : # Shift volume (to avoid numerical issues)
     135             : rvol: COMBINE ARG=volume PARAMETERS=7.8 PERIODIC=NO
     136             : 
     137             : # Weights
     138             : bias_weights: REWEIGHT_BIAS TEMP=500 ARG=mybias.bias
     139             : temp_press_weights: REWEIGHT_TEMP_PRESS TEMP=500 PRESSURE=0.06022140857 REWEIGHT_PRESSURE=180.66422571 VOLUME=volume
     140             : 
     141             : # Ensemble average of the volume at 300 K and 300 MPa
     142             : avg_vol: AVERAGE ARG=volume LOGWEIGHTS=bias_weights,temp_press_weights
     143             : # Ensemble average of the density at 300 K and 300 MPa
     144             : avg_density: CUSTOM ARG=avg_vol FUNC=1000/x PERIODIC=NO
     145             : 
     146             : PRINT ARG=avg_density FILE=COLVAR_REWEIGHT STRIDE=1
     147             : \endplumedfile
     148             : 
     149             : 
     150             : In this final example we calculate the ensemble average of the (particle) density at 300 K and 300 MPa (the simulation temperature and pressure were 500 K and 1 bar).
     151             : 
     152             : \plumedfile
     153             : energy: READ FILE=COLVAR VALUES=energy  IGNORE_TIME
     154             : volume: READ FILE=COLVAR VALUES=volume  IGNORE_TIME
     155             : mybias: READ FILE=COLVAR VALUES=mybias.bias  IGNORE_TIME
     156             : 
     157             : # Shift energy and volume (to avoid numerical issues)
     158             : rvol: COMBINE ARG=volume PARAMETERS=7.8 PERIODIC=NO
     159             : renergy: COMBINE ARG=energy PARAMETERS=-13250 PERIODIC=NO
     160             : 
     161             : # Weights
     162             : bias_weights: REWEIGHT_BIAS TEMP=500 ARG=mybias.bias
     163             : temp_press_weights: REWEIGHT_TEMP_PRESS TEMP=500 REWEIGHT_TEMP=300 PRESSURE=0.06022140857 REWEIGHT_PRESSURE=180.66422571 ENERGY=renergy VOLUME=rvol
     164             : 
     165             : # Ensemble average of the volume at 300 K and 300 MPa
     166             : avg_vol: AVERAGE ARG=volume LOGWEIGHTS=bias_weights,temp_press_weights
     167             : # Ensemble average of the density at 300 K and 300 MPa
     168             : avg_density: CUSTOM ARG=avg_vol FUNC=1000/x PERIODIC=NO
     169             : 
     170             : PRINT ARG=avg_density FILE=COLVAR_REWEIGHT STRIDE=1
     171             : \endplumedfile
     172             : 
     173             : */
     174             : //+ENDPLUMEDOC
     175             : 
     176             : namespace PLMD {
     177             : namespace bias {
     178             : 
     179             : class ReweightTemperaturePressure : public ReweightBase {
     180             : private:
     181             : ///
     182             :   double rpress_, press_, rtemp_;
     183             :   std::vector<Value*> myenergy, myvol;
     184             : public:
     185             :   static void registerKeywords(Keywords&);
     186             :   explicit ReweightTemperaturePressure(const ActionOptions&ao);
     187             :   double getLogWeight() override;
     188             : };
     189             : 
     190       10427 : PLUMED_REGISTER_ACTION(ReweightTemperaturePressure,"REWEIGHT_TEMP_PRESS")
     191             : 
     192           5 : void ReweightTemperaturePressure::registerKeywords(Keywords& keys ) {
     193           5 :   ReweightBase::registerKeywords( keys );
     194           5 :   keys.remove("ARG");
     195          10 :   keys.add("optional","ENERGY","Energy");
     196          10 :   keys.add("optional","VOLUME","Volume");
     197          15 :   keys.add("optional","REWEIGHT_PRESSURE","Reweighting pressure");
     198          10 :   keys.add("optional","PRESSURE","The system pressure");
     199          10 :   keys.add("optional","REWEIGHT_TEMP","Reweighting temperature");
     200           5 : }
     201             : 
     202           4 : ReweightTemperaturePressure::ReweightTemperaturePressure(const ActionOptions&ao):
     203             :   Action(ao),
     204           4 :   ReweightBase(ao)
     205             : {
     206             :   // Initialize to not defined (negative)
     207           4 :   rpress_=-1;
     208           4 :   press_=-1;
     209           4 :   rtemp_=-1;
     210           4 :   parse("REWEIGHT_PRESSURE",rpress_);
     211           4 :   parse("PRESSURE",press_);
     212           4 :   parse("REWEIGHT_TEMP",rtemp_);
     213           4 :   rtemp_*=plumed.getAtoms().getKBoltzmann();
     214             : 
     215           8 :   parseArgumentList("ENERGY",myenergy);
     216           4 :   if(!myenergy.empty()) {
     217           3 :     log.printf("  with energies: ");
     218           6 :     for(unsigned i=0; i<myenergy.size(); i++) log.printf(" %s",myenergy[i]->getName().c_str());
     219           3 :     log.printf("\n");
     220             :   }
     221             :   //requestArguments(myenergy);
     222             : 
     223           8 :   parseArgumentList("VOLUME",myvol);
     224           4 :   if(!myvol.empty()) {
     225           3 :     log.printf("  with volumes: ");
     226           6 :     for(unsigned i=0; i<myvol.size(); i++) log.printf(" %s",myvol[i]->getName().c_str());
     227           3 :     log.printf("\n");
     228             :   }
     229             : 
     230             :   std::vector<Value*> conc;
     231           4 :   conc.insert(conc.begin(), myenergy.begin(), myenergy.end());
     232           4 :   conc.insert(conc.end(), myvol.begin(), myvol.end());
     233           4 :   requestArguments(conc);
     234             : 
     235             :   // 4 possible cases
     236             :   // Case 1) Reweight from T to T' with V=const (canonical)
     237           4 :   if (rtemp_>=0 && press_<0 && rpress_<0 && !myenergy.empty() && myvol.empty() ) {
     238           1 :     log.printf("  reweighting simulation from temperature %f to temperature %f at constant volume \n",simtemp/plumed.getAtoms().getKBoltzmann(),rtemp_/plumed.getAtoms().getKBoltzmann() );
     239           1 :     log.printf("  WARNING: If the simulation is performed at constant pressure add the keywords PRESSURE and VOLUME \n" );
     240             :   }
     241             :   // Case 2) Reweight from T to T' with P=const (isothermal-isobaric)
     242           3 :   else if (rtemp_>=0 && press_>=0 && rpress_<0 && !myenergy.empty() && !myvol.empty() ) log.printf("  reweighting simulation from temperature %f to temperature %f at constant pressure %f \n",simtemp/plumed.getAtoms().getKBoltzmann(),rtemp_/plumed.getAtoms().getKBoltzmann(), press_ );
     243             :   // Case 3) Reweight from P to P' with T=const (isothermal-isobaric)
     244           2 :   else if (rtemp_<0 && press_>=0 && rpress_>=0 && myenergy.empty() && !myvol.empty() ) log.printf("  reweighting simulation from pressure %f to pressure %f at constant temperature %f\n",press_,rpress_,simtemp/plumed.getAtoms().getKBoltzmann() );
     245             :   // Case 4) Reweight from T,P to T',P' (isothermal-isobaric)
     246           1 :   else if (rtemp_>0 && press_>=0 && rpress_>=0 && !myenergy.empty() && !myvol.empty() ) log.printf("  reweighting simulation from temperature %f and pressure %f to temperature %f and pressure %f \n",simtemp/plumed.getAtoms().getKBoltzmann(), press_, rtemp_/plumed.getAtoms().getKBoltzmann(), rpress_);
     247           0 :   else error("Combination of ENERGY, VOLUME, REWEIGHT_PRESSURE, PRESSURE and REWEIGHT_TEMP not supported. Please refer to the manual for supported combinations.");
     248           4 : }
     249             : 
     250        1001 : double ReweightTemperaturePressure::getLogWeight() {
     251        2002 :   double energy=0.0; for(unsigned i=0; i<myenergy.size(); ++i) energy+=getArgument(i);
     252        2002 :   double volume=0.0; for(unsigned i=0; i<myvol.size(); ++i) volume+=getArgument(myenergy.size()+i);
     253             :   // 4 possible cases
     254             :   // Case 1) Reweight from T to T' with V=const (canonical)
     255        1001 :   if (rtemp_>=0 && press_<0 && rpress_<0) return ((1.0/simtemp)- (1.0/rtemp_) )*energy;
     256             :   // Case 2) Reweight from T to T' with P=const (isothermal-isobaric)
     257        1001 :   else if (rtemp_>=0 && press_>=0 && rpress_<0)  return ((1.0/simtemp)- (1.0/rtemp_) )*energy + ((1.0/simtemp) - (1.0/rtemp_))*press_*volume;
     258             :   // Case 3) Reweight from P to P' with T=const (isothermal-isobaric)
     259        1001 :   else if (rtemp_<0 && press_>=0 && rpress_>=0)  return (1.0/simtemp)*(press_ - rpress_)*volume;
     260             :   // Case 4) Reweight from T,P to T',P' (isothermal-isobaric)
     261        1001 :   else if (rtemp_>0 && press_>=0 && rpress_>=0) return ((1.0/simtemp)- (1.0/rtemp_) )*energy + ((1.0/simtemp)*press_ - (1.0/rtemp_)*rpress_ )*volume;
     262             :   else return 0;
     263             : }
     264             : 
     265             : }
     266             : }

Generated by: LCOV version 1.15