LCOV - code coverage report
Current view: top level - opes - OPESmetad.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 1022 1038 98.5 %
Date: 2026-11-05 10:19:04 Functions: 38 38 100.0 %

          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 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 (see [OPES](module_opes.md)) method with metadynamics-like target distribution is described in the first paper cited below.
      34             : 
      35             : This OPES_METAD action samples target distributions defined via their marginal $p^{\text{tg}}(\mathbf{s})$ over some collective variables (CVs), $\mathbf{s}=\mathbf{s}(\mathbf{x})$.
      36             : By default OPES_METAD targets the well-tempered distribution, $p^{\text{WT}}(\mathbf{s})\propto [P(\mathbf{s})]^{1/\gamma}$, where $\gamma$ is known as BIASFACTOR.
      37             : Similarly to [METAD](METAD.md), 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, $P(\mathbf{s})$.
      39             : A compression algorithm is used to prevent the number of kernels from growing linearly with the simulation time.
      40             : The bias at step $n$ is
      41             : 
      42             : $$
      43             : V_n(\mathbf{s}) = (1-1/\gamma)\frac{1}{\beta}\log\left(\frac{P_n(\mathbf{s})}{Z_n}+\epsilon\right)\, .
      44             : $$
      45             : 
      46             : See the first paper cited below for a complete description of the method.
      47             : 
      48             : As an intuitive picture, rather than gradually filling the metastable basins, OPES_METAD quickly tries to get a coarse idea of the full free energy surface (FES), and then slowly refines its details.
      49             : 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.
      50             : For this reason, it is possible to use standard umbrella sampling reweighting (see [REWEIGHT_BIAS](REWEIGHT_BIAS.md)) to analyse the trajectory.
      51             : 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 [sum_hills](sum_hills.md), but the preferred way to obtain a FES with OPES is via reweighting
      52             : (this is discussed in the tutorials you can access by clicking the button above).
      53             : The estimated $c(t)$ is printed for reference only, since it should converge to a fixed value as the bias converges.
      54             : This $c(t)$ should NOT be used for reweighting.
      55             : Similarly, the $Z_n$ factor is printed only for reference, and it should converge when no new region of the CV-space is explored.
      56             : 
      57             : Notice that OPES_METAD is more sensitive to degenerate CVs than [METAD](METAD.md).
      58             : If the employed CVs map different metastable basins onto the same CV-space region, then OPES_METAD will remain stuck rather than completely reshaping the bias.
      59             : This can be useful to diagnose problems with your collective variable.
      60             : If it is not possible to improve the set of CVs and remove this degeneracy, then you might instead consider to use [OPES_METAD_EXPLORE](OPES_METAD_EXPLORE.md) or [METAD](METAD.md).
      61             : 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 the second paper cited below).
      62             : On the contrary, if your CVs are not degenerate but only suboptimal, you should converge faster by using OPES_METAD instead of [METAD](METAD.md) as discussed in the first paper cited below.
      63             : 
      64             : The parameter BARRIER should be set to be at least equal to the highest free energy barrier you wish to overcome.
      65             : If it is much lower than that, you will not cross the barrier, if it is much higher, convergence might take a little longer.
      66             : If the system has a basin that is clearly more stable than the others, it is better to start the simulation from there.
      67             : 
      68             : By default, the kernels SIGMA is adaptive, estimated from the fluctuations over ADAPTIVE_SIGMA_STRIDE simulation steps (similar to [METAD](METAD.md) ADAPTIVE=DIFF, but contrary to that, no artifacts are introduced and the bias will converge to the correct one).
      69             : However, notice that depending on the system this might not be the optimal choice for SIGMA.
      70             : 
      71             : The kernels are Gaussians truncated at KERNEL_CUTOFF, in units of SIGMA.
      72             : They are force-shifted, so that both their value and their derivative go to zero at the cutoff.
      73             : At a distance $r$ from its center, in units of SIGMA, a kernel is proportional to $e^{-r^2/2}-c\,\big(1+(r_c^2-r^2)/2\big)$, where $r_c$ is the cutoff and $c=e^{-r_c^2/2}$, and it is zero beyond the cutoff.
      74             : The default cutoff is set from BARRIER, and the kernels then differ from Gaussians only in their far tails.
      75             : 
      76             : The kernels are summed using a neighbor list, which is rebuilt before any kernel outside it can get within the cutoff.
      77             : The result is the same as when summing all the kernels, and with two or more CVs it is usually much faster.
      78             : The neighbor list can be switched off with NLIST_OFF.
      79             : 
      80             : You can target a uniform flat distribution by explicitly setting BIASFACTOR=inf.
      81             : However, this should be useful only in very specific cases.
      82             : 
      83             : It is possible to take into account also of other bias potentials besides the one of OPES_METAD during the internal reweighting for $P(\mathbf{s})$ estimation.
      84             : To do so, one has to add those biases with the EXTRA_BIAS keyword, as in the example below.
      85             : 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).
      86             : Another possible usage of EXTRA_BIAS is to make sure that OPES_METAD does not push against another fixed bias added to restrain the CVs range (e.g. [UPPER_WALLS](UPPER_WALLS.md)).
      87             : 
      88             : Through the EXCLUDED_REGION keywork, it is possible to specify a region of CV space where no kernels will be deposited.
      89             : This can be useful for example for making sure the bias does not modify the transition region, thus allowing for rate calculation.
      90             : See below for an example of how to use this keyword.
      91             : 
      92             : 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).
      93             : For an exact restart you must use STATE_RFILE to read a checkpoint with all the needed info.
      94             : To save such checkpoints, define a STATE_WFILE and choose how often to print them with STATE_WSTRIDE.
      95             : By default this file is overwritten, but you can instead append to it using the flag STORE_STATES.
      96             : 
      97             : To continue a simulation with a static bias, for example once the bias has converged, restart from the STATE file and add UPDATE_UNTIL=0.
      98             : No new kernels are then deposited, and the bias remains the one read from STATE_RFILE (no STATE_WFILE is needed).
      99             : 
     100             : Multiple walkers are supported only with MPI communication, via the keyword WALKERS_MPI.
     101             : 
     102             : For synchronized beads of one ring polymer, WALKERS_SHARED_BIAS selects the
     103             : common log weight `mean_b(B(s_b)+EXTRA_BIAS_b)/kBT`, before exponentiation.
     104             : Use it only when the sampled bias Hamiltonian is that same bead average.
     105             : With a bead-local wall, define the wall before OPES and include its `.bias` in
     106             : EXTRA_BIAS to estimate the wall-free marginal; omit it to retain the wall in
     107             : the target ensemble. This option changes deposition weights, not bias forces.
     108             : It requires WALKERS_MPI, explicit SIGMA, equal temperatures and PACE, no
     109             : EXCLUDED_REGION, and synchronized updates on every bead. It is not available
     110             : for OPES_METAD_EXPLORE. Each bead still deposits a kernel, so the kernel counter
     111             : and neff remain walker counts, not independent ring-polymer sample counts.
     112             : The constant number of beads cancels between the KDE numerator and denominator.
     113             : A STATE or KERNELS history records this mode and bead count; changing either
     114             : requires a fresh history. Legacy histories retain the local-weight convention.
     115             : 
     116             : ## Examples
     117             : 
     118             : 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.
     119             : The tutorials on this method that can be accessed by clicking the tutorial button at the top of this page can also be useful to get started with the method.
     120             : 
     121             : The following is a minimal working example:
     122             : 
     123             : ```plumed
     124             : cv: DISTANCE ATOMS=1,2
     125             : opes: OPES_METAD ARG=cv PACE=200 BARRIER=40
     126             : PRINT STRIDE=200 FILE=COLVAR ARG=*
     127             : ```
     128             : 
     129             : Another more articulated one:
     130             : 
     131             : ```plumed
     132             : phi: TORSION ATOMS=5,7,9,15
     133             : psi: TORSION ATOMS=7,9,15,17
     134             : opes: OPES_METAD ...
     135             :   FILE=Kernels.data
     136             :   TEMP=300
     137             :   ARG=phi,psi
     138             :   PACE=500
     139             :   BARRIER=50
     140             :   SIGMA=0.15,0.15
     141             :   SIGMA_MIN=0.01,0.01
     142             :   STATE_RFILE=Restart.data
     143             :   STATE_WFILE=State.data
     144             :   STATE_WSTRIDE=500*100
     145             :   STORE_STATES
     146             :   WALKERS_MPI
     147             : ...
     148             : PRINT FMT=%g STRIDE=500 FILE=Colvar.data ARG=phi,psi,opes.*
     149             : ```
     150             : 
     151             : Next is an example of how to define a custom target distribution different from the well-tempered one.
     152             : Here we chose to focus more on the transition state, that is around $\phi=0$.
     153             : Our target distribution is a Gaussian centered there, thus the target free energy we want to sample is a parabola, $F^{\text{tg}}(\mathbf{s})=-\frac{1}{\beta} \log [p^{\text{tg}}(\mathbf{s})]$.
     154             : 
     155             : ```plumed
     156             : phi: TORSION ATOMS=5,7,9,15
     157             : FtgValue: CUSTOM ARG=phi PERIODIC=NO FUNC=(x/0.4)^2
     158             : Ftg: BIASVALUE ARG=FtgValue
     159             : opes: OPES_METAD ...
     160             :   ARG=phi
     161             :   PACE=500
     162             :   BARRIER=50
     163             :   SIGMA=0.2
     164             :   BIASFACTOR=inf
     165             :   EXTRA_BIAS=Ftg.bias
     166             : ...
     167             : PRINT FMT=%g STRIDE=500 FILE=COLVAR ARG=phi,Ftg.bias,opes.bias
     168             : ```
     169             : 
     170             : Notice that in order to reweight for the unbiased $P(\mathbf{s})$ during postprocessing, the total bias `Ftg.bias+opes.bias` must be used.
     171             : 
     172             : Finally, an example of how to use the EXCLUDED_REGION keyword.
     173             : It expects a characteristic function that is different from zero in the region to be excluded.
     174             : You can use [CUSTOM](CUSTOM.md) and a combination of the step function to define it.
     175             : With the following input no kernel is deposited in the transition state region of alanine dipeptide, defined by the interval $\phi \in [-0.6, 0.7]$:
     176             : 
     177             : ```plumed
     178             : phi: TORSION ATOMS=5,7,9,15
     179             : psi: TORSION ATOMS=7,9,15,17
     180             : xx: CUSTOM PERIODIC=NO ARG=phi FUNC=step(x+0.6)-step(x-0.7)
     181             : opes: OPES_METAD ...
     182             :   ARG=phi,psi
     183             :   PACE=500
     184             :   BARRIER=30
     185             :   EXCLUDED_REGION=xx
     186             : ...
     187             : PRINT FMT=%g STRIDE=500 FILE=COLVAR ARG=phi,psi,xx,opes.*
     188             : ```
     189             : 
     190             : */
     191             : //+ENDPLUMEDOC
     192             : 
     193             : template <class mode>
     194             : class OPESmetad : public bias::Bias {
     195             : 
     196             : private:
     197             :   bool isFirstStep_;
     198             :   unsigned NumOMP_;
     199             :   unsigned NumParallel_;
     200             :   unsigned rank_;
     201             :   unsigned NumWalkers_;
     202             :   unsigned walker_rank_;
     203             :   unsigned long long counter_;
     204             :   std::size_t ncv_;
     205             : 
     206             :   double kbt_;
     207             :   double biasfactor_;
     208             :   double bias_prefactor_;
     209             :   unsigned stride_;
     210             :   std::vector<double> sigma0_;
     211             :   std::vector<double> sigma_min_;
     212             :   unsigned adaptive_sigma_stride_;
     213             :   unsigned long long adaptive_counter_;
     214             :   std::vector<double> av_cv_;
     215             :   std::vector<double> av_M2_;
     216             :   bool fixed_sigma_;
     217             :   bool adaptive_sigma_;
     218             :   double epsilon_;
     219             :   double sum_weights_;
     220             :   double sum_weights2_;
     221             : 
     222             :   bool no_Zed_;
     223             :   double Zed_;
     224             :   double KDEnorm_;
     225             : 
     226             :   double threshold2_;
     227             :   bool recursive_merge_;
     228             : //kernels are truncated diagonal Gaussians, force-shifted so that their value and derivative go to zero at the cutoff
     229       27582 :   struct kernel {
     230             :     double height;
     231             :     std::vector<double> center;
     232             :     std::vector<double> sigma;
     233       27979 :     kernel(double h, const std::vector<double>& c,const std::vector<double>& s):
     234       27979 :       height(h),center(c),sigma(s) {}
     235             :   };
     236             :   double cutoff2_;
     237             :   double val_at_cutoff_;
     238             :   void mergeKernels(kernel&,const kernel&); //merge the second one into the first one
     239             :   double evaluateKernel(const kernel&,const std::vector<double>&) const;
     240             :   double shiftedGaussian(const double) const; //for a squared distance within the cutoff
     241             :   std::vector<kernel> kernels_; //all compressed kernels
     242             : //kernels summed at every step (all of them, or those in the neighbor list), with each CV in a
     243             : //contiguous array, so that the distances to all of them are computed in a loop without branches
     244             :   bool sum_outdated_; //kernels_ or nlist_index_ changed since the last updateSum()
     245             :   std::vector<double> sum_center_; //CV i of the k-th summed kernel is sum_center_[i*size+k]
     246             :   std::vector<double> sum_inv_sigma_; //same layout, inverse of sigma
     247             :   std::vector<double> sum_height_;
     248             :   std::vector<double> period_; //period of each CV, zero if not periodic
     249             :   std::vector<double> inv_period_;
     250             :   std::vector<double> cv_; //buffers for calculate(), to avoid allocations at every step
     251             :   std::vector<double> der_prob_;
     252             :   void updateSum();
     253             :   void sumKernels(const std::vector<double>&,const unsigned,const unsigned,double&,std::vector<double>&) const;
     254             :   OFile kernelsOfile_;
     255             : //neighbour list stuff
     256             :   bool nlist_;
     257             :   double nlist_param_; //kernels within sqrt(nlist_param_)*cutoff are in the list
     258             :   std::vector<unsigned> nlist_index_;
     259             :   std::vector<double> nlist_center_;
     260             :   unsigned nlist_steps_;
     261             :   bool nlist_update_;
     262             :   bool nlist_components_; //the nlker and nlsteps components, only with the deprecated NLIST flag
     263             :   double nlist_skin2_; //square of the largest displacement allowed, in units of nlist_sigma_min_
     264             :   std::vector<double> nlist_sigma_min_; //smallest sigma of all kernels, for each CV, at the last rebuild
     265             : //all kernels, with the same layout as the summed ones, to rebuild the list and update Zed quickly
     266             :   bool nlist_all_outdated_; //kernels_ changed since the last updateNlistAll()
     267             :   std::vector<double> nlist_all_center_;
     268             :   std::vector<double> nlist_all_inv_sigma_;
     269             :   std::vector<double> nlist_all_height_;
     270             :   std::vector<double> nlist_all_sigma_min_; //smallest sigma of all kernels, for each CV
     271             :   void updateNlistAll();
     272             :   void listKernels(const unsigned,const unsigned,std::vector<unsigned>&) const;
     273             : 
     274             :   bool calc_work_;
     275             :   double work_;
     276             :   double old_KDEnorm_;
     277             :   std::vector<kernel> delta_kernels_;
     278             :   double deltaSumUprob(const unsigned,const unsigned,const bool) const;
     279             : 
     280             :   Value* excluded_region_;
     281             :   std::vector<Value*> extra_biases_;
     282             :   bool walkers_shared_bias_;
     283             : 
     284             :   OFile stateOfile_;
     285             :   int wStateStride_;
     286             :   bool storeOldStates_;
     287             : 
     288             :   double getProbAndDerivatives(const std::vector<double>&,std::vector<double>&);
     289             :   void addKernel(const double,const std::vector<double>&,const std::vector<double>&);
     290             :   void addKernel(const double,const std::vector<double>&,const std::vector<double>&,const double); //also print to file
     291             :   unsigned getMergeableKernel(const std::vector<double>&,const unsigned,const bool all_kernels=false);
     292             :   void updateNlist(const std::vector<double>&);
     293             :   void dumpStateToFile();
     294             : 
     295             : public:
     296             :   explicit OPESmetad(const ActionOptions&);
     297             :   void calculate() override;
     298             :   void update() override;
     299             :   static void registerKeywords(Keywords& keys);
     300             : };
     301             : 
     302             : struct convergence {
     303             :   static const bool explore=false;
     304             : };
     305             : typedef OPESmetad<convergence> OPESmetad_c;
     306             : PLUMED_REGISTER_ACTION(OPESmetad_c,"OPES_METAD")
     307             : 
     308             : //OPES_METAD_EXPLORE is very similar from the point of view of the code,
     309             : //but conceptually it is better to make it a separate BIAS action
     310             : 
     311             : //+PLUMEDOC BIAS OPES_METAD_EXPLORE
     312             : /*
     313             : On-the-fly probability enhanced sampling with well-tempered target distribution in exploreation mode.
     314             : 
     315             : On-the-fly probability enhanced sampling with well-tempered target distribution ([OPES](module_opes.md)) with well-tempered target distribution, exploration mode as discussed in the paper cited below.
     316             : 
     317             : This [OPES_METAD_EXPLORE](OPES_METAD_EXPLORE.md) action samples the well-tempered target distribution, that is defined via its marginal $p^{\text{WT}}(\mathbf{s})\propto [P(\mathbf{s})]^{1/\gamma}$ over some collective variables (CVs), $\mathbf{s}=\mathbf{s}(\mathbf{x})$.
     318             : While [OPES_METAD](OPES_METAD.md) does so by estimating the unbiased distribution $P(\mathbf{s})$, OPES_METAD_EXPLORE instead estimates on-the-fly the target $p^{\text{WT}}(\mathbf{s})$ and uses it to define the bias.
     319             : The bias at step $n$ is
     320             : 
     321             : $$
     322             : V_n(\mathbf{s}) = (\gamma-1)\frac{1}{\beta}\log\left(\frac{p^{\text{WT}}_n(\mathbf{s})}{Z_n}+\epsilon\right)\, .
     323             : $$
     324             : 
     325             : See the paper cited below for a complete description of the method.
     326             : 
     327             : Intuitively, while [OPES_METAD](OPES_METAD.md) aims at quickly converging the reweighted free energy, OPES_METAD_EXPLORE aims at quickly sampling the target well-tempered distribution.
     328             : Given enough simulation time, both will converge to the same bias potential but they do so in a qualitatively different way.
     329             : Compared to [OPES_METAD](OPES_METAD.md), OPES_METAD_EXPLORE is more similar to [METAD](METAD.md), because it allows the bias to vary significantly, thus enhancing exploration.
     330             : This goes at the expenses of a typically slower convergence of the reweight estimate.
     331             : 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.
     332             : 
     333             : Similarly to [OPES_METAD](OPES_METAD.md), also OPES_METAD_EXPLORE uses a kernel density estimation with the same on-the-fly compression algorithm.
     334             : The only difference is that the kernels are not weighted, since it estimates the sampled distribution and not the reweighted unbiased one.
     335             : 
     336             : All the options of [OPES_METAD](OPES_METAD.md) are also available in OPES_METAD_EXPLORE, except for those that modify the target distribution, since only a well-tempered target is allowed in this case.
     337             : 
     338             : ## Examples
     339             : 
     340             : The following is a minimal working example:
     341             : 
     342             : ```plumed
     343             : cv: DISTANCE ATOMS=1,2
     344             : opes: OPES_METAD_EXPLORE ARG=cv PACE=500 BARRIER=40
     345             : PRINT STRIDE=100 FILE=COLVAR ARG=cv,opes.*
     346             : ```
     347             : 
     348             : */
     349             : //+ENDPLUMEDOC
     350             : 
     351             : struct exploration {
     352             :   static const bool explore=true;
     353             : };
     354             : typedef OPESmetad<exploration> OPESmetad_e;
     355             : PLUMED_REGISTER_ACTION(OPESmetad_e,"OPES_METAD_EXPLORE")
     356             : 
     357             : template <class mode>
     358         165 : void OPESmetad<mode>::registerKeywords(Keywords& keys) {
     359         165 :   Bias::registerKeywords(keys);
     360         165 :   keys.add("compulsory","TEMP","-1","temperature. If not set, it is taken from MD engine, but not all MD codes provide it");
     361         165 :   keys.add("compulsory","PACE","the frequency for kernel deposition");
     362         165 :   std::string info_sigma("the initial widths of the kernels");
     363             :   if(mode::explore) {
     364             :     info_sigma+=", divided by the square root of gamma";
     365             :   }
     366             :   info_sigma+=". If not set, an adaptive sigma will be used with the given ADAPTIVE_SIGMA_STRIDE";
     367         165 :   keys.add("compulsory","SIGMA","ADAPTIVE",info_sigma);
     368         165 :   keys.add("compulsory","BARRIER","the free energy barrier to be overcome. It is used to set BIASFACTOR, EPSILON, and KERNEL_CUTOFF to reasonable values");
     369         165 :   keys.add("compulsory","COMPRESSION_THRESHOLD","1","merge kernels if closer than this threshold, in units of sigma");
     370             : //extra options
     371         165 :   keys.add("optional","ADAPTIVE_SIGMA_STRIDE","number of steps for measuring adaptive sigma. Default is 10xPACE");
     372         165 :   keys.add("optional","SIGMA_MIN","never reduce SIGMA below this value");
     373         165 :   std::string info_biasfactor("the gamma bias factor used for the well-tempered target distribution. ");
     374             :   if(mode::explore) {
     375             :     info_biasfactor+="Cannot be 'inf'";
     376             :   } else {
     377             :     info_biasfactor+="Set to 'inf' for uniform flat target";
     378             :   }
     379         165 :   keys.add("optional","BIASFACTOR",info_biasfactor);
     380         165 :   keys.add("optional","EPSILON","the value of the regularization constant for the probability");
     381         165 :   keys.add("optional","KERNEL_CUTOFF","truncate kernels at this distance, in units of sigma. The truncated kernels are force-shifted, see above");
     382         165 :   keys.add("optional","NLIST_PARAMETERS","( default=3.0 ) the kernels within sqrt(NLIST_PARAMETERS)*KERNEL_CUTOFF are in the neighbor list. "
     383             :            "Larger values give a larger list, rebuilt less often. A second value is accepted for backward compatibility, but is not used");
     384         165 :   keys.addFlag("NLIST_OFF",false,"do not use the neighbor list for the kernels summation. The result is the same, but it can be slower when there are many kernels");
     385         330 :   keys.addDeprecatedFlag("NLIST","");
     386         165 :   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");
     387         165 :   keys.addFlag("RECURSIVE_MERGE_OFF",false,"do not recursively attempt kernel merging when a new one is added");
     388         165 :   keys.addFlag("NO_ZED",false,"do not normalize over the explored CV space, Z_n=1");
     389             : //kernels and state files
     390         165 :   keys.add("compulsory","FILE","KERNELS","a file in which the list of all deposited kernels is stored");
     391         165 :   keys.add("optional","FMT","specify format for KERNELS file");
     392         165 :   keys.add("optional","STATE_RFILE","read from this file the compressed kernels and all the info needed to RESTART the simulation");
     393         165 :   keys.add("optional","STATE_WFILE","write to this file the compressed kernels and all the info needed to RESTART the simulation");
     394         165 :   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)");
     395         165 :   keys.addFlag("STORE_STATES",false,"append to STATE_WFILE instead of overwriting it each time");
     396             : //miscellaneous
     397         330 :   keys.addInputKeyword("optional","EXCLUDED_REGION","scalar","kernels are not deposited when the action provided here has a nonzero value, see example above");
     398             :   if(!mode::explore) {
     399         138 :     keys.addFlag("WALKERS_SHARED_BIAS",false,"use the mean bias plus EXTRA_BIAS over synchronous WALKERS_MPI replicas as the common deposition log weight; for a single ring polymer only");
     400         276 :     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)");
     401             :   }
     402         165 :   keys.addFlag("CALC_WORK",false,"calculate the total accumulated work done by the bias since last restart");
     403         165 :   keys.addFlag("WALKERS_MPI",false,"switch on MPI version of multiple walkers");
     404         165 :   keys.addFlag("SERIAL",false,"perform calculations in serial");
     405         165 :   keys.use("RESTART");
     406         165 :   keys.use("UPDATE_FROM");
     407         165 :   keys.use("UPDATE_UNTIL");
     408             : 
     409             : //output components
     410         330 :   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");
     411         330 :   keys.addOutputComponent("zed","default","scalar","estimate of Z_n. should become flat once no new CV-space region is explored");
     412         330 :   keys.addOutputComponent("neff","default","scalar","effective sample size");
     413         330 :   keys.addOutputComponent("nker","default","scalar","total number of compressed kernels used to represent the bias");
     414         330 :   keys.addOutputComponent("work","CALC_WORK","scalar","total accumulated work done by the bias");
     415         330 :   keys.addOutputComponent("nlker","NLIST","scalar","number of kernels in the neighbor list");
     416         330 :   keys.addOutputComponent("nlsteps","NLIST","scalar","number of steps from last neighbor list update");
     417             :   if( !mode::explore ) {
     418         138 :     keys.addDOI("10.1021/acs.jpclett.0c00497");
     419         276 :     keys.addDOI("10.1016/j.revip.2017.05.001");
     420             :   } else {
     421          54 :     keys.addDOI("10.1021/acs.jctc.2c00152");
     422             :   }
     423         165 : }
     424             : 
     425             : template <class mode>
     426         157 : OPESmetad<mode>::OPESmetad(const ActionOptions& ao)
     427             :   : PLUMED_BIAS_INIT(ao)
     428         157 :   , isFirstStep_(true)
     429         157 :   , counter_(1)
     430         157 :   , ncv_(getNumberOfArguments())
     431         157 :   , Zed_(1)
     432         157 :   , work_(0)
     433         157 :   , excluded_region_(NULL) {
     434         314 :   std::string error_in_input1("Error in input in action "+getName()+" with label "+getLabel()+": the keyword ");
     435         201 :   std::string error_in_input2(" could not be read correctly");
     436             : 
     437             : //set kbt_
     438         157 :   const double kB=getKBoltzmann();
     439         157 :   kbt_=getkBT();
     440         157 :   plumed_massert(std::isfinite(kbt_) && kbt_>0,"OPES requires a finite positive temperature");
     441             : 
     442             : //other compulsory input
     443         157 :   long long pace=0;
     444         157 :   parse("PACE",pace);
     445         165 :   plumed_massert(pace>0 && static_cast<unsigned long long>(pace)<=std::numeric_limits<unsigned>::max(),
     446             :                  "PACE must be greater than zero and no larger than "+std::to_string(std::numeric_limits<unsigned>::max()));
     447         153 :   stride_=static_cast<unsigned>(pace);
     448             : 
     449         153 :   double barrier=0;
     450         197 :   parse("BARRIER",barrier);
     451         153 :   plumed_massert(barrier>=0,"the BARRIER should be greater than zero");
     452             : 
     453         153 :   biasfactor_=barrier/kbt_;
     454             :   std::string biasfactor_str;
     455         153 :   parse("BIASFACTOR",biasfactor_str);
     456         153 :   if(biasfactor_str=="inf" || biasfactor_str=="INF") {
     457           4 :     biasfactor_=std::numeric_limits<double>::infinity();
     458           4 :     bias_prefactor_=1;
     459             :   } else {
     460         149 :     if(biasfactor_str.length()>0) {
     461           3 :       plumed_massert(Tools::convertNoexcept(biasfactor_str,biasfactor_),error_in_input1+"BIASFACTOR"+error_in_input2);
     462             :     }
     463         149 :     plumed_massert(biasfactor_>1,"BIASFACTOR must be greater than one (use 'inf' for uniform target)");
     464         149 :     bias_prefactor_=1-1./biasfactor_;
     465             :   }
     466             :   if(mode::explore) {
     467          21 :     plumed_massert(!std::isinf(biasfactor_),"BIASFACTOR=inf is not compatible with EXPLORE mode");
     468          21 :     bias_prefactor_=biasfactor_-1;
     469             :   }
     470             : 
     471         153 :   adaptive_sigma_=false;
     472         153 :   adaptive_sigma_stride_=0;
     473         193 :   parse("ADAPTIVE_SIGMA_STRIDE",adaptive_sigma_stride_);
     474         153 :   std::vector<std::string> sigma_str;
     475         153 :   parseVector("SIGMA",sigma_str);
     476         153 :   sigma0_.resize(ncv_);
     477             :   double dummy;
     478         153 :   if(sigma_str.size()==1 && !Tools::convertNoexcept(sigma_str[0],dummy)) {
     479          23 :     plumed_massert(sigma_str[0]=="ADAPTIVE" || sigma_str[0]=="adaptive",error_in_input1+"SIGMA"+error_in_input2);
     480          23 :     plumed_massert(!std::isinf(biasfactor_),"cannot use BIASFACTOR=inf with adaptive SIGMA");
     481          23 :     adaptive_counter_=0;
     482          23 :     if(adaptive_sigma_stride_==0) {
     483          12 :       adaptive_sigma_stride_=10*stride_;  //NB: this is arbitrary, chosen from few tests
     484             :     }
     485          23 :     av_cv_.resize(ncv_,0);
     486          23 :     av_M2_.resize(ncv_,0);
     487          23 :     plumed_massert(adaptive_sigma_stride_>=stride_,"better to chose ADAPTIVE_SIGMA_STRIDE > PACE");
     488          23 :     adaptive_sigma_=true;
     489             :   } else {
     490         130 :     plumed_massert(sigma_str.size()==ncv_,"number of SIGMA parameters does not match number of arguments");
     491         130 :     plumed_massert(adaptive_sigma_stride_==0,"if SIGMA is not ADAPTIVE you cannot set an ADAPTIVE_SIGMA_STRIDE");
     492         265 :     for(unsigned i=0; i<ncv_; i++) {
     493         139 :       plumed_massert(Tools::convertNoexcept(sigma_str[i],sigma0_[i]),error_in_input1+"SIGMA"+error_in_input2);
     494         143 :       plumed_massert(std::isfinite(sigma0_[i]) && sigma0_[i]>0,"SIGMA values must be finite and greater than zero");
     495             :       if(mode::explore) {
     496          13 :         sigma0_[i]*=std::sqrt(biasfactor_);  //the sigma of the target is broader Ftg(s)=1/gamma*F(s)
     497             :       }
     498             :     }
     499             :   }
     500         298 :   parseVector("SIGMA_MIN",sigma_min_);
     501         149 :   plumed_massert(sigma_min_.size()==0 || sigma_min_.size()==ncv_,"number of SIGMA_MIN does not match number of arguments");
     502         155 :   for(double sigma : sigma_min_) {
     503          14 :     plumed_massert(std::isfinite(sigma) && sigma>0,"SIGMA_MIN values must be finite and greater than zero");
     504             :   }
     505         145 :   if(sigma_min_.size()>0 && !adaptive_sigma_) {
     506           3 :     for(unsigned i=0; i<ncv_; i++) {
     507           2 :       plumed_massert(sigma_min_[i]<=sigma0_[i],"SIGMA_MIN should be smaller than SIGMA");
     508             :     }
     509             :   }
     510             : 
     511         145 :   epsilon_=std::exp(-barrier/bias_prefactor_/kbt_);
     512         145 :   parse("EPSILON",epsilon_);
     513         145 :   plumed_massert(epsilon_>0,"you must choose a value for EPSILON greater than zero. Is your BARRIER too high?");
     514         145 :   sum_weights_=std::pow(epsilon_,bias_prefactor_); //to avoid NANs we start with counter_=1 and w0=exp(beta*V0)
     515         145 :   sum_weights2_=sum_weights_*sum_weights_;
     516             : 
     517         145 :   double cutoff=sqrt(2.*barrier/bias_prefactor_/kbt_);
     518             :   if(mode::explore) {
     519          17 :     cutoff=sqrt(2.*barrier/kbt_);  //otherwise it is too small
     520             :   }
     521         145 :   parse("KERNEL_CUTOFF",cutoff);
     522         145 :   plumed_massert(cutoff>0,"you must choose a value for KERNEL_CUTOFF greater than zero");
     523         145 :   cutoff2_=cutoff*cutoff;
     524         145 :   val_at_cutoff_=std::exp(-0.5*cutoff2_);
     525             : 
     526         145 :   threshold2_=1;
     527         145 :   parse("COMPRESSION_THRESHOLD",threshold2_);
     528         145 :   threshold2_*=threshold2_;
     529         145 :   if(threshold2_!=0) {
     530         145 :     plumed_massert(threshold2_>0 && threshold2_<cutoff2_,"COMPRESSION_THRESHOLD cannot be bigger than the KERNEL_CUTOFF");
     531             :   }
     532             : 
     533             : //setup neighbor list, used by default
     534         145 :   bool nlist_off=false;
     535         145 :   parseFlag("NLIST_OFF",nlist_off);
     536         145 :   bool nlist_flag=false; //deprecated, it only adds the nlker and nlsteps components, as in previous versions
     537         145 :   parseFlag("NLIST",nlist_flag);
     538         145 :   plumed_massert(!(nlist_off && nlist_flag),"NLIST and NLIST_OFF cannot be used together");
     539         145 :   nlist_=!nlist_off;
     540         145 :   nlist_components_=nlist_flag;
     541         145 :   std::vector<double> nlist_param;
     542         145 :   parseVector("NLIST_PARAMETERS",nlist_param);
     543         145 :   nlist_param_=3.0;//*cutoff2_ -> max distance of neighbors
     544         145 :   if(nlist_param.size()>0) {
     545           6 :     plumed_massert(!nlist_off,"NLIST_PARAMETERS cannot be used with NLIST_OFF");
     546           6 :     plumed_massert(nlist_param.size()<=2,"NLIST_PARAMETERS takes one value");
     547           6 :     plumed_massert(nlist_param[0]>1.0,"NLIST_PARAMETERS must be greater than 1");
     548           6 :     nlist_param_=nlist_param[0];
     549             :   }
     550         145 :   nlist_center_.resize(ncv_);
     551         145 :   nlist_steps_=0;
     552         145 :   nlist_update_=true;
     553             :   //the list is rebuilt before any kernel outside it can get within the cutoff,
     554             :   //i.e. when the CV moves out of a skin of (sqrt(nlist_param_)-1)*cutoff, in units of the smallest sigma
     555         145 :   nlist_skin2_=std::pow(std::sqrt(nlist_param_)-1,2)*cutoff2_;
     556         145 :   nlist_sigma_min_.resize(ncv_,std::numeric_limits<double>::max());
     557         145 :   nlist_all_outdated_=true;
     558             : 
     559             : //setup the sum of the kernels
     560         145 :   sum_outdated_=true;
     561         145 :   period_.resize(ncv_,0.);
     562         145 :   inv_period_.resize(ncv_,0.);
     563         145 :   cv_.resize(ncv_);
     564         145 :   der_prob_.resize(ncv_);
     565         319 :   for(unsigned i=0; i<ncv_; i++) {
     566         174 :     if(getPntrToArgument(i)->isPeriodic()) {
     567          44 :       period_[i]=getPntrToArgument(i)->getMaxMinusMin();
     568          44 :       inv_period_[i]=1./period_[i];
     569             :     }
     570             :   }
     571             : 
     572             : //optional stuff
     573         145 :   no_Zed_=false;
     574         145 :   parseFlag("NO_ZED",no_Zed_);
     575         145 :   if(no_Zed_) {
     576             :     //this makes it more gentle in the initial phase
     577           6 :     sum_weights_=1;
     578           6 :     sum_weights2_=1;
     579             :   }
     580         145 :   fixed_sigma_=false;
     581         145 :   parseFlag("FIXED_SIGMA",fixed_sigma_);
     582         145 :   bool recursive_merge_off=false;
     583         145 :   parseFlag("RECURSIVE_MERGE_OFF",recursive_merge_off);
     584         145 :   recursive_merge_=!recursive_merge_off;
     585         177 :   parseFlag("CALC_WORK",calc_work_);
     586             : 
     587             : //options involving extra arguments
     588         145 :   std::vector<Value*> args;
     589         290 :   parseArgumentList("EXCLUDED_REGION",args);
     590         145 :   if(args.size()>0) {
     591           4 :     plumed_massert(args.size()==1,"only one characteristic function should define the region to be excluded");
     592           4 :     requestExtraDependencies(args);
     593           4 :     excluded_region_=args[0];
     594             :   }
     595             :   if(!mode::explore) {
     596         256 :     parseArgumentList("EXTRA_BIAS",extra_biases_);
     597         128 :     if(extra_biases_.size()>0) {
     598          34 :       requestExtraDependencies(extra_biases_);
     599             :     }
     600             :   }
     601             : 
     602         145 :   walkers_shared_bias_=false;
     603             :   if(!mode::explore) {
     604         288 :     parseFlag("WALKERS_SHARED_BIAS",walkers_shared_bias_);
     605             :   }
     606             : 
     607             : //kernels file
     608             :   std::string kernelsFileName;
     609         322 :   parse("FILE",kernelsFileName);
     610             :   std::string fmt;
     611         322 :   parse("FMT",fmt);
     612             : 
     613             : //output checkpoint of current state
     614             :   std::string restartFileName;
     615         322 :   parse("STATE_RFILE",restartFileName);
     616             :   std::string stateFileName;
     617         145 :   parse("STATE_WFILE",stateFileName);
     618         145 :   wStateStride_=0;
     619         145 :   parse("STATE_WSTRIDE",wStateStride_);
     620         145 :   storeOldStates_=false;
     621         145 :   parseFlag("STORE_STATES",storeOldStates_);
     622         145 :   if(wStateStride_!=0 || storeOldStates_) {
     623         116 :     plumed_massert(stateFileName.length()>0,"filename for storing simulation status not specified, use STATE_WFILE");
     624             :   }
     625         145 :   if(wStateStride_>0) {
     626         116 :     plumed_massert(wStateStride_>=(int)stride_,"STATE_WSTRIDE is in units of MD steps, thus it is suggested to use a multiple of PACE");
     627             :   }
     628         145 :   if(stateFileName.length()>0 && wStateStride_==0) {
     629           1 :     wStateStride_=-1;  //will print only on CPT events (checkpoints set by some MD engines, like gromacs)
     630             :   }
     631             : 
     632             : //multiple walkers //TODO implement also external mw for cp2k
     633         145 :   bool walkers_mpi=false;
     634         145 :   parseFlag("WALKERS_MPI",walkers_mpi);
     635         145 :   if(walkers_mpi) {
     636             :     //If this Action is not compiled with MPI the user is informed and we exit gracefully
     637         114 :     plumed_massert(Communicator::plumedHasMPI(),"Invalid walkers configuration: WALKERS_MPI flag requires MPI compilation");
     638         114 :     plumed_massert(Communicator::initialized(),"Invalid walkers configuration: WALKERS_MPI needs the communicator correctly initialized.");
     639         114 :     NumWalkers_=getNumberOfReplicas();
     640         114 :     walker_rank_=getReplicaIndex();
     641             :   } else {
     642          31 :     NumWalkers_=1;
     643          31 :     walker_rank_=0;
     644             :   }
     645             : 
     646             : // A shared-path estimator needs one synchronous deposition group. Ordinary
     647             : // independent walkers retain their original local weights and counters.
     648         128 :   if(walkers_mpi && !mode::explore) {
     649         110 :     std::vector<int> flags(NumWalkers_);
     650         110 :     const int flag=walkers_shared_bias_ ? 1 : 0;
     651         110 :     if(comm.Get_rank()==0) {
     652          64 :       multi_sim_comm.Allgather(flag,flags);
     653             :     }
     654         110 :     comm.Bcast(flags,0);
     655         348 :     for(int other : flags) {
     656         246 :       plumed_massert(other==flag,"WALKERS_SHARED_BIAS must agree on every walker");
     657             :     }
     658             :   }
     659         141 :   if(walkers_shared_bias_) {
     660          68 :     plumed_massert(walkers_mpi,"WALKERS_SHARED_BIAS requires WALKERS_MPI");
     661             :     // Reject on every rank before the next collective, even if only one
     662             :     // walker requests an option that could skip a deposition collective.
     663          68 :     std::vector<int> unsupported(NumWalkers_);
     664          68 :     const int local_unsupported=(excluded_region_!=NULL || adaptive_sigma_) ? 1 : 0;
     665          68 :     if(comm.Get_rank()==0) {
     666          40 :       multi_sim_comm.Allgather(local_unsupported,unsupported);
     667             :     }
     668          68 :     comm.Bcast(unsupported,0);
     669         212 :     for(int flag : unsupported) {
     670         160 :       plumed_massert(flag==0,
     671             :                      "WALKERS_SHARED_BIAS requires explicit SIGMA and no EXCLUDED_REGION on every walker");
     672             :     }
     673          68 :     std::vector<double> temperatures(NumWalkers_);
     674          60 :     std::vector<unsigned> strides(NumWalkers_);
     675          60 :     if(comm.Get_rank()==0) {
     676          36 :       multi_sim_comm.Allgather(kbt_,temperatures);
     677          36 :       multi_sim_comm.Allgather(stride_,strides);
     678             :     }
     679          60 :     comm.Bcast(temperatures,0);
     680          60 :     comm.Bcast(strides,0);
     681         204 :     for(unsigned w=0; w<NumWalkers_; ++w) {
     682         144 :       plumed_massert(temperatures[w]==kbt_ && strides[w]==stride_,
     683             :                      "WALKERS_SHARED_BIAS requires identical temperatures and PACE");
     684             :     }
     685          60 :     log.printf("  shared-path deposition: mean bias plus mean EXTRA_BIAS; walker counts are not independent frame ESS\n");
     686          60 :   }
     687             : 
     688             : //parallelization stuff
     689         133 :   NumOMP_=OpenMP::getNumThreads();
     690         133 :   NumParallel_=comm.Get_size();
     691         133 :   rank_=comm.Get_rank();
     692         133 :   bool serial=false;
     693         133 :   parseFlag("SERIAL",serial);
     694         133 :   if(serial) {
     695           4 :     NumOMP_=1;
     696           4 :     NumParallel_=1;
     697           4 :     rank_=0;
     698             :   }
     699             : 
     700         133 :   checkRead();
     701             : 
     702             : //restart if needed
     703             :   bool convertKernelsToState=false;
     704         133 :   if(getRestart()) {
     705             :     bool stateRestart=true;
     706          65 :     if(restartFileName.length()==0) {
     707             :       stateRestart=false;
     708             :       restartFileName=kernelsFileName;
     709             :     }
     710          65 :     IFile ifile;
     711          65 :     ifile.link(*this);
     712          65 :     if(ifile.FileExist(restartFileName)) {
     713          65 :       bool tmp_nlist=nlist_;
     714          65 :       nlist_=false; // NLIST is not needed while restarting
     715          65 :       ifile.open(restartFileName);
     716          65 :       log.printf("  RESTART - make sure all used options are compatible\n");
     717          65 :       log.printf("    restarting from: %s\n",restartFileName.c_str());
     718          65 :       std::string action_name=getName();
     719          65 :       if(stateRestart) {
     720          58 :         log.printf("    it should be a STATE file (not a KERNELS file)\n");
     721             :         action_name+="_state";
     722             :       } else {
     723           7 :         log.printf(" +++ WARNING +++ RESTART from KERNELS might be approximate, use STATE_WFILE and STATE_RFILE to restart from the exact state\n");
     724             :         action_name+="_kernels";
     725             :       }
     726             :       std::string old_action_name;
     727          65 :       ifile.scanField("action",old_action_name);
     728          65 :       plumed_massert(action_name==old_action_name,"RESTART - mismatch between old and new action name. Expected '"+action_name+"', but found '"+old_action_name+"'");
     729          85 :       std::string weight_mode="local";
     730         130 :       if(ifile.FieldExist("walker_weight_mode")) {
     731          72 :         ifile.scanField("walker_weight_mode",weight_mode);
     732             :       }
     733         110 :       plumed_massert(weight_mode==(walkers_shared_bias_ ? "shared_path" : "local"),
     734             :                      "RESTART - walker weight mode mismatch; start a new bias history");
     735          49 :       if(walkers_shared_bias_) {
     736          28 :         unsigned old_walkers=0;
     737          48 :         ifile.scanField("shared_path_walkers",old_walkers);
     738          32 :         plumed_massert(old_walkers==NumWalkers_,"RESTART - shared-path bead count mismatch");
     739             :       }
     740             :       std::string old_biasfactor_str;
     741          45 :       ifile.scanField("biasfactor",old_biasfactor_str);
     742          45 :       if(old_biasfactor_str=="inf" || old_biasfactor_str=="INF") {
     743           1 :         if(!std::isinf(biasfactor_)) {
     744           0 :           log.printf(" +++ WARNING +++ previous bias factor was inf while now it is %g\n",biasfactor_);
     745             :         }
     746             :       } else {
     747             :         double old_biasfactor;
     748          44 :         ifile.scanField("biasfactor",old_biasfactor);
     749          44 :         if(std::abs(biasfactor_-old_biasfactor)>1e-6*biasfactor_) {
     750           0 :           log.printf(" +++ WARNING +++ previous bias factor was %g while now it is %g. diff = %g\n",old_biasfactor,biasfactor_,biasfactor_-old_biasfactor);
     751             :         }
     752             :       }
     753             :       double old_epsilon;
     754          45 :       ifile.scanField("epsilon",old_epsilon);
     755          45 :       if(std::abs(epsilon_-old_epsilon)>1e-6*epsilon_) {
     756           8 :         log.printf(" +++ WARNING +++ previous epsilon was %g while now it is %g. diff = %g\n",old_epsilon,epsilon_,epsilon_-old_epsilon);
     757             :       }
     758             :       double old_cutoff;
     759          45 :       ifile.scanField("kernel_cutoff",old_cutoff);
     760          45 :       if(std::abs(cutoff-old_cutoff)>1e-6*cutoff) {
     761           0 :         log.printf(" +++ WARNING +++ previous kernel_cutoff was %g while now it is %g. diff = %g\n",old_cutoff,cutoff,cutoff-old_cutoff);
     762             :       }
     763             :       double old_threshold;
     764          45 :       const double threshold=sqrt(threshold2_);
     765          45 :       ifile.scanField("compression_threshold",old_threshold);
     766          45 :       if(std::abs(threshold-old_threshold)>1e-6*threshold) {
     767           0 :         log.printf(" +++ WARNING +++ previous compression_threshold was %g while now it is %g. diff = %g\n",old_threshold,threshold,threshold-old_threshold);
     768             :       }
     769          45 :       if(stateRestart) {
     770          38 :         ifile.scanField("zed",Zed_);
     771          38 :         ifile.scanField("sum_weights",sum_weights_);
     772          38 :         ifile.scanField("sum_weights2",sum_weights2_);
     773          38 :         ifile.scanField("counter",counter_);
     774          38 :         if(adaptive_sigma_) {
     775           6 :           ifile.scanField("adaptive_counter",adaptive_counter_);
     776           6 :           if(NumWalkers_==1) {
     777           6 :             for(unsigned i=0; i<ncv_; i++) {
     778           8 :               ifile.scanField("sigma0_"+getPntrToArgument(i)->getName(),sigma0_[i]);
     779           8 :               ifile.scanField("av_cv_"+getPntrToArgument(i)->getName(),av_cv_[i]);
     780           8 :               ifile.scanField("av_M2_"+getPntrToArgument(i)->getName(),av_M2_[i]);
     781             :             }
     782             :           } else {
     783          12 :             for(unsigned w=0; w<NumWalkers_; w++)
     784          24 :               for(unsigned i=0; i<ncv_; i++) {
     785             :                 double tmp0,tmp1,tmp2;
     786          32 :                 const std::string arg_iw=getPntrToArgument(i)->getName()+"_"+std::to_string(w);
     787          16 :                 ifile.scanField("sigma0_"+arg_iw,tmp0);
     788          16 :                 ifile.scanField("av_cv_"+arg_iw,tmp1);
     789          16 :                 ifile.scanField("av_M2_"+arg_iw,tmp2);
     790          16 :                 if(w==walker_rank_) {
     791           8 :                   sigma0_[i]=tmp0;
     792           8 :                   av_cv_[i]=tmp1;
     793           8 :                   av_M2_[i]=tmp2;
     794             :                 }
     795             :               }
     796             :           }
     797             :         }
     798             :       }
     799         103 :       for(unsigned i=0; i<ncv_; i++) {
     800          58 :         if(getPntrToArgument(i)->isPeriodic()) {
     801             :           std::string arg_min,arg_max;
     802          26 :           getPntrToArgument(i)->getDomain(arg_min,arg_max);
     803             :           std::string file_min,file_max;
     804          26 :           ifile.scanField("min_"+getPntrToArgument(i)->getName(),file_min);
     805          26 :           ifile.scanField("max_"+getPntrToArgument(i)->getName(),file_max);
     806          26 :           plumed_massert(file_min==arg_min,"RESTART - mismatch between old and new ARG periodicity");
     807          26 :           plumed_massert(file_max==arg_max,"RESTART - mismatch between old and new ARG periodicity");
     808             :         }
     809             :       }
     810          45 :       if(stateRestart) {
     811             :         double time;
     812         220 :         while(ifile.scanField("time",time)) {
     813          72 :           std::vector<double> center(ncv_);
     814          72 :           std::vector<double> sigma(ncv_);
     815             :           double height;
     816         168 :           for(unsigned i=0; i<ncv_; i++) {
     817          96 :             ifile.scanField(getPntrToArgument(i)->getName(),center[i]);
     818             :           }
     819         168 :           for(unsigned i=0; i<ncv_; i++) {
     820         192 :             ifile.scanField("sigma_"+getPntrToArgument(i)->getName(),sigma[i]);
     821             :           }
     822          72 :           ifile.scanField("height",height);
     823          72 :           ifile.scanField();
     824          72 :           kernels_.emplace_back(height,center,sigma);
     825             :         }
     826          38 :         log.printf("    a total of %lu kernels where read\n",kernels_.size());
     827             :       } else {
     828           7 :         ifile.allowIgnoredFields(); //this allows for multiple restart, but without checking for consistency between them!
     829             :         double time;
     830         358 :         while(ifile.scanField("time",time)) {
     831         172 :           std::vector<double> center(ncv_);
     832         172 :           std::vector<double> sigma(ncv_);
     833             :           double height;
     834             :           double logweight;
     835         516 :           for(unsigned i=0; i<ncv_; i++) {
     836         344 :             ifile.scanField(getPntrToArgument(i)->getName(),center[i]);
     837             :           }
     838         516 :           for(unsigned i=0; i<ncv_; i++) {
     839         688 :             ifile.scanField("sigma_"+getPntrToArgument(i)->getName(),sigma[i]);
     840             :           }
     841         172 :           ifile.scanField("height",height);
     842         172 :           ifile.scanField("logweight",logweight);
     843         172 :           ifile.scanField();
     844         172 :           if(counter_==(1+walker_rank_) && adaptive_sigma_) {
     845             :             //the first kernel has sigma=s*sigma0, where s is the rescaling at the first deposition,
     846             :             //and height=w*prod_i(sigma0_i/sigma_i)=w/s^ncv, with w=1 for EXPLORE, so s can be recovered
     847             :             //(exactly, unless SIGMA_MIN was used)
     848           2 :             const double prod_ratio=mode::explore?height:height*std::exp(-logweight);
     849           2 :             const double s=std::pow(prod_ratio,-1./ncv_);
     850           6 :             for(unsigned i=0; i<ncv_; i++) {
     851           4 :               sigma0_[i]=sigma[i]/s;
     852             :             }
     853             :           }
     854         172 :           addKernel(height,center,sigma);
     855         172 :           const double weight=std::exp(logweight);
     856         172 :           sum_weights_+=weight; //this sum is slightly inaccurate, because when printing some precision is lost
     857         172 :           sum_weights2_+=weight*weight;
     858         172 :           counter_++;
     859             :         }
     860           7 :         KDEnorm_=mode::explore?counter_:sum_weights_;
     861           7 :         if(!no_Zed_) {
     862             :           //all kernels evaluated at all centers, with the kernel sum used for the bias (nlist_ is off here).
     863             :           //Each MPI process takes a contiguous share of the centers, split among the OpenMP threads
     864           4 :           updateSum();
     865           4 :           const unsigned size=kernels_.size();
     866           4 :           const unsigned share=(size+NumParallel_-1)/NumParallel_;
     867           4 :           const unsigned begin=std::min(rank_*share,size);
     868           4 :           const unsigned end=std::min(begin+share,size);
     869           4 :           double sum_uprob=0;
     870           4 :           #pragma omp parallel num_threads(NumOMP_)
     871             :           {
     872             :             std::vector<double> unused_der(ncv_); //derivatives are not needed
     873             :             #pragma omp for reduction(+:sum_uprob) nowait
     874             :             for(unsigned k=begin; k<end; k++) {
     875             :               sumKernels(kernels_[k].center,0,size,sum_uprob,unused_der);
     876             :             }
     877             :           }
     878           4 :           if(NumParallel_>1) {
     879           0 :             comm.Sum(sum_uprob);
     880             :           }
     881           4 :           Zed_=sum_uprob/KDEnorm_/kernels_.size();
     882           4 :           sum_outdated_=true; //the neighbor list, if any, is not set yet
     883             :         }
     884           7 :         log.printf("    a total of %llu kernels where read, and compressed to %lu\n",counter_-1,kernels_.size());
     885             :         convertKernelsToState=true;
     886             :       }
     887          45 :       ifile.reset(false);
     888          45 :       ifile.close();
     889          45 :       nlist_=tmp_nlist;
     890             :     } else { //same behaviour as METAD
     891           0 :       plumed_merror("RESTART requested, but file '"+restartFileName+"' was not found!\n  Set RESTART=NO or provide a restart file");
     892             :     }
     893          45 :     if(NumWalkers_>1) { //make sure that all walkers are doing the same thing
     894          38 :       const unsigned kernels_size=kernels_.size();
     895          38 :       std::vector<unsigned> all_kernels_size(NumWalkers_);
     896          38 :       if(comm.Get_rank()==0) {
     897          26 :         multi_sim_comm.Allgather(kernels_size,all_kernels_size);
     898             :       }
     899          38 :       comm.Bcast(all_kernels_size,0);
     900             :       bool same_number_of_kernels=true;
     901          92 :       for(unsigned w=1; w<NumWalkers_; w++)
     902          54 :         if(all_kernels_size[0]!=all_kernels_size[w]) {
     903             :           same_number_of_kernels=false;
     904             :         }
     905          38 :       plumed_massert(same_number_of_kernels,"RESTART - not all walkers are reading the same file!");
     906          38 :     }
     907         133 :   } else if(restartFileName.length()>0) {
     908           4 :     log.printf(" +++ WARNING +++ the provided STATE_RFILE will be ignored, since RESTART was not requested\n");
     909             :   }
     910             : 
     911             : //sync all walkers to avoid opening files before reading is over (see also METAD)
     912         113 :   comm.Barrier();
     913         113 :   if(comm.Get_rank()==0 && walkers_mpi) {
     914          52 :     multi_sim_comm.Barrier();
     915             :   }
     916             : 
     917             : //setup output kernels file
     918         113 :   kernelsOfile_.link(*this);
     919         113 :   if(NumWalkers_>1) {
     920          82 :     if(walker_rank_>0) {
     921             :       kernelsFileName="/dev/null";  //only first walker writes on file
     922             :     }
     923         164 :     kernelsOfile_.enforceSuffix("");
     924             :   }
     925         113 :   kernelsOfile_.open(kernelsFileName);
     926         113 :   if(fmt.length()>0) {
     927         190 :     kernelsOfile_.fmtField(" "+fmt);
     928             :   }
     929             :   kernelsOfile_.setHeavyFlush(); //do I need it?
     930             :   //define and set const fields
     931         113 :   if(walkers_shared_bias_) {
     932          48 :     kernelsOfile_.addConstantField("walker_weight_mode");
     933          48 :     kernelsOfile_.addConstantField("shared_path_walkers");
     934          96 :     kernelsOfile_.printField("walker_weight_mode","shared_path");
     935          96 :     kernelsOfile_.printField("shared_path_walkers",NumWalkers_);
     936             :   }
     937         113 :   kernelsOfile_.addConstantField("action");
     938         113 :   kernelsOfile_.addConstantField("biasfactor");
     939         113 :   kernelsOfile_.addConstantField("epsilon");
     940         113 :   kernelsOfile_.addConstantField("kernel_cutoff");
     941         113 :   kernelsOfile_.addConstantField("compression_threshold");
     942         255 :   for(unsigned i=0; i<ncv_; i++) {
     943         142 :     kernelsOfile_.setupPrintValue(getPntrToArgument(i));
     944             :   }
     945         226 :   kernelsOfile_.printField("action",getName()+"_kernels");
     946         113 :   kernelsOfile_.printField("biasfactor",biasfactor_);
     947         113 :   kernelsOfile_.printField("epsilon",epsilon_);
     948         113 :   kernelsOfile_.printField("kernel_cutoff",sqrt(cutoff2_));
     949         113 :   kernelsOfile_.printField("compression_threshold",sqrt(threshold2_));
     950             : 
     951             : //open file for storing state
     952         113 :   if(wStateStride_!=0) {
     953          85 :     stateOfile_.link(*this);
     954          85 :     if(NumWalkers_>1) {
     955          80 :       if(walker_rank_>0) {
     956             :         stateFileName="/dev/null";  //only first walker writes on file
     957             :       }
     958         160 :       stateOfile_.enforceSuffix("");
     959             :     }
     960          85 :     stateOfile_.open(stateFileName);
     961          85 :     if(fmt.length()>0) {
     962         170 :       stateOfile_.fmtField(" "+fmt);
     963             :     }
     964          85 :     if(convertKernelsToState) {
     965           2 :       dumpStateToFile();
     966             :     }
     967             :   }
     968             : 
     969             : //set initial old values
     970         113 :   KDEnorm_=mode::explore?counter_:sum_weights_;
     971         113 :   old_KDEnorm_=KDEnorm_;
     972             : 
     973             : //add and set output components
     974         226 :   addComponent("rct");
     975         113 :   componentIsNotPeriodic("rct");
     976         226 :   getPntrToComponent("rct")->set(kbt_*std::log(sum_weights_/counter_));
     977         226 :   addComponent("zed");
     978         113 :   componentIsNotPeriodic("zed");
     979         226 :   getPntrToComponent("zed")->set(Zed_);
     980         226 :   addComponent("neff");
     981         113 :   componentIsNotPeriodic("neff");
     982         226 :   getPntrToComponent("neff")->set(std::pow(1+sum_weights_,2)/(1+sum_weights2_));
     983         226 :   addComponent("nker");
     984         113 :   componentIsNotPeriodic("nker");
     985         113 :   getPntrToComponent("nker")->set(kernels_.size());
     986         113 :   if(calc_work_) {
     987          14 :     addComponent("work");
     988          14 :     componentIsNotPeriodic("work");
     989             :   }
     990         113 :   if(nlist_components_) {
     991          10 :     addComponent("nlker");
     992          10 :     componentIsNotPeriodic("nlker");
     993          10 :     addComponent("nlsteps");
     994          10 :     componentIsNotPeriodic("nlsteps");
     995             :   }
     996             : 
     997             : //printing some info
     998         113 :   log.printf("  temperature = %g\n",kbt_/kB);
     999         113 :   log.printf("  beta = %g\n",1./kbt_);
    1000         113 :   log.printf("  depositing new kernels with PACE = %u\n",stride_);
    1001         113 :   log.printf("  expected BARRIER is %g\n",barrier);
    1002         113 :   log.printf("  using target distribution with BIASFACTOR gamma = %g\n",biasfactor_);
    1003         113 :   if(std::isinf(biasfactor_)) {
    1004           4 :     log.printf("    (thus a uniform flat target distribution, no well-tempering)\n");
    1005             :   }
    1006         113 :   if(excluded_region_!=NULL) {
    1007           2 :     log.printf(" -- EXCLUDED_REGION: kernels will be deposited only when '%s' is equal to zero\n",excluded_region_->getName().c_str());
    1008             :   }
    1009         113 :   if(extra_biases_.size()>0) {
    1010          26 :     log.printf(" -- EXTRA_BIAS: ");
    1011          53 :     for(unsigned e=0; e<extra_biases_.size(); e++) {
    1012          27 :       log.printf("%s ",extra_biases_[e]->getName().c_str());
    1013             :     }
    1014          26 :     log.printf("will be reweighted\n");
    1015             :   }
    1016         113 :   if(adaptive_sigma_) {
    1017          21 :     log.printf("  adaptive SIGMA will be used, with ADAPTIVE_SIGMA_STRIDE = %u\n",adaptive_sigma_stride_);
    1018          21 :     unsigned x=std::ceil(adaptive_sigma_stride_/stride_);
    1019          21 :     log.printf("    thus the first x kernel depositions will be skipped, x = ADAPTIVE_SIGMA_STRIDE/PACE = %u\n",x);
    1020             :   } else {
    1021          92 :     log.printf("  kernels have initial SIGMA = ");
    1022         193 :     for(unsigned i=0; i<ncv_; i++) {
    1023         101 :       log.printf(" %g",sigma0_[i]);
    1024             :     }
    1025          92 :     log.printf("\n");
    1026             :   }
    1027         113 :   if(sigma_min_.size()>0) {
    1028           3 :     log.printf("  kernels have a SIGMA_MIN = ");
    1029           9 :     for(unsigned i=0; i<ncv_; i++) {
    1030           6 :       log.printf(" %g",sigma_min_[i]);
    1031             :     }
    1032           3 :     log.printf("\n");
    1033             :   }
    1034         113 :   if(fixed_sigma_) {
    1035          86 :     log.printf(" -- FIXED_SIGMA: sigma will not decrease as the simulation proceeds\n");
    1036             :   }
    1037         113 :   log.printf("  kernels are truncated with KERNELS_CUTOFF = %g\n",cutoff);
    1038         113 :   if(cutoff<3.5) {
    1039          82 :     log.printf(" +++ WARNING +++ probably kernels are truncated too much\n");
    1040             :   }
    1041         113 :   log.printf("  the value at cutoff is = %g\n",val_at_cutoff_);
    1042         113 :   log.printf("  regularization EPSILON = %g\n",epsilon_);
    1043         113 :   if(val_at_cutoff_>epsilon_*(1+1e-6)) {
    1044           7 :     log.printf(" +++ WARNING +++ the KERNEL_CUTOFF might be too small for the given EPSILON\n");
    1045             :   }
    1046         113 :   log.printf("  kernels will be compressed when closer than COMPRESSION_THRESHOLD = %g\n",sqrt(threshold2_));
    1047         113 :   if(threshold2_==0) {
    1048           0 :     log.printf(" +++ WARNING +++ kernels will never merge, expect slowdowns\n");
    1049             :   }
    1050         113 :   if(!recursive_merge_) {
    1051           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");
    1052             :   }
    1053         113 :   if(nlist_) {
    1054          90 :     log.printf("  kernels are summed using a neighbor list, with NLIST_PARAMETERS = %g (NLIST_OFF to disable it)\n",nlist_param_);
    1055          90 :     if(nlist_param.size()==2) {
    1056           4 :       log.printf(" +++ WARNING +++ the second of NLIST_PARAMETERS is not used anymore, the neighbor list is now exact\n");
    1057             :     }
    1058          90 :     if(nlist_flag) {
    1059           5 :       log.printf(" -- NLIST: this flag is not needed anymore, the neighbor list is used by default\n");
    1060             :     }
    1061             :   } else {
    1062          23 :     log.printf(" -- NLIST_OFF: all kernels are summed, without a neighbor list\n");
    1063             :   }
    1064         113 :   if(no_Zed_) {
    1065           6 :     log.printf(" -- NO_ZED: using fixed normalization factor = %g\n",Zed_);
    1066             :   }
    1067         113 :   if(wStateStride_>0) {
    1068          84 :     log.printf("  state checkpoints are written on file %s every %d MD steps\n",stateFileName.c_str(),wStateStride_);
    1069             :   }
    1070         113 :   if(wStateStride_==-1) {
    1071           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());
    1072             :   }
    1073         113 :   if(walkers_mpi) {
    1074          82 :     log.printf(" -- WALKERS_MPI: if multiple replicas are present, they will share the same bias via MPI\n");
    1075             :   }
    1076         113 :   if(NumWalkers_>1) {
    1077          82 :     log.printf("  using multiple walkers\n");
    1078          82 :     log.printf("    number of walkers: %u\n",NumWalkers_);
    1079          82 :     log.printf("    walker rank: %u\n",walker_rank_);
    1080             :   }
    1081         113 :   int mw_warning=0;
    1082         113 :   if(!walkers_mpi && comm.Get_rank()==0 && multi_sim_comm.Get_size()>(int)NumWalkers_) {
    1083           0 :     mw_warning=1;
    1084             :   }
    1085         113 :   comm.Bcast(mw_warning,0);
    1086         113 :   if(mw_warning) { //log.printf messes up with comm, so never use it without Bcast!
    1087           0 :     log.printf(" +++ WARNING +++ multiple replicas will NOT communicate unless the flag WALKERS_MPI is used\n");
    1088             :   }
    1089         113 :   if(NumParallel_>1) {
    1090          64 :     log.printf("  using multiple MPI processes per simulation: %u\n",NumParallel_);
    1091             :   }
    1092         113 :   if(NumOMP_>1) {
    1093         109 :     log.printf("  using multiple OpenMP threads per simulation: %u\n",NumOMP_);
    1094             :   }
    1095         113 :   if(serial) {
    1096           4 :     log.printf(" -- SERIAL: no loop parallelization, despite %d MPI processes and %u OpenMP threads available\n",comm.Get_size(),OpenMP::getNumThreads());
    1097             :   }
    1098         113 :   log.printf("  Bibliography: ");
    1099         113 :   log<<plumed.cite("M. Invernizzi and M. Parrinello, J. Phys. Chem. Lett. 11, 2731-2736 (2020)");
    1100          96 :   if(mode::explore || adaptive_sigma_) {
    1101          73 :     log<<plumed.cite("M. Invernizzi and M. Parrinello, J. Chem. Theory Comput. 18, 3988-3996 (2022)");
    1102             :   }
    1103         113 :   log.printf("\n");
    1104         574 : }
    1105             : 
    1106             : template <class mode>
    1107       65767 : void OPESmetad<mode>::calculate() {
    1108             : //get cv
    1109       65767 :   std::vector<double>& cv=cv_;
    1110      196605 :   for(unsigned i=0; i<ncv_; i++) {
    1111      130838 :     cv[i]=getArgument(i);
    1112             :   }
    1113             : 
    1114             : //check neighbor list
    1115       65767 :   if(nlist_) {
    1116       33486 :     nlist_steps_++;
    1117       33486 :     if(getExchangeStep()) {
    1118           0 :       nlist_update_=true;
    1119             :     } else {
    1120             :       //kernels outside the list cannot be within the cutoff as long as this displacement is within the skin
    1121             :       double norm2=0;
    1122       99890 :       for(unsigned i=0; i<ncv_; i++) {
    1123       66404 :         double diff=cv[i]-nlist_center_[i];
    1124       66404 :         diff-=period_[i]*std::nearbyint(diff*inv_period_[i]); //zero for non-periodic CVs
    1125       66404 :         const double dist_i=diff/nlist_sigma_min_[i];
    1126       66404 :         norm2+=dist_i*dist_i;
    1127             :       }
    1128       33486 :       if(norm2>nlist_skin2_) {
    1129       16652 :         nlist_update_=true;
    1130             :       }
    1131             :     }
    1132       33486 :     if(nlist_update_) {
    1133       17211 :       updateNlist(cv);
    1134             :     }
    1135             :   }
    1136             : 
    1137             : //set bias and forces
    1138       65767 :   std::vector<double>& der_prob=der_prob_;
    1139             :   std::fill(der_prob.begin(),der_prob.end(),0.);
    1140       65767 :   const double prob=getProbAndDerivatives(cv,der_prob);
    1141       65767 :   const double bias=kbt_*bias_prefactor_*std::log(prob/Zed_+epsilon_);
    1142       65767 :   setBias(bias);
    1143      196605 :   for(unsigned i=0; i<ncv_; i++) {
    1144      130838 :     setOutputForce(i,-kbt_*bias_prefactor_/(prob/Zed_+epsilon_)*der_prob[i]/Zed_);
    1145             :   }
    1146       65767 : }
    1147             : 
    1148             : template <class mode>
    1149       65445 : void OPESmetad<mode>::update() {
    1150       65445 :   if(isFirstStep_) { //same in MetaD, useful for restarts?
    1151          97 :     isFirstStep_=false;
    1152          97 :     return;
    1153             :   }
    1154             : 
    1155             : //update variance if adaptive sigma
    1156       65348 :   if(adaptive_sigma_) {
    1157       64642 :     adaptive_counter_++;
    1158       64642 :     unsigned tau=adaptive_sigma_stride_;
    1159       64642 :     if(adaptive_counter_<adaptive_sigma_stride_) {
    1160         455 :       tau=adaptive_counter_;
    1161             :     }
    1162      193876 :     for(unsigned i=0; i<ncv_; i++) {
    1163             :       //Welford's online algorithm for standard deviation
    1164      129234 :       const double cv_i=getArgument(i);
    1165      129234 :       const double diff_i=difference(i,av_cv_[i],cv_i);
    1166      129234 :       av_cv_[i]+=diff_i/tau; //exponentially decaying average
    1167      129234 :       av_M2_[i]+=diff_i*difference(i,av_cv_[i],cv_i);
    1168             :     }
    1169       64642 :     if(adaptive_counter_<adaptive_sigma_stride_ && counter_==1) { //counter_>1 if restarting
    1170             :       return;  //do not apply bias before having measured sigma
    1171             :     }
    1172             :   }
    1173             : 
    1174             : //do update
    1175       64911 :   if(getStep()%stride_==0 && (excluded_region_==NULL || excluded_region_->get()==0)) {
    1176       13233 :     old_KDEnorm_=KDEnorm_;
    1177       13233 :     delta_kernels_.clear();
    1178       13233 :     unsigned old_nker=kernels_.size();
    1179             : 
    1180             :     //get new kernel height
    1181       13233 :     double log_weight=getOutputQuantity(0)/kbt_; //first value is always the current bias
    1182       13317 :     for(unsigned e=0; e<extra_biases_.size(); e++) {
    1183          84 :       log_weight+=extra_biases_[e]->get()/kbt_;  //extra biases contribute to the weight
    1184             :     }
    1185       13233 :     if(walkers_shared_bias_) {
    1186         112 :       if(comm.Get_rank()==0) {
    1187          68 :         multi_sim_comm.Sum(log_weight);
    1188          68 :         log_weight/=NumWalkers_;
    1189             :       }
    1190         112 :       comm.Bcast(log_weight,0);
    1191             :     }
    1192       13233 :     double height=std::exp(log_weight);
    1193             : 
    1194             :     //update sum_weights_ and neff
    1195       13233 :     double sum_heights=height;
    1196       13233 :     double sum_heights2=height*height;
    1197       13233 :     if(NumWalkers_>1) {
    1198         302 :       if(comm.Get_rank()==0) {
    1199         226 :         multi_sim_comm.Sum(sum_heights);
    1200         226 :         multi_sim_comm.Sum(sum_heights2);
    1201             :       }
    1202         302 :       comm.Bcast(sum_heights,0);
    1203         302 :       comm.Bcast(sum_heights2,0);
    1204             :     }
    1205       13233 :     counter_+=NumWalkers_;
    1206       13233 :     sum_weights_+=sum_heights;
    1207       13233 :     sum_weights2_+=sum_heights2;
    1208       13233 :     const double neff=std::pow(1+sum_weights_,2)/(1+sum_weights2_); //adding 1 makes it more robust at the start
    1209       13233 :     getPntrToComponent("rct")->set(kbt_*std::log(sum_weights_/counter_));
    1210       13233 :     getPntrToComponent("neff")->set(neff);
    1211             :     if(mode::explore) {
    1212        6468 :       KDEnorm_=counter_;
    1213        6468 :       height=1; //plain KDE, bias reweight does not enter here
    1214             :     } else {
    1215        6765 :       KDEnorm_=sum_weights_;
    1216             :     }
    1217             : 
    1218             :     //if needed, rescale sigma and height
    1219       13233 :     std::vector<double> sigma=sigma0_;
    1220       13233 :     if(adaptive_sigma_) {
    1221        6478 :       const double factor=mode::explore?1:biasfactor_;
    1222       12901 :       if(counter_==1+NumWalkers_) { //first time only
    1223          38 :         for(unsigned i=0; i<ncv_; i++) {
    1224          25 :           av_M2_[i]*=biasfactor_;  //from unbiased, thus must be adjusted
    1225             :         }
    1226          38 :         for(unsigned i=0; i<ncv_; i++) {
    1227          25 :           sigma0_[i]=std::sqrt(av_M2_[i]/adaptive_counter_/factor);
    1228             :         }
    1229          13 :         if(sigma_min_.size()==0) {
    1230          38 :           for(unsigned i=0; i<ncv_; i++) {
    1231          25 :             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");
    1232             :           }
    1233             :         } else {
    1234           0 :           for(unsigned i=0; i<ncv_; i++) {
    1235           0 :             sigma0_[i]=std::max(sigma0_[i],sigma_min_[i]);
    1236             :           }
    1237             :         }
    1238             :       }
    1239       38698 :       for(unsigned i=0; i<ncv_; i++) {
    1240       25797 :         sigma[i]=std::sqrt(av_M2_[i]/adaptive_counter_/factor);
    1241             :       }
    1242       12901 :       if(sigma_min_.size()==0) {
    1243       38548 :         for(unsigned i=0; i<ncv_; i++) {
    1244       25697 :           if(sigma[i]<1e-6) {
    1245           0 :             log.printf("+++ WARNING +++ the ADAPTIVE SIGMA is suspiciously small, you should set a safe SIGMA_MIN. 1e-6 will be used here\n");
    1246           0 :             sigma[i]=1e-6;
    1247           0 :             sigma_min_.resize(ncv_,1e-6);
    1248             :           }
    1249             :         }
    1250             :       } else {
    1251         150 :         for(unsigned i=0; i<ncv_; i++) {
    1252         100 :           sigma[i]=std::max(sigma[i],sigma_min_[i]);
    1253             :         }
    1254             :       }
    1255             :     }
    1256       13233 :     if(!fixed_sigma_) {
    1257        6426 :       const double size=mode::explore?counter_:neff; //for EXPLORE neff is not relevant
    1258       12973 :       const double s_rescaling=std::pow(size*(ncv_+2.)/4.,-1./(4+ncv_));
    1259       38898 :       for(unsigned i=0; i<ncv_; i++) {
    1260       25925 :         sigma[i]*=s_rescaling;
    1261             :       }
    1262       12973 :       if(sigma_min_.size()>0) {
    1263         150 :         for(unsigned i=0; i<ncv_; i++) {
    1264         100 :           sigma[i]=std::max(sigma[i],sigma_min_[i]);
    1265             :         }
    1266             :       }
    1267             :     }
    1268             :     //the height should be divided by sqrt(2*pi)*sigma0_,
    1269             :     //but this overall factor would be canceled when dividing by Zed
    1270             :     //thus we skip it altogether, but keep any other sigma rescaling
    1271       39478 :     for(unsigned i=0; i<ncv_; i++) {
    1272       26245 :       height*=(sigma0_[i]/sigma[i]);
    1273             :     }
    1274             : 
    1275             :     //get new kernel center
    1276       13233 :     std::vector<double> center(ncv_);
    1277       39478 :     for(unsigned i=0; i<ncv_; i++) {
    1278       26245 :       center[i]=getArgument(i);
    1279             :     }
    1280             : 
    1281             :     //add new kernel(s)
    1282       13233 :     if(NumWalkers_==1) {
    1283       12931 :       addKernel(height,center,sigma,log_weight);
    1284             :     } else {
    1285         302 :       std::vector<double> all_height(NumWalkers_,0.0);
    1286         302 :       std::vector<double> all_center(NumWalkers_*ncv_,0.0);
    1287         302 :       std::vector<double> all_sigma(NumWalkers_*ncv_,0.0);
    1288         302 :       std::vector<double> all_logweight(NumWalkers_,0.0);
    1289         302 :       if(comm.Get_rank()==0) {
    1290         226 :         multi_sim_comm.Allgather(height,all_height);
    1291         226 :         multi_sim_comm.Allgather(center,all_center);
    1292         226 :         multi_sim_comm.Allgather(sigma,all_sigma);
    1293         226 :         multi_sim_comm.Allgather(log_weight,all_logweight);
    1294             :       }
    1295         302 :       comm.Bcast(all_height,0);
    1296         302 :       comm.Bcast(all_center,0);
    1297         302 :       comm.Bcast(all_sigma,0);
    1298         302 :       comm.Bcast(all_logweight,0);
    1299         302 :       if(nlist_) {
    1300             :         //gather all the nlist_index_, so merging can be done using it
    1301         238 :         std::vector<int> all_nlist_size(NumWalkers_);
    1302         238 :         if(comm.Get_rank()==0) {
    1303         194 :           all_nlist_size[walker_rank_]=nlist_index_.size();
    1304         194 :           multi_sim_comm.Sum(all_nlist_size);
    1305             :         }
    1306         238 :         comm.Bcast(all_nlist_size,0);
    1307             :         unsigned tot_size=0;
    1308         762 :         for(unsigned w=0; w<NumWalkers_; w++) {
    1309         524 :           tot_size+=all_nlist_size[w];
    1310             :         }
    1311         238 :         if(tot_size>0) {
    1312         210 :           std::vector<int> disp(NumWalkers_);
    1313         460 :           for(unsigned w=0; w<NumWalkers_-1; w++) {
    1314         250 :             disp[w+1]=disp[w]+all_nlist_size[w];
    1315             :           }
    1316         210 :           std::vector<unsigned> all_nlist_index(tot_size);
    1317         210 :           if(comm.Get_rank()==0) {
    1318         176 :             multi_sim_comm.Allgatherv(nlist_index_,all_nlist_index,&all_nlist_size[0],&disp[0]);
    1319             :           }
    1320         210 :           comm.Bcast(all_nlist_index,0);
    1321         210 :           std::set<unsigned> nlist_index_set(all_nlist_index.begin(),all_nlist_index.end()); //remove duplicates and sort
    1322         210 :           nlist_index_.assign(nlist_index_set.begin(),nlist_index_set.end());
    1323         210 :           sum_outdated_=true;
    1324         210 :         }
    1325             :       }
    1326         954 :       for(unsigned w=0; w<NumWalkers_; w++) {
    1327         652 :         std::vector<double> center_w(all_center.begin()+ncv_*w,all_center.begin()+ncv_*(w+1));
    1328         652 :         std::vector<double> sigma_w(all_sigma.begin()+ncv_*w,all_sigma.begin()+ncv_*(w+1));
    1329         652 :         addKernel(all_height[w],center_w,sigma_w,all_logweight[w]);
    1330             :       }
    1331             :     }
    1332       13233 :     getPntrToComponent("nker")->set(kernels_.size());
    1333       13233 :     if(nlist_) {
    1334        6779 :       if(nlist_components_) {
    1335         212 :         getPntrToComponent("nlker")->set(nlist_index_.size());
    1336             :       }
    1337        6779 :       if(NumWalkers_>1) { //the list is now the union of the walkers' lists, needed only for the merges
    1338         238 :         nlist_update_=true;
    1339             :       }
    1340             :     }
    1341             : 
    1342             :     //update Zed_
    1343       13233 :     if(!no_Zed_) {
    1344       13173 :       double sum_uprob=0;
    1345       13173 :       const double ks=kernels_.size(); //in double, since ks*ks overflows an unsigned for more than 65535 kernels
    1346       13173 :       const double ds=delta_kernels_.size();
    1347       13173 :       const bool few_kernels=(ks*ks<(3*ks*ds+2*ds*ds*NumParallel_+100)); //this seems reasonable, but is not rigorous...
    1348       13173 :       if(few_kernels) { //really needed? Probably is almost always false
    1349        4265 :         #pragma omp parallel num_threads(NumOMP_)
    1350             :         {
    1351             :           #pragma omp for reduction(+:sum_uprob) nowait
    1352             :           for(unsigned k=rank_; k<kernels_.size(); k+=NumParallel_)
    1353             :             for(unsigned kk=0; kk<kernels_.size(); kk++) {
    1354             :               sum_uprob+=evaluateKernel(kernels_[kk],kernels_[k].center);
    1355             :             }
    1356             :         }
    1357        4265 :         if(NumParallel_>1) {
    1358         202 :           comm.Sum(sum_uprob);
    1359             :         }
    1360             :       } else {
    1361             :         // Here instead of redoing the full summation, we add only the changes, knowing that
    1362             :         // uprob = old_uprob + delta_uprob
    1363             :         // and we also need to consider that in the new sum there are some novel centers and some disappeared ones
    1364             :         // All kernels are used: the summed ones without the neighbor list, otherwise the copy used to rebuild the list,
    1365             :         // since a merged kernel changes the sum also at centers outside the list.
    1366             :         // Each MPI process takes a contiguous share of them, split in blocks among the OpenMP threads
    1367        8908 :         const bool all=nlist_;
    1368        8908 :         if(all && nlist_all_outdated_) {
    1369        4483 :           updateNlistAll();
    1370             :         }
    1371        4425 :         if(!all && sum_outdated_) {
    1372        4425 :           updateSum();
    1373             :         }
    1374        8908 :         const unsigned size=all?nlist_all_height_.size():sum_height_.size();
    1375        8908 :         const unsigned share=(size+NumParallel_-1)/NumParallel_;
    1376        8908 :         const unsigned begin=std::min(rank_*share,size);
    1377        8908 :         const unsigned end=std::min(begin+share,size);
    1378             :         constexpr unsigned omp_block=64;
    1379        8908 :         double delta_sum_uprob=0;
    1380        8908 :         if(NumOMP_==1 || end-begin<2*NumOMP_*omp_block) {
    1381        4824 :           delta_sum_uprob=deltaSumUprob(begin,end,all);
    1382             :         } else {
    1383        4084 :           const unsigned nblocks=(end-begin+omp_block-1)/omp_block;
    1384        4084 :           #pragma omp parallel num_threads(NumOMP_)
    1385             :           {
    1386             :             #pragma omp for reduction(+:delta_sum_uprob) nowait
    1387             :             for(unsigned n=0; n<nblocks; n++) {
    1388             :               const unsigned b=begin+n*omp_block;
    1389             :               delta_sum_uprob+=deltaSumUprob(b,std::min(b+omp_block,end),all);
    1390             :             }
    1391             :           }
    1392             :         }
    1393        8908 :         if(NumParallel_>1) {
    1394           0 :           comm.Sum(delta_sum_uprob);
    1395             :         }
    1396        8908 :         #pragma omp parallel num_threads(NumOMP_)
    1397             :         {
    1398             :           #pragma omp for reduction(+:delta_sum_uprob)
    1399             :           for(unsigned d=0; d<delta_kernels_.size(); d++) {
    1400             :             for(unsigned dd=0; dd<delta_kernels_.size(); dd++) {
    1401             :               //now subtract the delta_uprob added before, but not needed
    1402             :               const double sign=delta_kernels_[d].height<0?-1:1;
    1403             :               delta_sum_uprob-=sign*evaluateKernel(delta_kernels_[dd],delta_kernels_[d].center);
    1404             :             }
    1405             :           }
    1406             :         }
    1407        8908 :         sum_uprob=Zed_*old_KDEnorm_*old_nker+delta_sum_uprob;
    1408             :       }
    1409       13173 :       Zed_=sum_uprob/KDEnorm_/kernels_.size();
    1410       26346 :       getPntrToComponent("zed")->set(Zed_);
    1411             :     }
    1412             : 
    1413             :     //calculate work if requested
    1414       13233 :     if(calc_work_) {
    1415          70 :       std::vector<double> dummy(ncv_); //derivatives are not actually needed
    1416          70 :       const double prob=getProbAndDerivatives(center,dummy);
    1417          70 :       const double new_bias=kbt_*bias_prefactor_*std::log(prob/Zed_+epsilon_);
    1418          70 :       work_+=new_bias-getOutputQuantity(0);
    1419         140 :       getPntrToComponent("work")->set(work_);
    1420             :     }
    1421             :   }
    1422             : 
    1423             : //dump state if requested
    1424       64911 :   if( (wStateStride_>0 && getStep()%wStateStride_==0) || (wStateStride_==-1 && getCPT()) ) {
    1425         194 :     dumpStateToFile();
    1426             :   }
    1427             : }
    1428             : 
    1429             : template <class mode>
    1430       65837 : double OPESmetad<mode>::getProbAndDerivatives(const std::vector<double>& cv,std::vector<double>& der_prob) {
    1431       65837 :   if(sum_outdated_) {
    1432       22160 :     updateSum();
    1433             :   }
    1434             :   //each MPI process sums a contiguous share of the kernels, split in blocks among the OpenMP threads
    1435       65837 :   const unsigned size=sum_height_.size();
    1436       65837 :   const unsigned share=(size+NumParallel_-1)/NumParallel_;
    1437       65837 :   const unsigned begin=std::min(rank_*share,size);
    1438       65837 :   const unsigned end=std::min(begin+share,size);
    1439             :   constexpr unsigned omp_block=64;
    1440       65837 :   double prob=0.0;
    1441       65837 :   if(NumOMP_==1 || end-begin<2*NumOMP_*omp_block) {
    1442       55629 :     sumKernels(cv,begin,end,prob,der_prob);
    1443             :   } else {
    1444       10208 :     const unsigned nblocks=(end-begin+omp_block-1)/omp_block;
    1445       10208 :     #pragma omp parallel num_threads(NumOMP_)
    1446             :     {
    1447             :       double omp_prob=0;
    1448             :       std::vector<double> omp_deriv(ncv_,0.);
    1449             :       #pragma omp for nowait
    1450             :       for(unsigned n=0; n<nblocks; n++) {
    1451             :         const unsigned b=begin+n*omp_block;
    1452             :         sumKernels(cv,b,std::min(b+omp_block,end),omp_prob,omp_deriv);
    1453             :       }
    1454             :       #pragma omp critical
    1455             :       {
    1456             :         prob+=omp_prob;
    1457             :         for(unsigned i=0; i<ncv_; i++) {
    1458             :           der_prob[i]+=omp_deriv[i];
    1459             :         }
    1460             :       }
    1461             :     }
    1462             :   }
    1463       65837 :   if(NumParallel_>1) {
    1464         596 :     comm.Sum(prob);
    1465         596 :     comm.Sum(der_prob);
    1466             :   }
    1467             : //normalize the estimate
    1468       65837 :   prob/=KDEnorm_;
    1469      196805 :   for(unsigned i=0; i<ncv_; i++) {
    1470      130968 :     der_prob[i]/=KDEnorm_;
    1471             :   }
    1472             : 
    1473       65837 :   return prob;
    1474             : }
    1475             : 
    1476             : template <class mode>
    1477       26589 : void OPESmetad<mode>::updateSum() {
    1478       26589 :   const unsigned size=nlist_?nlist_index_.size():kernels_.size();
    1479       26589 :   sum_center_.resize(ncv_*size);
    1480       26589 :   sum_inv_sigma_.resize(ncv_*size);
    1481       26589 :   sum_height_.resize(size);
    1482     1506913 :   for(unsigned k=0; k<size; k++) {
    1483     1480324 :     const kernel& G=kernels_[nlist_?nlist_index_[k]:k];
    1484     1480324 :     sum_height_[k]=G.height;
    1485     4440478 :     for(unsigned i=0; i<ncv_; i++) {
    1486     2960154 :       sum_center_[i*size+k]=G.center[i];
    1487     2960154 :       sum_inv_sigma_[i*size+k]=1./G.sigma[i];
    1488             :     }
    1489             :   }
    1490       26589 :   sum_outdated_=false;
    1491       26589 : }
    1492             : 
    1493             : template <class mode>
    1494      150980 : void OPESmetad<mode>::sumKernels(const std::vector<double>& cv,const unsigned begin,const unsigned end,double& prob,std::vector<double>& der_prob) const {
    1495             :   //adds the summed kernels from begin to end to prob and der_prob (not normalized).
    1496             :   //For a block of kernels, the squared distances are first computed for all of them, without branches,
    1497             :   //then only the few within the cutoff are evaluated. The result is the same as summing one kernel at a time
    1498      150980 :   constexpr unsigned block=128;
    1499             :   double norm2[block];
    1500      150980 :   const unsigned size=sum_height_.size();
    1501      303125 :   for(unsigned b=begin; b<end; b+=block) {
    1502      152145 :     const unsigned nb=std::min(block,end-b);
    1503     7348069 :     for(unsigned k=0; k<nb; k++) {
    1504     7195924 :       norm2[k]=0;
    1505             :     }
    1506      455898 :     for(unsigned i=0; i<ncv_; i++) {
    1507      303753 :       const double* center_i=&sum_center_[i*size+b];
    1508             :       const double* inv_sigma_i=&sum_inv_sigma_[i*size+b];
    1509      303753 :       const double cv_i=cv[i];
    1510      303753 :       if(period_[i]>0) {
    1511             :         const double period=period_[i];
    1512        2267 :         const double inv_period=inv_period_[i];
    1513             :         //unlike Tools::pbc, nearbyint has no branches: it is a single instruction on aarch64 and on x86 with SSE4.1
    1514       11124 :         for(unsigned k=0; k<nb; k++) {
    1515        8857 :           double diff=cv_i-center_i[k];
    1516        8857 :           diff-=period*std::nearbyint(diff*inv_period);
    1517        8857 :           const double dist=diff*inv_sigma_i[k];
    1518        8857 :           norm2[k]+=dist*dist;
    1519             :         }
    1520             :       } else {
    1521    14683840 :         for(unsigned k=0; k<nb; k++) {
    1522    14382354 :           const double dist=(cv_i-center_i[k])*inv_sigma_i[k];
    1523    14382354 :           norm2[k]+=dist*dist;
    1524             :         }
    1525             :       }
    1526             :     }
    1527     7348069 :     for(unsigned k=0; k<nb; k++) {
    1528     7195924 :       if(norm2[k]>=cutoff2_) {
    1529     6921066 :         continue;
    1530             :       }
    1531             :       //force-shifted kernel: with c=exp(-rc2/2), its value is G*(exp(-r2/2)-c*(1+(rc2-r2)/2))
    1532             :       //and its derivative -G*(exp(-r2/2)-c)*dr2/2, both going to zero at the cutoff
    1533      274858 :       const double height=sum_height_[b+k];
    1534      274858 :       const double der_val=height*(std::exp(-0.5*norm2[k])-val_at_cutoff_);
    1535      274858 :       prob+=der_val-height*val_at_cutoff_*0.5*(cutoff2_-norm2[k]);
    1536      823987 :       for(unsigned i=0; i<ncv_; i++) {
    1537      549129 :         double diff=cv[i]-sum_center_[i*size+b+k];
    1538      549129 :         if(period_[i]>0) {
    1539        4677 :           diff-=period_[i]*std::nearbyint(diff*inv_period_[i]);
    1540             :         }
    1541      549129 :         const double inv_sigma=sum_inv_sigma_[i*size+b+k];
    1542      549129 :         der_prob[i]-=diff*inv_sigma*inv_sigma*der_val; //NB: we accumulate the derivative into der_prob
    1543             :       }
    1544             :     }
    1545             :   }
    1546      150980 : }
    1547             : 
    1548             : template <class mode>
    1549       42952 : double OPESmetad<mode>::deltaSumUprob(const unsigned begin,const unsigned end,const bool all) const {
    1550             :   //change of the sum of all kernels evaluated at all centers due to the delta_kernels_, for the kernels from
    1551             :   //begin to end: the delta kernels evaluated at the centers of these kernels, plus these kernels evaluated at the
    1552             :   //centers of the delta kernels (minus, for those that are gone). The kernels are the summed ones, or with all=true
    1553             :   //the nlist_all_ ones. As in sumKernels(), the squared distances of a block of kernels are computed without
    1554             :   //branches, both in units of the delta kernel sigma and of their own sigma
    1555       42952 :   const std::vector<double>& center=all?nlist_all_center_:sum_center_;
    1556       42952 :   const std::vector<double>& inv_sigma=all?nlist_all_inv_sigma_:sum_inv_sigma_;
    1557       42952 :   const std::vector<double>& height=all?nlist_all_height_:sum_height_;
    1558       42952 :   constexpr unsigned block=128;
    1559             :   double norm2_d[block]; //in units of the delta kernel sigma
    1560             :   double norm2_k[block]; //in units of their own sigma
    1561       42952 :   const unsigned size=height.size();
    1562             :   double delta_sum_uprob=0;
    1563       86778 :   for(unsigned b=begin; b<end; b+=block) {
    1564       86772 :     const unsigned nb=std::min(block,end-b);
    1565      109692 :     for(const kernel& D : delta_kernels_) {
    1566     4185142 :       for(unsigned k=0; k<nb; k++) {
    1567     4119276 :         norm2_d[k]=0;
    1568     4119276 :         norm2_k[k]=0;
    1569             :       }
    1570      197598 :       for(unsigned i=0; i<ncv_; i++) {
    1571      131732 :         const double* center_i=&center[i*size+b];
    1572             :         const double* inv_sigma_i=&inv_sigma[i*size+b];
    1573      131732 :         const double c_i=D.center[i];
    1574      131732 :         const double inv_sigma_d=1./D.sigma[i];
    1575      131732 :         if(period_[i]>0) {
    1576             :           const double period=period_[i];
    1577         424 :           const double inv_period=inv_period_[i];
    1578        9964 :           for(unsigned k=0; k<nb; k++) {
    1579        9540 :             double diff=c_i-center_i[k];
    1580        9540 :             diff-=period*std::nearbyint(diff*inv_period);
    1581        9540 :             const double dist_d=diff*inv_sigma_d;
    1582        9540 :             const double dist_k=diff*inv_sigma_i[k];
    1583        9540 :             norm2_d[k]+=dist_d*dist_d;
    1584        9540 :             norm2_k[k]+=dist_k*dist_k;
    1585             :           }
    1586             :         } else {
    1587     8360320 :           for(unsigned k=0; k<nb; k++) {
    1588     8229012 :             const double diff=c_i-center_i[k];
    1589     8229012 :             const double dist_d=diff*inv_sigma_d;
    1590     8229012 :             const double dist_k=diff*inv_sigma_i[k];
    1591     8229012 :             norm2_d[k]+=dist_d*dist_d;
    1592     8229012 :             norm2_k[k]+=dist_k*dist_k;
    1593             :           }
    1594             :         }
    1595             :       }
    1596       65866 :       const double sign=D.height<0?-1:1; //take away contribution from kernels that are gone, and add the one from new ones
    1597     4185142 :       for(unsigned k=0; k<nb; k++) {
    1598     4119276 :         if(norm2_d[k]<cutoff2_) {
    1599       84875 :           delta_sum_uprob+=D.height*shiftedGaussian(norm2_d[k]);
    1600             :         }
    1601     4119276 :         if(norm2_k[k]<cutoff2_) {
    1602       84353 :           delta_sum_uprob+=sign*height[b+k]*shiftedGaussian(norm2_k[k]);
    1603             :         }
    1604             :       }
    1605             :     }
    1606             :   }
    1607       42952 :   return delta_sum_uprob;
    1608             : }
    1609             : 
    1610             : template <class mode>
    1611       13755 : void OPESmetad<mode>::addKernel(const double height,const std::vector<double>& center,const std::vector<double>& sigma) {
    1612       13755 :   sum_outdated_=true;
    1613       13755 :   nlist_all_outdated_=true;
    1614             :   bool no_match=true;
    1615       13755 :   if(threshold2_!=0) {
    1616       13755 :     unsigned taker_k=getMergeableKernel(center,kernels_.size());
    1617       13755 :     if(taker_k<kernels_.size()) {
    1618             :       no_match=false;
    1619        9766 :       delta_kernels_.emplace_back(-1*kernels_[taker_k].height,kernels_[taker_k].center,kernels_[taker_k].sigma);
    1620       19532 :       mergeKernels(kernels_[taker_k],kernel(height,center,sigma));
    1621        9766 :       delta_kernels_.push_back(kernels_[taker_k]);
    1622        9766 :       if(recursive_merge_) { //the overhead is worth it if it keeps low the total number of kernels
    1623             :         //the neighbor list holds all kernels within the cutoff of the current CV, thus also those that can
    1624             :         //merge with the new kernel, but the merged kernel has moved: search all kernels
    1625             :         unsigned giver_k=taker_k;
    1626        9715 :         taker_k=getMergeableKernel(kernels_[giver_k].center,giver_k,true);
    1627       10112 :         while(taker_k<kernels_.size()) {
    1628             :           delta_kernels_.pop_back();
    1629         397 :           delta_kernels_.emplace_back(-1*kernels_[taker_k].height,kernels_[taker_k].center,kernels_[taker_k].sigma);
    1630         397 :           if(taker_k>giver_k) { //saves time when erasing
    1631             :             std::swap(taker_k,giver_k);
    1632             :           }
    1633         397 :           mergeKernels(kernels_[taker_k],kernels_[giver_k]);
    1634         397 :           delta_kernels_.push_back(kernels_[taker_k]);
    1635         397 :           kernels_.erase(kernels_.begin()+giver_k);
    1636         397 :           if(nlist_) { //remove the giver from the sorted list, shift the indexes after it, and make sure the taker is listed
    1637         198 :             std::vector<unsigned> new_nlist_index;
    1638         198 :             new_nlist_index.reserve(nlist_index_.size()+1);
    1639        2711 :             for(unsigned k : nlist_index_) {
    1640        2513 :               if(k!=giver_k) {
    1641        2316 :                 new_nlist_index.push_back(k<giver_k?k:k-1);
    1642             :               }
    1643             :             }
    1644         198 :             const auto taker_pos=std::lower_bound(new_nlist_index.begin(),new_nlist_index.end(),taker_k); //taker_k<giver_k
    1645         198 :             if(taker_pos==new_nlist_index.end() || *taker_pos!=taker_k) { //possible, since all kernels are searched
    1646           2 :               new_nlist_index.insert(taker_pos,taker_k);
    1647             :             }
    1648             :             nlist_index_.swap(new_nlist_index);
    1649         198 :           }
    1650             :           giver_k=taker_k;
    1651         397 :           taker_k=getMergeableKernel(kernels_[giver_k].center,giver_k,true);
    1652             :         }
    1653             :       }
    1654             :     }
    1655             :   }
    1656             :   if(no_match) {
    1657        3989 :     kernels_.emplace_back(height,center,sigma);
    1658        3989 :     delta_kernels_.emplace_back(height,center,sigma);
    1659        3989 :     if(nlist_) {
    1660        1980 :       nlist_index_.push_back(kernels_.size()-1);
    1661             :     }
    1662             :   }
    1663       13755 : }
    1664             : 
    1665             : template <class mode>
    1666       13583 : void OPESmetad<mode>::addKernel(const double height,const std::vector<double>& center,const std::vector<double>& sigma,const double logweight) {
    1667       13583 :   addKernel(height,center,sigma);
    1668             : //write to file
    1669       13583 :   kernelsOfile_.printField("time",getTime());
    1670       40304 :   for(unsigned i=0; i<ncv_; i++) {
    1671       26721 :     kernelsOfile_.printField(getPntrToArgument(i),center[i]);
    1672             :   }
    1673       40304 :   for(unsigned i=0; i<ncv_; i++) {
    1674       53442 :     kernelsOfile_.printField("sigma_"+getPntrToArgument(i)->getName(),sigma[i]);
    1675             :   }
    1676       13583 :   kernelsOfile_.printField("height",height);
    1677       13583 :   kernelsOfile_.printField("logweight",logweight);
    1678       13583 :   kernelsOfile_.printField();
    1679       13583 : }
    1680             : 
    1681             : template <class mode>
    1682       23867 : unsigned OPESmetad<mode>::getMergeableKernel(const std::vector<double>& giver_center,const unsigned giver_k,const bool all_kernels) {
    1683             :   //returns kernels_.size() if no match is found
    1684             :   //with NLIST only the kernels in the list are searched, unless all_kernels is true
    1685       23867 :   const bool use_nlist=(nlist_ && !all_kernels);
    1686       23867 :   const unsigned size=use_nlist?nlist_index_.size():kernels_.size();
    1687       23867 :   unsigned min_k=kernels_.size();
    1688       23867 :   double min_norm2=threshold2_;
    1689       23867 :   #pragma omp parallel num_threads(NumOMP_)
    1690             :   {
    1691             :     unsigned min_k_omp = min_k;
    1692             :     double min_norm2_omp = threshold2_;
    1693             :     #pragma omp for nowait
    1694             :     for(unsigned nk=rank_; nk<size; nk+=NumParallel_) {
    1695             :       const unsigned k=use_nlist?nlist_index_[nk]:nk;
    1696             :       if(k==giver_k) { //a kernel should not be merged with itself
    1697             :         continue;
    1698             :       }
    1699             :       double norm2=0;
    1700             :       for(unsigned i=0; i<ncv_; i++) {
    1701             :         const double dist_i=difference(i,giver_center[i],kernels_[k].center[i])/kernels_[k].sigma[i];
    1702             :         norm2+=dist_i*dist_i;
    1703             :         if(norm2>=min_norm2_omp) {
    1704             :           break;
    1705             :         }
    1706             :       }
    1707             :       if(norm2<min_norm2_omp) {
    1708             :         min_norm2_omp=norm2;
    1709             :         min_k_omp=k;
    1710             :       }
    1711             :     }
    1712             :     #pragma omp critical
    1713             :     {
    1714             :       if(min_norm2_omp < min_norm2) {
    1715             :         min_norm2 = min_norm2_omp;
    1716             :         min_k = min_k_omp;
    1717             :       }
    1718             :     }
    1719             :   }
    1720       23867 :   if(NumParallel_>1) {
    1721         674 :     std::vector<double> all_min_norm2(NumParallel_);
    1722         674 :     std::vector<unsigned> all_min_k(NumParallel_);
    1723         674 :     comm.Allgather(min_norm2,all_min_norm2);
    1724         674 :     comm.Allgather(min_k,all_min_k);
    1725             :     const unsigned best=std::distance(std::begin(all_min_norm2),std::min_element(std::begin(all_min_norm2),std::end(all_min_norm2)));
    1726         674 :     min_k=all_min_k[best];
    1727         674 :   }
    1728       23867 :   return min_k;
    1729             : }
    1730             : 
    1731             : template <class mode>
    1732       17211 : void OPESmetad<mode>::updateNlist(const std::vector<double>& new_center) {
    1733       17211 :   if(kernels_.size()==0) { //no need to check for neighbors
    1734         339 :     return;
    1735             :   }
    1736             : 
    1737       16872 :   nlist_center_=new_center;
    1738             :   nlist_index_.clear();
    1739       16872 :   if(nlist_all_outdated_) {
    1740        2154 :     updateNlistAll();
    1741             :   }
    1742             :   //smallest sigma of all kernels: it bounds the distance of the kernels outside the list from below.
    1743             :   //Using only those outside would never trigger a rebuild when all kernels are in the list
    1744       16872 :   nlist_sigma_min_=nlist_all_sigma_min_;
    1745             :   //each MPI process lists a contiguous share of the kernels, split in blocks among the OpenMP threads
    1746       16872 :   const unsigned size=kernels_.size();
    1747       16872 :   const unsigned share=(size+NumParallel_-1)/NumParallel_;
    1748       16872 :   const unsigned begin=std::min(rank_*share,size);
    1749       16872 :   const unsigned end=std::min(begin+share,size);
    1750             :   constexpr unsigned omp_block=64;
    1751       16872 :   if(NumOMP_==1 || end-begin<2*NumOMP_*omp_block) {
    1752       15357 :     listKernels(begin,end,nlist_index_);
    1753             :   } else {
    1754        1515 :     const unsigned nblocks=(end-begin+omp_block-1)/omp_block;
    1755        1515 :     #pragma omp parallel num_threads(NumOMP_)
    1756             :     {
    1757             :       std::vector<unsigned> private_nlist_index;
    1758             :       #pragma omp for nowait
    1759             :       for(unsigned n=0; n<nblocks; n++) {
    1760             :         const unsigned b=begin+n*omp_block;
    1761             :         listKernels(b,std::min(b+omp_block,end),private_nlist_index);
    1762             :       }
    1763             :       #pragma omp critical
    1764             :       nlist_index_.insert(nlist_index_.end(),private_nlist_index.begin(),private_nlist_index.end());
    1765             :     }
    1766        1515 :     if(recursive_merge_) {
    1767        1515 :       std::sort(nlist_index_.begin(),nlist_index_.end());
    1768             :     }
    1769             :   }
    1770       16872 :   if(NumParallel_>1) {
    1771         212 :     std::vector<int> all_nlist_size(NumParallel_);
    1772         212 :     all_nlist_size[rank_]=nlist_index_.size();
    1773         212 :     comm.Sum(all_nlist_size);
    1774             :     unsigned tot_size=0;
    1775         636 :     for(unsigned r=0; r<NumParallel_; r++) {
    1776         424 :       tot_size+=all_nlist_size[r];
    1777             :     }
    1778         212 :     if(tot_size>0) {
    1779         212 :       std::vector<int> disp(NumParallel_);
    1780         424 :       for(unsigned r=0; r<NumParallel_-1; r++) {
    1781         212 :         disp[r+1]=disp[r]+all_nlist_size[r];
    1782             :       }
    1783         212 :       std::vector<unsigned> local_nlist_index=nlist_index_;
    1784         212 :       nlist_index_.resize(tot_size);
    1785         212 :       comm.Allgatherv(local_nlist_index,nlist_index_,&all_nlist_size[0],&disp[0]);
    1786         212 :       if(recursive_merge_) {
    1787         210 :         std::sort(nlist_index_.begin(),nlist_index_.end());
    1788             :       }
    1789         212 :     }
    1790             :   }
    1791       16872 :   if(nlist_components_) {
    1792         244 :     getPntrToComponent("nlker")->set(nlist_index_.size());
    1793         488 :     getPntrToComponent("nlsteps")->set(nlist_steps_);
    1794             :   }
    1795       16872 :   nlist_steps_=0;
    1796       16872 :   nlist_update_=false;
    1797       16872 :   sum_outdated_=true;
    1798             : }
    1799             : 
    1800             : template <class mode>
    1801        6637 : void OPESmetad<mode>::updateNlistAll() {
    1802             :   //all kernels with each CV in a contiguous array, as for the sum, refreshed only when they changed
    1803        6637 :   const unsigned size=kernels_.size();
    1804        6637 :   nlist_all_center_.resize(ncv_*size);
    1805        6637 :   nlist_all_inv_sigma_.resize(ncv_*size);
    1806        6637 :   nlist_all_height_.resize(size);
    1807        6637 :   nlist_all_sigma_min_.assign(ncv_,std::numeric_limits<double>::max());
    1808     1387165 :   for(unsigned k=0; k<size; k++) {
    1809     1380528 :     nlist_all_height_[k]=kernels_[k].height;
    1810     4141315 :     for(unsigned i=0; i<ncv_; i++) {
    1811     2760787 :       nlist_all_center_[i*size+k]=kernels_[k].center[i];
    1812     2760787 :       nlist_all_inv_sigma_[i*size+k]=1./kernels_[k].sigma[i];
    1813     2760787 :       nlist_all_sigma_min_[i]=std::min(nlist_all_sigma_min_[i],kernels_[k].sigma[i]);
    1814             :     }
    1815             :   }
    1816        6637 :   nlist_all_outdated_=false;
    1817        6637 : }
    1818             : 
    1819             : template <class mode>
    1820       30786 : void OPESmetad<mode>::listKernels(const unsigned begin,const unsigned end,std::vector<unsigned>& index) const {
    1821             :   //appends to index the kernels from begin to end within the neighbor list cutoff.
    1822             :   //As in sumKernels(), the squared distances of a block of kernels are computed without branches
    1823       30786 :   constexpr unsigned block=128;
    1824             :   double norm2[block];
    1825       30786 :   const unsigned size=kernels_.size();
    1826       61818 :   for(unsigned b=begin; b<end; b+=block) {
    1827       31032 :     const unsigned nb=std::min(block,end-b);
    1828     1510697 :     for(unsigned k=0; k<nb; k++) {
    1829     1479665 :       norm2[k]=0;
    1830             :     }
    1831       92930 :     for(unsigned i=0; i<ncv_; i++) {
    1832       61898 :       const double* center_i=&nlist_all_center_[i*size+b];
    1833             :       const double* inv_sigma_i=&nlist_all_inv_sigma_[i*size+b];
    1834       61898 :       const double c_i=nlist_center_[i];
    1835       61898 :       if(period_[i]>0) {
    1836             :         const double period=period_[i];
    1837         996 :         const double inv_period=inv_period_[i];
    1838        9987 :         for(unsigned k=0; k<nb; k++) {
    1839        8991 :           double diff=c_i-center_i[k];
    1840        8991 :           diff-=period*std::nearbyint(diff*inv_period);
    1841        8991 :           const double dist=diff*inv_sigma_i[k];
    1842        8991 :           norm2[k]+=dist*dist;
    1843             :         }
    1844             :       } else {
    1845     3010950 :         for(unsigned k=0; k<nb; k++) {
    1846     2950048 :           const double dist=(c_i-center_i[k])*inv_sigma_i[k];
    1847     2950048 :           norm2[k]+=dist*dist;
    1848             :         }
    1849             :       }
    1850             :     }
    1851     1510697 :     for(unsigned k=0; k<nb; k++) {
    1852     1479665 :       if(norm2[k]<=nlist_param_*cutoff2_) {
    1853       50260 :         index.push_back(b+k);
    1854             :       }
    1855             :     }
    1856             :   }
    1857       30786 : }
    1858             : 
    1859             : template <class mode>
    1860         196 : void OPESmetad<mode>::dumpStateToFile() {
    1861             : //gather adaptive sigma info if needed
    1862             : //doing this while writing to file can lead to misterious slowdowns
    1863         196 :   std::vector<double> all_sigma0;
    1864         196 :   std::vector<double> all_av_cv;
    1865         196 :   std::vector<double> all_av_M2;
    1866         196 :   if(adaptive_sigma_ && NumWalkers_>1) {
    1867          16 :     all_sigma0.resize(NumWalkers_*ncv_);
    1868          16 :     all_av_cv.resize(NumWalkers_*ncv_);
    1869          16 :     all_av_M2.resize(NumWalkers_*ncv_);
    1870          16 :     if(comm.Get_rank()==0) {
    1871          16 :       multi_sim_comm.Allgather(sigma0_,all_sigma0);
    1872          16 :       multi_sim_comm.Allgather(av_cv_,all_av_cv);
    1873          16 :       multi_sim_comm.Allgather(av_M2_,all_av_M2);
    1874             :     }
    1875          16 :     comm.Bcast(all_sigma0,0);
    1876          16 :     comm.Bcast(all_av_cv,0);
    1877          16 :     comm.Bcast(all_av_M2,0);
    1878             :   }
    1879             : 
    1880             : //only the first walker writes the state, the others would write on /dev/null,
    1881             : //and their fields would pile up since they never rewind
    1882         196 :   if(walker_rank_>0) {
    1883             :     return;
    1884             :   }
    1885             : //rewrite header or rewind file
    1886          94 :   if(storeOldStates_) {
    1887           8 :     stateOfile_.clearFields();
    1888             :   } else {
    1889          86 :     stateOfile_.rewind();
    1890             :   }
    1891             : //define fields
    1892          94 :   if(walkers_shared_bias_) {
    1893          50 :     stateOfile_.addConstantField("walker_weight_mode");
    1894          50 :     stateOfile_.addConstantField("shared_path_walkers");
    1895         100 :     stateOfile_.printField("walker_weight_mode","shared_path");
    1896         100 :     stateOfile_.printField("shared_path_walkers",NumWalkers_);
    1897             :   }
    1898          94 :   stateOfile_.addConstantField("action");
    1899          94 :   stateOfile_.addConstantField("biasfactor");
    1900          94 :   stateOfile_.addConstantField("epsilon");
    1901          94 :   stateOfile_.addConstantField("kernel_cutoff");
    1902          94 :   stateOfile_.addConstantField("compression_threshold");
    1903          94 :   stateOfile_.addConstantField("zed");
    1904          94 :   stateOfile_.addConstantField("sum_weights");
    1905          94 :   stateOfile_.addConstantField("sum_weights2");
    1906          94 :   stateOfile_.addConstantField("counter");
    1907          94 :   if(adaptive_sigma_) {
    1908          12 :     stateOfile_.addConstantField("adaptive_counter");
    1909          12 :     if(NumWalkers_==1) {
    1910          12 :       for(unsigned i=0; i<ncv_; i++) {
    1911          16 :         stateOfile_.addConstantField("sigma0_"+getPntrToArgument(i)->getName());
    1912          16 :         stateOfile_.addConstantField("av_cv_"+getPntrToArgument(i)->getName());
    1913          16 :         stateOfile_.addConstantField("av_M2_"+getPntrToArgument(i)->getName());
    1914             :       }
    1915             :     } else {
    1916          24 :       for(unsigned w=0; w<NumWalkers_; w++)
    1917          48 :         for(unsigned i=0; i<ncv_; i++) {
    1918          64 :           const std::string arg_iw=getPntrToArgument(i)->getName()+"_"+std::to_string(w);
    1919          32 :           stateOfile_.addConstantField("sigma0_"+arg_iw);
    1920          32 :           stateOfile_.addConstantField("av_cv_"+arg_iw);
    1921          64 :           stateOfile_.addConstantField("av_M2_"+arg_iw);
    1922             :         }
    1923             :     }
    1924             :   }
    1925             : //print fields
    1926         200 :   for(unsigned i=0; i<ncv_; i++) { //periodicity of CVs
    1927         106 :     stateOfile_.setupPrintValue(getPntrToArgument(i));
    1928             :   }
    1929         188 :   stateOfile_.printField("action",getName()+"_state");
    1930          94 :   stateOfile_.printField("biasfactor",biasfactor_);
    1931          94 :   stateOfile_.printField("epsilon",epsilon_);
    1932          94 :   stateOfile_.printField("kernel_cutoff",sqrt(cutoff2_));
    1933          94 :   stateOfile_.printField("compression_threshold",sqrt(threshold2_));
    1934          94 :   stateOfile_.printField("zed",Zed_);
    1935          94 :   stateOfile_.printField("sum_weights",sum_weights_);
    1936          94 :   stateOfile_.printField("sum_weights2",sum_weights2_);
    1937          94 :   stateOfile_.printField("counter",counter_);
    1938          94 :   if(adaptive_sigma_) {
    1939          12 :     stateOfile_.printField("adaptive_counter",adaptive_counter_);
    1940          12 :     if(NumWalkers_==1) {
    1941          12 :       for(unsigned i=0; i<ncv_; i++) {
    1942          16 :         stateOfile_.printField("sigma0_"+getPntrToArgument(i)->getName(),sigma0_[i]);
    1943          16 :         stateOfile_.printField("av_cv_"+getPntrToArgument(i)->getName(),av_cv_[i]);
    1944          16 :         stateOfile_.printField("av_M2_"+getPntrToArgument(i)->getName(),av_M2_[i]);
    1945             :       }
    1946             :     } else {
    1947          24 :       for(unsigned w=0; w<NumWalkers_; w++)
    1948          48 :         for(unsigned i=0; i<ncv_; i++) {
    1949          64 :           const std::string arg_iw=getPntrToArgument(i)->getName()+"_"+std::to_string(w);
    1950          32 :           stateOfile_.printField("sigma0_"+arg_iw,all_sigma0[w*ncv_+i]);
    1951          32 :           stateOfile_.printField("av_cv_"+arg_iw,all_av_cv[w*ncv_+i]);
    1952          64 :           stateOfile_.printField("av_M2_"+arg_iw,all_av_M2[w*ncv_+i]);
    1953             :         }
    1954             :     }
    1955             :   }
    1956             : //print kernels
    1957         291 :   for(unsigned k=0; k<kernels_.size(); k++) {
    1958         197 :     stateOfile_.printField("time",getTime()); //this is not very usefull
    1959         445 :     for(unsigned i=0; i<ncv_; i++) {
    1960         248 :       stateOfile_.printField(getPntrToArgument(i),kernels_[k].center[i]);
    1961             :     }
    1962         445 :     for(unsigned i=0; i<ncv_; i++) {
    1963         496 :       stateOfile_.printField("sigma_"+getPntrToArgument(i)->getName(),kernels_[k].sigma[i]);
    1964             :     }
    1965         197 :     stateOfile_.printField("height",kernels_[k].height);
    1966         197 :     stateOfile_.printField();
    1967             :   }
    1968             : //make sure file is written even if small
    1969          94 :   if(!storeOldStates_) {
    1970          86 :     stateOfile_.flush();
    1971             :   }
    1972             : }
    1973             : 
    1974             : template <class mode>
    1975      129921 : inline double OPESmetad<mode>::evaluateKernel(const kernel& G,const std::vector<double>& x) const {
    1976             :   //NB: cannot be a method of kernel class, because uses external variables (for cutoff)
    1977             :   double norm2=0;
    1978      253886 :   for(unsigned i=0; i<ncv_; i++) {
    1979      197869 :     const double dist_i=difference(i,G.center[i],x[i])/G.sigma[i];
    1980      197869 :     norm2+=dist_i*dist_i;
    1981      197869 :     if(norm2>=cutoff2_) {
    1982             :       return 0;
    1983             :     }
    1984             :   }
    1985       56017 :   return G.height*shiftedGaussian(norm2);
    1986             : }
    1987             : 
    1988             : template <class mode>
    1989      225245 : inline double OPESmetad<mode>::shiftedGaussian(const double norm2) const {
    1990             :   //force-shifted Gaussian at a squared distance norm2 within the cutoff
    1991      225245 :   return std::exp(-0.5*norm2)-val_at_cutoff_*(1+0.5*(cutoff2_-norm2));
    1992             : }
    1993             : 
    1994             : template <class mode>
    1995       10163 : inline void OPESmetad<mode>::mergeKernels(kernel& k1,const kernel& k2) {
    1996       10163 :   const double h=k1.height+k2.height;
    1997       30136 :   for(unsigned i=0; i<k1.center.size(); i++) {
    1998       19973 :     const bool isPeriodic_i=getPntrToArgument(i)->isPeriodic();
    1999       19973 :     if(isPeriodic_i) {
    2000         917 :       k1.center[i]=k2.center[i]+difference(i,k2.center[i],k1.center[i]);  //fix PBC
    2001             :     }
    2002       19973 :     const double w1=k1.height/h;
    2003       19973 :     const double w2=k2.height/h;
    2004       19973 :     const double delta=k2.center[i]-k1.center[i];
    2005       19973 :     const double c_i=k1.center[i]+w2*delta;
    2006             :     // Merge centered second moments. Subtracting E[x]^2 from E[x^2]
    2007             :     // loses the width for narrow kernels far from the CV origin and can
    2008             :     // produce zero or negative variance from entirely finite input.
    2009       19973 :     const double ss_i=w1*k1.sigma[i]*k1.sigma[i]+
    2010       19973 :                       w2*k2.sigma[i]*k2.sigma[i]+w1*w2*delta*delta;
    2011       19973 :     if(isPeriodic_i) {
    2012         917 :       k1.center[i]=bringBackInPbc(i,c_i);
    2013             :     } else {
    2014       19056 :       k1.center[i]=c_i;
    2015             :     }
    2016       19973 :     k1.sigma[i]=sqrt(ss_i);
    2017             :   }
    2018       10163 :   k1.height=h;
    2019       10163 : }
    2020             : 
    2021             : }
    2022             : }

Generated by: LCOV version 1.16