LCOV - code coverage report
Current view: top level - opes - OPESmetad.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 788 823 95.7 %
Date: 2024-10-18 13:59:31 Functions: 27 28 96.4 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2020-2021 of Michele Invernizzi.
       3             : 
       4             :    This file is part of the OPES plumed module.
       5             : 
       6             :    The OPES plumed 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 OPES plumed 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             : #include "bias/Bias.h"
      20             : #include "core/PlumedMain.h"
      21             : #include "core/ActionRegister.h"
      22             : #include "tools/Communicator.h"
      23             : #include "tools/File.h"
      24             : #include "tools/OpenMP.h"
      25             : 
      26             : namespace PLMD {
      27             : namespace opes {
      28             : 
      29             : //+PLUMEDOC OPES_BIAS OPES_METAD
      30             : /*
      31             : On-the-fly probability enhanced sampling with metadynamics-like target distribution.
      32             : 
      33             : This On-the-fly probability enhanced sampling (\ref OPES "OPES") method with metadynamics-like target distribution is described in \cite Invernizzi2020rethinking.
      34             : 
      35             : This \ref OPES_METAD action samples target distributions defined via their marginal \f$p^{\text{tg}}(\mathbf{s})\f$ over some collective variables (CVs), \f$\mathbf{s}=\mathbf{s}(\mathbf{x})\f$.
      36             : By default \ref OPES_METAD targets the well-tempered distribution, \f$p^{\text{WT}}(\mathbf{s})\propto [P(\mathbf{s})]^{1/\gamma}\f$, where \f$\gamma\f$ is known as BIASFACTOR.
      37             : Similarly to \ref METAD, \ref OPES_METAD optimizes the bias on-the-fly, with a given PACE.
      38             : It does so by reweighting via kernel density estimation the unbiased distribution in the CV space, \f$P(\mathbf{s})\f$.
      39             : A compression algorithm is used to prevent the number of kernels from growing linearly with the simulation time.
      40             : The bias at step \f$n\f$ is
      41             : \f[
      42             : V_n(\mathbf{s}) = (1-1/\gamma)\frac{1}{\beta}\log\left(\frac{P_n(\mathbf{s})}{Z_n}+\epsilon\right)\, .
      43             : \f]
      44             : See Ref.\cite Invernizzi2020rethinking for a complete description of the method.
      45             : 
      46             : As an intuitive picture, rather than gradually filling the metastable basins, \ref OPES_METAD quickly tries to get a coarse idea of the full free energy surface (FES), and then slowly refines its details.
      47             : It has a fast initial exploration phase, and then becomes extremely conservative and does not significantly change the shape of the deposited bias any more, reaching a regime of quasi-static bias.
      48             : For this reason, it is possible to use standard umbrella sampling reweighting (see \ref REWEIGHT_BIAS) to analyse the trajectory.
      49             : At <a href="https://github.com/invemichele/opes/tree/master/postprocessing">this link</a> you can find some python scripts that work in a similar way to \ref sum_hills, but the preferred way to obtain a FES with OPES is via reweighting (see \ref opes-metad).
      50             : The estimated \f$c(t)\f$ is printed for reference only, since it should converge to a fixed value as the bias converges.
      51             : This \f$c(t)\f$ should NOT be used for reweighting.
      52             : Similarly, the \f$Z_n\f$ factor is printed only for reference, and it should converge when no new region of the CV-space is explored.
      53             : 
      54             : Notice that \ref OPES_METAD is more sensitive to degenerate CVs than \ref METAD.
      55             : If the employed CVs map different metastable basins onto the same CV-space region, then \ref OPES_METAD will remain stuck rather than completely reshaping the bias.
      56             : This can be useful to diagnose problems with your collective variable.
      57             : If it is not possible to improve the set of CVs and remove this degeneracy, then you might instead consider to use \ref OPES_METAD_EXPLORE or \ref METAD.
      58             : In this way you will be able to obtain an estimate of the FES, but be aware that you most likely will not reach convergence and thus this estimate will be subjected to systematic errors (see e.g. Fig.3 in \cite Pietrucci2017review).
      59             : On the contrary, if your CVs are not degenerate but only suboptimal, you should converge faster by using \ref OPES_METAD instead of \ref METAD \cite Invernizzi2020rethinking.
      60             : 
      61             : The parameter BARRIER should be set to be at least equal to the highest free energy barrier you wish to overcome.
      62             : If it is much lower than that, you will not cross the barrier, if it is much higher, convergence might take a little longer.
      63             : If the system has a basin that is clearly more stable than the others, it is better to start the simulation from there.
      64             : 
      65             : By default, the kernels SIGMA is adaptive, estimated from the fluctuations over ADAPTIVE_SIGMA_STRIDE simulation steps (similar to \ref METAD ADAPTIVE=DIFF, but contrary to that, no artifacts are introduced and the bias will converge to the correct one).
      66             : However, notice that depending on the system this might not be the optimal choice for SIGMA.
      67             : 
      68             : You can target a uniform flat distribution by explicitly setting BIASFACTOR=inf.
      69             : However, this should be useful only in very specific cases.
      70             : 
      71             : It is possible to take into account also of other bias potentials besides the one of \ref OPES_METAD during the internal reweighting for \f$P(\mathbf{s})\f$ estimation.
      72             : To do so, one has to add those biases with the EXTRA_BIAS keyword, as in the example below.
      73             : This allows one to define a custom target distribution by adding another bias potential equal to the desired target free energy and setting BIASFACTOR=inf (see example below).
      74             : Another possible usage of EXTRA_BIAS is to make sure that \ref OPES_METAD does not push against another fixed bias added to restrain the CVs range (e.g. \ref UPPER_WALLS).
      75             : 
      76             : Through the EXCLUDED_REGION keywork, it is possible to specify a region of CV space where no kernels will be deposited.
      77             : This can be useful for example for making sure the bias does not modify the transition region, thus allowing for rate calculation.
      78             : See below for an example of how to use this keyword.
      79             : 
      80             : Restart can be done from a KERNELS file, but it might be not perfect (due to limited precision when printing kernels to file, or if adaptive SIGMA is used).
      81             : For an exact restart you must use STATE_RFILE to read a checkpoint with all the needed info.
      82             : To save such checkpoints, define a STATE_WFILE and choose how often to print them with STATE_WSTRIDE.
      83             : By default this file is overwritten, but you can instead append to it using the flag STORE_STATES.
      84             : 
      85             : Multiple walkers are supported only with MPI communication, via the keyword WALKERS_MPI.
      86             : 
      87             : \par Examples
      88             : 
      89             : Several examples can be found on the <a href="https://www.plumed-nest.org/browse.html">PLUMED-NEST website</a>, by searching for the OPES keyword.
      90             : The \ref opes-metad can also be useful to get started with the method.
      91             : 
      92             : The following is a minimal working example:
      93             : 
      94             : \plumedfile
      95             : cv: DISTANCE ATOMS=1,2
      96             : opes: OPES_METAD ARG=cv PACE=200 BARRIER=40
      97             : PRINT STRIDE=200 FILE=COLVAR ARG=*
      98             : \endplumedfile
      99             : 
     100             : Another more articulated one:
     101             : 
     102             : \plumedfile
     103             : phi: TORSION ATOMS=5,7,9,15
     104             : psi: TORSION ATOMS=7,9,15,17
     105             : opes: OPES_METAD ...
     106             :   FILE=Kernels.data
     107             :   TEMP=300
     108             :   ARG=phi,psi
     109             :   PACE=500
     110             :   BARRIER=50
     111             :   SIGMA=0.15,0.15
     112             :   SIGMA_MIN=0.01,0.01
     113             :   STATE_RFILE=Restart.data
     114             :   STATE_WFILE=State.data
     115             :   STATE_WSTRIDE=500*100
     116             :   STORE_STATES
     117             :   WALKERS_MPI
     118             :   NLIST
     119             : ...
     120             : PRINT FMT=%g STRIDE=500 FILE=Colvar.data ARG=phi,psi,opes.*
     121             : \endplumedfile
     122             : 
     123             : Next is an example of how to define a custom target distribution different from the well-tempered one.
     124             : Here we chose to focus more on the transition state, that is around \f$\phi=0\f$.
     125             : Our target distribution is a Gaussian centered there, thus the target free energy we want to sample is a parabola, \f$F^{\text{tg}}(\mathbf{s})=-\frac{1}{\beta} \log [p^{\text{tg}}(\mathbf{s})]\f$.
     126             : 
     127             : \plumedfile
     128             : phi: TORSION ATOMS=5,7,9,15
     129             : FtgValue: CUSTOM ARG=phi PERIODIC=NO FUNC=(x/0.4)^2
     130             : Ftg: BIASVALUE ARG=FtgValue
     131             : opes: OPES_METAD ...
     132             :   ARG=phi
     133             :   PACE=500
     134             :   BARRIER=50
     135             :   SIGMA=0.2
     136             :   BIASFACTOR=inf
     137             :   EXTRA_BIAS=Ftg.bias
     138             : ...
     139             : PRINT FMT=%g STRIDE=500 FILE=COLVAR ARG=phi,Ftg.bias,opes.bias
     140             : \endplumedfile
     141             : 
     142             : Notice that in order to reweight for the unbiased \f$P(\mathbf{s})\f$ during postprocessing, the total bias `Ftg.bias+opes.bias` must be used.
     143             : 
     144             : Finally, an example of how to use the EXCLUDED_REGION keyword.
     145             : It expects a characteristic function that is different from zero in the region to be excluded.
     146             : You can use \ref CUSTOM and a combination of the step function to define it.
     147             : With the following input no kernel is deposited in the transition state region of alanine dipeptide, defined by the interval \f$\phi \in [-0.6, 0.7]\f$:
     148             : 
     149             : \plumedfile
     150             : phi: TORSION ATOMS=5,7,9,15
     151             : psi: TORSION ATOMS=7,9,15,17
     152             : xx: CUSTOM PERIODIC=NO ARG=phi FUNC=step(x+0.6)-step(x-0.7)
     153             : opes: OPES_METAD ...
     154             :   ARG=phi,psi
     155             :   PACE=500
     156             :   BARRIER=30
     157             :   EXCLUDED_REGION=xx
     158             :   NLIST
     159             : ...
     160             : PRINT FMT=%g STRIDE=500 FILE=COLVAR ARG=phi,psi,xx,opes.*
     161             : \endplumedfile
     162             : 
     163             : */
     164             : //+ENDPLUMEDOC
     165             : 
     166             : template <class mode>
     167             : class OPESmetad : public bias::Bias {
     168             : 
     169             : private:
     170             :   bool isFirstStep_;
     171             :   unsigned NumOMP_;
     172             :   unsigned NumParallel_;
     173             :   unsigned rank_;
     174             :   unsigned NumWalkers_;
     175             :   unsigned walker_rank_;
     176             :   unsigned long long counter_;
     177             :   std::size_t ncv_;
     178             : 
     179             :   double kbt_;
     180             :   double biasfactor_;
     181             :   double bias_prefactor_;
     182             :   unsigned stride_;
     183             :   std::vector<double> sigma0_;
     184             :   std::vector<double> sigma_min_;
     185             :   unsigned adaptive_sigma_stride_;
     186             :   unsigned long long adaptive_counter_;
     187             :   std::vector<double> av_cv_;
     188             :   std::vector<double> av_M2_;
     189             :   bool fixed_sigma_;
     190             :   bool adaptive_sigma_;
     191             :   double epsilon_;
     192             :   double sum_weights_;
     193             :   double sum_weights2_;
     194             : 
     195             :   bool no_Zed_;
     196             :   double Zed_;
     197             :   double KDEnorm_;
     198             : 
     199             :   double threshold2_;
     200             :   bool recursive_merge_;
     201             : //kernels are truncated diagonal Gaussians
     202        1050 :   struct kernel
     203             :   {
     204             :     double height;
     205             :     std::vector<double> center;
     206             :     std::vector<double> sigma;
     207        1050 :     kernel(double h, const std::vector<double>& c,const std::vector<double>& s):
     208        1050 :       height(h),center(c),sigma(s) {}
     209             :   };
     210             :   double cutoff2_;
     211             :   double val_at_cutoff_;
     212             :   void mergeKernels(kernel&,const kernel&); //merge the second one into the first one
     213             :   double evaluateKernel(const kernel&,const std::vector<double>&) const;
     214             :   double evaluateKernel(const kernel&,const std::vector<double>&,std::vector<double>&,std::vector<double>&);
     215             :   std::vector<kernel> kernels_; //all compressed kernels
     216             :   OFile kernelsOfile_;
     217             : //neighbour list stuff
     218             :   bool nlist_;
     219             :   double nlist_param_[2];
     220             :   std::vector<unsigned> nlist_index_;
     221             :   std::vector<double> nlist_center_;
     222             :   std::vector<double> nlist_dev2_;
     223             :   unsigned nlist_steps_;
     224             :   bool nlist_update_;
     225             :   bool nlist_pace_reset_;
     226             : 
     227             :   bool calc_work_;
     228             :   double work_;
     229             :   double old_KDEnorm_;
     230             :   std::vector<kernel> delta_kernels_;
     231             : 
     232             :   Value* excluded_region_;
     233             :   std::vector<Value*> extra_biases_;
     234             : 
     235             :   OFile stateOfile_;
     236             :   int wStateStride_;
     237             :   bool storeOldStates_;
     238             : 
     239             :   double getProbAndDerivatives(const std::vector<double>&,std::vector<double>&);
     240             :   void addKernel(const double,const std::vector<double>&,const std::vector<double>&);
     241             :   void addKernel(const double,const std::vector<double>&,const std::vector<double>&,const double); //also print to file
     242             :   unsigned getMergeableKernel(const std::vector<double>&,const unsigned);
     243             :   void updateNlist(const std::vector<double>&);
     244             :   void dumpStateToFile();
     245             : 
     246             : public:
     247             :   explicit OPESmetad(const ActionOptions&);
     248             :   void calculate() override;
     249             :   void update() override;
     250             :   static void registerKeywords(Keywords& keys);
     251             : };
     252             : 
     253             : struct convergence { static const bool explore=false; };
     254             : typedef OPESmetad<convergence> OPESmetad_c;
     255             : PLUMED_REGISTER_ACTION(OPESmetad_c,"OPES_METAD")
     256             : 
     257             : //OPES_METAD_EXPLORE is very similar from the point of view of the code,
     258             : //but conceptually it is better to make it a separate BIAS action
     259             : 
     260             : //+PLUMEDOC OPES_BIAS OPES_METAD_EXPLORE
     261             : /*
     262             : On-the-fly probability enhanced sampling with well-tempered target distribution in exploreation mode.
     263             : 
     264             : On-the-fly probability enhanced sampling with well-tempered target distribution (\ref OPES "OPES") with well-tempered target distribution, exploration mode \cite Invernizzi2022explore .
     265             : 
     266             : This \ref OPES_METAD_EXPLORE action samples the well-tempered target distribution, that is defined via its marginal \f$p^{\text{WT}}(\mathbf{s})\propto [P(\mathbf{s})]^{1/\gamma}\f$ over some collective variables (CVs), \f$\mathbf{s}=\mathbf{s}(\mathbf{x})\f$.
     267             : While \ref OPES_METAD does so by estimating the unbiased distribution \f$P(\mathbf{s})\f$, \ref OPES_METAD_EXPLORE instead estimates on-the-fly the target \f$p^{\text{WT}}(\mathbf{s})\f$ and uses it to define the bias.
     268             : The bias at step \f$n\f$ is
     269             : \f[
     270             : V_n(\mathbf{s}) = (\gamma-1)\frac{1}{\beta}\log\left(\frac{p^{\text{WT}}_n(\mathbf{s})}{Z_n}+\epsilon\right)\, .
     271             : \f]
     272             : See Ref.\cite Invernizzi2022explore for a complete description of the method.
     273             : 
     274             : Intuitively, while \ref OPES_METAD aims at quickly converging the reweighted free energy, \ref OPES_METAD_EXPLORE aims at quickly sampling the target well-tempered distribution.
     275             : Given enough simulation time, both will converge to the same bias potential but they do so in a qualitatively different way.
     276             : Compared to \ref OPES_METAD, \ref OPES_METAD_EXPLORE is more similar to \ref METAD, because it allows the bias to vary significantly, thus enhancing exploration.
     277             : This goes at the expenses of a typically slower convergence of the reweight estimate.
     278             : \ref OPES_METAD_EXPLORE can be useful e.g.~for simulating a new system with an unknown BARRIER, or for quickly testing the effectiveness of a new CV that might be degenerate.
     279             : 
     280             : Similarly to \ref OPES_METAD, also \ref OPES_METAD_EXPLORE uses a kernel density estimation with the same on-the-fly compression algorithm.
     281             : The only difference is that the kernels are not weighted, since it estimates the sampled distribution and not the reweighted unbiased one.
     282             : 
     283             : All the options of \ref OPES_METAD are also available in \ref OPES_METAD_EXPLORE, except for those that modify the target distribution, since only a well-tempered target is allowed in this case.
     284             : 
     285             : \par Examples
     286             : 
     287             : The following is a minimal working example:
     288             : 
     289             : \plumedfile
     290             : cv: DISTANCE ATOMS=1,2
     291             : opes: OPES_METAD_EXPLORE ARG=cv PACE=500 BARRIER=40
     292             : PRINT STRIDE=100 FILE=COLVAR ARG=cv,opes.*
     293             : \endplumedfile
     294             : */
     295             : //+ENDPLUMEDOC
     296             : 
     297             : struct exploration { static const bool explore=true; };
     298             : typedef OPESmetad<exploration> OPESmetad_e;
     299             : PLUMED_REGISTER_ACTION(OPESmetad_e,"OPES_METAD_EXPLORE")
     300             : 
     301             : template <class mode>
     302          25 : void OPESmetad<mode>::registerKeywords(Keywords& keys)
     303             : {
     304          25 :   Bias::registerKeywords(keys);
     305          50 :   keys.add("compulsory","TEMP","-1","temperature. If not set, it is taken from MD engine, but not all MD codes provide it");
     306          50 :   keys.add("compulsory","PACE","the frequency for kernel deposition");
     307          25 :   std::string info_sigma("the initial widths of the kernels");
     308             :   if(mode::explore)
     309             :     info_sigma+=", divided by the square root of gamma";
     310             :   info_sigma+=". If not set, an adaptive sigma will be used with the given ADAPTIVE_SIGMA_STRIDE";
     311          50 :   keys.add("compulsory","SIGMA","ADAPTIVE",info_sigma);
     312          50 :   keys.add("compulsory","BARRIER","the free energy barrier to be overcome. It is used to set BIASFACTOR, EPSILON, and KERNEL_CUTOFF to reasonable values");
     313          50 :   keys.add("compulsory","COMPRESSION_THRESHOLD","1","merge kernels if closer than this threshold, in units of sigma");
     314             : //extra options
     315          50 :   keys.add("optional","ADAPTIVE_SIGMA_STRIDE","number of steps for measuring adaptive sigma. Default is 10xPACE");
     316          50 :   keys.add("optional","SIGMA_MIN","never reduce SIGMA below this value");
     317          25 :   std::string info_biasfactor("the gamma bias factor used for the well-tempered target distribution. ");
     318             :   if(mode::explore)
     319             :     info_biasfactor+="Cannot be 'inf'";
     320             :   else
     321             :     info_biasfactor+="Set to 'inf' for uniform flat target";
     322          50 :   keys.add("optional","BIASFACTOR",info_biasfactor);
     323          50 :   keys.add("optional","EPSILON","the value of the regularization constant for the probability");
     324          50 :   keys.add("optional","KERNEL_CUTOFF","truncate kernels at this distance, in units of sigma");
     325          50 :   keys.add("optional","NLIST_PARAMETERS","( default=3.0,0.5 ) the two cutoff parameters for the kernels neighbor list");
     326          50 :   keys.addFlag("NLIST",false,"use neighbor list for kernels summation, faster but experimental");
     327          50 :   keys.addFlag("NLIST_PACE_RESET",false,"force the reset of the neighbor list at each PACE. Can be useful with WALKERS_MPI");
     328          50 :   keys.addFlag("FIXED_SIGMA",false,"do not decrease sigma as the simulation proceeds. Can be added in a RESTART, to keep in check the number of compressed kernels");
     329          50 :   keys.addFlag("RECURSIVE_MERGE_OFF",false,"do not recursively attempt kernel merging when a new one is added");
     330          50 :   keys.addFlag("NO_ZED",false,"do not normalize over the explored CV space, Z_n=1");
     331             : //kernels and state files
     332          50 :   keys.add("compulsory","FILE","KERNELS","a file in which the list of all deposited kernels is stored");
     333          50 :   keys.add("optional","FMT","specify format for KERNELS file");
     334          50 :   keys.add("optional","STATE_RFILE","read from this file the compressed kernels and all the info needed to RESTART the simulation");
     335          50 :   keys.add("optional","STATE_WFILE","write to this file the compressed kernels and all the info needed to RESTART the simulation");
     336          50 :   keys.add("optional","STATE_WSTRIDE","number of MD steps between writing the STATE_WFILE. Default is only on CPT events (but not all MD codes set them)");
     337          50 :   keys.addFlag("STORE_STATES",false,"append to STATE_WFILE instead of ovewriting it each time");
     338             : //miscellaneous
     339          50 :   keys.addInputKeyword("optional","EXCLUDED_REGION","scalar","kernels are not deposited when the action provided here has a nonzero value, see example above");
     340             :   if(!mode::explore)
     341          32 :     keys.addInputKeyword("optional","EXTRA_BIAS","scalar","consider also these other bias potentials for the internal reweighting. This can be used e.g. for sampling a custom target distribution (see example above)");
     342          50 :   keys.addFlag("CALC_WORK",false,"calculate the total accumulated work done by the bias since last restart");
     343          50 :   keys.addFlag("WALKERS_MPI",false,"switch on MPI version of multiple walkers");
     344          50 :   keys.addFlag("SERIAL",false,"perform calculations in serial");
     345          25 :   keys.use("RESTART");
     346          25 :   keys.use("UPDATE_FROM");
     347          25 :   keys.use("UPDATE_UNTIL");
     348             : 
     349             : //output components
     350          50 :   keys.addOutputComponent("rct","default","scalar","estimate of c(t). log(exp(beta V)/beta, should become flat as the simulation converges. Do NOT use for reweighting");
     351          50 :   keys.addOutputComponent("zed","default","scalar","estimate of Z_n. should become flat once no new CV-space region is explored");
     352          50 :   keys.addOutputComponent("neff","default","scalar","effective sample size");
     353          50 :   keys.addOutputComponent("nker","default","scalar","total number of compressed kernels used to represent the bias");
     354          50 :   keys.addOutputComponent("work","CALC_WORK","scalar","total accumulated work done by the bias");
     355          50 :   keys.addOutputComponent("nlker","NLIST","scalar","number of kernels in the neighbor list");
     356          50 :   keys.addOutputComponent("nlsteps","NLIST","scalar","number of steps from last neighbor list update");
     357          25 : }
     358             : 
     359             : template <class mode>
     360          21 : OPESmetad<mode>::OPESmetad(const ActionOptions& ao)
     361             :   : PLUMED_BIAS_INIT(ao)
     362          21 :   , isFirstStep_(true)
     363          21 :   , counter_(1)
     364          21 :   , ncv_(getNumberOfArguments())
     365          21 :   , Zed_(1)
     366          21 :   , work_(0)
     367          21 :   , excluded_region_(NULL)
     368             : {
     369          42 :   std::string error_in_input1("Error in input in action "+getName()+" with label "+getLabel()+": the keyword ");
     370          21 :   std::string error_in_input2(" could not be read correctly");
     371             : 
     372             : //set kbt_
     373          21 :   const double kB=getKBoltzmann();
     374          21 :   kbt_=getkBT();
     375             : 
     376             : //other compulsory input
     377          21 :   parse("PACE",stride_);
     378             : 
     379          21 :   double barrier=0;
     380          21 :   parse("BARRIER",barrier);
     381          21 :   plumed_massert(barrier>=0,"the BARRIER should be greater than zero");
     382             : 
     383          21 :   biasfactor_=barrier/kbt_;
     384             :   std::string biasfactor_str;
     385          42 :   parse("BIASFACTOR",biasfactor_str);
     386          38 :   if(biasfactor_str=="inf" || biasfactor_str=="INF")
     387             :   {
     388           4 :     biasfactor_=std::numeric_limits<double>::infinity();
     389           4 :     bias_prefactor_=1;
     390             :   }
     391             :   else
     392             :   {
     393          17 :     if(biasfactor_str.length()>0)
     394           3 :       plumed_massert(Tools::convertNoexcept(biasfactor_str,biasfactor_),error_in_input1+"BIASFACTOR"+error_in_input2);
     395          17 :     plumed_massert(biasfactor_>1,"BIASFACTOR must be greater than one (use 'inf' for uniform target)");
     396          17 :     bias_prefactor_=1-1./biasfactor_;
     397             :   }
     398             :   if(mode::explore)
     399             :   {
     400           7 :     plumed_massert(!std::isinf(biasfactor_),"BIASFACTOR=inf is not compatible with EXPLORE mode");
     401           7 :     bias_prefactor_=biasfactor_-1;
     402             :   }
     403             : 
     404          21 :   adaptive_sigma_=false;
     405          21 :   adaptive_sigma_stride_=0;
     406          42 :   parse("ADAPTIVE_SIGMA_STRIDE",adaptive_sigma_stride_);
     407             :   std::vector<std::string> sigma_str;
     408          21 :   parseVector("SIGMA",sigma_str);
     409          21 :   sigma0_.resize(ncv_);
     410             :   double dummy;
     411          21 :   if(sigma_str.size()==1 && !Tools::convertNoexcept(sigma_str[0],dummy))
     412             :   {
     413          11 :     plumed_massert(sigma_str[0]=="ADAPTIVE" || sigma_str[0]=="adaptive",error_in_input1+"SIGMA"+error_in_input2);
     414          11 :     plumed_massert(!std::isinf(biasfactor_),"cannot use BIASFACTOR=inf with adaptive SIGMA");
     415          11 :     adaptive_counter_=0;
     416          11 :     if(adaptive_sigma_stride_==0)
     417           2 :       adaptive_sigma_stride_=10*stride_; //NB: this is arbitrary, chosen from few tests
     418          11 :     av_cv_.resize(ncv_,0);
     419          11 :     av_M2_.resize(ncv_,0);
     420          11 :     plumed_massert(adaptive_sigma_stride_>=stride_,"better to chose ADAPTIVE_SIGMA_STRIDE > PACE");
     421          11 :     adaptive_sigma_=true;
     422             :   }
     423             :   else
     424             :   {
     425          10 :     plumed_massert(sigma_str.size()==ncv_,"number of SIGMA parameters does not match number of arguments");
     426          10 :     plumed_massert(adaptive_sigma_stride_==0,"if SIGMA is not ADAPTIVE you cannot set an ADAPTIVE_SIGMA_STRIDE");
     427          29 :     for(unsigned i=0; i<ncv_; i++)
     428             :     {
     429          19 :       plumed_massert(Tools::convertNoexcept(sigma_str[i],sigma0_[i]),error_in_input1+"SIGMA"+error_in_input2);
     430             :       if(mode::explore)
     431           6 :         sigma0_[i]*=std::sqrt(biasfactor_); //the sigma of the target is broader Ftg(s)=1/gamma*F(s)
     432             :     }
     433             :   }
     434          42 :   parseVector("SIGMA_MIN",sigma_min_);
     435          21 :   plumed_massert(sigma_min_.size()==0 || sigma_min_.size()==ncv_,"number of SIGMA_MIN does not match number of arguments");
     436          21 :   if(sigma_min_.size()>0 && !adaptive_sigma_)
     437             :   {
     438           3 :     for(unsigned i=0; i<ncv_; i++)
     439           2 :       plumed_massert(sigma_min_[i]<=sigma0_[i],"SIGMA_MIN should be smaller than SIGMA");
     440             :   }
     441             : 
     442          21 :   epsilon_=std::exp(-barrier/bias_prefactor_/kbt_);
     443          21 :   parse("EPSILON",epsilon_);
     444          21 :   plumed_massert(epsilon_>0,"you must choose a value for EPSILON greater than zero. Is your BARRIER too high?");
     445          21 :   sum_weights_=std::pow(epsilon_,bias_prefactor_); //to avoid NANs we start with counter_=1 and w0=exp(beta*V0)
     446          21 :   sum_weights2_=sum_weights_*sum_weights_;
     447             : 
     448          21 :   double cutoff=sqrt(2.*barrier/bias_prefactor_/kbt_);
     449             :   if(mode::explore)
     450           7 :     cutoff=sqrt(2.*barrier/kbt_); //otherwise it is too small
     451          21 :   parse("KERNEL_CUTOFF",cutoff);
     452          21 :   plumed_massert(cutoff>0,"you must choose a value for KERNEL_CUTOFF greater than zero");
     453          21 :   cutoff2_=cutoff*cutoff;
     454          21 :   val_at_cutoff_=std::exp(-0.5*cutoff2_);
     455             : 
     456          21 :   threshold2_=1;
     457          21 :   parse("COMPRESSION_THRESHOLD",threshold2_);
     458          21 :   threshold2_*=threshold2_;
     459          21 :   if(threshold2_!=0)
     460          21 :     plumed_massert(threshold2_>0 && threshold2_<cutoff2_,"COMPRESSION_THRESHOLD cannot be bigger than the KERNEL_CUTOFF");
     461             : 
     462             : //setup neighbor list
     463          21 :   nlist_=false;
     464          21 :   parseFlag("NLIST",nlist_);
     465          21 :   nlist_pace_reset_=false;
     466          21 :   parseFlag("NLIST_PACE_RESET",nlist_pace_reset_);
     467          21 :   if(nlist_pace_reset_)
     468           2 :     nlist_=true;
     469             :   std::vector<double> nlist_param;
     470          42 :   parseVector("NLIST_PARAMETERS",nlist_param);
     471          21 :   if(nlist_param.size()==0)
     472             :   {
     473          17 :     nlist_param_[0]=3.0;//*cutoff2_ -> max distance of neighbors
     474          17 :     nlist_param_[1]=0.5;//*nlist_dev2_[i] -> condition for rebuilding
     475             :   }
     476             :   else
     477             :   {
     478           4 :     nlist_=true;
     479           4 :     plumed_massert(nlist_param.size()==2,"two cutoff parameters are needed for the neighbor list");
     480           4 :     plumed_massert(nlist_param[0]>1.0,"the first of NLIST_PARAMETERS must be greater than 1. The smaller the first, the smaller should be the second as well");
     481           4 :     const double min_PARAM_1=(1.-1./std::sqrt(nlist_param[0]))+0.16;
     482           4 :     plumed_massert(nlist_param[1]>0,"the second of NLIST_PARAMETERS must be greater than 0");
     483           4 :     plumed_massert(nlist_param[1]<=min_PARAM_1,"the second of NLIST_PARAMETERS must be smaller to avoid systematic errors. Largest suggested value is: 1.16-1/sqrt(PARAM_0) = "+std::to_string(min_PARAM_1));
     484           4 :     nlist_param_[0]=nlist_param[0];
     485           4 :     nlist_param_[1]=nlist_param[1];
     486             :   }
     487          21 :   nlist_center_.resize(ncv_);
     488          21 :   nlist_dev2_.resize(ncv_,0.);
     489          21 :   nlist_steps_=0;
     490          21 :   nlist_update_=true;
     491             : 
     492             : //optional stuff
     493          21 :   no_Zed_=false;
     494          21 :   parseFlag("NO_ZED",no_Zed_);
     495          21 :   if(no_Zed_)
     496             :   { //this makes it more gentle in the initial phase
     497           6 :     sum_weights_=1;
     498           6 :     sum_weights2_=1;
     499             :   }
     500          21 :   fixed_sigma_=false;
     501          21 :   parseFlag("FIXED_SIGMA",fixed_sigma_);
     502          21 :   bool recursive_merge_off=false;
     503          21 :   parseFlag("RECURSIVE_MERGE_OFF",recursive_merge_off);
     504          21 :   recursive_merge_=!recursive_merge_off;
     505          42 :   parseFlag("CALC_WORK",calc_work_);
     506             : 
     507             : //options involving extra arguments
     508             :   std::vector<Value*> args;
     509          42 :   parseArgumentList("EXCLUDED_REGION",args);
     510          21 :   if(args.size()>0)
     511             :   {
     512           2 :     plumed_massert(args.size()==1,"only one characteristic function should define the region to be excluded");
     513           2 :     requestExtraDependencies(args);
     514           2 :     excluded_region_=args[0];
     515             :   }
     516             :   if(!mode::explore)
     517             :   {
     518          28 :     parseArgumentList("EXTRA_BIAS",extra_biases_);
     519          14 :     if(extra_biases_.size()>0)
     520           2 :       requestExtraDependencies(extra_biases_);
     521             :   }
     522             : 
     523             : //kernels file
     524             :   std::string kernelsFileName;
     525          42 :   parse("FILE",kernelsFileName);
     526             :   std::string fmt;
     527          42 :   parse("FMT",fmt);
     528             : 
     529             : //output checkpoint of current state
     530             :   std::string restartFileName;
     531          42 :   parse("STATE_RFILE",restartFileName);
     532             :   std::string stateFileName;
     533          21 :   parse("STATE_WFILE",stateFileName);
     534          21 :   wStateStride_=0;
     535          21 :   parse("STATE_WSTRIDE",wStateStride_);
     536          21 :   storeOldStates_=false;
     537          21 :   parseFlag("STORE_STATES",storeOldStates_);
     538          21 :   if(wStateStride_!=0 || storeOldStates_)
     539          10 :     plumed_massert(stateFileName.length()>0,"filename for storing simulation status not specified, use STATE_WFILE");
     540          21 :   if(wStateStride_>0)
     541          10 :     plumed_massert(wStateStride_>=(int)stride_,"STATE_WSTRIDE is in units of MD steps, thus it is suggested to use a multiple of PACE");
     542          21 :   if(stateFileName.length()>0 && wStateStride_==0)
     543           1 :     wStateStride_=-1;//will print only on CPT events (checkpoints set by some MD engines, like gromacs)
     544             : 
     545             : //multiple walkers //TODO implement also external mw for cp2k
     546          21 :   bool walkers_mpi=false;
     547          21 :   parseFlag("WALKERS_MPI",walkers_mpi);
     548          21 :   if(walkers_mpi)
     549             :   {
     550             :     //If this Action is not compiled with MPI the user is informed and we exit gracefully
     551          10 :     plumed_massert(Communicator::plumedHasMPI(),"Invalid walkers configuration: WALKERS_MPI flag requires MPI compilation");
     552          10 :     plumed_massert(Communicator::initialized(),"Invalid walkers configuration: WALKERS_MPI needs the communicator correctly initialized.");
     553             : 
     554          10 :     if(comm.Get_rank()==0)//multi_sim_comm works on first rank only
     555             :     {
     556          10 :       NumWalkers_=multi_sim_comm.Get_size();
     557          10 :       walker_rank_=multi_sim_comm.Get_rank();
     558             :     }
     559          10 :     comm.Bcast(NumWalkers_,0); //if each walker has more than one processor update them all
     560          10 :     comm.Bcast(walker_rank_,0);
     561             :   }
     562             :   else
     563             :   {
     564          11 :     NumWalkers_=1;
     565          11 :     walker_rank_=0;
     566             :   }
     567             : 
     568             : //parallelization stuff
     569          21 :   NumOMP_=OpenMP::getNumThreads();
     570          21 :   NumParallel_=comm.Get_size();
     571          21 :   rank_=comm.Get_rank();
     572          21 :   bool serial=false;
     573          21 :   parseFlag("SERIAL",serial);
     574          21 :   if(serial)
     575             :   {
     576           4 :     NumOMP_=1;
     577           4 :     NumParallel_=1;
     578           4 :     rank_=0;
     579             :   }
     580             : 
     581          21 :   checkRead();
     582             : 
     583             : //restart if needed
     584             :   bool convertKernelsToState=false;
     585          21 :   if(getRestart())
     586             :   {
     587             :     bool stateRestart=true;
     588          11 :     if(restartFileName.length()==0)
     589             :     {
     590             :       stateRestart=false;
     591             :       restartFileName=kernelsFileName;
     592             :     }
     593          11 :     IFile ifile;
     594          11 :     ifile.link(*this);
     595          11 :     if(ifile.FileExist(restartFileName))
     596             :     {
     597          11 :       bool tmp_nlist=nlist_;
     598          11 :       nlist_=false; // NLIST is not needed while restarting
     599          11 :       ifile.open(restartFileName);
     600          11 :       log.printf("  RESTART - make sure all used options are compatible\n");
     601          11 :       log.printf("    restarting from: %s\n",restartFileName.c_str());
     602          11 :       std::string action_name=getName();
     603          11 :       if(stateRestart)
     604             :       {
     605           6 :         log.printf("    it should be a STATE file (not a KERNELS file)\n");
     606             :         action_name+="_state";
     607             :       }
     608             :       else
     609             :       {
     610           5 :         log.printf(" +++ WARNING +++ RESTART from KERNELS might be approximate, use STATE_WFILE and STATE_RFILE to restart from the exact state\n");
     611             :         action_name+="_kernels";
     612             :       }
     613             :       std::string old_action_name;
     614          11 :       ifile.scanField("action",old_action_name);
     615          11 :       plumed_massert(action_name==old_action_name,"RESTART - mismatch between old and new action name. Expected '"+action_name+"', but found '"+old_action_name+"'");
     616             :       std::string old_biasfactor_str;
     617          22 :       ifile.scanField("biasfactor",old_biasfactor_str);
     618          21 :       if(old_biasfactor_str=="inf" || old_biasfactor_str=="INF")
     619             :       {
     620           1 :         if(!std::isinf(biasfactor_))
     621           0 :           log.printf(" +++ WARNING +++ previous bias factor was inf while now it is %g\n",biasfactor_);
     622             :       }
     623             :       else
     624             :       {
     625             :         double old_biasfactor;
     626          10 :         ifile.scanField("biasfactor",old_biasfactor);
     627          10 :         if(std::abs(biasfactor_-old_biasfactor)>1e-6*biasfactor_)
     628           0 :           log.printf(" +++ WARNING +++ previous bias factor was %g while now it is %g. diff = %g\n",old_biasfactor,biasfactor_,biasfactor_-old_biasfactor);
     629             :       }
     630             :       double old_epsilon;
     631          11 :       ifile.scanField("epsilon",old_epsilon);
     632          11 :       if(std::abs(epsilon_-old_epsilon)>1e-6*epsilon_)
     633           8 :         log.printf(" +++ WARNING +++ previous epsilon was %g while now it is %g. diff = %g\n",old_epsilon,epsilon_,epsilon_-old_epsilon);
     634             :       double old_cutoff;
     635          11 :       ifile.scanField("kernel_cutoff",old_cutoff);
     636          11 :       if(std::abs(cutoff-old_cutoff)>1e-6*cutoff)
     637           0 :         log.printf(" +++ WARNING +++ previous kernel_cutoff was %g while now it is %g. diff = %g\n",old_cutoff,cutoff,cutoff-old_cutoff);
     638             :       double old_threshold;
     639          11 :       const double threshold=sqrt(threshold2_);
     640          11 :       ifile.scanField("compression_threshold",old_threshold);
     641          11 :       if(std::abs(threshold-old_threshold)>1e-6*threshold)
     642           0 :         log.printf(" +++ WARNING +++ previous compression_threshold was %g while now it is %g. diff = %g\n",old_threshold,threshold,threshold-old_threshold);
     643          11 :       if(stateRestart)
     644             :       {
     645           6 :         ifile.scanField("zed",Zed_);
     646           6 :         ifile.scanField("sum_weights",sum_weights_);
     647           6 :         ifile.scanField("sum_weights2",sum_weights2_);
     648           6 :         ifile.scanField("counter",counter_);
     649           6 :         if(adaptive_sigma_)
     650             :         {
     651           6 :           ifile.scanField("adaptive_counter",adaptive_counter_);
     652           6 :           if(NumWalkers_==1)
     653             :           {
     654           6 :             for(unsigned i=0; i<ncv_; i++)
     655             :             {
     656           8 :               ifile.scanField("sigma0_"+getPntrToArgument(i)->getName(),sigma0_[i]);
     657           8 :               ifile.scanField("av_cv_"+getPntrToArgument(i)->getName(),av_cv_[i]);
     658           8 :               ifile.scanField("av_M2_"+getPntrToArgument(i)->getName(),av_M2_[i]);
     659             :             }
     660             :           }
     661             :           else
     662             :           {
     663          12 :             for(unsigned w=0; w<NumWalkers_; w++)
     664          24 :               for(unsigned i=0; i<ncv_; i++)
     665             :               {
     666             :                 double tmp0,tmp1,tmp2;
     667          32 :                 const std::string arg_iw=getPntrToArgument(i)->getName()+"_"+std::to_string(w);
     668          16 :                 ifile.scanField("sigma0_"+arg_iw,tmp0);
     669          16 :                 ifile.scanField("av_cv_"+arg_iw,tmp1);
     670          16 :                 ifile.scanField("av_M2_"+arg_iw,tmp2);
     671          16 :                 if(w==walker_rank_)
     672             :                 {
     673           8 :                   sigma0_[i]=tmp0;
     674           8 :                   av_cv_[i]=tmp1;
     675           8 :                   av_M2_[i]=tmp2;
     676             :                 }
     677             :               }
     678             :           }
     679             :         }
     680             :       }
     681          33 :       for(unsigned i=0; i<ncv_; i++)
     682             :       {
     683          22 :         if(getPntrToArgument(i)->isPeriodic())
     684             :         {
     685             :           std::string arg_min,arg_max;
     686          22 :           getPntrToArgument(i)->getDomain(arg_min,arg_max);
     687             :           std::string file_min,file_max;
     688          44 :           ifile.scanField("min_"+getPntrToArgument(i)->getName(),file_min);
     689          22 :           ifile.scanField("max_"+getPntrToArgument(i)->getName(),file_max);
     690          22 :           plumed_massert(file_min==arg_min,"RESTART - mismatch between old and new ARG periodicity");
     691          22 :           plumed_massert(file_max==arg_max,"RESTART - mismatch between old and new ARG periodicity");
     692             :         }
     693             :       }
     694          11 :       if(stateRestart)
     695             :       {
     696             :         double time;
     697          60 :         while(ifile.scanField("time",time))
     698             :         {
     699          24 :           std::vector<double> center(ncv_);
     700          24 :           std::vector<double> sigma(ncv_);
     701             :           double height;
     702          72 :           for(unsigned i=0; i<ncv_; i++)
     703          48 :             ifile.scanField(getPntrToArgument(i)->getName(),center[i]);
     704          72 :           for(unsigned i=0; i<ncv_; i++)
     705          96 :             ifile.scanField("sigma_"+getPntrToArgument(i)->getName(),sigma[i]);
     706          24 :           ifile.scanField("height",height);
     707          24 :           ifile.scanField();
     708          24 :           kernels_.emplace_back(height,center,sigma);
     709             :         }
     710           6 :         log.printf("    a total of %lu kernels where read\n",kernels_.size());
     711             :       }
     712             :       else
     713             :       {
     714           5 :         ifile.allowIgnoredFields(); //this allows for multiple restart, but without checking for consistency between them!
     715             :         double time;
     716         270 :         while(ifile.scanField("time",time))
     717             :         {
     718         130 :           std::vector<double> center(ncv_);
     719         130 :           std::vector<double> sigma(ncv_);
     720             :           double height;
     721             :           double logweight;
     722         390 :           for(unsigned i=0; i<ncv_; i++)
     723         260 :             ifile.scanField(getPntrToArgument(i)->getName(),center[i]);
     724         390 :           for(unsigned i=0; i<ncv_; i++)
     725         520 :             ifile.scanField("sigma_"+getPntrToArgument(i)->getName(),sigma[i]);
     726         130 :           if(counter_==(1+walker_rank_) && adaptive_sigma_)
     727           0 :             sigma0_=sigma;
     728         130 :           ifile.scanField("height",height);
     729         130 :           ifile.scanField("logweight",logweight);
     730         130 :           ifile.scanField();
     731         130 :           addKernel(height,center,sigma);
     732         130 :           const double weight=std::exp(logweight);
     733         130 :           sum_weights_+=weight; //this sum is slightly inaccurate, because when printing some precision is lost
     734         130 :           sum_weights2_+=weight*weight;
     735         130 :           counter_++;
     736             :         }
     737           5 :         KDEnorm_=mode::explore?counter_:sum_weights_;
     738           5 :         if(!no_Zed_)
     739             :         {
     740           2 :           double sum_uprob=0;
     741          48 :           for(unsigned k=rank_; k<kernels_.size(); k+=NumParallel_)
     742        1104 :             for(unsigned kk=0; kk<kernels_.size(); kk++)
     743        1058 :               sum_uprob+=evaluateKernel(kernels_[kk],kernels_[k].center);
     744           2 :           if(NumParallel_>1)
     745           0 :             comm.Sum(sum_uprob);
     746           2 :           Zed_=sum_uprob/KDEnorm_/kernels_.size();
     747             :         }
     748           5 :         log.printf("    a total of %llu kernels where read, and compressed to %lu\n",counter_-1,kernels_.size());
     749             :         convertKernelsToState=true;
     750             :       }
     751          11 :       ifile.reset(false);
     752          11 :       ifile.close();
     753          11 :       nlist_=tmp_nlist;
     754             :     }
     755             :     else //same behaviour as METAD
     756           0 :       plumed_merror("RESTART requested, but file '"+restartFileName+"' was not found!\n  Set RESTART=NO or provide a restart file");
     757          11 :     if(NumWalkers_>1) //make sure that all walkers are doing the same thing
     758             :     {
     759           6 :       const unsigned kernels_size=kernels_.size();
     760           6 :       std::vector<unsigned> all_kernels_size(NumWalkers_);
     761           6 :       if(comm.Get_rank()==0)
     762           6 :         multi_sim_comm.Allgather(kernels_size,all_kernels_size);
     763           6 :       comm.Bcast(all_kernels_size,0);
     764             :       bool same_number_of_kernels=true;
     765          12 :       for(unsigned w=1; w<NumWalkers_; w++)
     766           6 :         if(all_kernels_size[0]!=all_kernels_size[w])
     767             :           same_number_of_kernels=false;
     768           6 :       plumed_massert(same_number_of_kernels,"RESTART - not all walkers are reading the same file!");
     769             :     }
     770          11 :   }
     771          10 :   else if(restartFileName.length()>0)
     772           4 :     log.printf(" +++ WARNING +++ the provided STATE_RFILE will be ignored, since RESTART was not requested\n");
     773             : 
     774             : //sync all walkers to avoid opening files before reading is over (see also METAD)
     775          21 :   comm.Barrier();
     776          21 :   if(comm.Get_rank()==0 && walkers_mpi)
     777          10 :     multi_sim_comm.Barrier();
     778             : 
     779             : //setup output kernels file
     780          21 :   kernelsOfile_.link(*this);
     781          21 :   if(NumWalkers_>1)
     782             :   {
     783          10 :     if(walker_rank_>0)
     784             :       kernelsFileName="/dev/null"; //only first walker writes on file
     785          20 :     kernelsOfile_.enforceSuffix("");
     786             :   }
     787          21 :   kernelsOfile_.open(kernelsFileName);
     788          21 :   if(fmt.length()>0)
     789          42 :     kernelsOfile_.fmtField(" "+fmt);
     790             :   kernelsOfile_.setHeavyFlush(); //do I need it?
     791             :   //define and set const fields
     792          21 :   kernelsOfile_.addConstantField("action");
     793          21 :   kernelsOfile_.addConstantField("biasfactor");
     794          21 :   kernelsOfile_.addConstantField("epsilon");
     795          21 :   kernelsOfile_.addConstantField("kernel_cutoff");
     796          21 :   kernelsOfile_.addConstantField("compression_threshold");
     797          61 :   for(unsigned i=0; i<ncv_; i++)
     798          40 :     kernelsOfile_.setupPrintValue(getPntrToArgument(i));
     799          42 :   kernelsOfile_.printField("action",getName()+"_kernels");
     800          21 :   kernelsOfile_.printField("biasfactor",biasfactor_);
     801          21 :   kernelsOfile_.printField("epsilon",epsilon_);
     802          21 :   kernelsOfile_.printField("kernel_cutoff",sqrt(cutoff2_));
     803          21 :   kernelsOfile_.printField("compression_threshold",sqrt(threshold2_));
     804             : 
     805             : //open file for storing state
     806          21 :   if(wStateStride_!=0)
     807             :   {
     808          11 :     stateOfile_.link(*this);
     809          11 :     if(NumWalkers_>1)
     810             :     {
     811           8 :       if(walker_rank_>0)
     812             :         stateFileName="/dev/null"; //only first walker writes on file
     813          16 :       stateOfile_.enforceSuffix("");
     814             :     }
     815          11 :     stateOfile_.open(stateFileName);
     816          11 :     if(fmt.length()>0)
     817          22 :       stateOfile_.fmtField(" "+fmt);
     818          11 :     if(convertKernelsToState)
     819           0 :       dumpStateToFile();
     820             :   }
     821             : 
     822             : //set initial old values
     823          21 :   KDEnorm_=mode::explore?counter_:sum_weights_;
     824          21 :   old_KDEnorm_=KDEnorm_;
     825             : 
     826             : //add and set output components
     827          42 :   addComponent("rct");
     828          21 :   componentIsNotPeriodic("rct");
     829          42 :   getPntrToComponent("rct")->set(kbt_*std::log(sum_weights_/counter_));
     830          42 :   addComponent("zed");
     831          21 :   componentIsNotPeriodic("zed");
     832          42 :   getPntrToComponent("zed")->set(Zed_);
     833          42 :   addComponent("neff");
     834          21 :   componentIsNotPeriodic("neff");
     835          42 :   getPntrToComponent("neff")->set(std::pow(1+sum_weights_,2)/(1+sum_weights2_));
     836          42 :   addComponent("nker");
     837          21 :   componentIsNotPeriodic("nker");
     838          21 :   getPntrToComponent("nker")->set(kernels_.size());
     839          21 :   if(calc_work_)
     840             :   {
     841          14 :     addComponent("work");
     842          14 :     componentIsNotPeriodic("work");
     843             :   }
     844          21 :   if(nlist_)
     845             :   {
     846          10 :     addComponent("nlker");
     847          10 :     componentIsNotPeriodic("nlker");
     848          10 :     addComponent("nlsteps");
     849          10 :     componentIsNotPeriodic("nlsteps");
     850             :   }
     851             : 
     852             : //printing some info
     853          21 :   log.printf("  temperature = %g\n",kbt_/kB);
     854          21 :   log.printf("  beta = %g\n",1./kbt_);
     855          21 :   log.printf("  depositing new kernels with PACE = %u\n",stride_);
     856          21 :   log.printf("  expected BARRIER is %g\n",barrier);
     857          21 :   log.printf("  using target distribution with BIASFACTOR gamma = %g\n",biasfactor_);
     858          21 :   if(std::isinf(biasfactor_))
     859           4 :     log.printf("    (thus a uniform flat target distribution, no well-tempering)\n");
     860          21 :   if(excluded_region_!=NULL)
     861           2 :     log.printf(" -- EXCLUDED_REGION: kernels will be deposited only when '%s' is equal to zero\n",excluded_region_->getName().c_str());
     862          21 :   if(extra_biases_.size()>0)
     863             :   {
     864           2 :     log.printf(" -- EXTRA_BIAS: ");
     865           5 :     for(unsigned e=0; e<extra_biases_.size(); e++)
     866           3 :       log.printf("%s ",extra_biases_[e]->getName().c_str());
     867           2 :     log.printf("will be reweighted\n");
     868             :   }
     869          21 :   if(adaptive_sigma_)
     870             :   {
     871          11 :     log.printf("  adaptive SIGMA will be used, with ADAPTIVE_SIGMA_STRIDE = %u\n",adaptive_sigma_stride_);
     872          11 :     unsigned x=std::ceil(adaptive_sigma_stride_/stride_);
     873          11 :     log.printf("    thus the first x kernel depositions will be skipped, x = ADAPTIVE_SIGMA_STRIDE/PACE = %u\n",x);
     874             :   }
     875             :   else
     876             :   {
     877          10 :     log.printf("  kernels have initial SIGMA = ");
     878          29 :     for(unsigned i=0; i<ncv_; i++)
     879          19 :       log.printf(" %g",sigma0_[i]);
     880          10 :     log.printf("\n");
     881             :   }
     882          21 :   if(sigma_min_.size()>0)
     883             :   {
     884           3 :     log.printf("  kernels have a SIGMA_MIN = ");
     885           9 :     for(unsigned i=0; i<ncv_; i++)
     886           6 :       log.printf(" %g",sigma_min_[i]);
     887           3 :     log.printf("\n");
     888             :   }
     889          21 :   if(fixed_sigma_)
     890           6 :     log.printf(" -- FIXED_SIGMA: sigma will not decrease as the simulation proceeds\n");
     891          21 :   log.printf("  kernels are truncated with KERNELS_CUTOFF = %g\n",cutoff);
     892          21 :   if(cutoff<3.5)
     893           0 :     log.printf(" +++ WARNING +++ probably kernels are truncated too much\n");
     894          21 :   log.printf("  the value at cutoff is = %g\n",val_at_cutoff_);
     895          21 :   log.printf("  regularization EPSILON = %g\n",epsilon_);
     896          21 :   if(val_at_cutoff_>epsilon_*(1+1e-6))
     897           0 :     log.printf(" +++ WARNING +++ the KERNEL_CUTOFF might be too small for the given EPSILON\n");
     898          21 :   log.printf("  kernels will be compressed when closer than COMPRESSION_THRESHOLD = %g\n",sqrt(threshold2_));
     899          21 :   if(threshold2_==0)
     900           0 :     log.printf(" +++ WARNING +++ kernels will never merge, expect slowdowns\n");
     901          21 :   if(!recursive_merge_)
     902           6 :     log.printf(" -- RECURSIVE_MERGE_OFF: only one merge for each new kernel will be attempted. This is faster only if total number of kernels does not grow too much\n");
     903          21 :   if(nlist_)
     904           5 :     log.printf(" -- NLIST: using neighbor list for kernels, with parameters: %g,%g\n",nlist_param_[0],nlist_param_[1]);
     905          21 :   if(nlist_pace_reset_)
     906           2 :     log.printf(" -- NLIST_PACE_RESET: forcing the neighbor list to update every PACE\n");
     907          21 :   if(no_Zed_)
     908           6 :     log.printf(" -- NO_ZED: using fixed normalization factor = %g\n",Zed_);
     909          21 :   if(wStateStride_>0)
     910          10 :     log.printf("  state checkpoints are written on file %s every %d MD steps\n",stateFileName.c_str(),wStateStride_);
     911          21 :   if(wStateStride_==-1)
     912           1 :     log.printf("  state checkpoints are written on file %s only on CPT events (or never if MD code does define them!)\n",stateFileName.c_str());
     913          21 :   if(walkers_mpi)
     914          10 :     log.printf(" -- WALKERS_MPI: if multiple replicas are present, they will share the same bias via MPI\n");
     915          21 :   if(NumWalkers_>1)
     916             :   {
     917          10 :     log.printf("  using multiple walkers\n");
     918          10 :     log.printf("    number of walkers: %u\n",NumWalkers_);
     919          10 :     log.printf("    walker rank: %u\n",walker_rank_);
     920             :   }
     921          21 :   int mw_warning=0;
     922          21 :   if(!walkers_mpi && comm.Get_rank()==0 && multi_sim_comm.Get_size()>(int)NumWalkers_)
     923           0 :     mw_warning=1;
     924          21 :   comm.Bcast(mw_warning,0);
     925          21 :   if(mw_warning) //log.printf messes up with comm, so never use it without Bcast!
     926           0 :     log.printf(" +++ WARNING +++ multiple replicas will NOT communicate unless the flag WALKERS_MPI is used\n");
     927          21 :   if(NumParallel_>1)
     928           4 :     log.printf("  using multiple MPI processes per simulation: %u\n",NumParallel_);
     929          21 :   if(NumOMP_>1)
     930          17 :     log.printf("  using multiple OpenMP threads per simulation: %u\n",NumOMP_);
     931          21 :   if(serial)
     932           4 :     log.printf(" -- SERIAL: no loop parallelization, despite %d MPI processes and %u OpenMP threads available\n",comm.Get_size(),OpenMP::getNumThreads());
     933          21 :   log.printf("  Bibliography: ");
     934          42 :   log<<plumed.cite("M. Invernizzi and M. Parrinello, J. Phys. Chem. Lett. 11, 2731-2736 (2020)");
     935          14 :   if(mode::explore || adaptive_sigma_)
     936          28 :     log<<plumed.cite("M. Invernizzi and M. Parrinello, J. Chem. Theory Comput. 18, 3988-3996 (2022)");
     937          21 :   log.printf("\n");
     938          42 : }
     939             : 
     940             : template <class mode>
     941        1071 : void OPESmetad<mode>::calculate()
     942             : {
     943             : //get cv
     944        1071 :   std::vector<double> cv(ncv_);
     945        3111 :   for(unsigned i=0; i<ncv_; i++)
     946        2040 :     cv[i]=getArgument(i);
     947             : 
     948             : //check neighbor list
     949        1071 :   if(nlist_)
     950             :   {
     951         255 :     nlist_steps_++;
     952         255 :     if(getExchangeStep())
     953           0 :       nlist_update_=true;
     954             :     else
     955             :     {
     956         275 :       for(unsigned i=0; i<ncv_; i++)
     957             :       {
     958         270 :         const double diff_i=difference(i,cv[i],nlist_center_[i]);
     959         270 :         if(diff_i*diff_i>nlist_param_[1]*nlist_dev2_[i])
     960             :         {
     961         250 :           nlist_update_=true;
     962         250 :           break;
     963             :         }
     964             :       }
     965             :     }
     966         255 :     if(nlist_update_)
     967         250 :       updateNlist(cv);
     968             :   }
     969             : 
     970             : //set bias and forces
     971        1071 :   std::vector<double> der_prob(ncv_,0);
     972        1071 :   const double prob=getProbAndDerivatives(cv,der_prob);
     973        1071 :   const double bias=kbt_*bias_prefactor_*std::log(prob/Zed_+epsilon_);
     974        1071 :   setBias(bias);
     975        3111 :   for(unsigned i=0; i<ncv_; i++)
     976        2040 :     setOutputForce(i,-kbt_*bias_prefactor_/(prob/Zed_+epsilon_)*der_prob[i]/Zed_);
     977        1071 : }
     978             : 
     979             : template <class mode>
     980        1071 : void OPESmetad<mode>::update()
     981             : {
     982        1071 :   if(isFirstStep_)//same in MetaD, useful for restarts?
     983             :   {
     984          21 :     isFirstStep_=false;
     985          21 :     return;
     986             :   }
     987             : 
     988             : //update variance if adaptive sigma
     989        1050 :   if(adaptive_sigma_)
     990             :   {
     991         550 :     adaptive_counter_++;
     992         550 :     unsigned tau=adaptive_sigma_stride_;
     993         550 :     if(adaptive_counter_<adaptive_sigma_stride_)
     994          45 :       tau=adaptive_counter_;
     995        1600 :     for(unsigned i=0; i<ncv_; i++)
     996             :     { //Welford's online algorithm for standard deviation
     997        1050 :       const double cv_i=getArgument(i);
     998        1050 :       const double diff_i=difference(i,av_cv_[i],cv_i);
     999        1050 :       av_cv_[i]+=diff_i/tau; //exponentially decaying average
    1000        1050 :       av_M2_[i]+=diff_i*difference(i,av_cv_[i],cv_i);
    1001             :     }
    1002         550 :     if(adaptive_counter_<adaptive_sigma_stride_ && counter_==1) //counter_>1 if restarting
    1003             :       return; //do not apply bias before having measured sigma
    1004             :   }
    1005             : 
    1006             : //do update
    1007        1005 :   if(getStep()%stride_==0 && (excluded_region_==NULL || excluded_region_->get()==0))
    1008             :   {
    1009         257 :     old_KDEnorm_=KDEnorm_;
    1010         257 :     delta_kernels_.clear();
    1011         257 :     unsigned old_nker=kernels_.size();
    1012             : 
    1013             :     //get new kernel height
    1014         257 :     double log_weight=getOutputQuantity(0)/kbt_; //first value is always the current bias
    1015         277 :     for(unsigned e=0; e<extra_biases_.size(); e++)
    1016          20 :       log_weight+=extra_biases_[e]->get()/kbt_; //extra biases contribute to the weight
    1017         257 :     double height=std::exp(log_weight);
    1018             : 
    1019             :     //update sum_weights_ and neff
    1020         257 :     double sum_heights=height;
    1021         257 :     double sum_heights2=height*height;
    1022         257 :     if(NumWalkers_>1)
    1023             :     {
    1024         126 :       if(comm.Get_rank()==0)
    1025             :       {
    1026         126 :         multi_sim_comm.Sum(sum_heights);
    1027         126 :         multi_sim_comm.Sum(sum_heights2);
    1028             :       }
    1029         126 :       comm.Bcast(sum_heights,0);
    1030         126 :       comm.Bcast(sum_heights2,0);
    1031             :     }
    1032         257 :     counter_+=NumWalkers_;
    1033         257 :     sum_weights_+=sum_heights;
    1034         257 :     sum_weights2_+=sum_heights2;
    1035         257 :     const double neff=std::pow(1+sum_weights_,2)/(1+sum_weights2_); //adding 1 makes it more robust at the start
    1036         257 :     getPntrToComponent("rct")->set(kbt_*std::log(sum_weights_/counter_));
    1037         257 :     getPntrToComponent("neff")->set(neff);
    1038             :     if(mode::explore)
    1039             :     {
    1040          68 :       KDEnorm_=counter_;
    1041          68 :       height=1; //plain KDE, bias reweight does not enter here
    1042             :     }
    1043             :     else
    1044         189 :       KDEnorm_=sum_weights_;
    1045             : 
    1046             :     //if needed, rescale sigma and height
    1047         257 :     std::vector<double> sigma=sigma0_;
    1048         257 :     if(adaptive_sigma_)
    1049             :     {
    1050          93 :       const double factor=mode::explore?1:biasfactor_;
    1051         131 :       if(counter_==1+NumWalkers_) //first time only
    1052             :       {
    1053          14 :         for(unsigned i=0; i<ncv_; i++)
    1054           9 :           av_M2_[i]*=biasfactor_; //from unbiased, thus must be adjusted
    1055          14 :         for(unsigned i=0; i<ncv_; i++)
    1056           9 :           sigma0_[i]=std::sqrt(av_M2_[i]/adaptive_counter_/factor);
    1057           5 :         if(sigma_min_.size()==0)
    1058             :         {
    1059          14 :           for(unsigned i=0; i<ncv_; i++)
    1060           9 :             plumed_massert(sigma0_[i]>1e-6,"ADAPTIVE SIGMA is suspiciously small for CV i="+std::to_string(i)+"\nManually provide SIGMA or set a safe SIGMA_MIN to avoid possible issues");
    1061             :         }
    1062             :         else
    1063             :         {
    1064           0 :           for(unsigned i=0; i<ncv_; i++)
    1065           0 :             sigma0_[i]=std::max(sigma0_[i],sigma_min_[i]);
    1066             :         }
    1067             :       }
    1068         388 :       for(unsigned i=0; i<ncv_; i++)
    1069         257 :         sigma[i]=std::sqrt(av_M2_[i]/adaptive_counter_/factor);
    1070         131 :       if(sigma_min_.size()==0)
    1071             :       {
    1072         238 :         for(unsigned i=0; i<ncv_; i++)
    1073             :         {
    1074         157 :           if(sigma[i]<1e-6)
    1075             :           {
    1076           0 :             log.printf("+++ WARNING +++ the ADAPTIVE SIGMA is suspiciously small, you should set a safe SIGMA_MIN. 1e-6 will be used here\n");
    1077           0 :             sigma[i]=1e-6;
    1078           0 :             sigma_min_.resize(ncv_,1e-6);
    1079             :           }
    1080             :         }
    1081             :       }
    1082             :       else
    1083             :       {
    1084         150 :         for(unsigned i=0; i<ncv_; i++)
    1085         100 :           sigma[i]=std::max(sigma[i],sigma_min_[i]);
    1086             :       }
    1087             :     }
    1088         257 :     if(!fixed_sigma_)
    1089             :     {
    1090          38 :       const double size=mode::explore?counter_:neff; //for EXPLORE neff is not relevant
    1091         197 :       const double s_rescaling=std::pow(size*(ncv_+2.)/4.,-1./(4+ncv_));
    1092         576 :       for(unsigned i=0; i<ncv_; i++)
    1093         379 :         sigma[i]*=s_rescaling;
    1094         197 :       if(sigma_min_.size()>0)
    1095             :       {
    1096         150 :         for(unsigned i=0; i<ncv_; i++)
    1097         100 :           sigma[i]=std::max(sigma[i],sigma_min_[i]);
    1098             :       }
    1099             :     }
    1100             :     //the height should be divided by sqrt(2*pi)*sigma0_,
    1101             :     //but this overall factor would be canceled when dividing by Zed
    1102             :     //thus we skip it altogether, but keep any other sigma rescaling
    1103         756 :     for(unsigned i=0; i<ncv_; i++)
    1104         499 :       height*=(sigma0_[i]/sigma[i]);
    1105             : 
    1106             :     //get new kernel center
    1107         257 :     std::vector<double> center(ncv_);
    1108         756 :     for(unsigned i=0; i<ncv_; i++)
    1109         499 :       center[i]=getArgument(i);
    1110             : 
    1111             :     //add new kernel(s)
    1112         257 :     if(NumWalkers_==1)
    1113         131 :       addKernel(height,center,sigma,log_weight);
    1114             :     else
    1115             :     {
    1116         126 :       std::vector<double> all_height(NumWalkers_,0.0);
    1117         126 :       std::vector<double> all_center(NumWalkers_*ncv_,0.0);
    1118         126 :       std::vector<double> all_sigma(NumWalkers_*ncv_,0.0);
    1119         126 :       std::vector<double> all_logweight(NumWalkers_,0.0);
    1120         126 :       if(comm.Get_rank()==0)
    1121             :       {
    1122         126 :         multi_sim_comm.Allgather(height,all_height);
    1123         126 :         multi_sim_comm.Allgather(center,all_center);
    1124         126 :         multi_sim_comm.Allgather(sigma,all_sigma);
    1125         126 :         multi_sim_comm.Allgather(log_weight,all_logweight);
    1126             :       }
    1127         126 :       comm.Bcast(all_height,0);
    1128         126 :       comm.Bcast(all_center,0);
    1129         126 :       comm.Bcast(all_sigma,0);
    1130         126 :       comm.Bcast(all_logweight,0);
    1131         126 :       if(nlist_)
    1132             :       { //gather all the nlist_index_, so merging can be done using it
    1133          50 :         std::vector<int> all_nlist_size(NumWalkers_);
    1134          50 :         if(comm.Get_rank()==0)
    1135             :         {
    1136          50 :           all_nlist_size[walker_rank_]=nlist_index_.size();
    1137          50 :           multi_sim_comm.Sum(all_nlist_size);
    1138             :         }
    1139          50 :         comm.Bcast(all_nlist_size,0);
    1140             :         unsigned tot_size=0;
    1141         150 :         for(unsigned w=0; w<NumWalkers_; w++)
    1142         100 :           tot_size+=all_nlist_size[w];
    1143          50 :         if(tot_size>0)
    1144             :         {
    1145          50 :           std::vector<int> disp(NumWalkers_);
    1146         100 :           for(unsigned w=0; w<NumWalkers_-1; w++)
    1147          50 :             disp[w+1]=disp[w]+all_nlist_size[w];
    1148          50 :           std::vector<unsigned> all_nlist_index(tot_size);
    1149          50 :           if(comm.Get_rank()==0)
    1150          50 :             multi_sim_comm.Allgatherv(nlist_index_,all_nlist_index,&all_nlist_size[0],&disp[0]);
    1151          50 :           comm.Bcast(all_nlist_index,0);
    1152          50 :           std::set<unsigned> nlist_index_set(all_nlist_index.begin(),all_nlist_index.end()); //remove duplicates and sort
    1153          50 :           nlist_index_.assign(nlist_index_set.begin(),nlist_index_set.end());
    1154             :         }
    1155             :       }
    1156         378 :       for(unsigned w=0; w<NumWalkers_; w++)
    1157             :       {
    1158         252 :         std::vector<double> center_w(all_center.begin()+ncv_*w,all_center.begin()+ncv_*(w+1));
    1159         252 :         std::vector<double> sigma_w(all_sigma.begin()+ncv_*w,all_sigma.begin()+ncv_*(w+1));
    1160         252 :         addKernel(all_height[w],center_w,sigma_w,all_logweight[w]);
    1161             :       }
    1162             :     }
    1163         257 :     getPntrToComponent("nker")->set(kernels_.size());
    1164         257 :     if(nlist_)
    1165             :     {
    1166         106 :       getPntrToComponent("nlker")->set(nlist_index_.size());
    1167         106 :       if(nlist_pace_reset_)
    1168          50 :         nlist_update_=true;
    1169             :     }
    1170             : 
    1171             :     //update Zed_
    1172         257 :     if(!no_Zed_)
    1173             :     {
    1174         197 :       double sum_uprob=0;
    1175         197 :       const unsigned ks=kernels_.size();
    1176         197 :       const unsigned ds=delta_kernels_.size();
    1177         197 :       const bool few_kernels=(ks*ks<(3*ks*ds+2*ds*ds*NumParallel_+100)); //this seems reasonable, but is not rigorous...
    1178         197 :       if(few_kernels) //really needed? Probably is almost always false
    1179             :       {
    1180         147 :         #pragma omp parallel num_threads(NumOMP_)
    1181             :         {
    1182             :           #pragma omp for reduction(+:sum_uprob) nowait
    1183             :           for(unsigned k=rank_; k<kernels_.size(); k+=NumParallel_)
    1184             :             for(unsigned kk=0; kk<kernels_.size(); kk++)
    1185             :               sum_uprob+=evaluateKernel(kernels_[kk],kernels_[k].center);
    1186             :         }
    1187         147 :         if(NumParallel_>1)
    1188          50 :           comm.Sum(sum_uprob);
    1189             :       }
    1190             :       else
    1191             :       {
    1192             :         // Here instead of redoing the full summation, we add only the changes, knowing that
    1193             :         // uprob = old_uprob + delta_uprob
    1194             :         // and we also need to consider that in the new sum there are some novel centers and some disappeared ones
    1195          50 :         double delta_sum_uprob=0;
    1196          50 :         if(!nlist_)
    1197             :         {
    1198           0 :           #pragma omp parallel num_threads(NumOMP_)
    1199             :           {
    1200             :             #pragma omp for reduction(+:delta_sum_uprob) nowait
    1201             :             for(unsigned k=rank_; k<kernels_.size(); k+=NumParallel_)
    1202             :             {
    1203             :               for(unsigned d=0; d<delta_kernels_.size(); d++)
    1204             :               {
    1205             :                 const double sign=delta_kernels_[d].height<0?-1:1; //take away contribution from kernels that are gone, and add the one from new ones
    1206             :                 delta_sum_uprob+=evaluateKernel(delta_kernels_[d],kernels_[k].center)+sign*evaluateKernel(kernels_[k],delta_kernels_[d].center);
    1207             :               }
    1208             :             }
    1209             :           }
    1210             :         }
    1211             :         else
    1212             :         {
    1213          50 :           #pragma omp parallel num_threads(NumOMP_)
    1214             :           {
    1215             :             #pragma omp for reduction(+:delta_sum_uprob) nowait
    1216             :             for(unsigned nk=rank_; nk<nlist_index_.size(); nk+=NumParallel_)
    1217             :             {
    1218             :               const unsigned k=nlist_index_[nk];
    1219             :               for(unsigned d=0; d<delta_kernels_.size(); d++)
    1220             :               {
    1221             :                 const double sign=delta_kernels_[d].height<0?-1:1; //take away contribution from kernels that are gone, and add the one from new ones
    1222             :                 delta_sum_uprob+=evaluateKernel(delta_kernels_[d],kernels_[k].center)+sign*evaluateKernel(kernels_[k],delta_kernels_[d].center);
    1223             :               }
    1224             :             }
    1225             :           }
    1226             :         }
    1227          50 :         if(NumParallel_>1)
    1228           0 :           comm.Sum(delta_sum_uprob);
    1229          50 :         #pragma omp parallel num_threads(NumOMP_)
    1230             :         {
    1231             :           #pragma omp for reduction(+:delta_sum_uprob)
    1232             :           for(unsigned d=0; d<delta_kernels_.size(); d++)
    1233             :           {
    1234             :             for(unsigned dd=0; dd<delta_kernels_.size(); dd++)
    1235             :             { //now subtract the delta_uprob added before, but not needed
    1236             :               const double sign=delta_kernels_[d].height<0?-1:1;
    1237             :               delta_sum_uprob-=sign*evaluateKernel(delta_kernels_[dd],delta_kernels_[d].center);
    1238             :             }
    1239             :           }
    1240             :         }
    1241          50 :         sum_uprob=Zed_*old_KDEnorm_*old_nker+delta_sum_uprob;
    1242             :       }
    1243         197 :       Zed_=sum_uprob/KDEnorm_/kernels_.size();
    1244         394 :       getPntrToComponent("zed")->set(Zed_);
    1245             :     }
    1246             : 
    1247             :     //calculate work if requested
    1248         257 :     if(calc_work_)
    1249             :     {
    1250          70 :       std::vector<double> dummy(ncv_); //derivatives are not actually needed
    1251          70 :       const double prob=getProbAndDerivatives(center,dummy);
    1252          70 :       const double new_bias=kbt_*bias_prefactor_*std::log(prob/Zed_+epsilon_);
    1253          70 :       work_+=new_bias-getOutputQuantity(0);
    1254         140 :       getPntrToComponent("work")->set(work_);
    1255             :     }
    1256             :   }
    1257             : 
    1258             : //dump state if requested
    1259        1005 :   if( (wStateStride_>0 && getStep()%wStateStride_==0) || (wStateStride_==-1 && getCPT()) )
    1260          18 :     dumpStateToFile();
    1261             : }
    1262             : 
    1263             : template <class mode>
    1264        1141 : double OPESmetad<mode>::getProbAndDerivatives(const std::vector<double>& cv,std::vector<double>& der_prob)
    1265             : {
    1266        1141 :   double prob=0.0;
    1267        1141 :   if(!nlist_)
    1268             :   {
    1269         886 :     if(NumOMP_==1 || (unsigned)kernels_.size()<2*NumOMP_*NumParallel_)
    1270             :     {
    1271             :       // for performances and thread safety
    1272         707 :       std::vector<double> dist(ncv_);
    1273        2647 :       for(unsigned k=rank_; k<kernels_.size(); k+=NumParallel_)
    1274        1940 :         prob+=evaluateKernel(kernels_[k],cv,der_prob,dist);
    1275             :     }
    1276             :     else
    1277             :     {
    1278         179 :       #pragma omp parallel num_threads(NumOMP_)
    1279             :       {
    1280             :         std::vector<double> omp_deriv(der_prob.size(),0.);
    1281             :         // for performances and thread safety
    1282             :         std::vector<double> dist(ncv_);
    1283             :         #pragma omp for reduction(+:prob) nowait
    1284             :         for(unsigned k=rank_; k<kernels_.size(); k+=NumParallel_)
    1285             :           prob+=evaluateKernel(kernels_[k],cv,omp_deriv,dist);
    1286             :         #pragma omp critical
    1287             :         for(unsigned i=0; i<ncv_; i++)
    1288             :           der_prob[i]+=omp_deriv[i];
    1289             :       }
    1290             :     }
    1291             :   }
    1292             :   else
    1293             :   {
    1294         255 :     if(NumOMP_==1 || (unsigned)nlist_index_.size()<2*NumOMP_*NumParallel_)
    1295             :     {
    1296             :       // for performances and thread safety
    1297         230 :       std::vector<double> dist(ncv_);
    1298         660 :       for(unsigned nk=rank_; nk<nlist_index_.size(); nk+=NumParallel_)
    1299         430 :         prob+=evaluateKernel(kernels_[nlist_index_[nk]],cv,der_prob,dist);
    1300             :     }
    1301             :     else
    1302             :     {
    1303          25 :       #pragma omp parallel num_threads(NumOMP_)
    1304             :       {
    1305             :         std::vector<double> omp_deriv(der_prob.size(),0.);
    1306             :         // for performances and thread safety
    1307             :         std::vector<double> dist(ncv_);
    1308             :         #pragma omp for reduction(+:prob) nowait
    1309             :         for(unsigned nk=rank_; nk<nlist_index_.size(); nk+=NumParallel_)
    1310             :           prob+=evaluateKernel(kernels_[nlist_index_[nk]],cv,omp_deriv,dist);
    1311             :         #pragma omp critical
    1312             :         for(unsigned i=0; i<ncv_; i++)
    1313             :           der_prob[i]+=omp_deriv[i];
    1314             :       }
    1315             :     }
    1316             :   }
    1317        1141 :   if(NumParallel_>1)
    1318             :   {
    1319         224 :     comm.Sum(prob);
    1320         224 :     comm.Sum(der_prob);
    1321             :   }
    1322             : //normalize the estimate
    1323        1141 :   prob/=KDEnorm_;
    1324        3311 :   for(unsigned i=0; i<ncv_; i++)
    1325        2170 :     der_prob[i]/=KDEnorm_;
    1326             : 
    1327        1141 :   return prob;
    1328             : }
    1329             : 
    1330             : template <class mode>
    1331         513 : void OPESmetad<mode>::addKernel(const double height,const std::vector<double>& center,const std::vector<double>& sigma)
    1332             : {
    1333             :   bool no_match=true;
    1334         513 :   if(threshold2_!=0)
    1335             :   {
    1336         513 :     unsigned taker_k=getMergeableKernel(center,kernels_.size());
    1337         513 :     if(taker_k<kernels_.size())
    1338             :     {
    1339             :       no_match=false;
    1340         388 :       delta_kernels_.emplace_back(-1*kernels_[taker_k].height,kernels_[taker_k].center,kernels_[taker_k].sigma);
    1341         776 :       mergeKernels(kernels_[taker_k],kernel(height,center,sigma));
    1342         388 :       delta_kernels_.push_back(kernels_[taker_k]);
    1343         388 :       if(recursive_merge_) //the overhead is worth it if it keeps low the total number of kernels
    1344             :       {
    1345             :         unsigned giver_k=taker_k;
    1346         337 :         taker_k=getMergeableKernel(kernels_[giver_k].center,giver_k);
    1347         337 :         while(taker_k<kernels_.size())
    1348             :         {
    1349           0 :           delta_kernels_.pop_back();
    1350           0 :           delta_kernels_.emplace_back(-1*kernels_[taker_k].height,kernels_[taker_k].center,kernels_[taker_k].sigma);
    1351           0 :           if(taker_k>giver_k) //saves time when erasing
    1352             :             std::swap(taker_k,giver_k);
    1353           0 :           mergeKernels(kernels_[taker_k],kernels_[giver_k]);
    1354           0 :           delta_kernels_.push_back(kernels_[taker_k]);
    1355           0 :           kernels_.erase(kernels_.begin()+giver_k);
    1356           0 :           if(nlist_)
    1357             :           {
    1358             :             unsigned giver_nk=0;
    1359             :             bool found_giver=false;
    1360           0 :             for(unsigned nk=0; nk<nlist_index_.size(); nk++)
    1361             :             {
    1362           0 :               if(found_giver)
    1363           0 :                 nlist_index_[nk]--; //all the indexes shift due to erase
    1364           0 :               if(nlist_index_[nk]==giver_k)
    1365             :               {
    1366             :                 giver_nk=nk;
    1367             :                 found_giver=true;
    1368             :               }
    1369             :             }
    1370             :             plumed_dbg_massert(found_giver,"problem with merging and NLIST");
    1371           0 :             nlist_index_.erase(nlist_index_.begin()+giver_nk);
    1372             :           }
    1373             :           giver_k=taker_k;
    1374           0 :           taker_k=getMergeableKernel(kernels_[giver_k].center,giver_k);
    1375             :         }
    1376             :       }
    1377             :     }
    1378             :   }
    1379             :   if(no_match)
    1380             :   {
    1381         125 :     kernels_.emplace_back(height,center,sigma);
    1382         125 :     delta_kernels_.emplace_back(height,center,sigma);
    1383         125 :     if(nlist_)
    1384          12 :       nlist_index_.push_back(kernels_.size()-1);
    1385             :   }
    1386         513 : }
    1387             : 
    1388             : template <class mode>
    1389         383 : void OPESmetad<mode>::addKernel(const double height,const std::vector<double>& center,const std::vector<double>& sigma,const double logweight)
    1390             : {
    1391         383 :   addKernel(height,center,sigma);
    1392             : //write to file
    1393         383 :   kernelsOfile_.printField("time",getTime());
    1394        1134 :   for(unsigned i=0; i<ncv_; i++)
    1395         751 :     kernelsOfile_.printField(getPntrToArgument(i),center[i]);
    1396        1134 :   for(unsigned i=0; i<ncv_; i++)
    1397        1502 :     kernelsOfile_.printField("sigma_"+getPntrToArgument(i)->getName(),sigma[i]);
    1398         383 :   kernelsOfile_.printField("height",height);
    1399         383 :   kernelsOfile_.printField("logweight",logweight);
    1400         383 :   kernelsOfile_.printField();
    1401         383 : }
    1402             : 
    1403             : template <class mode>
    1404         850 : unsigned OPESmetad<mode>::getMergeableKernel(const std::vector<double>& giver_center,const unsigned giver_k)
    1405             : { //returns kernels_.size() if no match is found
    1406         850 :   unsigned min_k=kernels_.size();
    1407         850 :   double min_norm2=threshold2_;
    1408         850 :   if(!nlist_)
    1409             :   {
    1410         550 :     #pragma omp parallel num_threads(NumOMP_)
    1411             :     {
    1412             :       unsigned min_k_omp = min_k;
    1413             :       double min_norm2_omp = threshold2_;
    1414             :       #pragma omp for nowait
    1415             :       for(unsigned k=rank_; k<kernels_.size(); k+=NumParallel_)
    1416             :       {
    1417             :         if(k==giver_k) //a kernel should not be merged with itself
    1418             :           continue;
    1419             :         double norm2=0;
    1420             :         for(unsigned i=0; i<ncv_; i++)
    1421             :         {
    1422             :           const double dist_i=difference(i,giver_center[i],kernels_[k].center[i])/kernels_[k].sigma[i];
    1423             :           norm2+=dist_i*dist_i;
    1424             :           if(norm2>=min_norm2_omp)
    1425             :             break;
    1426             :         }
    1427             :         if(norm2<min_norm2_omp)
    1428             :         {
    1429             :           min_norm2_omp=norm2;
    1430             :           min_k_omp=k;
    1431             :         }
    1432             :       }
    1433             :       #pragma omp critical
    1434             :       {
    1435             :         if(min_norm2_omp < min_norm2)
    1436             :         {
    1437             :           min_norm2 = min_norm2_omp;
    1438             :           min_k = min_k_omp;
    1439             :         }
    1440             :       }
    1441             :     }
    1442             :   }
    1443             :   else
    1444             :   {
    1445         300 :     #pragma omp parallel num_threads(NumOMP_)
    1446             :     {
    1447             :       unsigned min_k_omp = min_k;
    1448             :       double min_norm2_omp = threshold2_;
    1449             :       #pragma omp for nowait
    1450             :       for(unsigned nk=rank_; nk<nlist_index_.size(); nk+=NumParallel_)
    1451             :       {
    1452             :         const unsigned k=nlist_index_[nk];
    1453             :         if(k==giver_k) //a kernel should not be merged with itself
    1454             :           continue;
    1455             :         double norm2=0;
    1456             :         for(unsigned i=0; i<ncv_; i++)
    1457             :         {
    1458             :           const double dist_i=difference(i,giver_center[i],kernels_[k].center[i])/kernels_[k].sigma[i];
    1459             :           norm2+=dist_i*dist_i;
    1460             :           if(norm2>=min_norm2)
    1461             :             break;
    1462             :         }
    1463             :         if(norm2<min_norm2_omp)
    1464             :         {
    1465             :           min_norm2_omp=norm2;
    1466             :           min_k_omp=k;
    1467             :         }
    1468             :       }
    1469             :       #pragma omp critical
    1470             :       {
    1471             :         if(min_norm2_omp < min_norm2)
    1472             :         {
    1473             :           min_norm2 = min_norm2_omp;
    1474             :           min_k = min_k_omp;
    1475             :         }
    1476             :       }
    1477             :     }
    1478             :   }
    1479         850 :   if(NumParallel_>1)
    1480             :   {
    1481         134 :     std::vector<double> all_min_norm2(NumParallel_);
    1482         134 :     std::vector<unsigned> all_min_k(NumParallel_);
    1483         134 :     comm.Allgather(min_norm2,all_min_norm2);
    1484         134 :     comm.Allgather(min_k,all_min_k);
    1485             :     const unsigned best=std::distance(std::begin(all_min_norm2),std::min_element(std::begin(all_min_norm2),std::end(all_min_norm2)));
    1486         134 :     min_k=all_min_k[best];
    1487             :   }
    1488         850 :   return min_k;
    1489             : }
    1490             : 
    1491             : template <class mode>
    1492         250 : void OPESmetad<mode>::updateNlist(const std::vector<double>& new_center)
    1493             : {
    1494         250 :   if(kernels_.size()==0) //no need to check for neighbors
    1495           6 :     return;
    1496             : 
    1497         244 :   nlist_center_=new_center;
    1498         244 :   nlist_index_.clear();
    1499             :   //first we gather all the nlist_index
    1500         244 :   if(NumOMP_==1 || (unsigned)kernels_.size()<2*NumOMP_*NumParallel_)
    1501             :   {
    1502         198 :     for(unsigned k=rank_; k<kernels_.size(); k+=NumParallel_)
    1503             :     {
    1504             :       double norm2_k=0;
    1505         444 :       for(unsigned i=0; i<ncv_; i++)
    1506             :       {
    1507         296 :         const double dist_ik=difference(i,nlist_center_[i],kernels_[k].center[i])/kernels_[k].sigma[i];
    1508         296 :         norm2_k+=dist_ik*dist_ik;
    1509             :       }
    1510         148 :       if(norm2_k<=nlist_param_[0]*cutoff2_)
    1511         104 :         nlist_index_.push_back(k);
    1512             :     }
    1513             :   }
    1514             :   else
    1515             :   {
    1516         194 :     #pragma omp parallel num_threads(NumOMP_)
    1517             :     {
    1518             :       std::vector<unsigned> private_nlist_index;
    1519             :       #pragma omp for nowait
    1520             :       for(unsigned k=rank_; k<kernels_.size(); k+=NumParallel_)
    1521             :       {
    1522             :         double norm2_k=0;
    1523             :         for(unsigned i=0; i<ncv_; i++)
    1524             :         {
    1525             :           const double dist_ik=difference(i,nlist_center_[i],kernels_[k].center[i])/kernels_[k].sigma[i];
    1526             :           norm2_k+=dist_ik*dist_ik;
    1527             :         }
    1528             :         if(norm2_k<=nlist_param_[0]*cutoff2_)
    1529             :           private_nlist_index.push_back(k);
    1530             :       }
    1531             :       #pragma omp critical
    1532             :       nlist_index_.insert(nlist_index_.end(),private_nlist_index.begin(),private_nlist_index.end());
    1533             :     }
    1534         194 :     if(recursive_merge_)
    1535         194 :       std::sort(nlist_index_.begin(),nlist_index_.end());
    1536             :   }
    1537         244 :   if(NumParallel_>1)
    1538             :   {
    1539         100 :     std::vector<int> all_nlist_size(NumParallel_);
    1540         100 :     all_nlist_size[rank_]=nlist_index_.size();
    1541         100 :     comm.Sum(all_nlist_size);
    1542             :     unsigned tot_size=0;
    1543         300 :     for(unsigned r=0; r<NumParallel_; r++)
    1544         200 :       tot_size+=all_nlist_size[r];
    1545         100 :     if(tot_size>0)
    1546             :     {
    1547         100 :       std::vector<int> disp(NumParallel_);
    1548         200 :       for(unsigned r=0; r<NumParallel_-1; r++)
    1549         100 :         disp[r+1]=disp[r]+all_nlist_size[r];
    1550         100 :       std::vector<unsigned> local_nlist_index=nlist_index_;
    1551         100 :       nlist_index_.resize(tot_size);
    1552         100 :       comm.Allgatherv(local_nlist_index,nlist_index_,&all_nlist_size[0],&disp[0]);
    1553         100 :       if(recursive_merge_)
    1554         100 :         std::sort(nlist_index_.begin(),nlist_index_.end());
    1555             :     }
    1556             :   }
    1557             :   //calculate the square deviation
    1558         244 :   std::vector<double> dev2(ncv_,0.);
    1559         773 :   for(unsigned k=rank_; k<nlist_index_.size(); k+=NumParallel_)
    1560             :   {
    1561        1587 :     for(unsigned i=0; i<ncv_; i++)
    1562             :     {
    1563        1058 :       const double diff_ik=difference(i,nlist_center_[i],kernels_[nlist_index_[k]].center[i]);
    1564        1058 :       dev2[i]+=diff_ik*diff_ik;
    1565             :     }
    1566             :   }
    1567         244 :   if(NumParallel_>1)
    1568         100 :     comm.Sum(dev2);
    1569         732 :   for(unsigned i=0; i<ncv_; i++)
    1570             :   {
    1571         488 :     if(dev2[i]==0) //e.g. if nlist_index_.size()==0
    1572          56 :       nlist_dev2_[i]=std::pow(kernels_.back().sigma[i],2);
    1573             :     else
    1574         432 :       nlist_dev2_[i]=dev2[i]/nlist_index_.size();
    1575             :   }
    1576         244 :   getPntrToComponent("nlker")->set(nlist_index_.size());
    1577         244 :   getPntrToComponent("nlsteps")->set(nlist_steps_);
    1578         244 :   nlist_steps_=0;
    1579         244 :   nlist_update_=false;
    1580             : }
    1581             : 
    1582             : template <class mode>
    1583          18 : void OPESmetad<mode>::dumpStateToFile()
    1584             : {
    1585             : //gather adaptive sigma info if needed
    1586             : //doing this while writing to file can lead to misterious slowdowns
    1587             :   std::vector<double> all_sigma0;
    1588             :   std::vector<double> all_av_cv;
    1589             :   std::vector<double> all_av_M2;
    1590          18 :   if(adaptive_sigma_ && NumWalkers_>1)
    1591             :   {
    1592          16 :     all_sigma0.resize(NumWalkers_*ncv_);
    1593          16 :     all_av_cv.resize(NumWalkers_*ncv_);
    1594          16 :     all_av_M2.resize(NumWalkers_*ncv_);
    1595          16 :     if(comm.Get_rank()==0)
    1596             :     {
    1597          16 :       multi_sim_comm.Allgather(sigma0_,all_sigma0);
    1598          16 :       multi_sim_comm.Allgather(av_cv_,all_av_cv);
    1599          16 :       multi_sim_comm.Allgather(av_M2_,all_av_M2);
    1600             :     }
    1601          16 :     comm.Bcast(all_sigma0,0);
    1602          16 :     comm.Bcast(all_av_cv,0);
    1603          16 :     comm.Bcast(all_av_M2,0);
    1604             :   }
    1605             : 
    1606             : //rewrite header or rewind file
    1607          18 :   if(storeOldStates_)
    1608          16 :     stateOfile_.clearFields();
    1609           2 :   else if(walker_rank_==0)
    1610           2 :     stateOfile_.rewind();
    1611             : //define fields
    1612          18 :   stateOfile_.addConstantField("action");
    1613          18 :   stateOfile_.addConstantField("biasfactor");
    1614          18 :   stateOfile_.addConstantField("epsilon");
    1615          18 :   stateOfile_.addConstantField("kernel_cutoff");
    1616          18 :   stateOfile_.addConstantField("compression_threshold");
    1617          18 :   stateOfile_.addConstantField("zed");
    1618          18 :   stateOfile_.addConstantField("sum_weights");
    1619          18 :   stateOfile_.addConstantField("sum_weights2");
    1620          18 :   stateOfile_.addConstantField("counter");
    1621          18 :   if(adaptive_sigma_)
    1622             :   {
    1623          18 :     stateOfile_.addConstantField("adaptive_counter");
    1624          18 :     if(NumWalkers_==1)
    1625             :     {
    1626           6 :       for(unsigned i=0; i<ncv_; i++)
    1627             :       {
    1628           8 :         stateOfile_.addConstantField("sigma0_"+getPntrToArgument(i)->getName());
    1629           8 :         stateOfile_.addConstantField("av_cv_"+getPntrToArgument(i)->getName());
    1630           8 :         stateOfile_.addConstantField("av_M2_"+getPntrToArgument(i)->getName());
    1631             :       }
    1632             :     }
    1633             :     else
    1634             :     {
    1635          48 :       for(unsigned w=0; w<NumWalkers_; w++)
    1636          96 :         for(unsigned i=0; i<ncv_; i++)
    1637             :         {
    1638         128 :           const std::string arg_iw=getPntrToArgument(i)->getName()+"_"+std::to_string(w);
    1639          64 :           stateOfile_.addConstantField("sigma0_"+arg_iw);
    1640          64 :           stateOfile_.addConstantField("av_cv_"+arg_iw);
    1641         128 :           stateOfile_.addConstantField("av_M2_"+arg_iw);
    1642             :         }
    1643             :     }
    1644             :   }
    1645             : //print fields
    1646          54 :   for(unsigned i=0; i<ncv_; i++) //periodicity of CVs
    1647          36 :     stateOfile_.setupPrintValue(getPntrToArgument(i));
    1648          36 :   stateOfile_.printField("action",getName()+"_state");
    1649          18 :   stateOfile_.printField("biasfactor",biasfactor_);
    1650          18 :   stateOfile_.printField("epsilon",epsilon_);
    1651          18 :   stateOfile_.printField("kernel_cutoff",sqrt(cutoff2_));
    1652          18 :   stateOfile_.printField("compression_threshold",sqrt(threshold2_));
    1653          18 :   stateOfile_.printField("zed",Zed_);
    1654          18 :   stateOfile_.printField("sum_weights",sum_weights_);
    1655          18 :   stateOfile_.printField("sum_weights2",sum_weights2_);
    1656          18 :   stateOfile_.printField("counter",counter_);
    1657          18 :   if(adaptive_sigma_)
    1658             :   {
    1659          18 :     stateOfile_.printField("adaptive_counter",adaptive_counter_);
    1660          18 :     if(NumWalkers_==1)
    1661             :     {
    1662           6 :       for(unsigned i=0; i<ncv_; i++)
    1663             :       {
    1664           8 :         stateOfile_.printField("sigma0_"+getPntrToArgument(i)->getName(),sigma0_[i]);
    1665           8 :         stateOfile_.printField("av_cv_"+getPntrToArgument(i)->getName(),av_cv_[i]);
    1666           8 :         stateOfile_.printField("av_M2_"+getPntrToArgument(i)->getName(),av_M2_[i]);
    1667             :       }
    1668             :     }
    1669             :     else
    1670             :     {
    1671          48 :       for(unsigned w=0; w<NumWalkers_; w++)
    1672          96 :         for(unsigned i=0; i<ncv_; i++)
    1673             :         {
    1674         128 :           const std::string arg_iw=getPntrToArgument(i)->getName()+"_"+std::to_string(w);
    1675          64 :           stateOfile_.printField("sigma0_"+arg_iw,all_sigma0[w*ncv_+i]);
    1676          64 :           stateOfile_.printField("av_cv_"+arg_iw,all_av_cv[w*ncv_+i]);
    1677         128 :           stateOfile_.printField("av_M2_"+arg_iw,all_av_M2[w*ncv_+i]);
    1678             :         }
    1679             :     }
    1680             :   }
    1681             : //print kernels
    1682          82 :   for(unsigned k=0; k<kernels_.size(); k++)
    1683             :   {
    1684          64 :     stateOfile_.printField("time",getTime()); //this is not very usefull
    1685         192 :     for(unsigned i=0; i<ncv_; i++)
    1686         128 :       stateOfile_.printField(getPntrToArgument(i),kernels_[k].center[i]);
    1687         192 :     for(unsigned i=0; i<ncv_; i++)
    1688         256 :       stateOfile_.printField("sigma_"+getPntrToArgument(i)->getName(),kernels_[k].sigma[i]);
    1689          64 :     stateOfile_.printField("height",kernels_[k].height);
    1690          64 :     stateOfile_.printField();
    1691             :   }
    1692             : //make sure file is written even if small
    1693          18 :   if(!storeOldStates_)
    1694           2 :     stateOfile_.flush();
    1695          18 : }
    1696             : 
    1697             : template <class mode>
    1698        5969 : inline double OPESmetad<mode>::evaluateKernel(const kernel& G,const std::vector<double>& x) const
    1699             : { //NB: cannot be a method of kernel class, because uses external variables (for cutoff)
    1700             :   double norm2=0;
    1701       13923 :   for(unsigned i=0; i<ncv_; i++)
    1702             :   {
    1703       10288 :     const double dist_i=difference(i,G.center[i],x[i])/G.sigma[i];
    1704       10288 :     norm2+=dist_i*dist_i;
    1705       10288 :     if(norm2>=cutoff2_)
    1706             :       return 0;
    1707             :   }
    1708        3635 :   return G.height*(std::exp(-0.5*norm2)-val_at_cutoff_);
    1709             : }
    1710             : 
    1711             : template <class mode>
    1712        3364 : inline double OPESmetad<mode>::evaluateKernel(const kernel& G,const std::vector<double>& x, std::vector<double>& acc_der, std::vector<double>& dist)
    1713             : { //NB: cannot be a method of kernel class, because uses external variables (for cutoff)
    1714             :   double norm2=0;
    1715        7483 :   for(unsigned i=0; i<ncv_; i++)
    1716             :   {
    1717        5578 :     dist[i]=difference(i,G.center[i],x[i])/G.sigma[i];
    1718        5578 :     norm2+=dist[i]*dist[i];
    1719        5578 :     if(norm2>=cutoff2_)
    1720             :       return 0;
    1721             :   }
    1722        1905 :   const double val=G.height*(std::exp(-0.5*norm2)-val_at_cutoff_);
    1723        5576 :   for(unsigned i=0; i<ncv_; i++)
    1724        3671 :     acc_der[i]-=dist[i]/G.sigma[i]*val; //NB: we accumulate the derivative into der
    1725             :   return val;
    1726             : }
    1727             : 
    1728             : template <class mode>
    1729         388 : inline void OPESmetad<mode>::mergeKernels(kernel& k1,const kernel& k2)
    1730             : {
    1731         388 :   const double h=k1.height+k2.height;
    1732        1159 :   for(unsigned i=0; i<k1.center.size(); i++)
    1733             :   {
    1734         771 :     const bool isPeriodic_i=getPntrToArgument(i)->isPeriodic();
    1735         771 :     if(isPeriodic_i)
    1736         771 :       k1.center[i]=k2.center[i]+difference(i,k2.center[i],k1.center[i]); //fix PBC
    1737         771 :     const double c_i=(k1.height*k1.center[i]+k2.height*k2.center[i])/h;
    1738         771 :     const double ss_k1_part=k1.height*(k1.sigma[i]*k1.sigma[i]+k1.center[i]*k1.center[i]);
    1739         771 :     const double ss_k2_part=k2.height*(k2.sigma[i]*k2.sigma[i]+k2.center[i]*k2.center[i]);
    1740         771 :     const double ss_i=(ss_k1_part+ss_k2_part)/h-c_i*c_i;
    1741         771 :     if(isPeriodic_i)
    1742         771 :       k1.center[i]=bringBackInPbc(i,c_i);
    1743             :     else
    1744           0 :       k1.center[i]=c_i;
    1745         771 :     k1.sigma[i]=sqrt(ss_i);
    1746             :   }
    1747         388 :   k1.height=h;
    1748         388 : }
    1749             : 
    1750             : }
    1751             : }

Generated by: LCOV version 1.16