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