LCOV - code coverage report
Current view: top level - isdb - MetainferenceBase.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 843 1002 84.1 %
Date: 2026-03-30 13:16:06 Functions: 24 28 85.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2017-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "MetainferenceBase.h"
      23             : #include "tools/File.h"
      24             : #include <chrono>
      25             : #include <numeric>
      26             : 
      27             : #ifndef M_PI
      28             : #define M_PI           3.14159265358979323846
      29             : #endif
      30             : 
      31             : namespace PLMD {
      32             : namespace isdb {
      33             : 
      34         152 : void MetainferenceBase::registerKeywords( Keywords& keys ) {
      35         152 :   Action::registerKeywords(keys);
      36         152 :   ActionAtomistic::registerKeywords(keys);
      37         152 :   ActionWithValue::registerKeywords(keys);
      38         152 :   ActionWithArguments::registerKeywords(keys);
      39         152 :   componentsAreNotOptional(keys);
      40         152 :   keys.use("ARG");
      41         304 :   keys.addFlag("DOSCORE",false,"activate metainference");
      42         304 :   keys.addFlag("NOENSEMBLE",false,"don't perform any replica-averaging");
      43         304 :   keys.addFlag("REWEIGHT",false,"simple REWEIGHT using the ARG as energy");
      44         304 :   keys.add("optional","AVERAGING", "Stride for calculation of averaged weights and sigma_mean");
      45         304 :   keys.add("compulsory","NOISETYPE","MGAUSS","functional form of the noise (GAUSS,MGAUSS,OUTLIERS,MOUTLIERS,GENERIC)");
      46         304 :   keys.add("compulsory","LIKELIHOOD","GAUSS","the likelihood for the GENERIC metainference model, GAUSS or LOGN");
      47         304 :   keys.add("compulsory","DFTILDE","0.1","fraction of sigma_mean used to evolve ftilde");
      48         304 :   keys.addFlag("SCALEDATA",false,"Set to TRUE if you want to sample a scaling factor common to all values and replicas");
      49         304 :   keys.add("compulsory","SCALE0","1.0","initial value of the scaling factor");
      50         304 :   keys.add("compulsory","SCALE_PRIOR","FLAT","either FLAT or GAUSSIAN");
      51         304 :   keys.add("optional","SCALE_MIN","minimum value of the scaling factor");
      52         304 :   keys.add("optional","SCALE_MAX","maximum value of the scaling factor");
      53         304 :   keys.add("optional","DSCALE","maximum MC move of the scaling factor");
      54         304 :   keys.addFlag("ADDOFFSET",false,"Set to TRUE if you want to sample an offset common to all values and replicas");
      55         304 :   keys.add("compulsory","OFFSET0","0.0","initial value of the offset");
      56         304 :   keys.add("compulsory","OFFSET_PRIOR","FLAT","either FLAT or GAUSSIAN");
      57         304 :   keys.add("optional","OFFSET_MIN","minimum value of the offset");
      58         304 :   keys.add("optional","OFFSET_MAX","maximum value of the offset");
      59         304 :   keys.add("optional","DOFFSET","maximum MC move of the offset");
      60         304 :   keys.add("optional","REGRES_ZERO","stride for regression with zero offset");
      61         304 :   keys.add("compulsory","SIGMA0","1.0","initial value of the uncertainty parameter");
      62         304 :   keys.add("compulsory","SIGMA_MIN","0.0","minimum value of the uncertainty parameter");
      63         304 :   keys.add("compulsory","SIGMA_MAX","10.","maximum value of the uncertainty parameter");
      64         304 :   keys.add("optional","DSIGMA","maximum MC move of the uncertainty parameter");
      65         304 :   keys.add("compulsory","OPTSIGMAMEAN","NONE","Set to NONE/SEM to manually set sigma mean, or to estimate it on the fly");
      66         304 :   keys.add("optional","SIGMA_MEAN0","starting value for the uncertainty in the mean estimate");
      67         304 :   keys.add("optional","SIGMA_MAX_STEPS", "Number of steps used to optimise SIGMA_MAX, before that the SIGMA_MAX value is used");
      68         304 :   keys.add("optional","TEMP","the system temperature - this is only needed if code doesn't pass the temperature to plumed");
      69         304 :   keys.add("optional","MC_STEPS","number of MC steps");
      70         304 :   keys.add("optional","MC_CHUNKSIZE","MC chunksize");
      71         304 :   keys.add("optional","STATUS_FILE","write a file with all the data useful for restart/continuation of Metainference");
      72         304 :   keys.add("optional","FMT","specify format for STATUS files (useful for decrease the number of digits in regtests)");
      73         304 :   keys.add("compulsory","WRITE_STRIDE","10000","write the status to a file every N steps, this can be used for restart/continuation");
      74         304 :   keys.add("optional","SELECTOR","name of selector");
      75         304 :   keys.add("optional","NSELECT","range of values for selector [0, N-1]");
      76         152 :   keys.use("RESTART");
      77         304 :   keys.addOutputComponent("score",        "default",      "the Metainference score");
      78         304 :   keys.addOutputComponent("sigma",        "default",      "uncertainty parameter");
      79         304 :   keys.addOutputComponent("sigmaMean",    "default",      "uncertainty in the mean estimate");
      80         304 :   keys.addOutputComponent("neff",         "default",      "effective number of replicas");
      81         304 :   keys.addOutputComponent("acceptSigma",  "default",      "MC acceptance for sigma values");
      82         304 :   keys.addOutputComponent("acceptScale",  "SCALEDATA",    "MC acceptance for scale value");
      83         304 :   keys.addOutputComponent("acceptFT",     "GENERIC",      "MC acceptance for general metainference f tilde value");
      84         304 :   keys.addOutputComponent("weight",       "REWEIGHT",     "weights of the weighted average");
      85         304 :   keys.addOutputComponent("biasDer",      "REWEIGHT",     "derivatives with respect to the bias");
      86         304 :   keys.addOutputComponent("scale",        "SCALEDATA",    "scale parameter");
      87         304 :   keys.addOutputComponent("offset",       "ADDOFFSET",    "offset parameter");
      88         304 :   keys.addOutputComponent("ftilde",       "GENERIC",      "ensemble average estimator");
      89         152 : }
      90             : 
      91         120 : MetainferenceBase::MetainferenceBase(const ActionOptions&ao):
      92             :   Action(ao),
      93             :   ActionAtomistic(ao),
      94             :   ActionWithArguments(ao),
      95             :   ActionWithValue(ao),
      96         120 :   doscore_(false),
      97         120 :   write_stride_(0),
      98         120 :   narg(0),
      99         120 :   doscale_(false),
     100         120 :   scale_(1.),
     101         120 :   scale_mu_(0),
     102         120 :   scale_min_(1),
     103         120 :   scale_max_(-1),
     104         120 :   Dscale_(-1),
     105         120 :   dooffset_(false),
     106         120 :   offset_(0.),
     107         120 :   offset_mu_(0),
     108         120 :   offset_min_(1),
     109         120 :   offset_max_(-1),
     110         120 :   Doffset_(-1),
     111         120 :   doregres_zero_(false),
     112         120 :   nregres_zero_(0),
     113         120 :   Dftilde_(0.1),
     114         120 :   random(3),
     115         120 :   MCsteps_(1),
     116         120 :   MCaccept_(0),
     117         120 :   MCacceptScale_(0),
     118         120 :   MCacceptFT_(0),
     119         120 :   MCtrial_(0),
     120         120 :   MCchunksize_(0),
     121         120 :   firstTime(true),
     122         120 :   do_reweight_(false),
     123         120 :   do_optsigmamean_(0),
     124         120 :   nsel_(1),
     125         120 :   iselect(0),
     126         120 :   optsigmamean_stride_(0),
     127         120 :   N_optimized_step_(0),
     128         120 :   optimized_step_(0),
     129         120 :   sigmamax_opt_done_(false),
     130         120 :   decay_w_(1.) {
     131         120 :   parseFlag("DOSCORE", doscore_);
     132             : 
     133         120 :   bool noensemble = false;
     134         120 :   parseFlag("NOENSEMBLE", noensemble);
     135             : 
     136             :   // set up replica stuff
     137         120 :   master = (comm.Get_rank()==0);
     138         120 :   if(master) {
     139          85 :     nrep_    = multi_sim_comm.Get_size();
     140          85 :     replica_ = multi_sim_comm.Get_rank();
     141          85 :     if(noensemble) {
     142           0 :       nrep_ = 1;
     143             :     }
     144             :   } else {
     145          35 :     nrep_    = 0;
     146          35 :     replica_ = 0;
     147             :   }
     148         120 :   comm.Sum(&nrep_,1);
     149         120 :   comm.Sum(&replica_,1);
     150             : 
     151         120 :   parse("SELECTOR", selector_);
     152         240 :   parse("NSELECT", nsel_);
     153             :   // do checks
     154         120 :   if(selector_.length()>0 && nsel_<=1) {
     155           0 :     error("With SELECTOR active, NSELECT must be greater than 1");
     156             :   }
     157         120 :   if(selector_.length()==0 && nsel_>1) {
     158           0 :     error("With NSELECT greater than 1, you must specify SELECTOR");
     159             :   }
     160             : 
     161             :   // initialise firstTimeW
     162         120 :   firstTimeW.resize(nsel_, true);
     163             : 
     164             :   // reweight implies a different number of arguments (the latest one must always be the bias)
     165         120 :   parseFlag("REWEIGHT", do_reweight_);
     166         120 :   if(do_reweight_&&getNumberOfArguments()!=1) {
     167           0 :     error("To REWEIGHT one must provide one single bias as an argument");
     168             :   }
     169         120 :   if(do_reweight_&&nrep_<2) {
     170           0 :     error("REWEIGHT can only be used in parallel with 2 or more replicas");
     171             :   }
     172         120 :   if(!getRestart()) {
     173         220 :     average_weights_.resize(nsel_, std::vector<double> (nrep_, 1./static_cast<double>(nrep_)));
     174             :   } else {
     175          20 :     average_weights_.resize(nsel_, std::vector<double> (nrep_, 0.));
     176             :   }
     177             : 
     178         120 :   unsigned averaging=0;
     179         120 :   parse("AVERAGING", averaging);
     180         120 :   if(averaging>0) {
     181           1 :     decay_w_ = 1./static_cast<double> (averaging);
     182           1 :     optsigmamean_stride_ = averaging;
     183             :   }
     184             : 
     185             :   std::string stringa_noise;
     186         240 :   parse("NOISETYPE",stringa_noise);
     187         120 :   if(stringa_noise=="GAUSS") {
     188           9 :     noise_type_ = GAUSS;
     189         111 :   } else if(stringa_noise=="MGAUSS") {
     190          90 :     noise_type_ = MGAUSS;
     191          21 :   } else if(stringa_noise=="OUTLIERS") {
     192          10 :     noise_type_ = OUTLIERS;
     193          11 :   } else if(stringa_noise=="MOUTLIERS") {
     194           8 :     noise_type_ = MOUTLIERS;
     195           3 :   } else if(stringa_noise=="GENERIC") {
     196           3 :     noise_type_ = GENERIC;
     197             :   } else {
     198           0 :     error("Unknown noise type!");
     199             :   }
     200             : 
     201         120 :   if(noise_type_== GENERIC) {
     202             :     std::string stringa_like;
     203           6 :     parse("LIKELIHOOD",stringa_like);
     204           3 :     if(stringa_like=="GAUSS") {
     205           2 :       gen_likelihood_ = LIKE_GAUSS;
     206           1 :     } else if(stringa_like=="LOGN") {
     207           1 :       gen_likelihood_ = LIKE_LOGN;
     208             :     } else {
     209           0 :       error("Unknown likelihood type!");
     210             :     }
     211             : 
     212           6 :     parse("DFTILDE",Dftilde_);
     213             :   }
     214             : 
     215         120 :   parse("WRITE_STRIDE",write_stride_);
     216         240 :   parse("STATUS_FILE",status_file_name_);
     217         120 :   if(status_file_name_=="") {
     218         240 :     status_file_name_ = "MISTATUS"+getLabel();
     219             :   } else {
     220           0 :     status_file_name_ = status_file_name_+getLabel();
     221             :   }
     222             : 
     223             :   std::string stringa_optsigma;
     224         240 :   parse("OPTSIGMAMEAN", stringa_optsigma);
     225         120 :   if(stringa_optsigma=="NONE") {
     226         115 :     do_optsigmamean_=0;
     227           5 :   } else if(stringa_optsigma=="SEM") {
     228           4 :     do_optsigmamean_=1;
     229           1 :   } else if(stringa_optsigma=="SEM_MAX") {
     230           0 :     do_optsigmamean_=2;
     231             :   }
     232             : 
     233         120 :   unsigned aver_max_steps=0;
     234         120 :   parse("SIGMA_MAX_STEPS", aver_max_steps);
     235         120 :   if(aver_max_steps==0&&do_optsigmamean_==2) {
     236           0 :     aver_max_steps=averaging*2000;
     237             :   }
     238         120 :   if(aver_max_steps>0&&do_optsigmamean_<2) {
     239           0 :     error("SIGMA_MAX_STEPS can only be used together with OPTSIGMAMEAN=SEM_MAX");
     240             :   }
     241         120 :   if(aver_max_steps>0&&do_optsigmamean_==2) {
     242           0 :     N_optimized_step_=aver_max_steps;
     243             :   }
     244         120 :   if(aver_max_steps>0&&aver_max_steps<averaging) {
     245           0 :     error("SIGMA_MAX_STEPS must be greater than AVERAGING");
     246             :   }
     247             : 
     248             :   std::vector<double> read_sigma_mean_;
     249         120 :   parseVector("SIGMA_MEAN0",read_sigma_mean_);
     250         120 :   if(do_optsigmamean_==0 && read_sigma_mean_.size()==0 && !getRestart() && doscore_) {
     251           0 :     error("If you don't use OPTSIGMAMEAN and you are not RESTARTING then you MUST SET SIGMA_MEAN0");
     252             :   }
     253             : 
     254         120 :   if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
     255         101 :     if(read_sigma_mean_.size()>0) {
     256          25 :       sigma_mean2_.resize(read_sigma_mean_.size());
     257          50 :       for(unsigned i=0; i<read_sigma_mean_.size(); i++) {
     258          25 :         sigma_mean2_[i]=read_sigma_mean_[i]*read_sigma_mean_[i];
     259             :       }
     260             :     } else {
     261          76 :       sigma_mean2_.resize(1,0.000001);
     262             :     }
     263             :   } else {
     264          19 :     if(read_sigma_mean_.size()==1) {
     265          19 :       sigma_mean2_.resize(1, read_sigma_mean_[0]*read_sigma_mean_[0]);
     266           0 :     } else if(read_sigma_mean_.size()==0) {
     267           0 :       sigma_mean2_.resize(1, 0.000001);
     268             :     } else {
     269           0 :       error("If you want to use more than one SIGMA_MEAN0 you should use NOISETYPE=MGAUSS|MOUTLIERS");
     270             :     }
     271             :   }
     272             : 
     273         120 :   parseFlag("SCALEDATA", doscale_);
     274         120 :   if(doscale_) {
     275             :     std::string stringa_noise;
     276          24 :     parse("SCALE_PRIOR",stringa_noise);
     277          12 :     if(stringa_noise=="GAUSSIAN") {
     278           0 :       scale_prior_ = SC_GAUSS;
     279          12 :     } else if(stringa_noise=="FLAT") {
     280          12 :       scale_prior_ = SC_FLAT;
     281             :     } else {
     282           0 :       error("Unknown SCALE_PRIOR type!");
     283             :     }
     284          12 :     parse("SCALE0",scale_);
     285          12 :     parse("DSCALE",Dscale_);
     286          12 :     if(Dscale_<0.) {
     287           0 :       error("DSCALE must be set when using SCALEDATA");
     288             :     }
     289          12 :     if(scale_prior_==SC_GAUSS) {
     290           0 :       scale_mu_=scale_;
     291             :     } else {
     292          12 :       parse("SCALE_MIN",scale_min_);
     293          12 :       parse("SCALE_MAX",scale_max_);
     294          12 :       if(scale_max_<scale_min_) {
     295           0 :         error("SCALE_MAX and SCALE_MIN must be set when using SCALE_PRIOR=FLAT");
     296             :       }
     297             :     }
     298             :   }
     299             : 
     300         120 :   parseFlag("ADDOFFSET", dooffset_);
     301         120 :   if(dooffset_) {
     302             :     std::string stringa_noise;
     303          12 :     parse("OFFSET_PRIOR",stringa_noise);
     304           6 :     if(stringa_noise=="GAUSSIAN") {
     305           0 :       offset_prior_ = SC_GAUSS;
     306           6 :     } else if(stringa_noise=="FLAT") {
     307           6 :       offset_prior_ = SC_FLAT;
     308             :     } else {
     309           0 :       error("Unknown OFFSET_PRIOR type!");
     310             :     }
     311           6 :     parse("OFFSET0",offset_);
     312           6 :     parse("DOFFSET",Doffset_);
     313           6 :     if(offset_prior_==SC_GAUSS) {
     314           0 :       offset_mu_=offset_;
     315           0 :       if(Doffset_<0.) {
     316           0 :         error("DOFFSET must be set when using OFFSET_PRIOR=GAUSS");
     317             :       }
     318             :     } else {
     319           6 :       parse("OFFSET_MIN",offset_min_);
     320           6 :       parse("OFFSET_MAX",offset_max_);
     321           6 :       if(Doffset_<0) {
     322           0 :         Doffset_ = 0.05*(offset_max_ - offset_min_);
     323             :       }
     324           6 :       if(offset_max_<offset_min_) {
     325           0 :         error("OFFSET_MAX and OFFSET_MIN must be set when using OFFSET_PRIOR=FLAT");
     326             :       }
     327             :     }
     328             :   }
     329             : 
     330             :   // regression with zero intercept
     331         120 :   parse("REGRES_ZERO", nregres_zero_);
     332         120 :   if(nregres_zero_>0) {
     333             :     // set flag
     334           1 :     doregres_zero_=true;
     335             :     // check if already sampling scale and offset
     336           1 :     if(doscale_) {
     337           0 :       error("REGRES_ZERO and SCALEDATA are mutually exclusive");
     338             :     }
     339           1 :     if(dooffset_) {
     340           0 :       error("REGRES_ZERO and ADDOFFSET are mutually exclusive");
     341             :     }
     342             :   }
     343             : 
     344             :   std::vector<double> readsigma;
     345         120 :   parseVector("SIGMA0",readsigma);
     346         120 :   if((noise_type_!=MGAUSS&&noise_type_!=MOUTLIERS&&noise_type_!=GENERIC)&&readsigma.size()>1) {
     347           0 :     error("If you want to use more than one SIGMA you should use NOISETYPE=MGAUSS|MOUTLIERS|GENERIC");
     348             :   }
     349         120 :   if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
     350         101 :     sigma_.resize(readsigma.size());
     351         101 :     sigma_=readsigma;
     352             :   } else {
     353          19 :     sigma_.resize(1, readsigma[0]);
     354             :   }
     355             : 
     356             :   std::vector<double> readsigma_min;
     357         120 :   parseVector("SIGMA_MIN",readsigma_min);
     358         120 :   if((noise_type_!=MGAUSS&&noise_type_!=MOUTLIERS&&noise_type_!=GENERIC)&&readsigma_min.size()>1) {
     359           0 :     error("If you want to use more than one SIGMA you should use NOISETYPE=MGAUSS|MOUTLIERS|GENERIC");
     360             :   }
     361         120 :   if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
     362         101 :     sigma_min_.resize(readsigma_min.size());
     363         101 :     sigma_min_=readsigma_min;
     364             :   } else {
     365          19 :     sigma_min_.resize(1, readsigma_min[0]);
     366             :   }
     367             : 
     368             :   std::vector<double> readsigma_max;
     369         120 :   parseVector("SIGMA_MAX",readsigma_max);
     370         120 :   if((noise_type_!=MGAUSS&&noise_type_!=MOUTLIERS&&noise_type_!=GENERIC)&&readsigma_max.size()>1) {
     371           0 :     error("If you want to use more than one SIGMA you should use NOISETYPE=MGAUSS|MOUTLIERS|GENERIC");
     372             :   }
     373         120 :   if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
     374         101 :     sigma_max_.resize(readsigma_max.size());
     375         101 :     sigma_max_=readsigma_max;
     376             :   } else {
     377          19 :     sigma_max_.resize(1, readsigma_max[0]);
     378             :   }
     379             : 
     380         120 :   if(sigma_max_.size()!=sigma_min_.size()) {
     381           0 :     error("The number of values for SIGMA_MIN and SIGMA_MAX must be the same");
     382             :   }
     383             : 
     384             :   std::vector<double> read_dsigma;
     385         120 :   parseVector("DSIGMA",read_dsigma);
     386         120 :   if((noise_type_!=MGAUSS&&noise_type_!=MOUTLIERS&&noise_type_!=GENERIC)&&readsigma_max.size()>1) {
     387           0 :     error("If you want to use more than one SIGMA you should use NOISETYPE=MGAUSS|MOUTLIERS|GENERIC");
     388             :   }
     389         120 :   if(read_dsigma.size()>0) {
     390          44 :     Dsigma_.resize(read_dsigma.size());
     391          44 :     Dsigma_=read_dsigma;
     392             :   } else {
     393          76 :     Dsigma_.resize(sigma_max_.size(), -1.);
     394             :     /* in this case Dsigma is initialised after reading the restart file if present */
     395             :   }
     396             : 
     397         120 :   parse("FMT",fmt_);
     398             : 
     399             :   // monte carlo stuff
     400         120 :   parse("MC_STEPS",MCsteps_);
     401         120 :   parse("MC_CHUNKSIZE", MCchunksize_);
     402             :   // get temperature
     403         120 :   double temp=0.0;
     404         120 :   parse("TEMP",temp);
     405         120 :   if(temp>0.0) {
     406          44 :     kbt_=plumed.getAtoms().getKBoltzmann()*temp;
     407             :   } else {
     408          76 :     kbt_=plumed.getAtoms().getKbT();
     409             :   }
     410         120 :   if(kbt_==0.0&&doscore_) {
     411           0 :     error("Unless the MD engine passes the temperature to plumed, you must specify it using TEMP");
     412             :   }
     413             : 
     414             :   // initialize random seed
     415             :   unsigned iseed;
     416         120 :   if(master) {
     417          85 :     auto ts = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now()).time_since_epoch().count();
     418          85 :     iseed = static_cast<unsigned>(ts)+replica_;
     419             :   } else {
     420          35 :     iseed = 0;
     421             :   }
     422         120 :   comm.Sum(&iseed, 1);
     423             :   // this is used for ftilde and sigma both the move and the acceptance
     424             :   // this is different for each replica
     425         120 :   random[0].setSeed(-iseed);
     426         120 :   if(doscale_||dooffset_) {
     427             :     // in this case we want the same seed everywhere
     428          18 :     auto ts = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now()).time_since_epoch().count();
     429          18 :     iseed = static_cast<unsigned>(ts);
     430          18 :     if(master&&nrep_>1) {
     431           6 :       multi_sim_comm.Bcast(iseed,0);
     432             :     }
     433          18 :     comm.Bcast(iseed,0);
     434             :     // this is used for scale and offset sampling and acceptance
     435          18 :     random[1].setSeed(-iseed);
     436             :   }
     437             :   // this is used for random chunk of sigmas, and it is different for each replica
     438         120 :   if(master) {
     439          85 :     auto ts = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now()).time_since_epoch().count();
     440          85 :     iseed = static_cast<unsigned>(ts)+replica_;
     441             :   } else {
     442          35 :     iseed = 0;
     443             :   }
     444         120 :   comm.Sum(&iseed, 1);
     445         120 :   random[2].setSeed(-iseed);
     446             : 
     447             :   // outfile stuff
     448         120 :   if(write_stride_>0&&doscore_) {
     449          44 :     sfile_.link(*this);
     450          44 :     sfile_.open(status_file_name_);
     451          44 :     if(fmt_.length()>0) {
     452           1 :       sfile_.fmtField(fmt_);
     453             :     }
     454             :   }
     455             : 
     456         120 : }
     457             : 
     458         120 : MetainferenceBase::~MetainferenceBase() {
     459         120 :   if(sfile_.isOpen()) {
     460          44 :     sfile_.close();
     461             :   }
     462         600 : }
     463             : 
     464          44 : void MetainferenceBase::Initialise(const unsigned input) {
     465             :   setNarg(input);
     466          44 :   if(narg!=parameters.size()) {
     467             :     std::string num1;
     468           0 :     Tools::convert(parameters.size(),num1);
     469             :     std::string num2;
     470           0 :     Tools::convert(narg,num2);
     471           0 :     std::string msg = "The number of experimental values " + num1 +" must be the same of the calculated values " + num2;
     472           0 :     error(msg);
     473             :   }
     474             : 
     475             :   // resize std::vector for sigma_mean history
     476          44 :   sigma_mean2_last_.resize(nsel_);
     477          88 :   for(unsigned i=0; i<nsel_; i++) {
     478          44 :     sigma_mean2_last_[i].resize(narg);
     479             :   }
     480          44 :   if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
     481          25 :     if(sigma_mean2_.size()==1) {
     482          25 :       double tmp = sigma_mean2_[0];
     483          25 :       sigma_mean2_.resize(narg, tmp);
     484           0 :     } else if(sigma_mean2_.size()>1&&sigma_mean2_.size()!=narg) {
     485           0 :       error("SIGMA_MEAN0 can accept either one single value or as many values as the number of arguments (with NOISETYPE=MGAUSS|MOUTLIERS|GENERIC)");
     486             :     }
     487             :     // set the initial value for the history
     488          50 :     for(unsigned i=0; i<nsel_; i++)
     489        2499 :       for(unsigned j=0; j<narg; j++) {
     490        2474 :         sigma_mean2_last_[i][j].push_back(sigma_mean2_[j]);
     491             :       }
     492             :   } else {
     493             :     // set the initial value for the history
     494          38 :     for(unsigned i=0; i<nsel_; i++)
     495         113 :       for(unsigned j=0; j<narg; j++) {
     496          94 :         sigma_mean2_last_[i][j].push_back(sigma_mean2_[0]);
     497             :       }
     498             :   }
     499             : 
     500             :   // set sigma_bias
     501          44 :   if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
     502          25 :     if(sigma_.size()==1) {
     503          25 :       double tmp = sigma_[0];
     504          25 :       sigma_.resize(narg, tmp);
     505           0 :     } else if(sigma_.size()>1&&sigma_.size()!=narg) {
     506           0 :       error("SIGMA0 can accept either one single value or as many values as the number of arguments (with NOISETYPE=MGAUSS|MOUTLIERS|GENERIC)");
     507             :     }
     508          25 :     if(sigma_min_.size()==1) {
     509          25 :       double tmp = sigma_min_[0];
     510          25 :       sigma_min_.resize(narg, tmp);
     511           0 :     } else if(sigma_min_.size()>1&&sigma_min_.size()!=narg) {
     512           0 :       error("SIGMA_MIN can accept either one single value or as many values as the number of arguments (with NOISETYPE=MGAUSS|MOUTLIERS|GENERIC)");
     513             :     }
     514          25 :     if(sigma_max_.size()==1) {
     515          25 :       double tmp = sigma_max_[0];
     516          25 :       sigma_max_.resize(narg, tmp);
     517           0 :     } else if(sigma_max_.size()>1&&sigma_max_.size()!=narg) {
     518           0 :       error("SIGMA_MAX can accept either one single value or as many values as the number of arguments (with NOISETYPE=MGAUSS|MOUTLIERS|GENERIC)");
     519             :     }
     520          25 :     if(Dsigma_.size()==1) {
     521          25 :       double tmp = Dsigma_[0];
     522          25 :       Dsigma_.resize(narg, tmp);
     523           0 :     } else if(Dsigma_.size()>1&&Dsigma_.size()!=narg) {
     524           0 :       error("DSIGMA can accept either one single value or as many values as the number of arguments (with NOISETYPE=MGAUSS|MOUTLIERS|GENERIC)");
     525             :     }
     526             :   }
     527             : 
     528          44 :   sigma_max_est_.resize(sigma_max_.size(), 0.);
     529             : 
     530          44 :   IFile restart_sfile;
     531          44 :   restart_sfile.link(*this);
     532          44 :   if(getRestart()&&restart_sfile.FileExist(status_file_name_)) {
     533          10 :     firstTime = false;
     534          20 :     for(unsigned i=0; i<nsel_; i++) {
     535             :       firstTimeW[i] = false;
     536             :     }
     537          10 :     restart_sfile.open(status_file_name_);
     538          10 :     log.printf("  Restarting from %s\n", status_file_name_.c_str());
     539             :     double dummy;
     540          20 :     if(restart_sfile.scanField("time",dummy)) {
     541             :       // check for syncronisation
     542          10 :       std::vector<double> dummy_time(nrep_,0);
     543          10 :       if(master&&nrep_>1) {
     544           0 :         dummy_time[replica_] = dummy;
     545           0 :         multi_sim_comm.Sum(dummy_time);
     546             :       }
     547          10 :       comm.Sum(dummy_time);
     548          10 :       for(unsigned i=1; i<nrep_; i++) {
     549           0 :         std::string msg = "METAINFERENCE restart files " + status_file_name_ + "  are not in sync";
     550           0 :         if(dummy_time[i]!=dummy_time[0]) {
     551           0 :           plumed_merror(msg);
     552             :         }
     553             :       }
     554             :       // nsel
     555          20 :       for(unsigned i=0; i<sigma_mean2_last_.size(); i++) {
     556             :         std::string msg_i;
     557          10 :         Tools::convert(i,msg_i);
     558             :         // narg
     559          10 :         if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
     560           0 :           for(unsigned j=0; j<narg; ++j) {
     561             :             std::string msg_j;
     562           0 :             Tools::convert(j,msg_j);
     563           0 :             std::string msg = msg_i+"_"+msg_j;
     564             :             double read_sm;
     565           0 :             restart_sfile.scanField("sigmaMean_"+msg,read_sm);
     566           0 :             sigma_mean2_last_[i][j][0] = read_sm*read_sm;
     567             :           }
     568             :         }
     569          10 :         if(noise_type_==GAUSS||noise_type_==OUTLIERS) {
     570             :           double read_sm;
     571             :           std::string msg_j;
     572          10 :           Tools::convert(0,msg_j);
     573          10 :           std::string msg = msg_i+"_"+msg_j;
     574          10 :           restart_sfile.scanField("sigmaMean_"+msg,read_sm);
     575          80 :           for(unsigned j=0; j<narg; j++) {
     576          70 :             sigma_mean2_last_[i][j][0] = read_sm*read_sm;
     577             :           }
     578             :         }
     579             :       }
     580             : 
     581          20 :       for(unsigned i=0; i<sigma_.size(); ++i) {
     582             :         std::string msg;
     583          10 :         Tools::convert(i,msg);
     584          20 :         restart_sfile.scanField("sigma_"+msg,sigma_[i]);
     585             :       }
     586          20 :       for(unsigned i=0; i<sigma_max_.size(); ++i) {
     587             :         std::string msg;
     588          10 :         Tools::convert(i,msg);
     589          10 :         restart_sfile.scanField("sigma_max_"+msg,sigma_max_[i]);
     590          10 :         sigmamax_opt_done_=true;
     591             :       }
     592          10 :       if(noise_type_==GENERIC) {
     593           0 :         for(unsigned i=0; i<ftilde_.size(); ++i) {
     594             :           std::string msg;
     595           0 :           Tools::convert(i,msg);
     596           0 :           restart_sfile.scanField("ftilde_"+msg,ftilde_[i]);
     597             :         }
     598             :       }
     599          10 :       restart_sfile.scanField("scale0_",scale_);
     600          10 :       restart_sfile.scanField("offset0_",offset_);
     601             : 
     602          20 :       for(unsigned i=0; i<nsel_; i++) {
     603             :         std::string msg;
     604          10 :         Tools::convert(i,msg);
     605             :         double tmp_w;
     606          10 :         restart_sfile.scanField("weight_"+msg,tmp_w);
     607          10 :         if(master) {
     608          10 :           average_weights_[i][replica_] = tmp_w;
     609          10 :           if(nrep_>1) {
     610           0 :             multi_sim_comm.Sum(&average_weights_[i][0], nrep_);
     611             :           }
     612             :         }
     613          10 :         comm.Sum(&average_weights_[i][0], nrep_);
     614             :       }
     615             : 
     616             :     }
     617          10 :     restart_sfile.scanField();
     618          10 :     restart_sfile.close();
     619             :   }
     620             : 
     621             :   /* If DSIGMA is not yet initialised do it now */
     622        2537 :   for(unsigned i=0; i<sigma_max_.size(); i++)
     623        2493 :     if(Dsigma_[i]==-1) {
     624           0 :       Dsigma_[i] = 0.05*(sigma_max_[i] - sigma_min_[i]);
     625             :     }
     626             : 
     627          44 :   addComponentWithDerivatives("score");
     628          44 :   componentIsNotPeriodic("score");
     629          44 :   valueScore=getPntrToComponent("score");
     630             : 
     631          44 :   if(do_reweight_) {
     632          22 :     addComponent("biasDer");
     633          22 :     componentIsNotPeriodic("biasDer");
     634          22 :     addComponent("weight");
     635          44 :     componentIsNotPeriodic("weight");
     636             :   }
     637             : 
     638          44 :   addComponent("neff");
     639          44 :   componentIsNotPeriodic("neff");
     640             : 
     641          44 :   if(doscale_ || doregres_zero_) {
     642          13 :     addComponent("scale");
     643          13 :     componentIsNotPeriodic("scale");
     644          13 :     valueScale=getPntrToComponent("scale");
     645             :   }
     646             : 
     647          44 :   if(dooffset_) {
     648           6 :     addComponent("offset");
     649           6 :     componentIsNotPeriodic("offset");
     650           6 :     valueOffset=getPntrToComponent("offset");
     651             :   }
     652             : 
     653          44 :   if(dooffset_||doscale_) {
     654          18 :     addComponent("acceptScale");
     655          18 :     componentIsNotPeriodic("acceptScale");
     656          18 :     valueAcceptScale=getPntrToComponent("acceptScale");
     657             :   }
     658             : 
     659          44 :   if(noise_type_==GENERIC) {
     660           3 :     addComponent("acceptFT");
     661           3 :     componentIsNotPeriodic("acceptFT");
     662           3 :     valueAcceptFT=getPntrToComponent("acceptFT");
     663             :   }
     664             : 
     665          44 :   addComponent("acceptSigma");
     666          44 :   componentIsNotPeriodic("acceptSigma");
     667          44 :   valueAccept=getPntrToComponent("acceptSigma");
     668             : 
     669          44 :   if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
     670        2499 :     for(unsigned i=0; i<sigma_mean2_.size(); ++i) {
     671             :       std::string num;
     672        2474 :       Tools::convert(i,num);
     673        2474 :       addComponent("sigmaMean-"+num);
     674        2474 :       componentIsNotPeriodic("sigmaMean-"+num);
     675        2474 :       valueSigmaMean.push_back(getPntrToComponent("sigmaMean-"+num));
     676        2474 :       getPntrToComponent("sigmaMean-"+num)->set(std::sqrt(sigma_mean2_[i]));
     677        2474 :       addComponent("sigma-"+num);
     678        2474 :       componentIsNotPeriodic("sigma-"+num);
     679        2474 :       valueSigma.push_back(getPntrToComponent("sigma-"+num));
     680        2474 :       getPntrToComponent("sigma-"+num)->set(sigma_[i]);
     681        2474 :       if(noise_type_==GENERIC) {
     682           6 :         addComponent("ftilde-"+num);
     683           6 :         componentIsNotPeriodic("ftilde-"+num);
     684           6 :         valueFtilde.push_back(getPntrToComponent("ftilde-"+num));
     685             :       }
     686             :     }
     687          25 :   } else {
     688          19 :     addComponent("sigmaMean");
     689          19 :     componentIsNotPeriodic("sigmaMean");
     690          19 :     valueSigmaMean.push_back(getPntrToComponent("sigmaMean"));
     691          19 :     getPntrToComponent("sigmaMean")->set(std::sqrt(sigma_mean2_[0]));
     692          19 :     addComponent("sigma");
     693          19 :     componentIsNotPeriodic("sigma");
     694          19 :     valueSigma.push_back(getPntrToComponent("sigma"));
     695          38 :     getPntrToComponent("sigma")->set(sigma_[0]);
     696             :   }
     697             : 
     698          44 :   switch(noise_type_) {
     699           3 :   case GENERIC:
     700           3 :     log.printf("  with general metainference ");
     701           3 :     if(gen_likelihood_==LIKE_GAUSS) {
     702           2 :       log.printf(" and a gaussian likelihood\n");
     703           1 :     } else if(gen_likelihood_==LIKE_LOGN) {
     704           1 :       log.printf(" and a log-normal likelihood\n");
     705             :     }
     706           3 :     log.printf("  ensemble average parameter sampled with a step %lf of sigma_mean\n", Dftilde_);
     707             :     break;
     708           9 :   case GAUSS:
     709           9 :     log.printf("  with gaussian noise and a single noise parameter for all the data\n");
     710             :     break;
     711          14 :   case MGAUSS:
     712          14 :     log.printf("  with gaussian noise and a noise parameter for each data point\n");
     713             :     break;
     714          10 :   case OUTLIERS:
     715          10 :     log.printf("  with long tailed gaussian noise and a single noise parameter for all the data\n");
     716             :     break;
     717           8 :   case MOUTLIERS:
     718           8 :     log.printf("  with long tailed gaussian noise and a noise parameter for each data point\n");
     719             :     break;
     720             :   }
     721             : 
     722          44 :   if(doscale_) {
     723             :     // check that the scale value is the same for all replicas
     724          12 :     std::vector<double> dummy_scale(nrep_,0);
     725          12 :     if(master&&nrep_>1) {
     726           6 :       dummy_scale[replica_] = scale_;
     727           6 :       multi_sim_comm.Sum(dummy_scale);
     728             :     }
     729          12 :     comm.Sum(dummy_scale);
     730          24 :     for(unsigned i=1; i<nrep_; i++) {
     731          12 :       std::string msg = "The SCALE value must be the same for all replicas: check your input or restart file";
     732          12 :       if(dummy_scale[i]!=dummy_scale[0]) {
     733           0 :         plumed_merror(msg);
     734             :       }
     735             :     }
     736          12 :     log.printf("  sampling a common scaling factor with:\n");
     737          12 :     log.printf("    initial scale parameter %f\n",scale_);
     738          12 :     if(scale_prior_==SC_GAUSS) {
     739           0 :       log.printf("    gaussian prior with mean %f and width %f\n",scale_mu_,Dscale_);
     740             :     }
     741          12 :     if(scale_prior_==SC_FLAT) {
     742          12 :       log.printf("    flat prior between %f - %f\n",scale_min_,scale_max_);
     743          12 :       log.printf("    maximum MC move of scale parameter %f\n",Dscale_);
     744             :     }
     745             :   }
     746             : 
     747          44 :   if(dooffset_) {
     748             :     // check that the offset value is the same for all replicas
     749           6 :     std::vector<double> dummy_offset(nrep_,0);
     750           6 :     if(master&&nrep_>1) {
     751           0 :       dummy_offset[replica_] = offset_;
     752           0 :       multi_sim_comm.Sum(dummy_offset);
     753             :     }
     754           6 :     comm.Sum(dummy_offset);
     755           6 :     for(unsigned i=1; i<nrep_; i++) {
     756           0 :       std::string msg = "The OFFSET value must be the same for all replicas: check your input or restart file";
     757           0 :       if(dummy_offset[i]!=dummy_offset[0]) {
     758           0 :         plumed_merror(msg);
     759             :       }
     760             :     }
     761           6 :     log.printf("  sampling a common offset with:\n");
     762           6 :     log.printf("    initial offset parameter %f\n",offset_);
     763           6 :     if(offset_prior_==SC_GAUSS) {
     764           0 :       log.printf("    gaussian prior with mean %f and width %f\n",offset_mu_,Doffset_);
     765             :     }
     766           6 :     if(offset_prior_==SC_FLAT) {
     767           6 :       log.printf("    flat prior between %f - %f\n",offset_min_,offset_max_);
     768           6 :       log.printf("    maximum MC move of offset parameter %f\n",Doffset_);
     769             :     }
     770             :   }
     771             : 
     772          44 :   if(doregres_zero_) {
     773           1 :     log.printf("  doing regression with zero intercept with stride: %d\n", nregres_zero_);
     774             :   }
     775             : 
     776          44 :   log.printf("  number of experimental data points %u\n",narg);
     777          44 :   log.printf("  number of replicas %u\n",nrep_);
     778          44 :   log.printf("  initial data uncertainties");
     779        2537 :   for(unsigned i=0; i<sigma_.size(); ++i) {
     780        2493 :     log.printf(" %f", sigma_[i]);
     781             :   }
     782          44 :   log.printf("\n");
     783          44 :   log.printf("  minimum data uncertainties");
     784        2537 :   for(unsigned i=0; i<sigma_.size(); ++i) {
     785        2493 :     log.printf(" %f",sigma_min_[i]);
     786             :   }
     787          44 :   log.printf("\n");
     788          44 :   log.printf("  maximum data uncertainties");
     789        2537 :   for(unsigned i=0; i<sigma_.size(); ++i) {
     790        2493 :     log.printf(" %f",sigma_max_[i]);
     791             :   }
     792          44 :   log.printf("\n");
     793          44 :   log.printf("  maximum MC move of data uncertainties");
     794        2537 :   for(unsigned i=0; i<sigma_.size(); ++i) {
     795        2493 :     log.printf(" %f",Dsigma_[i]);
     796             :   }
     797          44 :   log.printf("\n");
     798          44 :   log.printf("  temperature of the system %f\n",kbt_);
     799          44 :   log.printf("  MC steps %u\n",MCsteps_);
     800          44 :   log.printf("  initial standard errors of the mean");
     801        2537 :   for(unsigned i=0; i<sigma_mean2_.size(); ++i) {
     802        2493 :     log.printf(" %f", std::sqrt(sigma_mean2_[i]));
     803             :   }
     804          44 :   log.printf("\n");
     805             : 
     806             :   //resize the number of metainference derivatives and the number of back-calculated data
     807          44 :   metader_.resize(narg, 0.);
     808          44 :   calc_data_.resize(narg, 0.);
     809             : 
     810          88 :   log<<"  Bibliography "<<plumed.cite("Bonomi, Camilloni, Cavalli, Vendruscolo, Sci. Adv. 2, e150117 (2016)");
     811          44 :   if(do_reweight_) {
     812          44 :     log<<plumed.cite("Bonomi, Camilloni, Vendruscolo, Sci. Rep. 6, 31232 (2016)");
     813             :   }
     814          44 :   if(do_optsigmamean_>0) {
     815           8 :     log<<plumed.cite("Loehr, Jussupow, Camilloni, J. Chem. Phys. 146, 165102 (2017)");
     816             :   }
     817          88 :   log<<plumed.cite("Bonomi, Camilloni, Bioinformatics, 33, 3999 (2017)");
     818          44 :   log<<"\n";
     819          44 : }
     820             : 
     821           0 : void MetainferenceBase::Selector() {
     822           0 :   iselect = 0;
     823             :   // set the value of selector for  REM-like stuff
     824           0 :   if(selector_.length()>0) {
     825           0 :     iselect = static_cast<unsigned>(plumed.passMap[selector_]);
     826             :   }
     827           0 : }
     828             : 
     829         120 : double MetainferenceBase::getEnergySP(const std::vector<double> &mean, const std::vector<double> &sigma,
     830             :                                       const double scale, const double offset) {
     831         120 :   const double scale2 = scale*scale;
     832         120 :   const double sm2    = sigma_mean2_[0];
     833         120 :   const double ss2    = sigma[0]*sigma[0] + scale2*sm2;
     834         120 :   const double sss    = sigma[0]*sigma[0] + sm2;
     835             : 
     836             :   double ene = 0.0;
     837         120 :   #pragma omp parallel num_threads(OpenMP::getNumThreads()) shared(ene)
     838             :   {
     839             :     #pragma omp for reduction( + : ene)
     840             :     for(unsigned i=0; i<narg; ++i) {
     841             :       const double dev = scale*mean[i]-parameters[i]+offset;
     842             :       const double a2 = 0.5*dev*dev + ss2;
     843             :       if(sm2 > 0.0) {
     844             :         ene += std::log(2.0*a2/(1.0-std::exp(-a2/sm2)));
     845             :       } else {
     846             :         ene += std::log(2.0*a2);
     847             :       }
     848             :     }
     849             :   }
     850             :   // add one single Jeffrey's prior and one normalisation per data point
     851         120 :   ene += 0.5*std::log(sss) + static_cast<double>(narg)*0.5*std::log(0.5*M_PI*M_PI/ss2);
     852         120 :   if(doscale_ || doregres_zero_) {
     853          12 :     ene += 0.5*std::log(sss);
     854             :   }
     855         120 :   if(dooffset_) {
     856           0 :     ene += 0.5*std::log(sss);
     857             :   }
     858         120 :   return kbt_ * ene;
     859             : }
     860             : 
     861        5328 : double MetainferenceBase::getEnergySPE(const std::vector<double> &mean, const std::vector<double> &sigma,
     862             :                                        const double scale, const double offset) {
     863        5328 :   const double scale2 = scale*scale;
     864             :   double ene = 0.0;
     865        5328 :   #pragma omp parallel num_threads(OpenMP::getNumThreads()) shared(ene)
     866             :   {
     867             :     #pragma omp for reduction( + : ene)
     868             :     for(unsigned i=0; i<narg; ++i) {
     869             :       const double sm2 = sigma_mean2_[i];
     870             :       const double ss2 = sigma[i]*sigma[i] + scale2*sm2;
     871             :       const double sss = sigma[i]*sigma[i] + sm2;
     872             :       const double dev = scale*mean[i]-parameters[i]+offset;
     873             :       const double a2  = 0.5*dev*dev + ss2;
     874             :       if(sm2 > 0.0) {
     875             :         ene += 0.5*std::log(sss) + 0.5*std::log(0.5*M_PI*M_PI/ss2) + std::log(2.0*a2/(1.0-std::exp(-a2/sm2)));
     876             :       } else {
     877             :         ene += 0.5*std::log(sss) + 0.5*std::log(0.5*M_PI*M_PI/ss2) + std::log(2.0*a2);
     878             :       }
     879             :       if(doscale_ || doregres_zero_) {
     880             :         ene += 0.5*std::log(sss);
     881             :       }
     882             :       if(dooffset_) {
     883             :         ene += 0.5*std::log(sss);
     884             :       }
     885             :     }
     886             :   }
     887        5328 :   return kbt_ * ene;
     888             : }
     889             : 
     890         144 : double MetainferenceBase::getEnergyMIGEN(const std::vector<double> &mean, const std::vector<double> &ftilde, const std::vector<double> &sigma,
     891             :     const double scale, const double offset) {
     892             :   double ene = 0.0;
     893         144 :   #pragma omp parallel num_threads(OpenMP::getNumThreads()) shared(ene)
     894             :   {
     895             :     #pragma omp for reduction( + : ene)
     896             :     for(unsigned i=0; i<narg; ++i) {
     897             :       const double inv_sb2  = 1./(sigma[i]*sigma[i]);
     898             :       const double inv_sm2  = 1./sigma_mean2_[i];
     899             :       double devb = 0;
     900             :       if(gen_likelihood_==LIKE_GAUSS) {
     901             :         devb = scale*ftilde[i]-parameters[i]+offset;
     902             :       } else if(gen_likelihood_==LIKE_LOGN) {
     903             :         devb = std::log(scale*ftilde[i]/parameters[i]);
     904             :       }
     905             :       double devm = mean[i] - ftilde[i];
     906             :       // deviation + normalisation + jeffrey
     907             :       double normb = 0.;
     908             :       if(gen_likelihood_==LIKE_GAUSS) {
     909             :         normb = -0.5*std::log(0.5/M_PI*inv_sb2);
     910             :       } else if(gen_likelihood_==LIKE_LOGN) {
     911             :         normb = -0.5*std::log(0.5/M_PI*inv_sb2/(parameters[i]*parameters[i]));
     912             :       }
     913             :       const double normm         = -0.5*std::log(0.5/M_PI*inv_sm2);
     914             :       const double jeffreys      = -0.5*std::log(2.*inv_sb2);
     915             :       ene += 0.5*devb*devb*inv_sb2 + 0.5*devm*devm*inv_sm2 + normb + normm + jeffreys;
     916             :       if(doscale_ || doregres_zero_) {
     917             :         ene += jeffreys;
     918             :       }
     919             :       if(dooffset_) {
     920             :         ene += jeffreys;
     921             :       }
     922             :     }
     923             :   }
     924         144 :   return kbt_ * ene;
     925             : }
     926             : 
     927         626 : double MetainferenceBase::getEnergyGJ(const std::vector<double> &mean, const std::vector<double> &sigma,
     928             :                                       const double scale, const double offset) {
     929         626 :   const double scale2  = scale*scale;
     930         626 :   const double inv_s2  = 1./(sigma[0]*sigma[0] + scale2*sigma_mean2_[0]);
     931         626 :   const double inv_sss = 1./(sigma[0]*sigma[0] + sigma_mean2_[0]);
     932             : 
     933             :   double ene = 0.0;
     934         626 :   #pragma omp parallel num_threads(OpenMP::getNumThreads()) shared(ene)
     935             :   {
     936             :     #pragma omp for reduction( + : ene)
     937             :     for(unsigned i=0; i<narg; ++i) {
     938             :       double dev = scale*mean[i]-parameters[i]+offset;
     939             :       ene += 0.5*dev*dev*inv_s2;
     940             :     }
     941             :   }
     942         626 :   const double normalisation = -0.5*std::log(0.5/M_PI*inv_s2);
     943         626 :   const double jeffreys = -0.5*std::log(2.*inv_sss);
     944             :   // add Jeffrey's prior in case one sigma for all data points + one normalisation per datapoint
     945         626 :   ene += jeffreys + static_cast<double>(narg)*normalisation;
     946         626 :   if(doscale_ || doregres_zero_) {
     947           0 :     ene += jeffreys;
     948             :   }
     949         626 :   if(dooffset_) {
     950         108 :     ene += jeffreys;
     951             :   }
     952             : 
     953         626 :   return kbt_ * ene;
     954             : }
     955             : 
     956         368 : double MetainferenceBase::getEnergyGJE(const std::vector<double> &mean, const std::vector<double> &sigma,
     957             :                                        const double scale, const double offset) {
     958         368 :   const double scale2 = scale*scale;
     959             : 
     960             :   double ene = 0.0;
     961         368 :   #pragma omp parallel num_threads(OpenMP::getNumThreads()) shared(ene)
     962             :   {
     963             :     #pragma omp for reduction( + : ene)
     964             :     for(unsigned i=0; i<narg; ++i) {
     965             :       const double inv_s2  = 1./(sigma[i]*sigma[i] + scale2*sigma_mean2_[i]);
     966             :       const double inv_sss = 1./(sigma[i]*sigma[i] + sigma_mean2_[i]);
     967             :       double dev = scale*mean[i]-parameters[i]+offset;
     968             :       // deviation + normalisation + jeffrey
     969             :       const double normalisation = -0.5*std::log(0.5/M_PI*inv_s2);
     970             :       const double jeffreys      = -0.5*std::log(2.*inv_sss);
     971             :       ene += 0.5*dev*dev*inv_s2 + normalisation + jeffreys;
     972             :       if(doscale_ || doregres_zero_) {
     973             :         ene += jeffreys;
     974             :       }
     975             :       if(dooffset_) {
     976             :         ene += jeffreys;
     977             :       }
     978             :     }
     979             :   }
     980         368 :   return kbt_ * ene;
     981             : }
     982             : 
     983          36 : void MetainferenceBase::moveTilde(const std::vector<double> &mean_, double &old_energy) {
     984          36 :   std::vector<double> new_ftilde(sigma_.size());
     985          36 :   new_ftilde = ftilde_;
     986             : 
     987             :   // change all tildes
     988         108 :   for(unsigned j=0; j<sigma_.size(); j++) {
     989          72 :     const double r3 = random[0].Gaussian();
     990          72 :     const double ds3 = Dftilde_*std::sqrt(sigma_mean2_[j])*r3;
     991          72 :     new_ftilde[j] = ftilde_[j] + ds3;
     992             :   }
     993             :   // calculate new energy
     994          36 :   double new_energy = getEnergyMIGEN(mean_,new_ftilde,sigma_,scale_,offset_);
     995             : 
     996             :   // accept or reject
     997          36 :   const double delta = ( new_energy - old_energy ) / kbt_;
     998             :   // if delta is negative always accept move
     999          36 :   if( delta <= 0.0 ) {
    1000          36 :     old_energy = new_energy;
    1001          36 :     ftilde_ = new_ftilde;
    1002          36 :     MCacceptFT_++;
    1003             :     // otherwise extract random number
    1004             :   } else {
    1005           0 :     const double s = random[0].RandU01();
    1006           0 :     if( s < std::exp(-delta) ) {
    1007           0 :       old_energy = new_energy;
    1008           0 :       ftilde_ = new_ftilde;
    1009           0 :       MCacceptFT_++;
    1010             :     }
    1011             :   }
    1012          36 : }
    1013             : 
    1014        1896 : void MetainferenceBase::moveScaleOffset(const std::vector<double> &mean_, double &old_energy) {
    1015        1896 :   double new_scale = scale_;
    1016             : 
    1017        1896 :   if(doscale_) {
    1018        1824 :     if(scale_prior_==SC_FLAT) {
    1019        1824 :       const double r1 = random[1].Gaussian();
    1020        1824 :       const double ds1 = Dscale_*r1;
    1021        1824 :       new_scale += ds1;
    1022             :       // check boundaries
    1023        1824 :       if(new_scale > scale_max_) {
    1024           0 :         new_scale = 2.0 * scale_max_ - new_scale;
    1025             :       }
    1026        1824 :       if(new_scale < scale_min_) {
    1027           0 :         new_scale = 2.0 * scale_min_ - new_scale;
    1028             :       }
    1029             :     } else {
    1030           0 :       const double r1 = random[1].Gaussian();
    1031           0 :       const double ds1 = 0.5*(scale_mu_-new_scale)+Dscale_*std::exp(1)/M_PI*r1;
    1032           0 :       new_scale += ds1;
    1033             :     }
    1034             :   }
    1035             : 
    1036        1896 :   double new_offset = offset_;
    1037             : 
    1038        1896 :   if(dooffset_) {
    1039          72 :     if(offset_prior_==SC_FLAT) {
    1040          72 :       const double r1 = random[1].Gaussian();
    1041          72 :       const double ds1 = Doffset_*r1;
    1042          72 :       new_offset += ds1;
    1043             :       // check boundaries
    1044          72 :       if(new_offset > offset_max_) {
    1045           0 :         new_offset = 2.0 * offset_max_ - new_offset;
    1046             :       }
    1047          72 :       if(new_offset < offset_min_) {
    1048           0 :         new_offset = 2.0 * offset_min_ - new_offset;
    1049             :       }
    1050             :     } else {
    1051           0 :       const double r1 = random[1].Gaussian();
    1052           0 :       const double ds1 = 0.5*(offset_mu_-new_offset)+Doffset_*std::exp(1)/M_PI*r1;
    1053           0 :       new_offset += ds1;
    1054             :     }
    1055             :   }
    1056             : 
    1057             :   // calculate new energy
    1058             :   double new_energy = 0.;
    1059             : 
    1060        1896 :   switch(noise_type_) {
    1061          36 :   case GAUSS:
    1062          36 :     new_energy = getEnergyGJ(mean_,sigma_,new_scale,new_offset);
    1063             :     break;
    1064          48 :   case MGAUSS:
    1065          48 :     new_energy = getEnergyGJE(mean_,sigma_,new_scale,new_offset);
    1066             :     break;
    1067           0 :   case OUTLIERS:
    1068           0 :     new_energy = getEnergySP(mean_,sigma_,new_scale,new_offset);
    1069             :     break;
    1070        1776 :   case MOUTLIERS:
    1071        1776 :     new_energy = getEnergySPE(mean_,sigma_,new_scale,new_offset);
    1072             :     break;
    1073          36 :   case GENERIC:
    1074          36 :     new_energy = getEnergyMIGEN(mean_,ftilde_,sigma_,new_scale,new_offset);
    1075             :     break;
    1076             :   }
    1077             : 
    1078             :   // for the scale/offset we need to consider the total energy
    1079        1896 :   std::vector<double> totenergies(2);
    1080        1896 :   if(master) {
    1081         984 :     totenergies[0] = old_energy;
    1082         984 :     totenergies[1] = new_energy;
    1083         984 :     if(nrep_>1) {
    1084         912 :       multi_sim_comm.Sum(totenergies);
    1085             :     }
    1086             :   } else {
    1087         912 :     totenergies[0] = 0;
    1088         912 :     totenergies[1] = 0;
    1089             :   }
    1090        1896 :   comm.Sum(totenergies);
    1091             : 
    1092             :   // accept or reject
    1093        1896 :   const double delta = ( totenergies[1] - totenergies[0] ) / kbt_;
    1094             :   // if delta is negative always accept move
    1095        1896 :   if( delta <= 0.0 ) {
    1096        1896 :     old_energy = new_energy;
    1097        1896 :     scale_ = new_scale;
    1098        1896 :     offset_ = new_offset;
    1099        1896 :     MCacceptScale_++;
    1100             :     // otherwise extract random number
    1101             :   } else {
    1102           0 :     double s = random[1].RandU01();
    1103           0 :     if( s < std::exp(-delta) ) {
    1104           0 :       old_energy = new_energy;
    1105           0 :       scale_ = new_scale;
    1106           0 :       offset_ = new_offset;
    1107           0 :       MCacceptScale_++;
    1108             :     }
    1109             :   }
    1110        1896 : }
    1111             : 
    1112        2327 : void MetainferenceBase::moveSigmas(const std::vector<double> &mean_, double &old_energy, const unsigned i, const std::vector<unsigned> &indices, bool &breaknow) {
    1113        2327 :   std::vector<double> new_sigma(sigma_.size());
    1114        2327 :   new_sigma = sigma_;
    1115             : 
    1116             :   // change MCchunksize_ sigmas
    1117        2327 :   if (MCchunksize_ > 0) {
    1118           0 :     if ((MCchunksize_ * i) >= sigma_.size()) {
    1119             :       // This means we are not moving any sigma, so we should break immediately
    1120           0 :       breaknow = true;
    1121             :     }
    1122             : 
    1123             :     // change random sigmas
    1124           0 :     for(unsigned j=0; j<MCchunksize_; j++) {
    1125           0 :       const unsigned shuffle_index = j + MCchunksize_ * i;
    1126           0 :       if (shuffle_index >= sigma_.size()) {
    1127             :         // Going any further will segfault but we should still evaluate the sigmas we changed
    1128             :         break;
    1129             :       }
    1130           0 :       const unsigned index = indices[shuffle_index];
    1131           0 :       const double r2 = random[0].Gaussian();
    1132           0 :       const double ds2 = Dsigma_[index]*r2;
    1133           0 :       new_sigma[index] = sigma_[index] + ds2;
    1134             :       // check boundaries
    1135           0 :       if(new_sigma[index] > sigma_max_[index]) {
    1136           0 :         new_sigma[index] = 2.0 * sigma_max_[index] - new_sigma[index];
    1137             :       }
    1138           0 :       if(new_sigma[index] < sigma_min_[index]) {
    1139           0 :         new_sigma[index] = 2.0 * sigma_min_[index] - new_sigma[index];
    1140             :       }
    1141             :     }
    1142             :   } else {
    1143             :     // change all sigmas
    1144       13714 :     for(unsigned j=0; j<sigma_.size(); j++) {
    1145       11387 :       const double r2 = random[0].Gaussian();
    1146       11387 :       const double ds2 = Dsigma_[j]*r2;
    1147       11387 :       new_sigma[j] = sigma_[j] + ds2;
    1148             :       // check boundaries
    1149       11387 :       if(new_sigma[j] > sigma_max_[j]) {
    1150           0 :         new_sigma[j] = 2.0 * sigma_max_[j] - new_sigma[j];
    1151             :       }
    1152       11387 :       if(new_sigma[j] < sigma_min_[j]) {
    1153           0 :         new_sigma[j] = 2.0 * sigma_min_[j] - new_sigma[j];
    1154             :       }
    1155             :     }
    1156             :   }
    1157             : 
    1158        2327 :   if (breaknow) {
    1159             :     // We didnt move any sigmas, so no sense in evaluating anything
    1160             :     return;
    1161             :   }
    1162             : 
    1163             :   // calculate new energy
    1164             :   double new_energy = 0.;
    1165        2327 :   switch(noise_type_) {
    1166         295 :   case GAUSS:
    1167         295 :     new_energy = getEnergyGJ(mean_,new_sigma,scale_,offset_);
    1168             :     break;
    1169         160 :   case MGAUSS:
    1170         160 :     new_energy = getEnergyGJE(mean_,new_sigma,scale_,offset_);
    1171             :     break;
    1172          60 :   case OUTLIERS:
    1173          60 :     new_energy = getEnergySP(mean_,new_sigma,scale_,offset_);
    1174             :     break;
    1175        1776 :   case MOUTLIERS:
    1176        1776 :     new_energy = getEnergySPE(mean_,new_sigma,scale_,offset_);
    1177             :     break;
    1178          36 :   case GENERIC:
    1179          36 :     new_energy = getEnergyMIGEN(mean_,ftilde_,new_sigma,scale_,offset_);
    1180             :     break;
    1181             :   }
    1182             : 
    1183             :   // accept or reject
    1184        2327 :   const double delta = ( new_energy - old_energy ) / kbt_;
    1185             :   // if delta is negative always accept move
    1186        2327 :   if( delta <= 0.0 ) {
    1187        2327 :     old_energy = new_energy;
    1188        2327 :     sigma_ = new_sigma;
    1189        2327 :     MCaccept_++;
    1190             :     // otherwise extract random number
    1191             :   } else {
    1192           0 :     const double s = random[0].RandU01();
    1193           0 :     if( s < std::exp(-delta) ) {
    1194           0 :       old_energy = new_energy;
    1195           0 :       sigma_ = new_sigma;
    1196           0 :       MCaccept_++;
    1197             :     }
    1198             :   }
    1199             : }
    1200             : 
    1201        2327 : double MetainferenceBase::doMonteCarlo(const std::vector<double> &mean_) {
    1202             :   // calculate old energy with the updated coordinates
    1203        2327 :   double old_energy=0.;
    1204             : 
    1205        2327 :   switch(noise_type_) {
    1206         295 :   case GAUSS:
    1207         295 :     old_energy = getEnergyGJ(mean_,sigma_,scale_,offset_);
    1208         295 :     break;
    1209         160 :   case MGAUSS:
    1210         160 :     old_energy = getEnergyGJE(mean_,sigma_,scale_,offset_);
    1211         160 :     break;
    1212          60 :   case OUTLIERS:
    1213          60 :     old_energy = getEnergySP(mean_,sigma_,scale_,offset_);
    1214          60 :     break;
    1215        1776 :   case MOUTLIERS:
    1216        1776 :     old_energy = getEnergySPE(mean_,sigma_,scale_,offset_);
    1217        1776 :     break;
    1218          36 :   case GENERIC:
    1219          36 :     old_energy = getEnergyMIGEN(mean_,ftilde_,sigma_,scale_,offset_);
    1220          36 :     break;
    1221             :   }
    1222             : 
    1223             :   // do not run MC if this is a replica-exchange trial
    1224        2327 :   if(!getExchangeStep()) {
    1225             : 
    1226             :     // Create std::vector of random sigma indices
    1227             :     std::vector<unsigned> indices;
    1228        2327 :     if (MCchunksize_ > 0) {
    1229           0 :       for (unsigned j=0; j<sigma_.size(); j++) {
    1230           0 :         indices.push_back(j);
    1231             :       }
    1232           0 :       random[2].Shuffle(indices);
    1233             :     }
    1234        2327 :     bool breaknow = false;
    1235             : 
    1236             :     // cycle on MC steps
    1237        4654 :     for(unsigned i=0; i<MCsteps_; ++i) {
    1238        2327 :       MCtrial_++;
    1239             :       // propose move for ftilde
    1240        2327 :       if(noise_type_==GENERIC) {
    1241          36 :         moveTilde(mean_, old_energy);
    1242             :       }
    1243             :       // propose move for scale and/or offset
    1244        2327 :       if(doscale_||dooffset_) {
    1245        1896 :         moveScaleOffset(mean_, old_energy);
    1246             :       }
    1247             :       // propose move for sigma
    1248        2327 :       moveSigmas(mean_, old_energy, i, indices, breaknow);
    1249             :       // exit from the loop if this is the case
    1250        2327 :       if(breaknow) {
    1251             :         break;
    1252             :       }
    1253             :     }
    1254             : 
    1255             :     /* save the result of the sampling */
    1256             :     /* ftilde */
    1257        2327 :     if(noise_type_==GENERIC) {
    1258          36 :       double accept = static_cast<double>(MCacceptFT_) / static_cast<double>(MCtrial_);
    1259          36 :       valueAcceptFT->set(accept);
    1260         108 :       for(unsigned i=0; i<sigma_.size(); i++) {
    1261          72 :         valueFtilde[i]->set(ftilde_[i]);
    1262             :       }
    1263             :     }
    1264             :     /* scale and offset */
    1265        2327 :     if(doscale_ || doregres_zero_) {
    1266        1830 :       valueScale->set(scale_);
    1267             :     }
    1268        2327 :     if(dooffset_) {
    1269          72 :       valueOffset->set(offset_);
    1270             :     }
    1271        2327 :     if(doscale_||dooffset_) {
    1272        1896 :       double accept = static_cast<double>(MCacceptScale_) / static_cast<double>(MCtrial_);
    1273        1896 :       valueAcceptScale->set(accept);
    1274             :     }
    1275             :     /* sigmas */
    1276       13714 :     for(unsigned i=0; i<sigma_.size(); i++) {
    1277       11387 :       valueSigma[i]->set(sigma_[i]);
    1278             :     }
    1279        2327 :     double accept = static_cast<double>(MCaccept_) / static_cast<double>(MCtrial_);
    1280        2327 :     valueAccept->set(accept);
    1281             :   }
    1282             : 
    1283             :   // here we sum the score over the replicas to get the full metainference score that we save as a bias
    1284        2327 :   if(master) {
    1285        1329 :     if(nrep_>1) {
    1286        1022 :       multi_sim_comm.Sum(old_energy);
    1287             :     }
    1288             :   } else {
    1289         998 :     old_energy=0;
    1290             :   }
    1291        2327 :   comm.Sum(old_energy);
    1292             : 
    1293             :   // this is the energy with current coordinates and parameters
    1294        2327 :   return old_energy;
    1295             : }
    1296             : 
    1297             : /*
    1298             :    In the following energy-force functions we don't add the normalisation and the jeffreys priors
    1299             :    because they are not needed for the forces, the correct MetaInference energy is the one calculated
    1300             :    in the Monte-Carlo
    1301             : */
    1302             : 
    1303          60 : void MetainferenceBase::getEnergyForceSP(const std::vector<double> &mean, const std::vector<double> &dmean_x,
    1304             :     const std::vector<double> &dmean_b) {
    1305          60 :   const double scale2 = scale_*scale_;
    1306          60 :   const double sm2    = sigma_mean2_[0];
    1307          60 :   const double ss2    = sigma_[0]*sigma_[0] + scale2*sm2;
    1308          60 :   std::vector<double> f(narg,0);
    1309             : 
    1310          60 :   if(master) {
    1311          60 :     #pragma omp parallel num_threads(OpenMP::getNumThreads())
    1312             :     {
    1313             :       #pragma omp for
    1314             :       for(unsigned i=0; i<narg; ++i) {
    1315             :         const double dev = scale_*mean[i]-parameters[i]+offset_;
    1316             :         const double a2 = 0.5*dev*dev + ss2;
    1317             :         if(sm2 > 0.0) {
    1318             :           const double t = std::exp(-a2/sm2);
    1319             :           const double dt = 1./t;
    1320             :           const double dit = 1./(1.-dt);
    1321             :           f[i] = -scale_*dev*(dit/sm2 + 1./a2);
    1322             :         } else {
    1323             :           f[i] = -scale_*dev*(1./a2);
    1324             :         }
    1325             :       }
    1326             :     }
    1327             :     // collect contribution to forces and energy from other replicas
    1328          60 :     if(nrep_>1) {
    1329           0 :       multi_sim_comm.Sum(&f[0],narg);
    1330             :     }
    1331             :   }
    1332             :   // intra-replica summation
    1333          60 :   comm.Sum(&f[0],narg);
    1334             : 
    1335             :   double w_tmp = 0.;
    1336         480 :   for(unsigned i=0; i<narg; ++i) {
    1337         420 :     setMetaDer(i, -kbt_*f[i]*dmean_x[i]);
    1338         420 :     w_tmp += kbt_*f[i]*dmean_b[i];
    1339             :   }
    1340             : 
    1341          60 :   if(do_reweight_) {
    1342           0 :     setArgDerivatives(valueScore, -w_tmp);
    1343           0 :     getPntrToComponent("biasDer")->set(-w_tmp);
    1344             :   }
    1345          60 : }
    1346             : 
    1347        1776 : void MetainferenceBase::getEnergyForceSPE(const std::vector<double> &mean, const std::vector<double> &dmean_x,
    1348             :     const std::vector<double> &dmean_b) {
    1349        1776 :   const double scale2 = scale_*scale_;
    1350        1776 :   std::vector<double> f(narg,0);
    1351             : 
    1352        1776 :   if(master) {
    1353         888 :     #pragma omp parallel num_threads(OpenMP::getNumThreads())
    1354             :     {
    1355             :       #pragma omp for
    1356             :       for(unsigned i=0; i<narg; ++i) {
    1357             :         const double sm2 = sigma_mean2_[i];
    1358             :         const double ss2 = sigma_[i]*sigma_[i] + scale2*sm2;
    1359             :         const double dev = scale_*mean[i]-parameters[i]+offset_;
    1360             :         const double a2  = 0.5*dev*dev + ss2;
    1361             :         if(sm2 > 0.0) {
    1362             :           const double t   = std::exp(-a2/sm2);
    1363             :           const double dt  = 1./t;
    1364             :           const double dit = 1./(1.-dt);
    1365             :           f[i] = -scale_*dev*(dit/sm2 + 1./a2);
    1366             :         } else {
    1367             :           f[i] = -scale_*dev*(1./a2);
    1368             :         }
    1369             :       }
    1370             :     }
    1371             :     // collect contribution to forces and energy from other replicas
    1372         888 :     if(nrep_>1) {
    1373         888 :       multi_sim_comm.Sum(&f[0],narg);
    1374             :     }
    1375             :   }
    1376        1776 :   comm.Sum(&f[0],narg);
    1377             : 
    1378             :   double w_tmp = 0.;
    1379        8880 :   for(unsigned i=0; i<narg; ++i) {
    1380        7104 :     setMetaDer(i, -kbt_ * dmean_x[i] * f[i]);
    1381        7104 :     w_tmp += kbt_ * dmean_b[i] *f[i];
    1382             :   }
    1383             : 
    1384        1776 :   if(do_reweight_) {
    1385        1776 :     setArgDerivatives(valueScore, -w_tmp);
    1386        3552 :     getPntrToComponent("biasDer")->set(-w_tmp);
    1387             :   }
    1388        1776 : }
    1389             : 
    1390         295 : void MetainferenceBase::getEnergyForceGJ(const std::vector<double> &mean, const std::vector<double> &dmean_x,
    1391             :     const std::vector<double> &dmean_b) {
    1392         295 :   const double scale2 = scale_*scale_;
    1393         295 :   double inv_s2=0.;
    1394             : 
    1395         295 :   if(master) {
    1396         253 :     inv_s2 = 1./(sigma_[0]*sigma_[0] + scale2*sigma_mean2_[0]);
    1397         253 :     if(nrep_>1) {
    1398          42 :       multi_sim_comm.Sum(inv_s2);
    1399             :     }
    1400             :   }
    1401         295 :   comm.Sum(inv_s2);
    1402             : 
    1403         295 :   double w_tmp = 0.;
    1404         295 :   #pragma omp parallel num_threads(OpenMP::getNumThreads()) shared(w_tmp)
    1405             :   {
    1406             :     #pragma omp for reduction( + : w_tmp)
    1407             :     for(unsigned i=0; i<narg; ++i) {
    1408             :       const double dev = scale_*mean[i]-parameters[i]+offset_;
    1409             :       const double mult = dev*scale_*inv_s2;
    1410             :       setMetaDer(i, kbt_*dmean_x[i]*mult);
    1411             :       w_tmp += kbt_*dmean_b[i]*mult;
    1412             :     }
    1413             :   }
    1414             : 
    1415         295 :   if(do_reweight_) {
    1416          84 :     setArgDerivatives(valueScore, w_tmp);
    1417         168 :     getPntrToComponent("biasDer")->set(w_tmp);
    1418             :   }
    1419         295 : }
    1420             : 
    1421         160 : void MetainferenceBase::getEnergyForceGJE(const std::vector<double> &mean, const std::vector<double> &dmean_x,
    1422             :     const std::vector<double> &dmean_b) {
    1423         160 :   const double scale2 = scale_*scale_;
    1424         160 :   std::vector<double> inv_s2(sigma_.size(),0.);
    1425             : 
    1426         160 :   if(master) {
    1427        2044 :     for(unsigned i=0; i<sigma_.size(); ++i) {
    1428        1952 :       inv_s2[i] = 1./(sigma_[i]*sigma_[i] + scale2*sigma_mean2_[i]);
    1429             :     }
    1430          92 :     if(nrep_>1) {
    1431          92 :       multi_sim_comm.Sum(&inv_s2[0],sigma_.size());
    1432             :     }
    1433             :   }
    1434         160 :   comm.Sum(&inv_s2[0],sigma_.size());
    1435             : 
    1436         160 :   double w_tmp = 0.;
    1437         160 :   #pragma omp parallel num_threads(OpenMP::getNumThreads()) shared(w_tmp)
    1438             :   {
    1439             :     #pragma omp for reduction( + : w_tmp)
    1440             :     for(unsigned i=0; i<narg; ++i) {
    1441             :       const double dev  = scale_*mean[i]-parameters[i]+offset_;
    1442             :       const double mult = dev*scale_*inv_s2[i];
    1443             :       setMetaDer(i, kbt_*dmean_x[i]*mult);
    1444             :       w_tmp += kbt_*dmean_b[i]*mult;
    1445             :     }
    1446             :   }
    1447             : 
    1448         160 :   if(do_reweight_) {
    1449          76 :     setArgDerivatives(valueScore, w_tmp);
    1450         152 :     getPntrToComponent("biasDer")->set(w_tmp);
    1451             :   }
    1452         160 : }
    1453             : 
    1454          36 : void MetainferenceBase::getEnergyForceMIGEN(const std::vector<double> &mean, const std::vector<double> &dmean_x, const std::vector<double> &dmean_b) {
    1455          36 :   std::vector<double> inv_s2(sigma_.size(),0.);
    1456          36 :   std::vector<double> dev(sigma_.size(),0.);
    1457          36 :   std::vector<double> dev2(sigma_.size(),0.);
    1458             : 
    1459         108 :   for(unsigned i=0; i<sigma_.size(); ++i) {
    1460          72 :     inv_s2[i]   = 1./sigma_mean2_[i];
    1461          72 :     if(master) {
    1462          72 :       dev[i]  = (mean[i]-ftilde_[i]);
    1463          72 :       dev2[i] = dev[i]*dev[i];
    1464             :     }
    1465             :   }
    1466          36 :   if(master&&nrep_>1) {
    1467           0 :     multi_sim_comm.Sum(&dev[0],dev.size());
    1468           0 :     multi_sim_comm.Sum(&dev2[0],dev2.size());
    1469             :   }
    1470          36 :   comm.Sum(&dev[0],dev.size());
    1471          36 :   comm.Sum(&dev2[0],dev2.size());
    1472             : 
    1473          36 :   double dene_b = 0.;
    1474          36 :   #pragma omp parallel num_threads(OpenMP::getNumThreads()) shared(dene_b)
    1475             :   {
    1476             :     #pragma omp for reduction( + : dene_b)
    1477             :     for(unsigned i=0; i<narg; ++i) {
    1478             :       const double dene_x  = kbt_*inv_s2[i]*dmean_x[i]*dev[i];
    1479             :       dene_b += kbt_*inv_s2[i]*dmean_b[i]*dev[i];
    1480             :       setMetaDer(i, dene_x);
    1481             :     }
    1482             :   }
    1483             : 
    1484          36 :   if(do_reweight_) {
    1485           0 :     setArgDerivatives(valueScore, dene_b);
    1486           0 :     getPntrToComponent("biasDer")->set(dene_b);
    1487             :   }
    1488          36 : }
    1489             : 
    1490        2327 : void MetainferenceBase::get_weights(double &weight, double &norm, double &neff) {
    1491        2327 :   const double dnrep = static_cast<double>(nrep_);
    1492             :   // calculate the weights either from BIAS
    1493        2327 :   if(do_reweight_) {
    1494        1936 :     std::vector<double> bias(nrep_,0);
    1495        1936 :     if(master) {
    1496         980 :       bias[replica_] = getArgument(0);
    1497         980 :       if(nrep_>1) {
    1498         980 :         multi_sim_comm.Sum(&bias[0], nrep_);
    1499             :       }
    1500             :     }
    1501        1936 :     comm.Sum(&bias[0], nrep_);
    1502             : 
    1503             :     // accumulate weights
    1504        1936 :     if(!firstTimeW[iselect]) {
    1505        5742 :       for(unsigned i=0; i<nrep_; ++i) {
    1506        3828 :         const double delta=bias[i]-average_weights_[iselect][i];
    1507        3828 :         average_weights_[iselect][i]+=decay_w_*delta;
    1508             :       }
    1509             :     } else {
    1510             :       firstTimeW[iselect] = false;
    1511          66 :       for(unsigned i=0; i<nrep_; ++i) {
    1512          44 :         average_weights_[iselect][i] = bias[i];
    1513             :       }
    1514             :     }
    1515             : 
    1516             :     // set average back into bias and set norm to one
    1517        1936 :     const double maxbias = *(std::max_element(average_weights_[iselect].begin(), average_weights_[iselect].end()));
    1518        5808 :     for(unsigned i=0; i<nrep_; ++i) {
    1519        3872 :       bias[i] = std::exp((average_weights_[iselect][i]-maxbias)/kbt_);
    1520             :     }
    1521             :     // set local weight, norm and weight variance
    1522        1936 :     weight = bias[replica_];
    1523             :     double w2=0.;
    1524        5808 :     for(unsigned i=0; i<nrep_; ++i) {
    1525        3872 :       w2 += bias[i]*bias[i];
    1526        3872 :       norm += bias[i];
    1527             :     }
    1528        1936 :     neff = norm*norm/w2;
    1529        3872 :     getPntrToComponent("weight")->set(weight/norm);
    1530             :   } else {
    1531             :     // or arithmetic ones
    1532         391 :     neff = dnrep;
    1533         391 :     weight = 1.0;
    1534         391 :     norm = dnrep;
    1535             :   }
    1536        2327 :   getPntrToComponent("neff")->set(neff);
    1537        2327 : }
    1538             : 
    1539        2327 : void MetainferenceBase::get_sigma_mean(const double weight, const double norm, const double neff, const std::vector<double> &mean) {
    1540        2327 :   const double dnrep    = static_cast<double>(nrep_);
    1541        2327 :   std::vector<double> sigma_mean2_tmp(sigma_mean2_.size());
    1542             : 
    1543        2327 :   if(do_optsigmamean_>0) {
    1544             :     // remove first entry of the history std::vector
    1545          84 :     if(sigma_mean2_last_[iselect][0].size()==optsigmamean_stride_&&optsigmamean_stride_>0)
    1546           0 :       for(unsigned i=0; i<narg; ++i) {
    1547           0 :         sigma_mean2_last_[iselect][i].erase(sigma_mean2_last_[iselect][i].begin());
    1548             :       }
    1549             :     /* this is the current estimate of sigma mean for each argument
    1550             :        there is one of this per argument in any case  because it is
    1551             :        the maximum among these to be used in case of GAUSS/OUTLIER */
    1552          84 :     std::vector<double> sigma_mean2_now(narg,0);
    1553          84 :     if(master) {
    1554         672 :       for(unsigned i=0; i<narg; ++i) {
    1555         630 :         sigma_mean2_now[i] = weight*(calc_data_[i]-mean[i])*(calc_data_[i]-mean[i]);
    1556             :       }
    1557          42 :       if(nrep_>1) {
    1558          42 :         multi_sim_comm.Sum(&sigma_mean2_now[0], narg);
    1559             :       }
    1560             :     }
    1561          84 :     comm.Sum(&sigma_mean2_now[0], narg);
    1562        1344 :     for(unsigned i=0; i<narg; ++i) {
    1563        1260 :       sigma_mean2_now[i] *= 1.0/(neff-1.)/norm;
    1564             :     }
    1565             : 
    1566             :     // add sigma_mean2 to history
    1567          84 :     if(optsigmamean_stride_>0) {
    1568           0 :       for(unsigned i=0; i<narg; ++i) {
    1569           0 :         sigma_mean2_last_[iselect][i].push_back(sigma_mean2_now[i]);
    1570             :       }
    1571             :     } else {
    1572        1344 :       for(unsigned i=0; i<narg; ++i)
    1573        1260 :         if(sigma_mean2_now[i] > sigma_mean2_last_[iselect][i][0]) {
    1574         288 :           sigma_mean2_last_[iselect][i][0] = sigma_mean2_now[i];
    1575             :         }
    1576             :     }
    1577             : 
    1578          84 :     if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
    1579        1344 :       for(unsigned i=0; i<narg; ++i) {
    1580             :         /* set to the maximum in history std::vector */
    1581        1260 :         sigma_mean2_tmp[i] = *max_element(sigma_mean2_last_[iselect][i].begin(), sigma_mean2_last_[iselect][i].end());
    1582             :         /* the standard error of the mean */
    1583        1260 :         valueSigmaMean[i]->set(std::sqrt(sigma_mean2_tmp[i]));
    1584        1260 :         if(noise_type_==GENERIC) {
    1585           0 :           sigma_min_[i] = std::sqrt(sigma_mean2_tmp[i]);
    1586           0 :           if(sigma_[i] < sigma_min_[i]) {
    1587           0 :             sigma_[i] = sigma_min_[i];
    1588             :           }
    1589             :         }
    1590             :       }
    1591           0 :     } else if(noise_type_==GAUSS||noise_type_==OUTLIERS) {
    1592             :       // find maximum for each data point
    1593             :       std::vector <double> max_values;
    1594           0 :       for(unsigned i=0; i<narg; ++i) {
    1595           0 :         max_values.push_back(*max_element(sigma_mean2_last_[iselect][i].begin(), sigma_mean2_last_[iselect][i].end()));
    1596             :       }
    1597             :       // find maximum across data points
    1598           0 :       const double max_now = *max_element(max_values.begin(), max_values.end());
    1599             :       // set new value
    1600           0 :       sigma_mean2_tmp[0] = max_now;
    1601           0 :       valueSigmaMean[0]->set(std::sqrt(sigma_mean2_tmp[0]));
    1602             :     }
    1603             :     // endif sigma mean optimization
    1604             :     // start sigma max optimization
    1605          84 :     if(do_optsigmamean_>1&&!sigmamax_opt_done_) {
    1606           0 :       for(unsigned i=0; i<sigma_max_.size(); i++) {
    1607           0 :         if(sigma_max_est_[i]<sigma_mean2_tmp[i]&&optimized_step_>optsigmamean_stride_) {
    1608           0 :           sigma_max_est_[i]=sigma_mean2_tmp[i];
    1609             :         }
    1610             :         // ready to set once and for all the value of sigma_max
    1611           0 :         if(optimized_step_==N_optimized_step_) {
    1612           0 :           sigmamax_opt_done_=true;
    1613           0 :           for(unsigned i=0; i<sigma_max_.size(); i++) {
    1614           0 :             sigma_max_[i]=std::sqrt(sigma_max_est_[i]*dnrep);
    1615           0 :             Dsigma_[i] = 0.05*(sigma_max_[i] - sigma_min_[i]);
    1616           0 :             if(sigma_[i]>sigma_max_[i]) {
    1617           0 :               sigma_[i]=sigma_max_[i];
    1618             :             }
    1619             :           }
    1620             :         }
    1621             :       }
    1622           0 :       optimized_step_++;
    1623             :     }
    1624             :     // end sigma max optimization
    1625             :   } else {
    1626        2243 :     if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
    1627       11660 :       for(unsigned i=0; i<narg; ++i) {
    1628        9772 :         sigma_mean2_tmp[i] = sigma_mean2_last_[iselect][i][0];
    1629        9772 :         valueSigmaMean[i]->set(std::sqrt(sigma_mean2_tmp[i]));
    1630             :       }
    1631         355 :     } else if(noise_type_==GAUSS||noise_type_==OUTLIERS) {
    1632         355 :       sigma_mean2_tmp[0] = sigma_mean2_last_[iselect][0][0];
    1633         355 :       valueSigmaMean[0]->set(std::sqrt(sigma_mean2_tmp[0]));
    1634             :     }
    1635             :   }
    1636             : 
    1637        2327 :   sigma_mean2_ = sigma_mean2_tmp;
    1638        2327 : }
    1639             : 
    1640        2327 : void MetainferenceBase::replica_averaging(const double weight, const double norm, std::vector<double> &mean, std::vector<double> &dmean_b) {
    1641        2327 :   if(master) {
    1642        8048 :     for(unsigned i=0; i<narg; ++i) {
    1643        6719 :       mean[i] = weight/norm*calc_data_[i];
    1644             :     }
    1645        1329 :     if(nrep_>1) {
    1646        1022 :       multi_sim_comm.Sum(&mean[0], narg);
    1647             :     }
    1648             :   }
    1649        2327 :   comm.Sum(&mean[0], narg);
    1650             :   // set the derivative of the mean with respect to the bias
    1651       14628 :   for(unsigned i=0; i<narg; ++i) {
    1652       12301 :     dmean_b[i] = weight/norm/kbt_*(calc_data_[i]-mean[i])*decay_w_;
    1653             :   }
    1654             : 
    1655             :   // this is only for generic metainference
    1656        2327 :   if(firstTime) {
    1657          34 :     ftilde_ = mean;
    1658          34 :     firstTime = false;
    1659             :   }
    1660        2327 : }
    1661             : 
    1662           6 : void MetainferenceBase::do_regression_zero(const std::vector<double> &mean) {
    1663             : // parameters[i] = scale_ * mean[i]: find scale_ with linear regression
    1664             :   double num = 0.0;
    1665             :   double den = 0.0;
    1666          48 :   for(unsigned i=0; i<parameters.size(); ++i) {
    1667          42 :     num += mean[i] * parameters[i];
    1668          42 :     den += mean[i] * mean[i];
    1669             :   }
    1670           6 :   if(den>0) {
    1671           6 :     scale_ = num / den;
    1672             :   } else {
    1673           0 :     scale_ = 1.0;
    1674             :   }
    1675           6 : }
    1676             : 
    1677        2327 : double MetainferenceBase::getScore() {
    1678             :   /* Metainference */
    1679             :   /* 1) collect weights */
    1680        2327 :   double weight = 0.;
    1681        2327 :   double neff = 0.;
    1682        2327 :   double norm = 0.;
    1683        2327 :   get_weights(weight, norm, neff);
    1684             : 
    1685             :   /* 2) calculate average */
    1686        2327 :   std::vector<double> mean(getNarg(),0);
    1687             :   // this is the derivative of the mean with respect to the argument
    1688        2327 :   std::vector<double> dmean_x(getNarg(),weight/norm);
    1689             :   // this is the derivative of the mean with respect to the bias
    1690        2327 :   std::vector<double> dmean_b(getNarg(),0);
    1691             :   // calculate it
    1692        2327 :   replica_averaging(weight, norm, mean, dmean_b);
    1693             : 
    1694             :   /* 3) calculates parameters */
    1695        2327 :   get_sigma_mean(weight, norm, neff, mean);
    1696             : 
    1697             :   // in case of regression with zero intercept, calculate scale
    1698        2327 :   if(doregres_zero_ && getStep()%nregres_zero_==0) {
    1699           6 :     do_regression_zero(mean);
    1700             :   }
    1701             : 
    1702             :   /* 4) run monte carlo */
    1703        2327 :   double ene = doMonteCarlo(mean);
    1704             : 
    1705             :   // calculate bias and forces
    1706        2327 :   switch(noise_type_) {
    1707         295 :   case GAUSS:
    1708         295 :     getEnergyForceGJ(mean, dmean_x, dmean_b);
    1709             :     break;
    1710         160 :   case MGAUSS:
    1711         160 :     getEnergyForceGJE(mean, dmean_x, dmean_b);
    1712             :     break;
    1713          60 :   case OUTLIERS:
    1714          60 :     getEnergyForceSP(mean, dmean_x, dmean_b);
    1715             :     break;
    1716        1776 :   case MOUTLIERS:
    1717        1776 :     getEnergyForceSPE(mean, dmean_x, dmean_b);
    1718             :     break;
    1719          36 :   case GENERIC:
    1720          36 :     getEnergyForceMIGEN(mean, dmean_x, dmean_b);
    1721             :     break;
    1722             :   }
    1723             : 
    1724        2327 :   return ene;
    1725             : }
    1726             : 
    1727         120 : void MetainferenceBase::writeStatus() {
    1728         120 :   if(!doscore_) {
    1729             :     return;
    1730             :   }
    1731          44 :   sfile_.rewind();
    1732          44 :   sfile_.printField("time",getTimeStep()*getStep());
    1733             :   //nsel
    1734          88 :   for(unsigned i=0; i<sigma_mean2_last_.size(); i++) {
    1735             :     std::string msg_i,msg_j;
    1736          44 :     Tools::convert(i,msg_i);
    1737             :     std::vector <double> max_values;
    1738             :     //narg
    1739        2612 :     for(unsigned j=0; j<narg; ++j) {
    1740        2568 :       Tools::convert(j,msg_j);
    1741        2568 :       std::string msg = msg_i+"_"+msg_j;
    1742        2568 :       if(noise_type_==MGAUSS||noise_type_==MOUTLIERS||noise_type_==GENERIC) {
    1743        7422 :         sfile_.printField("sigmaMean_"+msg,std::sqrt(*max_element(sigma_mean2_last_[i][j].begin(), sigma_mean2_last_[i][j].end())));
    1744             :       } else {
    1745             :         // find maximum for each data point
    1746         188 :         max_values.push_back(*max_element(sigma_mean2_last_[i][j].begin(), sigma_mean2_last_[i][j].end()));
    1747             :       }
    1748             :     }
    1749          44 :     if(noise_type_==GAUSS||noise_type_==OUTLIERS) {
    1750             :       // find maximum across data points
    1751          19 :       const double max_now = std::sqrt(*max_element(max_values.begin(), max_values.end()));
    1752          19 :       Tools::convert(0,msg_j);
    1753          19 :       std::string msg = msg_i+"_"+msg_j;
    1754          38 :       sfile_.printField("sigmaMean_"+msg, max_now);
    1755             :     }
    1756             :   }
    1757        2537 :   for(unsigned i=0; i<sigma_.size(); ++i) {
    1758             :     std::string msg;
    1759        2493 :     Tools::convert(i,msg);
    1760        4986 :     sfile_.printField("sigma_"+msg,sigma_[i]);
    1761             :   }
    1762        2537 :   for(unsigned i=0; i<sigma_max_.size(); ++i) {
    1763             :     std::string msg;
    1764        2493 :     Tools::convert(i,msg);
    1765        4986 :     sfile_.printField("sigma_max_"+msg,sigma_max_[i]);
    1766             :   }
    1767          44 :   if(noise_type_==GENERIC) {
    1768           9 :     for(unsigned i=0; i<ftilde_.size(); ++i) {
    1769             :       std::string msg;
    1770           6 :       Tools::convert(i,msg);
    1771          12 :       sfile_.printField("ftilde_"+msg,ftilde_[i]);
    1772             :     }
    1773             :   }
    1774          44 :   sfile_.printField("scale0_",scale_);
    1775          44 :   sfile_.printField("offset0_",offset_);
    1776          88 :   for(unsigned i=0; i<average_weights_.size(); i++) {
    1777             :     std::string msg_i;
    1778          44 :     Tools::convert(i,msg_i);
    1779          88 :     sfile_.printField("weight_"+msg_i,average_weights_[i][replica_]);
    1780             :   }
    1781          44 :   sfile_.printField();
    1782          44 :   sfile_.flush();
    1783             : }
    1784             : 
    1785             : }
    1786             : }
    1787             : 

Generated by: LCOV version 1.16