5da2b4d1d7553b10ab692ecef0b8b8462140be4e
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_wham.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7  * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
8  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9  * and including many others, as listed in the AUTHORS file in the
10  * top-level source directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38
39 /*! \internal \file
40  *  \brief Implementation of the Weighted Histogram Analysis Method (WHAM)
41  *
42  *  \author Jochen Hub <jhub@gwdg.de>
43  */
44 #include "gmxpre.h"
45
46 #include "config.h"
47
48 #include <cassert>
49 #include <cctype>
50 #include <cmath>
51 #include <cstdio>
52 #include <cstdlib>
53 #include <cstring>
54
55 #include <algorithm>
56
57 #include "gromacs/commandline/pargs.h"
58 #include "gromacs/fileio/tpxio.h"
59 #include "gromacs/fileio/xvgr.h"
60 #include "gromacs/gmxana/gmx_ana.h"
61 #include "gromacs/math/functions.h"
62 #include "gromacs/math/units.h"
63 #include "gromacs/math/vec.h"
64 #include "gromacs/mdtypes/inputrec.h"
65 #include "gromacs/mdtypes/md_enums.h"
66 #include "gromacs/mdtypes/pull_params.h"
67 #include "gromacs/mdtypes/state.h"
68 #include "gromacs/pulling/pull.h"
69 #include "gromacs/random/tabulatednormaldistribution.h"
70 #include "gromacs/random/threefry.h"
71 #include "gromacs/random/uniformintdistribution.h"
72 #include "gromacs/random/uniformrealdistribution.h"
73 #include "gromacs/utility/arraysize.h"
74 #include "gromacs/utility/cstringutil.h"
75 #include "gromacs/utility/exceptions.h"
76 #include "gromacs/utility/fatalerror.h"
77 #include "gromacs/utility/futil.h"
78 #include "gromacs/utility/gmxomp.h"
79 #include "gromacs/utility/path.h"
80 #include "gromacs/utility/pleasecite.h"
81 #include "gromacs/utility/smalloc.h"
82
83 //! longest file names allowed in input files
84 #define WHAM_MAXFILELEN 2048
85
86 /*! \brief
87  * enum for energy units
88  */
89 enum
90 {
91     enSel,
92     en_kJ,
93     en_kCal,
94     en_kT,
95     enNr
96 };
97 /*! \brief
98  * enum for type of input files (tpr or pullx/pullf)
99  */
100 enum
101 {
102     whamin_unknown,
103     whamin_tpr,
104     whamin_pullxf,
105 };
106
107 /*! \brief enum for bootstrapping method
108  *
109  * These bootstrap methods are supported:
110  *  - bootstrap complete histograms with continuous weights (Bayesian bootstrap)
111  *    (bsMethod_BayesianHist)
112  *  - bootstrap complete histograms (bsMethod_hist)
113  *  - bootstrap trajectories from given umbrella histograms. This generates new
114  *    "synthetic" histograms (bsMethod_traj)
115  *  - bootstrap trajectories from Gaussian with mu/sigma computed from
116  *    the respective histogram (bsMethod_trajGauss). This gives very similar
117  *    results compared to bsMethod_traj.
118  *
119  *  ********************************************************************
120  *  FOR MORE DETAILS ON THE BOOTSTRAP METHODS (INCLUDING EXAMPLES), SEE
121  *  JS Hub, BL de Groot, D van der Spoel
122  *  g_wham - A free weighted histogram analysis implementation including
123  *  robust error and autocorrelation estimates,
124  *  J Chem Theory Comput, 6(12), 3713-3720 (2010)
125  *  ********************************************************************
126  */
127 enum
128 {
129     bsMethod_unknown,
130     bsMethod_BayesianHist,
131     bsMethod_hist,
132     bsMethod_traj,
133     bsMethod_trajGauss
134 };
135
136 //! Parameters of one pull coordinate
137 typedef struct
138 {
139     PullingAlgorithm  pull_type;       //!< such as constraint, umbrella, ...
140     PullGroupGeometry geometry;        //!< such as distance, direction, cylinder
141     int               ngroup;          //!< the number of pull groups involved
142     ivec              dim;             //!< pull dimension with geometry distance
143     int               ndim;            //!< nr of pull_dim != 0
144     real              k;               //!< force constants in tpr file
145     real              init_dist;       //!< reference displacement
146     char              coord_unit[256]; //!< unit of the displacement
147 } t_pullcoord;
148
149 //! Parameters of the umbrella potentials
150 typedef struct
151 {
152     /*!
153      * \name Using umbrella pull code since gromacs 4.x
154      */
155     /*!\{*/
156     int          npullcrds;      //!< nr of umbrella pull coordinates for reading
157     t_pullcoord* pcrd;           //!< the pull coordinates
158     gmx_bool     bPrintCOM;      //!< COMs of pull groups writtn in pullx.xvg
159     gmx_bool     bPrintRefValue; //!< Reference value for the coordinate written in pullx.xvg
160     gmx_bool     bPrintComp;     //!< Components of pull distance written to pullx.xvg ?
161
162     /*!\}*/
163 } t_UmbrellaHeader;
164
165 //! Data in the umbrella histograms
166 typedef struct
167 {
168     int      nPull; //!< nr of pull groups in this pullf/pullx file
169     double** Histo; //!< nPull histograms
170     double** cum;   //!< nPull cumulative distribution functions
171     int      nBin;  //!< nr of bins. identical to opt->bins
172     double*  k;     //!< force constants for the nPull coords
173     double*  pos;   //!< umbrella positions for the nPull coords
174     double* z; //!< z=(-Fi/kT) for the nPull coords. These values are iteratively computed during wham
175     int*    N;    //!< nr of data points in nPull histograms.
176     int*    Ntot; //!< also nr of data points. N and Ntot only differ if bHistEq==TRUE
177
178     /*! \brief  g = 1 + 2*tau[int]/dt where tau is the integrated autocorrelation time.
179      *
180      * Compare, e.g. Ferrenberg/Swendsen, PRL 63:1195 (1989),
181      * Kumar et al, J Comp Chem 13, 1011-1021 (1992), eq. 28
182      */
183     double* g;
184     double* tau;       //!< intetrated autocorrelation time (IACT)
185     double* tausmooth; //!< smoothed IACT
186
187     double dt; //!< timestep in the input data. Can be adapted with gmx wham option -dt
188
189     /*! \brief TRUE, if any data point of the histogram is within min and max, otherwise FALSE */
190     gmx_bool** bContrib;
191     real**     ztime; //!< input data z(t) as a function of time. Required to compute ACTs
192
193     /*! \brief average force estimated from average displacement, fAv=dzAv*k
194      *
195      *  Used for integration to guess the potential.
196      */
197     real*   forceAv;
198     real*   aver;     //!< average of histograms
199     real*   sigma;    //!< stddev of histograms
200     double* bsWeight; //!< for bootstrapping complete histograms with continuous weights
201 } t_UmbrellaWindow;
202
203 //! Selection of pull coordinates to be used in WHAM (one structure for each tpr file)
204 typedef struct
205 {
206     int       n;    //!< total nr of pull coords in this tpr file
207     int       nUse; //!< nr of pull coords used
208     gmx_bool* bUse; //!< boolean array of size n. =1 if used, =0 if not
209 } t_coordselection;
210
211 //! Parameters of WHAM
212 typedef struct UmbrellaOptions // NOLINT(clang-analyzer-optin.performance.Padding)
213 {
214     /*!
215      * \name Input stuff
216      */
217     /*!\{*/
218     const char *fnTpr, *fnPullf, *fnCoordSel;
219     const char* fnPullx;              //!< file names of input
220     gmx_bool    bTpr, bPullf, bPullx; //!< input file types given?
221     real        tmin, tmax, dt;       //!< only read input within tmin and tmax with dt
222
223     gmx_bool bInitPotByIntegration; //!< before WHAM, guess potential by force integration. Yields 1.5 to 2 times faster convergence
224     int stepUpdateContrib; //!< update contribution table every ... iterations. Accelerates WHAM.
225     int nCoordsel;         //!< if >0: use only certain group in WHAM, if ==0: use all groups
226     t_coordselection* coordsel; //!< for each tpr file: which pull coordinates to use in WHAM?
227     /*!\}*/
228     /*!
229      * \name Basic WHAM options
230      */
231     /*!\{*/
232     int  bins; //!< nr of bins, min, max, and dz of profile
233     real min, max, dz;
234     real Temperature, Tolerance; //!< temperature, converged when probability changes less than Tolerance
235     gmx_bool bCycl;              //!< generate cyclic (periodic) PMF
236     /*!\}*/
237     /*!
238      * \name Output control
239      */
240     /*!\{*/
241     gmx_bool bLog; //!< energy output (instead of probability) for profile
242     int      unit; //!< unit for PMF output kJ/mol or kT or kCal/mol
243     gmx_bool bSym; //!< symmetrize PMF around z=0 after WHAM, useful for membranes etc.
244     /*! \brief after wham, set prof to zero at this z-position.
245      * When bootstrapping, set zProf0 to a "stable" reference position.
246      */
247     real     zProf0;
248     gmx_bool bProf0Set; //!< setting profile to 0 at zProf0?
249
250     gmx_bool bBoundsOnly, bHistOnly; //!< determine min and max, or write histograms and exit
251     gmx_bool bAuto;                  //!< determine min and max automatically but do not exit
252
253     gmx_bool          verbose;    //!< more noisy wham mode
254     int               stepchange; //!< print maximum change in prof after how many interations
255     gmx_output_env_t* oenv;       //!< xvgr options
256     /*!\}*/
257     /*!
258      * \name Autocorrelation stuff
259      */
260     /*!\{*/
261     gmx_bool bTauIntGiven, bCalcTauInt; //!< IACT given or should be calculated?
262     real     sigSmoothIact;             //!< sigma of Gaussian to smooth ACTs
263     gmx_bool bAllowReduceIact; //!< Allow to reduce ACTs during smoothing. Otherwise ACT are only increased during smoothing
264     real     acTrestart; //!< when computing ACT, time between restarting points
265
266     /* \brief Enforce the same weight for each umbella window, that is
267      *  calculate with the same number of data points for
268      *  each window. That can be reasonable, if the histograms
269      *  have different length, but due to autocorrelation,
270      *  a longer simulation should not have larger weightin wham.
271      */
272     gmx_bool bHistEq;
273     /*!\}*/
274
275     /*!
276      * \name Bootstrapping stuff
277      */
278     /*!\{*/
279     int nBootStrap; //!< nr of bootstraps (50 is usually enough)
280
281     /* \brief bootstrap method
282      *
283      * if == bsMethod_hist, consider complete histograms as independent
284      * data points and, hence, only mix complete histograms.
285      * if == bsMethod_BayesianHist, consider complete histograms
286      * as independent data points, but assign random weights
287      * to the histograms during the bootstrapping ("Bayesian bootstrap")
288      * In case of long correlations (e.g., inside a channel), these
289      * will yield a more realistic error.
290      * if == bsMethod_traj(Gauss), generate synthetic histograms
291      * for each given
292      * histogram by generating an autocorrelated random sequence
293      * that is distributed according to the respective given
294      * histogram. With bsMethod_trajGauss, bootstrap from a Gaussian
295      * (instead of from the umbrella histogram) to generate a new
296      * histogram.
297      */
298     int bsMethod;
299
300     /* \brief  autocorrelation time (ACT) used to generate synthetic histograms. If ==0, use calculated ACF */
301     real tauBootStrap;
302
303     /* \brief when mixing histograms, mix only histograms withing blocks
304               long the reaction coordinate xi. Avoids gaps along xi. */
305     int histBootStrapBlockLength;
306
307     int bsSeed; //!< random seed for bootstrapping
308
309     /* \brief Write cumulative distribution functions (CDFs) of histograms
310               and write the generated histograms for each bootstrap */
311     gmx_bool bs_verbose;
312     /*!\}*/
313     /*!
314      * \name tabulated umbrella potential stuff
315      */
316     /*!\{*/
317     gmx_bool bTab;
318     double * tabX, *tabY, tabMin, tabMax, tabDz;
319     int      tabNbins;
320     /*!\}*/
321     gmx::DefaultRandomEngine           rng;                //!< gromacs random number generator
322     gmx::TabulatedNormalDistribution<> normalDistribution; //!< Uses default: real output, 14-bit table
323 } t_UmbrellaOptions;
324
325 //! Make an umbrella window (may contain several histograms)
326 static t_UmbrellaWindow* initUmbrellaWindows(int nwin)
327 {
328     t_UmbrellaWindow* win;
329     int               i;
330     snew(win, nwin);
331     for (i = 0; i < nwin; i++)
332     {
333         win[i].Histo = win[i].cum = nullptr;
334         win[i].k = win[i].pos = win[i].z = nullptr;
335         win[i].N = win[i].Ntot = nullptr;
336         win[i].g = win[i].tau = win[i].tausmooth = nullptr;
337         win[i].bContrib                          = nullptr;
338         win[i].ztime                             = nullptr;
339         win[i].forceAv                           = nullptr;
340         win[i].aver = win[i].sigma = nullptr;
341         win[i].bsWeight            = nullptr;
342     }
343     return win;
344 }
345
346 //! Delete an umbrella window (may contain several histograms)
347 static void freeUmbrellaWindows(t_UmbrellaWindow* win, int nwin)
348 {
349     int i, j;
350     for (i = 0; i < nwin; i++)
351     {
352         if (win[i].Histo)
353         {
354             for (j = 0; j < win[i].nPull; j++)
355             {
356                 sfree(win[i].Histo[j]);
357             }
358         }
359         if (win[i].cum)
360         {
361             for (j = 0; j < win[i].nPull; j++)
362             {
363                 sfree(win[i].cum[j]);
364             }
365         }
366         if (win[i].bContrib)
367         {
368             for (j = 0; j < win[i].nPull; j++)
369             {
370                 sfree(win[i].bContrib[j]);
371             }
372         }
373         sfree(win[i].Histo);
374         sfree(win[i].cum);
375         sfree(win[i].k);
376         sfree(win[i].pos);
377         sfree(win[i].z);
378         sfree(win[i].N);
379         sfree(win[i].Ntot);
380         sfree(win[i].g);
381         sfree(win[i].tau);
382         sfree(win[i].tausmooth);
383         sfree(win[i].bContrib);
384         sfree(win[i].ztime);
385         sfree(win[i].forceAv);
386         sfree(win[i].aver);
387         sfree(win[i].sigma);
388         sfree(win[i].bsWeight);
389     }
390     sfree(win);
391 }
392
393 /*! \brief
394  * Read and setup tabulated umbrella potential
395  */
396 static void setup_tab(const char* fn, t_UmbrellaOptions* opt)
397 {
398     int      i, ny, nl;
399     double** y;
400
401     printf("Setting up tabulated potential from file %s\n", fn);
402     nl            = read_xvg(fn, &y, &ny);
403     opt->tabNbins = nl;
404     if (ny != 2)
405     {
406         gmx_fatal(FARGS, "Found %d columns in %s. Expected 2.\n", ny, fn);
407     }
408     opt->tabMin = y[0][0];
409     opt->tabMax = y[0][nl - 1];
410     opt->tabDz  = (opt->tabMax - opt->tabMin) / (nl - 1);
411     if (opt->tabDz <= 0)
412     {
413         gmx_fatal(FARGS,
414                   "The tabulated potential in %s must be provided in \n"
415                   "ascending z-direction",
416                   fn);
417     }
418     for (i = 0; i < nl - 1; i++)
419     {
420         if (std::abs(y[0][i + 1] - y[0][i] - opt->tabDz) > opt->tabDz / 1e6)
421         {
422             gmx_fatal(FARGS, "z-values in %s are not equally spaced.\n", fn);
423         }
424     }
425     snew(opt->tabY, nl);
426     snew(opt->tabX, nl);
427     for (i = 0; i < nl; i++)
428     {
429         opt->tabX[i] = y[0][i];
430         opt->tabY[i] = y[1][i];
431     }
432     printf("Found equally spaced tabulated potential from %g to %g, spacing %g\n",
433            opt->tabMin,
434            opt->tabMax,
435            opt->tabDz);
436 }
437
438 //! smarter fgets
439 static char* fgets3(FILE* fp, char ptr[], int* len)
440 {
441     char* p;
442     int   slen;
443
444     if (fgets(ptr, *len - 1, fp) == nullptr)
445     {
446         return nullptr;
447     }
448     p = ptr;
449     while ((std::strchr(ptr, '\n') == nullptr) && (!feof(fp)))
450     {
451         /* This line is longer than len characters, let's increase len! */
452         *len += STRLEN;
453         p += STRLEN;
454         srenew(ptr, *len);
455         if (fgets(p - 1, STRLEN, fp) == nullptr)
456         {
457             break;
458         }
459     }
460     slen = std::strlen(ptr);
461     if (ptr[slen - 1] == '\n')
462     {
463         ptr[slen - 1] = '\0';
464     }
465
466     return ptr;
467 }
468
469 /*! \brief Set identical weights for all histograms
470  *
471  * Normally, the weight is given by the number data points in each
472  * histogram, together with the autocorrelation time. This can be overwritten
473  * by this routine (not recommended). Since we now support autocorrelations, it is better to set
474  * an appropriate autocorrelation times instead of using this function.
475  */
476 static void enforceEqualWeights(t_UmbrellaWindow* window, int nWindows)
477 {
478     int    i, k, j, NEnforced;
479     double ratio;
480
481     NEnforced = window[0].Ntot[0];
482     printf("\nFound -hist-eq. Enforcing equal weights for all histograms, \ni.e. doing a "
483            "non-weighted histogram analysis method. Ndata = %d\n",
484            NEnforced);
485     /* enforce all histograms to have the same weight as the very first histogram */
486
487     for (j = 0; j < nWindows; ++j)
488     {
489         for (k = 0; k < window[j].nPull; ++k)
490         {
491             ratio = 1.0 * NEnforced / window[j].Ntot[k];
492             for (i = 0; i < window[0].nBin; ++i)
493             {
494                 window[j].Histo[k][i] *= ratio;
495             }
496             window[j].N[k] = gmx::roundToInt(ratio * window[j].N[k]);
497         }
498     }
499 }
500
501 /*! \brief Simple linear interpolation between two given tabulated points
502  */
503 static double tabulated_pot(double dist, t_UmbrellaOptions* opt)
504 {
505     int    jl, ju;
506     double pl, pu, dz, dp;
507
508     jl = static_cast<int>(std::floor((dist - opt->tabMin) / opt->tabDz));
509     ju = jl + 1;
510     if (jl < 0 || ju >= opt->tabNbins)
511     {
512         gmx_fatal(FARGS,
513                   "Distance %f out of bounds of tabulated potential (jl=%d, ju=%d).\n"
514                   "Provide an extended table.",
515                   dist,
516                   jl,
517                   ju);
518     }
519     pl = opt->tabY[jl];
520     pu = opt->tabY[ju];
521     dz = dist - opt->tabX[jl];
522     dp = (pu - pl) * dz / opt->tabDz;
523     return pl + dp;
524 }
525
526
527 /*! \brief
528  * Check which bins substiantially contribute (accelerates WHAM)
529  *
530  * Don't worry, that routine does not mean we compute the PMF in limited precision.
531  * After rapid convergence (using only substiantal contributions), we always switch to
532  * full precision.
533  */
534 static void setup_acc_wham(const double* profile, t_UmbrellaWindow* window, int nWindows, t_UmbrellaOptions* opt)
535 {
536     int        i, j, k, nGrptot = 0, nContrib = 0, nTot = 0;
537     double     U, min = opt->min, dz = opt->dz, temp, ztot_half, distance, ztot, contrib1, contrib2;
538     gmx_bool   bAnyContrib;
539     static int bFirst = 1;
540     static double wham_contrib_lim;
541
542     if (bFirst)
543     {
544         for (i = 0; i < nWindows; ++i)
545         {
546             nGrptot += window[i].nPull;
547         }
548         wham_contrib_lim = opt->Tolerance / nGrptot;
549     }
550
551     ztot      = opt->max - opt->min;
552     ztot_half = ztot / 2;
553
554     for (i = 0; i < nWindows; ++i)
555     {
556         if (!window[i].bContrib)
557         {
558             snew(window[i].bContrib, window[i].nPull);
559         }
560         for (j = 0; j < window[i].nPull; ++j)
561         {
562             if (!window[i].bContrib[j])
563             {
564                 snew(window[i].bContrib[j], opt->bins);
565             }
566             bAnyContrib = FALSE;
567             for (k = 0; k < opt->bins; ++k)
568             {
569                 temp     = (1.0 * k + 0.5) * dz + min;
570                 distance = temp - window[i].pos[j]; /* distance to umbrella center */
571                 if (opt->bCycl)
572                 {                             /* in cyclic wham:             */
573                     if (distance > ztot_half) /*    |distance| < ztot_half   */
574                     {
575                         distance -= ztot;
576                     }
577                     else if (distance < -ztot_half)
578                     {
579                         distance += ztot;
580                     }
581                 }
582                 /* Note: there are two contributions to bin k in the wham equations:
583                    i)  N[j]*exp(- U/(c_boltz*opt->Temperature) + window[i].z[j])
584                    ii) exp(- U/(c_boltz*opt->Temperature))
585                    where U is the umbrella potential
586                    If any of these number is larger wham_contrib_lim, I set contrib=TRUE
587                  */
588
589                 if (!opt->bTab)
590                 {
591                     U = 0.5 * window[i].k[j] * gmx::square(distance); /* harmonic potential assumed. */
592                 }
593                 else
594                 {
595                     U = tabulated_pot(distance, opt); /* Use tabulated potential     */
596                 }
597                 contrib1 = profile[k] * std::exp(-U / (gmx::c_boltz * opt->Temperature));
598                 contrib2 = window[i].N[j]
599                            * std::exp(-U / (gmx::c_boltz * opt->Temperature) + window[i].z[j]);
600                 window[i].bContrib[j][k] = (contrib1 > wham_contrib_lim || contrib2 > wham_contrib_lim);
601                 bAnyContrib              = bAnyContrib || window[i].bContrib[j][k];
602                 if (window[i].bContrib[j][k])
603                 {
604                     nContrib++;
605                 }
606                 nTot++;
607             }
608             /* If this histo is far outside min and max all bContrib may be FALSE,
609                causing a floating point exception later on. To avoid that, switch
610                them all to true.*/
611             if (!bAnyContrib)
612             {
613                 for (k = 0; k < opt->bins; ++k)
614                 {
615                     window[i].bContrib[j][k] = TRUE;
616                 }
617             }
618         }
619     }
620     if (bFirst)
621     {
622         printf("Initialized rapid wham stuff (contrib tolerance %g)\n"
623                "Evaluating only %d of %d expressions.\n\n",
624                wham_contrib_lim,
625                nContrib,
626                nTot);
627     }
628
629     if (opt->verbose)
630     {
631         printf("Updated rapid wham stuff. (evaluating only %d of %d contributions)\n", nContrib, nTot);
632     }
633     bFirst = 0;
634 }
635
636 //! Compute the PMF (one of the two main WHAM routines)
637 static void calc_profile(double* profile, t_UmbrellaWindow* window, int nWindows, t_UmbrellaOptions* opt, gmx_bool bExact)
638 {
639     double ztot_half, ztot, min = opt->min, dz = opt->dz;
640
641     ztot      = opt->max - opt->min;
642     ztot_half = ztot / 2;
643
644 #pragma omp parallel
645     {
646         try
647         {
648             int nthreads  = gmx_omp_get_max_threads();
649             int thread_id = gmx_omp_get_thread_num();
650             int i;
651             int i0 = thread_id * opt->bins / nthreads;
652             int i1 = std::min(opt->bins, ((thread_id + 1) * opt->bins) / nthreads);
653
654             for (i = i0; i < i1; ++i)
655             {
656                 int    j, k;
657                 double num, denom, invg, temp = 0, distance, U = 0;
658                 num = denom = 0.;
659                 for (j = 0; j < nWindows; ++j)
660                 {
661                     for (k = 0; k < window[j].nPull; ++k)
662                     {
663                         invg = 1.0 / window[j].g[k] * window[j].bsWeight[k];
664                         temp = (1.0 * i + 0.5) * dz + min;
665                         num += invg * window[j].Histo[k][i];
666
667                         if (!(bExact || window[j].bContrib[k][i]))
668                         {
669                             continue;
670                         }
671                         distance = temp - window[j].pos[k]; /* distance to umbrella center */
672                         if (opt->bCycl)
673                         {                             /* in cyclic wham:             */
674                             if (distance > ztot_half) /*    |distance| < ztot_half   */
675                             {
676                                 distance -= ztot;
677                             }
678                             else if (distance < -ztot_half)
679                             {
680                                 distance += ztot;
681                             }
682                         }
683
684                         if (!opt->bTab)
685                         {
686                             U = 0.5 * window[j].k[k] * gmx::square(distance); /* harmonic potential assumed. */
687                         }
688                         else
689                         {
690                             U = tabulated_pot(distance, opt); /* Use tabulated potential     */
691                         }
692                         denom += invg * window[j].N[k]
693                                  * std::exp(-U / (gmx::c_boltz * opt->Temperature) + window[j].z[k]);
694                     }
695                 }
696                 profile[i] = num / denom;
697             }
698         }
699         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
700     }
701 }
702
703 //! Compute the free energy offsets z (one of the two main WHAM routines)
704 static double calc_z(const double* profile, t_UmbrellaWindow* window, int nWindows, t_UmbrellaOptions* opt, gmx_bool bExact)
705 {
706     double min = opt->min, dz = opt->dz, ztot_half, ztot;
707     double maxglob = -1e20;
708
709     ztot      = opt->max - opt->min;
710     ztot_half = ztot / 2;
711
712 #pragma omp parallel
713     {
714         try
715         {
716             int    nthreads  = gmx_omp_get_max_threads();
717             int    thread_id = gmx_omp_get_thread_num();
718             int    i;
719             int    i0     = thread_id * nWindows / nthreads;
720             int    i1     = std::min(nWindows, ((thread_id + 1) * nWindows) / nthreads);
721             double maxloc = -1e20;
722
723             for (i = i0; i < i1; ++i)
724             {
725                 double total = 0, temp, distance, U = 0;
726                 int    j, k;
727
728                 for (j = 0; j < window[i].nPull; ++j)
729                 {
730                     total = 0;
731                     for (k = 0; k < window[i].nBin; ++k)
732                     {
733                         if (!(bExact || window[i].bContrib[j][k]))
734                         {
735                             continue;
736                         }
737                         temp     = (1.0 * k + 0.5) * dz + min;
738                         distance = temp - window[i].pos[j]; /* distance to umbrella center */
739                         if (opt->bCycl)
740                         {                             /* in cyclic wham:             */
741                             if (distance > ztot_half) /*    |distance| < ztot_half   */
742                             {
743                                 distance -= ztot;
744                             }
745                             else if (distance < -ztot_half)
746                             {
747                                 distance += ztot;
748                             }
749                         }
750
751                         if (!opt->bTab)
752                         {
753                             U = 0.5 * window[i].k[j] * gmx::square(distance); /* harmonic potential assumed. */
754                         }
755                         else
756                         {
757                             U = tabulated_pot(distance, opt); /* Use tabulated potential     */
758                         }
759                         total += profile[k] * std::exp(-U / (gmx::c_boltz * opt->Temperature));
760                     }
761                     /* Avoid floating point exception if window is far outside min and max */
762                     if (total != 0.0)
763                     {
764                         total = -std::log(total);
765                     }
766                     else
767                     {
768                         total = 1000.0;
769                     }
770                     temp = std::abs(total - window[i].z[j]);
771                     if (temp > maxloc)
772                     {
773                         maxloc = temp;
774                     }
775                     window[i].z[j] = total;
776                 }
777             }
778             /* Now get maximum maxloc from the threads and put in maxglob */
779             if (maxloc > maxglob)
780             {
781 #pragma omp critical
782                 {
783                     if (maxloc > maxglob)
784                     {
785                         maxglob = maxloc;
786                     }
787                 }
788             }
789         }
790         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
791     }
792
793     return maxglob;
794 }
795
796 //! Make PMF symmetric around 0 (useful e.g. for membranes)
797 static void symmetrizeProfile(double* profile, t_UmbrellaOptions* opt)
798 {
799     int     i, j, bins = opt->bins;
800     double *prof2, min = opt->min, max = opt->max, dz = opt->dz, zsym, deltaz, profsym;
801     double  z, z1;
802
803     if (min > 0. || max < 0.)
804     {
805         gmx_fatal(FARGS, "Cannot symmetrize profile around z=0 with min=%f and max=%f\n", opt->min, opt->max);
806     }
807
808     snew(prof2, bins);
809
810     for (i = 0; i < bins; i++)
811     {
812         z    = min + (i + 0.5) * dz;
813         zsym = -z;
814         /* bin left of zsym */
815         j = gmx::roundToInt((zsym - min) / dz) - 1;
816         if (j >= 0 && (j + 1) < bins)
817         {
818             /* interpolate profile linearly between bins j and j+1 */
819             z1      = min + (j + 0.5) * dz;
820             deltaz  = zsym - z1;
821             profsym = profile[j] + (profile[j + 1] - profile[j]) / dz * deltaz;
822             /* average between left and right */
823             prof2[i] = 0.5 * (profsym + profile[i]);
824         }
825         else
826         {
827             prof2[i] = profile[i];
828         }
829     }
830
831     std::memcpy(profile, prof2, bins * sizeof(double));
832     sfree(prof2);
833 }
834
835 //! Set energy unit (kJ/mol,kT,kCal/mol) and set it to zero at opt->zProf0
836 static void prof_normalization_and_unit(double* profile, t_UmbrellaOptions* opt)
837 {
838     int    i, bins, imin;
839     double unit_factor = 1., diff;
840
841     bins = opt->bins;
842
843     /* Not log? Nothing to do! */
844     if (!opt->bLog)
845     {
846         return;
847     }
848
849     /* Get profile in units of kT, kJ/mol, or kCal/mol */
850     if (opt->unit == en_kT)
851     {
852         unit_factor = 1.0;
853     }
854     else if (opt->unit == en_kJ)
855     {
856         unit_factor = gmx::c_boltz * opt->Temperature;
857     }
858     else if (opt->unit == en_kCal)
859     {
860         unit_factor = (gmx::c_boltz / gmx::c_cal2Joule) * opt->Temperature;
861     }
862     else
863     {
864         gmx_fatal(FARGS, "Sorry, I don't know this energy unit.");
865     }
866
867     for (i = 0; i < bins; i++)
868     {
869         if (profile[i] > 0.0)
870         {
871             profile[i] = -std::log(profile[i]) * unit_factor;
872         }
873     }
874
875     /* shift to zero at z=opt->zProf0 */
876     if (!opt->bProf0Set)
877     {
878         diff = profile[0];
879     }
880     else
881     {
882         /* Get bin with shortest distance to opt->zProf0
883            (-0.5 from bin position and +0.5 from rounding cancel) */
884         imin = static_cast<int>((opt->zProf0 - opt->min) / opt->dz);
885         if (imin < 0)
886         {
887             imin = 0;
888         }
889         else if (imin >= bins)
890         {
891             imin = bins - 1;
892         }
893         diff = profile[imin];
894     }
895
896     /* Shift to zero */
897     for (i = 0; i < bins; i++)
898     {
899         profile[i] -= diff;
900     }
901 }
902
903 //! Make an array of random integers (used for bootstrapping)
904 static void getRandomIntArray(int nPull, int blockLength, int* randomArray, gmx::DefaultRandomEngine* rng)
905 {
906     gmx::UniformIntDistribution<int> dist(0, blockLength - 1);
907
908     int ipull, blockBase, nr, ipullRandom;
909
910     if (blockLength == 0)
911     {
912         blockLength = nPull;
913     }
914
915     for (ipull = 0; ipull < nPull; ipull++)
916     {
917         blockBase = (ipull / blockLength) * blockLength;
918         do
919         {                             /* make sure nothing bad happens in the last block */
920             nr          = dist(*rng); // [0,blockLength-1]
921             ipullRandom = blockBase + nr;
922         } while (ipullRandom >= nPull);
923         if (ipullRandom < 0 || ipullRandom >= nPull)
924         {
925             gmx_fatal(FARGS,
926                       "Ups, random iWin = %d, nPull = %d, nr = %d, "
927                       "blockLength = %d, blockBase = %d\n",
928                       ipullRandom,
929                       nPull,
930                       nr,
931                       blockLength,
932                       blockBase);
933         }
934         randomArray[ipull] = ipullRandom;
935     }
936 }
937
938 /*! \brief Set pull group information of a synthetic histogram
939  *
940  * This is used when bootstapping new trajectories and thereby create new histogtrams,
941  * but it is not required if we bootstrap complete histograms.
942  */
943 static void copy_pullgrp_to_synthwindow(t_UmbrellaWindow* synthWindow, t_UmbrellaWindow* thisWindow, int pullid)
944 {
945     synthWindow->N[0]        = thisWindow->N[pullid];
946     synthWindow->Histo[0]    = thisWindow->Histo[pullid];
947     synthWindow->pos[0]      = thisWindow->pos[pullid];
948     synthWindow->z[0]        = thisWindow->z[pullid];
949     synthWindow->k[0]        = thisWindow->k[pullid];
950     synthWindow->bContrib[0] = thisWindow->bContrib[pullid];
951     synthWindow->g[0]        = thisWindow->g[pullid];
952     synthWindow->bsWeight[0] = thisWindow->bsWeight[pullid];
953 }
954
955 /*! \brief Calculate cumulative distribution function of of all histograms.
956  *
957  * This allow to create random number sequences
958  * which are distributed according to the histograms. Required to generate
959  * the "synthetic" histograms for the Bootstrap method
960  */
961 static void calc_cumulatives(t_UmbrellaWindow*  window,
962                              int                nWindows,
963                              t_UmbrellaOptions* opt,
964                              const char*        fnhist,
965                              const char*        xlabel)
966 {
967     int         i, j, k, nbin;
968     double      last;
969     std::string fn;
970     FILE*       fp = nullptr;
971
972     if (opt->bs_verbose)
973     {
974         fn = gmx::Path::concatenateBeforeExtension(fnhist, "_cumul");
975         fp = xvgropen(fn.c_str(), "CDFs of umbrella windows", xlabel, "CDF", opt->oenv);
976     }
977
978     nbin = opt->bins;
979     for (i = 0; i < nWindows; i++)
980     {
981         snew(window[i].cum, window[i].nPull);
982         for (j = 0; j < window[i].nPull; j++)
983         {
984             snew(window[i].cum[j], nbin + 1);
985             window[i].cum[j][0] = 0.;
986             for (k = 1; k <= nbin; k++)
987             {
988                 window[i].cum[j][k] = window[i].cum[j][k - 1] + window[i].Histo[j][k - 1];
989             }
990
991             /* normalize CDFs. Ensure cum[nbin]==1 */
992             last = window[i].cum[j][nbin];
993             for (k = 0; k <= nbin; k++)
994             {
995                 window[i].cum[j][k] /= last;
996             }
997         }
998     }
999
1000     printf("Cumulative distribution functions of all histograms created.\n");
1001     if (opt->bs_verbose)
1002     {
1003         for (k = 0; k <= nbin; k++)
1004         {
1005             fprintf(fp, "%g\t", opt->min + k * opt->dz);
1006             for (i = 0; i < nWindows; i++)
1007             {
1008                 for (j = 0; j < window[i].nPull; j++)
1009                 {
1010                     fprintf(fp, "%g\t", window[i].cum[j][k]);
1011                 }
1012             }
1013             fprintf(fp, "\n");
1014         }
1015         printf("Wrote cumulative distribution functions to %s\n", fn.c_str());
1016         xvgrclose(fp);
1017     }
1018 }
1019
1020
1021 /*! \brief Return j such that xx[j] <= x < xx[j+1]
1022  *
1023  *  This is used to generate a random sequence distributed according to a histogram
1024  */
1025 static void searchCumulative(const double xx[], int n, double x, int* j)
1026 {
1027     int ju, jm, jl;
1028
1029     jl = -1;
1030     ju = n;
1031     while (ju - jl > 1)
1032     {
1033         jm = (ju + jl) >> 1;
1034         if (x >= xx[jm])
1035         {
1036             jl = jm;
1037         }
1038         else
1039         {
1040             ju = jm;
1041         }
1042     }
1043     if (x == xx[0])
1044     {
1045         *j = 0;
1046     }
1047     else if (x == xx[n - 1])
1048     {
1049         *j = n - 2;
1050     }
1051     else
1052     {
1053         *j = jl;
1054     }
1055 }
1056
1057 //! Bootstrap new trajectories and thereby generate new (bootstrapped) histograms
1058 static void create_synthetic_histo(t_UmbrellaWindow*  synthWindow,
1059                                    t_UmbrellaWindow*  thisWindow,
1060                                    int                pullid,
1061                                    t_UmbrellaOptions* opt)
1062 {
1063     int    N, i, nbins, r_index, ibin;
1064     double r, tausteps = 0.0, a, ap, dt, x, invsqrt2, g, y, sig = 0., z, mu = 0.;
1065     char   errstr[1024];
1066
1067     N     = thisWindow->N[pullid];
1068     dt    = thisWindow->dt;
1069     nbins = thisWindow->nBin;
1070
1071     /* tau = autocorrelation time */
1072     if (opt->tauBootStrap > 0.0)
1073     {
1074         tausteps = opt->tauBootStrap / dt;
1075     }
1076     else if (opt->bTauIntGiven || opt->bCalcTauInt)
1077     {
1078         /* calc tausteps from g=1+2tausteps */
1079         g        = thisWindow->g[pullid];
1080         tausteps = (g - 1) / 2;
1081     }
1082     else
1083     {
1084         sprintf(errstr,
1085                 "When generating hypothetical trajectories from given umbrella histograms,\n"
1086                 "autocorrelation times (ACTs) are required. Otherwise the statistical error\n"
1087                 "cannot be predicted. You have 3 options:\n"
1088                 "1) Make gmx wham estimate the ACTs (options -ac and -acsig).\n"
1089                 "2) Calculate the ACTs by yourself (e.g. with g_analyze) and provide them\n");
1090         std::strcat(errstr,
1091                     "   with option -iiact for all umbrella windows.\n"
1092                     "3) If all ACTs are identical and know, you can define them with -bs-tau.\n"
1093                     "   Use option (3) only if you are sure what you're doing, you may severely\n"
1094                     "   underestimate the error if a too small ACT is given.\n");
1095         gmx_fatal(FARGS, "%s", errstr);
1096     }
1097
1098     synthWindow->N[0]        = N;
1099     synthWindow->pos[0]      = thisWindow->pos[pullid];
1100     synthWindow->z[0]        = thisWindow->z[pullid];
1101     synthWindow->k[0]        = thisWindow->k[pullid];
1102     synthWindow->bContrib[0] = thisWindow->bContrib[pullid];
1103     synthWindow->g[0]        = thisWindow->g[pullid];
1104     synthWindow->bsWeight[0] = thisWindow->bsWeight[pullid];
1105
1106     for (i = 0; i < nbins; i++)
1107     {
1108         synthWindow->Histo[0][i] = 0.;
1109     }
1110
1111     if (opt->bsMethod == bsMethod_trajGauss)
1112     {
1113         sig = thisWindow->sigma[pullid];
1114         mu  = thisWindow->aver[pullid];
1115     }
1116
1117     /* Genrate autocorrelated Gaussian random variable with autocorrelation time tau
1118        Use the following:
1119        If x and y are random numbers from N(0,1) (Gaussian with average 0 and sigma=1),
1120        then
1121        z = a*x + sqrt(1-a^2)*y
1122        is also from N(0,1), and cov(z,x) = a. Thus, by gerenating a sequence
1123        x' = a*x + sqrt(1-a^2)*y, the sequnce x(t) is from N(0,1) and has an autocorrelation
1124        function
1125        C(t) = exp(-t/tau) with tau=-1/ln(a)
1126
1127        Then, use error function to turn the Gaussian random variable into a uniformly
1128        distributed one in [0,1]. Eventually, use cumulative distribution function of
1129        histogram to get random variables distributed according to histogram.
1130        Note: The ACT of the flat distribution and of the generated histogram is not
1131        100% exactly tau, but near tau (my test was 3.8 instead of 4).
1132      */
1133     a        = std::exp(-1.0 / tausteps);
1134     ap       = std::sqrt(1.0 - a * a);
1135     invsqrt2 = 1.0 / std::sqrt(2.0);
1136
1137     /* init random sequence */
1138     x = opt->normalDistribution(opt->rng);
1139
1140     if (opt->bsMethod == bsMethod_traj)
1141     {
1142         /* bootstrap points from the umbrella histograms */
1143         for (i = 0; i < N; i++)
1144         {
1145             y = opt->normalDistribution(opt->rng);
1146             x = a * x + ap * y;
1147             /* get flat distribution in [0,1] using cumulative distribution function of Gauusian
1148                Note: CDF(Gaussian) = 0.5*{1+erf[x/sqrt(2)]}
1149              */
1150             r = 0.5 * (1 + std::erf(x * invsqrt2));
1151             searchCumulative(thisWindow->cum[pullid], nbins + 1, r, &r_index);
1152             synthWindow->Histo[0][r_index] += 1.;
1153         }
1154     }
1155     else if (opt->bsMethod == bsMethod_trajGauss)
1156     {
1157         /* bootstrap points from a Gaussian with the same average and sigma
1158            as the respective umbrella histogram. The idea was, that -given
1159            limited sampling- the bootstrapped histograms are otherwise biased
1160            from the limited sampling of the US histos. However, bootstrapping from
1161            the Gaussian seems to yield a similar estimate. */
1162         i = 0;
1163         while (i < N)
1164         {
1165             y    = opt->normalDistribution(opt->rng);
1166             x    = a * x + ap * y;
1167             z    = x * sig + mu;
1168             ibin = static_cast<int>(std::floor((z - opt->min) / opt->dz));
1169             if (opt->bCycl)
1170             {
1171                 if (ibin < 0)
1172                 {
1173                     while ((ibin += nbins) < 0) {}
1174                 }
1175                 else if (ibin >= nbins)
1176                 {
1177                     while ((ibin -= nbins) >= nbins) {}
1178                 }
1179             }
1180
1181             if (ibin >= 0 && ibin < nbins)
1182             {
1183                 synthWindow->Histo[0][ibin] += 1.;
1184                 i++;
1185             }
1186         }
1187     }
1188     else
1189     {
1190         gmx_fatal(FARGS, "Unknown bsMethod (id %d). That should not happen.\n", opt->bsMethod);
1191     }
1192 }
1193
1194 /*! \brief Write all histograms to a file
1195  *
1196  * If bs_index>=0, a number is added to the output file name to allow the ouput of all
1197  * sets of bootstrapped histograms.
1198  */
1199 static void print_histograms(const char*        fnhist,
1200                              t_UmbrellaWindow*  window,
1201                              int                nWindows,
1202                              int                bs_index,
1203                              t_UmbrellaOptions* opt,
1204                              const char*        xlabel)
1205 {
1206     std::string fn, title;
1207     FILE*       fp;
1208     int         bins, l, i, j;
1209
1210     if (bs_index >= 0)
1211     {
1212         fn    = gmx::Path::concatenateBeforeExtension(fnhist, gmx::formatString("_bs%d", bs_index));
1213         title = gmx::formatString("Umbrella histograms. Bootstrap #%d", bs_index);
1214     }
1215     else
1216     {
1217         fn    = gmx_strdup(fnhist);
1218         title = gmx::formatString("Umbrella histograms");
1219     }
1220
1221     fp   = xvgropen(fn.c_str(), title.c_str(), xlabel, "count", opt->oenv);
1222     bins = opt->bins;
1223
1224     /* Write histograms */
1225     for (l = 0; l < bins; ++l)
1226     {
1227         fprintf(fp, "%e\t", (l + 0.5) * opt->dz + opt->min);
1228         for (i = 0; i < nWindows; ++i)
1229         {
1230             for (j = 0; j < window[i].nPull; ++j)
1231             {
1232                 fprintf(fp, "%e\t", window[i].Histo[j][l]);
1233             }
1234         }
1235         fprintf(fp, "\n");
1236     }
1237
1238     xvgrclose(fp);
1239     printf("Wrote %s\n", fn.c_str());
1240 }
1241
1242 //! Make random weights for histograms for the Bayesian bootstrap of complete histograms)
1243 static void setRandomBsWeights(t_UmbrellaWindow* synthwin, int nAllPull, t_UmbrellaOptions* opt)
1244 {
1245     int                                i;
1246     double*                            r;
1247     gmx::UniformRealDistribution<real> dist(0, nAllPull);
1248
1249     snew(r, nAllPull);
1250
1251     /* generate ordered random numbers between 0 and nAllPull  */
1252     for (i = 0; i < nAllPull - 1; i++)
1253     {
1254         r[i] = dist(opt->rng);
1255     }
1256     std::sort(r, r + nAllPull - 1);
1257     r[nAllPull - 1] = 1.0 * nAllPull;
1258
1259     synthwin[0].bsWeight[0] = r[0];
1260     for (i = 1; i < nAllPull; i++)
1261     {
1262         synthwin[i].bsWeight[0] = r[i] - r[i - 1];
1263     }
1264
1265     /* avoid to have zero weight by adding a tiny value */
1266     for (i = 0; i < nAllPull; i++)
1267     {
1268         if (synthwin[i].bsWeight[0] < 1e-5)
1269         {
1270             synthwin[i].bsWeight[0] = 1e-5;
1271         }
1272     }
1273
1274     sfree(r);
1275 }
1276
1277 //! The main bootstrapping routine
1278 static void do_bootstrapping(const char*        fnres,
1279                              const char*        fnprof,
1280                              const char*        fnhist,
1281                              const char*        xlabel,
1282                              char*              ylabel,
1283                              double*            profile,
1284                              t_UmbrellaWindow*  window,
1285                              int                nWindows,
1286                              t_UmbrellaOptions* opt)
1287 {
1288     t_UmbrellaWindow* synthWindow;
1289     double *          bsProfile, *bsProfiles_av, *bsProfiles_av2, maxchange = 1e20, tmp, stddev;
1290     int               i, j, *randomArray = nullptr, winid, pullid, ib;
1291     int               iAllPull, nAllPull, *allPull_winId, *allPull_pullId;
1292     FILE*             fp;
1293     gmx_bool          bExact = FALSE;
1294
1295     /* init random generator */
1296     if (opt->bsSeed == 0)
1297     {
1298         opt->bsSeed = static_cast<int>(gmx::makeRandomSeed());
1299     }
1300     opt->rng.seed(opt->bsSeed);
1301
1302     snew(bsProfile, opt->bins);
1303     snew(bsProfiles_av, opt->bins);
1304     snew(bsProfiles_av2, opt->bins);
1305
1306     /* Create array of all pull groups. Note that different windows
1307        may have different nr of pull groups
1308        First: Get total nr of pull groups */
1309     nAllPull = 0;
1310     for (i = 0; i < nWindows; i++)
1311     {
1312         nAllPull += window[i].nPull;
1313     }
1314     snew(allPull_winId, nAllPull);
1315     snew(allPull_pullId, nAllPull);
1316     iAllPull = 0;
1317     /* Setup one array of all pull groups */
1318     for (i = 0; i < nWindows; i++)
1319     {
1320         for (j = 0; j < window[i].nPull; j++)
1321         {
1322             allPull_winId[iAllPull]  = i;
1323             allPull_pullId[iAllPull] = j;
1324             iAllPull++;
1325         }
1326     }
1327
1328     /* setup stuff for synthetic windows */
1329     snew(synthWindow, nAllPull);
1330     for (i = 0; i < nAllPull; i++)
1331     {
1332         synthWindow[i].nPull = 1;
1333         synthWindow[i].nBin  = opt->bins;
1334         snew(synthWindow[i].Histo, 1);
1335         if (opt->bsMethod == bsMethod_traj || opt->bsMethod == bsMethod_trajGauss)
1336         {
1337             snew(synthWindow[i].Histo[0], opt->bins);
1338         }
1339         snew(synthWindow[i].N, 1);
1340         snew(synthWindow[i].pos, 1);
1341         snew(synthWindow[i].z, 1);
1342         snew(synthWindow[i].k, 1);
1343         snew(synthWindow[i].bContrib, 1);
1344         snew(synthWindow[i].g, 1);
1345         snew(synthWindow[i].bsWeight, 1);
1346     }
1347
1348     switch (opt->bsMethod)
1349     {
1350         case bsMethod_hist:
1351             printf("\n\nWhen computing statistical errors by bootstrapping entire histograms:\n");
1352             please_cite(stdout, "Hub2006");
1353             break;
1354         case bsMethod_BayesianHist:
1355             /* just copy all histogams into synthWindow array */
1356             for (i = 0; i < nAllPull; i++)
1357             {
1358                 winid  = allPull_winId[i];
1359                 pullid = allPull_pullId[i];
1360                 copy_pullgrp_to_synthwindow(synthWindow + i, window + winid, pullid);
1361             }
1362             break;
1363         case bsMethod_traj:
1364         case bsMethod_trajGauss: calc_cumulatives(window, nWindows, opt, fnhist, xlabel); break;
1365         default: gmx_fatal(FARGS, "Unknown bootstrap method. That should not have happened.\n");
1366     }
1367
1368     /* do bootstrapping */
1369     fp = xvgropen(fnprof, "Bootstrap profiles", xlabel, ylabel, opt->oenv);
1370     for (ib = 0; ib < opt->nBootStrap; ib++)
1371     {
1372         printf("  *******************************************\n"
1373                "  ******** Start bootstrap nr %d ************\n"
1374                "  *******************************************\n",
1375                ib + 1);
1376
1377         switch (opt->bsMethod)
1378         {
1379             case bsMethod_hist:
1380                 /* bootstrap complete histograms from given histograms */
1381                 srenew(randomArray, nAllPull);
1382                 getRandomIntArray(nAllPull, opt->histBootStrapBlockLength, randomArray, &opt->rng);
1383                 for (i = 0; i < nAllPull; i++)
1384                 {
1385                     winid  = allPull_winId[randomArray[i]];
1386                     pullid = allPull_pullId[randomArray[i]];
1387                     copy_pullgrp_to_synthwindow(synthWindow + i, window + winid, pullid);
1388                 }
1389                 break;
1390             case bsMethod_BayesianHist:
1391                 /* keep histos, but assign random weights ("Bayesian bootstrap") */
1392                 setRandomBsWeights(synthWindow, nAllPull, opt);
1393                 break;
1394             case bsMethod_traj:
1395             case bsMethod_trajGauss:
1396                 /* create new histos from given histos, that is generate new hypothetical
1397                    trajectories */
1398                 for (i = 0; i < nAllPull; i++)
1399                 {
1400                     winid  = allPull_winId[i];
1401                     pullid = allPull_pullId[i];
1402                     create_synthetic_histo(synthWindow + i, window + winid, pullid, opt);
1403                 }
1404                 break;
1405         }
1406
1407         /* write histos in case of verbose output */
1408         if (opt->bs_verbose)
1409         {
1410             print_histograms(fnhist, synthWindow, nAllPull, ib, opt, xlabel);
1411         }
1412
1413         /* do wham */
1414         i         = 0;
1415         bExact    = FALSE;
1416         maxchange = 1e20;
1417         std::memcpy(bsProfile, profile, opt->bins * sizeof(double)); /* use profile as guess */
1418         do
1419         {
1420             if ((i % opt->stepUpdateContrib) == 0)
1421             {
1422                 setup_acc_wham(bsProfile, synthWindow, nAllPull, opt);
1423             }
1424             if (maxchange < opt->Tolerance)
1425             {
1426                 bExact = TRUE;
1427             }
1428             if (((i % opt->stepchange) == 0 || i == 1) && i != 0)
1429             {
1430                 printf("\t%4d) Maximum change %e\n", i, maxchange);
1431             }
1432             calc_profile(bsProfile, synthWindow, nAllPull, opt, bExact);
1433             i++;
1434         } while ((maxchange = calc_z(bsProfile, synthWindow, nAllPull, opt, bExact)) > opt->Tolerance
1435                  || !bExact);
1436         printf("\tConverged in %d iterations. Final maximum change %g\n", i, maxchange);
1437
1438         if (opt->bLog)
1439         {
1440             prof_normalization_and_unit(bsProfile, opt);
1441         }
1442
1443         /* symmetrize profile around z=0 */
1444         if (opt->bSym)
1445         {
1446             symmetrizeProfile(bsProfile, opt);
1447         }
1448
1449         /* save stuff to get average and stddev */
1450         for (i = 0; i < opt->bins; i++)
1451         {
1452             tmp = bsProfile[i];
1453             bsProfiles_av[i] += tmp;
1454             bsProfiles_av2[i] += tmp * tmp;
1455             fprintf(fp, "%e\t%e\n", (i + 0.5) * opt->dz + opt->min, tmp);
1456         }
1457         fprintf(fp, "%s\n", output_env_get_print_xvgr_codes(opt->oenv) ? "&" : "");
1458     }
1459     xvgrclose(fp);
1460
1461     /* write average and stddev */
1462     fp = xvgropen(fnres, "Average and stddev from bootstrapping", xlabel, ylabel, opt->oenv);
1463     if (output_env_get_print_xvgr_codes(opt->oenv))
1464     {
1465         fprintf(fp, "@TYPE xydy\n");
1466     }
1467     for (i = 0; i < opt->bins; i++)
1468     {
1469         bsProfiles_av[i] /= opt->nBootStrap;
1470         bsProfiles_av2[i] /= opt->nBootStrap;
1471         tmp    = bsProfiles_av2[i] - gmx::square(bsProfiles_av[i]);
1472         stddev = (tmp >= 0.) ? std::sqrt(tmp) : 0.; /* Catch rouding errors */
1473         fprintf(fp, "%e\t%e\t%e\n", (i + 0.5) * opt->dz + opt->min, bsProfiles_av[i], stddev);
1474     }
1475     xvgrclose(fp);
1476     printf("Wrote boot strap result to %s\n", fnres);
1477 }
1478
1479 //! Return type of input file based on file extension (xvg or tpr)
1480 static int whaminFileType(char* fn)
1481 {
1482     int len;
1483     len = std::strlen(fn);
1484     if (std::strcmp(fn + len - 3, "tpr") == 0)
1485     {
1486         return whamin_tpr;
1487     }
1488     else if (std::strcmp(fn + len - 3, "xvg") == 0 || std::strcmp(fn + len - 6, "xvg.gz") == 0)
1489     {
1490         return whamin_pullxf;
1491     }
1492     else
1493     {
1494         gmx_fatal(FARGS,
1495                   "Unknown file type of %s. Should be tpr or xvg. Use GROMACS 2021 or earlier to "
1496                   "read pdo files.\n",
1497                   fn);
1498     }
1499 }
1500
1501 //! Read the files names in pullf/pullx-files.dat, tpr-files.dat
1502 static void read_wham_in(const char* fn, char*** filenamesRet, int* nfilesRet, t_UmbrellaOptions* opt)
1503 {
1504     char **filename = nullptr, tmp[WHAM_MAXFILELEN + 2];
1505     int    nread, sizenow, i, block = 1;
1506     FILE*  fp;
1507
1508     fp      = gmx_ffopen(fn, "r");
1509     nread   = 0;
1510     sizenow = 0;
1511     while (fgets(tmp, sizeof(tmp), fp) != nullptr)
1512     {
1513         if (std::strlen(tmp) >= WHAM_MAXFILELEN)
1514         {
1515             gmx_fatal(FARGS, "Filename too long in %s. Only %d characters allowed.\n", fn, WHAM_MAXFILELEN);
1516         }
1517         if (nread >= sizenow)
1518         {
1519             sizenow += block;
1520             srenew(filename, sizenow);
1521             for (i = sizenow - block; i < sizenow; i++)
1522             {
1523                 snew(filename[i], WHAM_MAXFILELEN);
1524             }
1525         }
1526         /* remove newline if there is one */
1527         if (tmp[std::strlen(tmp) - 1] == '\n')
1528         {
1529             tmp[std::strlen(tmp) - 1] = '\0';
1530         }
1531         std::strcpy(filename[nread], tmp);
1532         if (opt->verbose)
1533         {
1534             printf("Found file %s in %s\n", filename[nread], fn);
1535         }
1536         nread++;
1537     }
1538     *filenamesRet = filename;
1539     *nfilesRet    = nread;
1540 }
1541
1542 //! translate 0/1 to N/Y to write pull dimensions
1543 #define int2YN(a) (((a) == 0) ? ("N") : ("Y"))
1544
1545 //! Read pull groups from a tpr file (including position, force const, geometry, number of groups)
1546 static void read_tpr_header(const char* fn, t_UmbrellaHeader* header, t_UmbrellaOptions* opt, t_coordselection* coordsel)
1547 {
1548     t_inputrec  irInstance;
1549     t_inputrec* ir = &irInstance;
1550     t_state     state;
1551     static int  first = 1;
1552
1553     /* printf("Reading %s \n",fn); */
1554     read_tpx_state(fn, ir, &state, nullptr);
1555
1556     if (!ir->bPull)
1557     {
1558         gmx_fatal(FARGS, "This is not a tpr with COM pulling");
1559     }
1560     if (ir->pull->ncoord == 0)
1561     {
1562         gmx_fatal(FARGS, "No pull coordinates found in %s", fn);
1563     }
1564
1565     /* Read overall pull info */
1566     header->npullcrds      = ir->pull->ncoord;
1567     header->bPrintCOM      = ir->pull->bPrintCOM;
1568     header->bPrintRefValue = ir->pull->bPrintRefValue;
1569     header->bPrintComp     = ir->pull->bPrintComp;
1570
1571     /* Read pull coordinates */
1572     snew(header->pcrd, header->npullcrds);
1573     for (int i = 0; i < ir->pull->ncoord; i++)
1574     {
1575         header->pcrd[i].pull_type = ir->pull->coord[i].eType;
1576         header->pcrd[i].geometry  = ir->pull->coord[i].eGeom;
1577         header->pcrd[i].ngroup    = ir->pull->coord[i].ngroup;
1578         /* Angle type coordinates are handled fully in degrees in gmx wham.
1579          * The pull "distance" appears with a power of -2 in the force constant,
1580          * so we need to multiply with the internal units (radians for angle)
1581          * to user units (degrees for an angle) with the same power.
1582          */
1583         header->pcrd[i].k = ir->pull->coord[i].k
1584                             / gmx::square(pull_conversion_factor_internal2userinput(ir->pull->coord[i]));
1585         header->pcrd[i].init_dist = ir->pull->coord[i].init;
1586
1587         copy_ivec(ir->pull->coord[i].dim, header->pcrd[i].dim);
1588         header->pcrd[i].ndim =
1589                 header->pcrd[i].dim[XX] + header->pcrd[i].dim[YY] + header->pcrd[i].dim[ZZ];
1590
1591         std::strcpy(header->pcrd[i].coord_unit, pull_coordinate_units(ir->pull->coord[i]));
1592
1593         if (ir->efep != FreeEnergyPerturbationType::No && ir->pull->coord[i].k != ir->pull->coord[i].kB)
1594         {
1595             gmx_fatal(FARGS,
1596                       "Seems like you did free-energy perturbation, and you perturbed the force "
1597                       "constant."
1598                       " This is not supported.\n");
1599         }
1600         if (coordsel && (coordsel->n != ir->pull->ncoord))
1601         {
1602             gmx_fatal(FARGS,
1603                       "Found %d pull coordinates in %s, but %d columns in the respective line\n"
1604                       "coordinate selection file (option -is)\n",
1605                       ir->pull->ncoord,
1606                       fn,
1607                       coordsel->n);
1608         }
1609     }
1610
1611     /* Check pull coords for consistency */
1612     PullGroupGeometry geom          = PullGroupGeometry::Count;
1613     ivec              thedim        = { 0, 0, 0 };
1614     bool              geometryIsSet = false;
1615     for (int i = 0; i < ir->pull->ncoord; i++)
1616     {
1617         if (coordsel == nullptr || coordsel->bUse[i])
1618         {
1619             if (header->pcrd[i].pull_type != PullingAlgorithm::Umbrella)
1620             {
1621                 gmx_fatal(FARGS,
1622                           "%s: Pull coordinate %d is of type \"%s\", expected \"umbrella\". Only "
1623                           "umbrella coodinates can enter WHAM.\n"
1624                           "If you have umbrella and non-umbrella coordinates, you can select the "
1625                           "umbrella coordinates with gmx wham -is\n",
1626                           fn,
1627                           i + 1,
1628                           enumValueToString(header->pcrd[i].pull_type));
1629             }
1630             if (!geometryIsSet)
1631             {
1632                 geom = header->pcrd[i].geometry;
1633                 copy_ivec(header->pcrd[i].dim, thedim);
1634                 geometryIsSet = true;
1635             }
1636             if (geom != header->pcrd[i].geometry)
1637             {
1638                 gmx_fatal(FARGS,
1639                           "%s: Your pull coordinates have different pull geometry (coordinate 1: "
1640                           "%s, coordinate %d: %s)\n"
1641                           "If you want to use only some pull coordinates in WHAM, please select "
1642                           "them with option gmx wham -is\n",
1643                           fn,
1644                           enumValueToString(geom),
1645                           i + 1,
1646                           enumValueToString(header->pcrd[i].geometry));
1647             }
1648             if (thedim[XX] != header->pcrd[i].dim[XX] || thedim[YY] != header->pcrd[i].dim[YY]
1649                 || thedim[ZZ] != header->pcrd[i].dim[ZZ])
1650             {
1651                 gmx_fatal(FARGS,
1652                           "%s: Your pull coordinates have different pull dimensions (coordinate 1: "
1653                           "%s %s %s, coordinate %d: %s %s %s)\n"
1654                           "If you want to use only some pull coordinates in WHAM, please select "
1655                           "them with option gmx wham -is\n",
1656                           fn,
1657                           int2YN(thedim[XX]),
1658                           int2YN(thedim[YY]),
1659                           int2YN(thedim[ZZ]),
1660                           i + 1,
1661                           int2YN(header->pcrd[i].dim[XX]),
1662                           int2YN(header->pcrd[i].dim[YY]),
1663                           int2YN(header->pcrd[i].dim[ZZ]));
1664             }
1665             if (header->pcrd[i].geometry == PullGroupGeometry::Cylinder)
1666             {
1667                 if (header->pcrd[i].dim[XX] || header->pcrd[i].dim[YY] || (!header->pcrd[i].dim[ZZ]))
1668                 {
1669                     gmx_fatal(
1670                             FARGS,
1671                             "With pull geometry 'cylinder', expected pulling in Z direction only.\n"
1672                             "However, found dimensions [%s %s %s]\n",
1673                             int2YN(header->pcrd[i].dim[XX]),
1674                             int2YN(header->pcrd[i].dim[YY]),
1675                             int2YN(header->pcrd[i].dim[ZZ]));
1676                 }
1677             }
1678             if (header->pcrd[i].k <= 0.0)
1679             {
1680                 gmx_fatal(FARGS,
1681                           "%s: Pull coordinate %d has force constant of of %g.\n"
1682                           "That doesn't seem to be an Umbrella tpr.\n",
1683                           fn,
1684                           i + 1,
1685                           header->pcrd[i].k);
1686             }
1687         }
1688     }
1689
1690     if (opt->verbose || first)
1691     {
1692         printf("\nFile %s, %d coordinates, with these options:\n", fn, header->npullcrds);
1693         int maxlen = 0;
1694         for (int i = 0; i < ir->pull->ncoord; i++)
1695         {
1696             int lentmp = strlen(enumValueToString(header->pcrd[i].geometry));
1697             maxlen     = (lentmp > maxlen) ? lentmp : maxlen;
1698         }
1699         char fmt[STRLEN];
1700         sprintf(fmt,
1701                 "\tGeometry %%-%ds  k = %%-8g  position = %%-8g  dimensions [%%s %%s %%s] (%%d "
1702                 "dimensions). Used: %%s\n",
1703                 maxlen + 1);
1704         for (int i = 0; i < ir->pull->ncoord; i++)
1705         {
1706             bool use = (coordsel == nullptr || coordsel->bUse[i]);
1707             printf(fmt,
1708                    enumValueToString(header->pcrd[i].geometry),
1709                    header->pcrd[i].k,
1710                    header->pcrd[i].init_dist,
1711                    int2YN(header->pcrd[i].dim[XX]),
1712                    int2YN(header->pcrd[i].dim[YY]),
1713                    int2YN(header->pcrd[i].dim[ZZ]),
1714                    header->pcrd[i].ndim,
1715                    use ? "Yes" : "No");
1716             printf("\tPull group coordinates of %d groups expected in pullx files.\n",
1717                    ir->pull->bPrintCOM ? header->pcrd[i].ngroup : 0);
1718         }
1719         printf("\tReference value of the coordinate%s expected in pullx files.\n",
1720                header->bPrintRefValue ? "" : " not");
1721     }
1722     if (!opt->verbose && first)
1723     {
1724         printf("\tUse option -v to see this output for all input tpr files\n\n");
1725     }
1726
1727     first = 0;
1728 }
1729
1730 //! Read pullx.xvg or pullf.xvg
1731 static void read_pull_xf(const char*        fn,
1732                          t_UmbrellaHeader*  header,
1733                          t_UmbrellaWindow*  window,
1734                          t_UmbrellaOptions* opt,
1735                          gmx_bool           bGetMinMax,
1736                          real*              mintmp,
1737                          real*              maxtmp,
1738                          t_coordselection*  coordsel)
1739 {
1740     double **       y = nullptr, pos = 0., t, force, time0 = 0., dt;
1741     int             ny, nt, bins, ibin, i, g, gUsed, dstep = 1;
1742     int             nColExpect, ntot, column;
1743     real            min, max, minfound = 1e20, maxfound = -1e20;
1744     gmx_bool        dt_ok, timeok;
1745     const char*     quantity;
1746     const int       blocklen = 4096;
1747     int*            lennow   = nullptr;
1748     static gmx_bool bFirst   = TRUE;
1749
1750     /*
1751      * Data columns in pull output:
1752      *  - in force output pullf.xvg:
1753      *    No reference columns, one column per pull coordinate
1754      *
1755      *  - in position output pullx.xvg:
1756      *     * optionally, ndim columns for COMs of all groups (depending on on mdp options pull-print-com);
1757      *     * The displacement, always one column. Note: with pull-print-components = yes, the dx/dy/dz would
1758      *       be written separately into pullx file, but this is not supported and throws an error below;
1759      *     * optionally, the position of the reference coordinate (depending on pull-print-ref-value)
1760      */
1761
1762     if (header->bPrintComp && opt->bPullx)
1763     {
1764         gmx_fatal(
1765                 FARGS,
1766                 "gmx wham cannot read pullx files if the components of the coordinate was written\n"
1767                 "(mdp option pull-print-components). Provide the pull force files instead (with "
1768                 "option -if).\n");
1769     }
1770
1771     int *nColThisCrd, *nColCOMCrd, *nColRefCrd;
1772     snew(nColThisCrd, header->npullcrds);
1773     snew(nColCOMCrd, header->npullcrds);
1774     snew(nColRefCrd, header->npullcrds);
1775
1776     if (!opt->bPullx)
1777     {
1778         /* pullf reading: simply one column per coordinate */
1779         for (g = 0; g < header->npullcrds; g++)
1780         {
1781             nColThisCrd[g] = 1;
1782             nColCOMCrd[g]  = 0;
1783             nColRefCrd[g]  = 0;
1784         }
1785     }
1786     else
1787     {
1788         /* pullx reading. Note explanation above. */
1789         for (g = 0; g < header->npullcrds; g++)
1790         {
1791             nColRefCrd[g] = (header->bPrintRefValue ? 1 : 0);
1792             nColCOMCrd[g] = (header->bPrintCOM ? header->pcrd[g].ndim * header->pcrd[g].ngroup : 0);
1793             nColThisCrd[g] = 1 + nColCOMCrd[g] + nColRefCrd[g];
1794         }
1795     }
1796
1797     nColExpect = 1; /* time column */
1798     for (g = 0; g < header->npullcrds; g++)
1799     {
1800         nColExpect += nColThisCrd[g];
1801     }
1802
1803     /* read pullf or pullx. Could be optimized if min and max are given. */
1804     nt = read_xvg(fn, &y, &ny);
1805
1806     /* Check consistency */
1807     quantity = opt->bPullx ? "position" : "force";
1808     if (nt < 1)
1809     {
1810         gmx_fatal(FARGS, "Empty pull %s file %s\n", quantity, fn);
1811     }
1812     if (bFirst || opt->verbose)
1813     {
1814         printf("\nReading pull %s file %s, expecting %d columns:\n", quantity, fn, nColExpect);
1815         for (i = 0; i < header->npullcrds; i++)
1816         {
1817             printf("\tColumns for pull coordinate %d\n", i + 1);
1818             printf("\t\treaction coordinate:             %d\n"
1819                    "\t\tcenter-of-mass of groups:        %d\n"
1820                    "\t\treference position column:       %s\n",
1821                    1,
1822                    nColCOMCrd[i],
1823                    (header->bPrintRefValue ? "Yes" : "No"));
1824         }
1825         printf("\tFound %d times in %s\n", nt, fn);
1826         bFirst = FALSE;
1827     }
1828     if (nColExpect != ny)
1829     {
1830         gmx_fatal(FARGS,
1831                   "Expected %d columns (including time column) in %s, but found %d."
1832                   " Maybe you confused options -if and -ix ?",
1833                   nColExpect,
1834                   fn,
1835                   ny);
1836     }
1837
1838     if (!bGetMinMax)
1839     {
1840         assert(window);
1841         bins = opt->bins;
1842         min  = opt->min;
1843         max  = opt->max;
1844         if (nt > 1)
1845         {
1846             window->dt = y[0][1] - y[0][0];
1847         }
1848         else if (opt->nBootStrap && opt->tauBootStrap != 0.0)
1849         {
1850             fprintf(stderr, "\n *** WARNING, Could not determine time step in %s\n", fn);
1851         }
1852
1853         /* Need to alocate memory and set up structure for windows */
1854         if (coordsel)
1855         {
1856             /* Use only groups selected with option -is file */
1857             if (header->npullcrds != coordsel->n)
1858             {
1859                 gmx_fatal(FARGS,
1860                           "tpr file contains %d pull groups, but expected %d from group selection "
1861                           "file\n",
1862                           header->npullcrds,
1863                           coordsel->n);
1864             }
1865             window->nPull = coordsel->nUse;
1866         }
1867         else
1868         {
1869             window->nPull = header->npullcrds;
1870         }
1871
1872         window->nBin = bins;
1873         snew(window->Histo, window->nPull);
1874         snew(window->z, window->nPull);
1875         snew(window->k, window->nPull);
1876         snew(window->pos, window->nPull);
1877         snew(window->N, window->nPull);
1878         snew(window->Ntot, window->nPull);
1879         snew(window->g, window->nPull);
1880         snew(window->bsWeight, window->nPull);
1881         window->bContrib = nullptr;
1882
1883         if (opt->bCalcTauInt)
1884         {
1885             snew(window->ztime, window->nPull);
1886         }
1887         else
1888         {
1889             window->ztime = nullptr;
1890         }
1891         snew(lennow, window->nPull);
1892
1893         for (g = 0; g < window->nPull; ++g)
1894         {
1895             window->z[g]        = 1;
1896             window->bsWeight[g] = 1.;
1897             window->N[g]        = 0;
1898             window->Ntot[g]     = 0;
1899             window->g[g]        = 1.;
1900             snew(window->Histo[g], bins);
1901
1902             if (opt->bCalcTauInt)
1903             {
1904                 window->ztime[g] = nullptr;
1905             }
1906         }
1907
1908         /* Copying umbrella center and force const is more involved since not
1909            all pull groups from header (tpr file) may be used in window variable */
1910         for (g = 0, gUsed = 0; g < header->npullcrds; ++g)
1911         {
1912             if (coordsel && !coordsel->bUse[g])
1913             {
1914                 continue;
1915             }
1916             window->k[gUsed]   = header->pcrd[g].k;
1917             window->pos[gUsed] = header->pcrd[g].init_dist;
1918             gUsed++;
1919         }
1920     }
1921     else
1922     { /* only determine min and max */
1923         minfound = 1e20;
1924         maxfound = -1e20;
1925         min = max = bins = 0; /* Get rid of warnings */
1926     }
1927
1928
1929     for (i = 0; i < nt; i++)
1930     {
1931         /* Do you want that time frame? */
1932         t = 1.0 / 1000 * (gmx::roundToInt64((y[0][i] * 1000))); /* round time to fs */
1933
1934         /* get time step and get dstep from opt->dt */
1935         if (i == 0)
1936         {
1937             time0 = t;
1938         }
1939         else if (i == 1)
1940         {
1941             dt = t - time0;
1942             if (opt->dt > 0.0)
1943             {
1944                 dstep = gmx::roundToInt(opt->dt / dt);
1945                 if (dstep == 0)
1946                 {
1947                     dstep = 1;
1948                 }
1949             }
1950             if (!bGetMinMax)
1951             {
1952                 window->dt = dt * dstep;
1953             }
1954         }
1955
1956         dt_ok  = (i % dstep == 0);
1957         timeok = (dt_ok && t >= opt->tmin && t <= opt->tmax);
1958         /*if (opt->verbose)
1959            printf(" time = %f, (tmin,tmax)=(%e,%e), dt_ok=%d timeok=%d\n",
1960            t,opt->tmin, opt->tmax, dt_ok,timeok); */
1961         if (timeok)
1962         {
1963             /* Note: if coordsel == NULL:
1964              *          all groups in pullf/x file are stored in this window, and gUsed == g
1965              *       if coordsel != NULL:
1966              *          only groups with coordsel.bUse[g]==TRUE are stored. gUsed is not always equal g
1967              */
1968             gUsed = -1;
1969             for (g = 0; g < header->npullcrds; ++g)
1970             {
1971                 /* was this group selected for application in WHAM? */
1972                 if (coordsel && !coordsel->bUse[g])
1973                 {
1974                     continue;
1975                 }
1976                 gUsed++;
1977
1978                 if (opt->bPullf)
1979                 {
1980                     /* y has 1 time column y[0] and one column per force y[1],...,y[nCrds] */
1981                     force = y[g + 1][i];
1982                     pos   = -force / header->pcrd[g].k + header->pcrd[g].init_dist;
1983                 }
1984                 else
1985                 {
1986                     /* Pick the correct column index.
1987                        Note that there is always exactly one displacement column.
1988                      */
1989                     column = 1;
1990                     for (int j = 0; j < g; j++)
1991                     {
1992                         column += nColThisCrd[j];
1993                     }
1994                     pos = y[column][i];
1995                 }
1996
1997                 /* printf("crd %d dpos %f poseq %f pos %f \n",g,dpos,poseq,pos); */
1998                 if (bGetMinMax)
1999                 {
2000                     if (pos < minfound)
2001                     {
2002                         minfound = pos;
2003                     }
2004                     if (pos > maxfound)
2005                     {
2006                         maxfound = pos;
2007                     }
2008                 }
2009                 else
2010                 {
2011                     if (gUsed >= window->nPull)
2012                     {
2013                         gmx_fatal(FARGS,
2014                                   "gUsed too large (%d, nPull=%d). This error should have been "
2015                                   "caught before.\n",
2016                                   gUsed,
2017                                   window->nPull);
2018                     }
2019
2020                     if (opt->bCalcTauInt && !bGetMinMax)
2021                     {
2022                         /* save time series for autocorrelation analysis */
2023                         ntot = window->Ntot[gUsed];
2024                         /* printf("i %d, ntot %d, lennow[g] = %d\n",i,ntot,lennow[g]); */
2025                         if (ntot >= lennow[gUsed])
2026                         {
2027                             lennow[gUsed] += blocklen;
2028                             srenew(window->ztime[gUsed], lennow[gUsed]);
2029                         }
2030                         window->ztime[gUsed][ntot] = pos;
2031                     }
2032
2033                     ibin = static_cast<int>(std::floor((pos - min) / (max - min) * bins));
2034                     if (opt->bCycl)
2035                     {
2036                         if (ibin < 0)
2037                         {
2038                             while ((ibin += bins) < 0) {}
2039                         }
2040                         else if (ibin >= bins)
2041                         {
2042                             while ((ibin -= bins) >= bins) {}
2043                         }
2044                     }
2045                     if (ibin >= 0 && ibin < bins)
2046                     {
2047                         window->Histo[gUsed][ibin] += 1.;
2048                         window->N[gUsed]++;
2049                     }
2050                     window->Ntot[gUsed]++;
2051                 }
2052             }
2053         }
2054         else if (t > opt->tmax)
2055         {
2056             if (opt->verbose)
2057             {
2058                 printf("time %f larger than tmax %f, stop reading this pullx/pullf file\n", t, opt->tmax);
2059             }
2060             break;
2061         }
2062     }
2063
2064     if (bGetMinMax)
2065     {
2066         *mintmp = minfound;
2067         *maxtmp = maxfound;
2068     }
2069     sfree(lennow);
2070     for (i = 0; i < ny; i++)
2071     {
2072         sfree(y[i]);
2073     }
2074 }
2075
2076 //! read pullf-files.dat or pullx-files.dat and tpr-files.dat
2077 static void read_tpr_pullxf_files(char**             fnTprs,
2078                                   char**             fnPull,
2079                                   int                nfiles,
2080                                   t_UmbrellaHeader*  header,
2081                                   t_UmbrellaWindow*  window,
2082                                   t_UmbrellaOptions* opt)
2083 {
2084     int  i;
2085     real mintmp, maxtmp;
2086
2087     printf("Reading %d tpr and pullf files\n", nfiles);
2088
2089     /* min and max not given? */
2090     if (opt->bAuto)
2091     {
2092         printf("Automatic determination of boundaries...\n");
2093         opt->min = 1e20;
2094         opt->max = -1e20;
2095         for (i = 0; i < nfiles; i++)
2096         {
2097             if (whaminFileType(fnTprs[i]) != whamin_tpr)
2098             {
2099                 gmx_fatal(FARGS, "Expected the %d'th file in input file to be a tpr file\n", i);
2100             }
2101             read_tpr_header(fnTprs[i], header, opt, (opt->nCoordsel > 0) ? &opt->coordsel[i] : nullptr);
2102             if (whaminFileType(fnPull[i]) != whamin_pullxf)
2103             {
2104                 gmx_fatal(FARGS,
2105                           "Expected the %d'th file in input file to be a xvg (pullx/pullf) file\n",
2106                           i);
2107             }
2108             read_pull_xf(fnPull[i],
2109                          header,
2110                          nullptr,
2111                          opt,
2112                          TRUE,
2113                          &mintmp,
2114                          &maxtmp,
2115                          (opt->nCoordsel > 0) ? &opt->coordsel[i] : nullptr);
2116             if (maxtmp > opt->max)
2117             {
2118                 opt->max = maxtmp;
2119             }
2120             if (mintmp < opt->min)
2121             {
2122                 opt->min = mintmp;
2123             }
2124         }
2125         printf("\nDetermined boundaries to %f and %f\n\n", opt->min, opt->max);
2126         if (opt->bBoundsOnly)
2127         {
2128             printf("Found option -boundsonly, now exiting.\n");
2129             exit(0);
2130         }
2131     }
2132     /* store stepsize in profile */
2133     opt->dz = (opt->max - opt->min) / opt->bins;
2134
2135     bool foundData = false;
2136     for (i = 0; i < nfiles; i++)
2137     {
2138         if (whaminFileType(fnTprs[i]) != whamin_tpr)
2139         {
2140             gmx_fatal(FARGS, "Expected the %d'th file in input file to be a tpr file\n", i);
2141         }
2142         read_tpr_header(fnTprs[i], header, opt, (opt->nCoordsel > 0) ? &opt->coordsel[i] : nullptr);
2143         if (whaminFileType(fnPull[i]) != whamin_pullxf)
2144         {
2145             gmx_fatal(
2146                     FARGS, "Expected the %d'th file in input file to be a xvg (pullx/pullf) file\n", i);
2147         }
2148         read_pull_xf(fnPull[i],
2149                      header,
2150                      window + i,
2151                      opt,
2152                      FALSE,
2153                      nullptr,
2154                      nullptr,
2155                      (opt->nCoordsel > 0) ? &opt->coordsel[i] : nullptr);
2156         if (window[i].Ntot[0] == 0)
2157         {
2158             fprintf(stderr, "\nWARNING, no data points read from file %s (check -b option)\n", fnPull[i]);
2159         }
2160         else
2161         {
2162             foundData = true;
2163         }
2164     }
2165     if (!foundData)
2166     {
2167         gmx_fatal(FARGS,
2168                   "No data points were found in pullf/pullx files. Maybe you need to specify the "
2169                   "-b option?\n");
2170     }
2171
2172     for (i = 0; i < nfiles; i++)
2173     {
2174         sfree(fnTprs[i]);
2175         sfree(fnPull[i]);
2176     }
2177     sfree(fnTprs);
2178     sfree(fnPull);
2179 }
2180
2181 /*! \brief Read integrated autocorrelation times from input file (option -iiact)
2182  *
2183  * Note: Here we consider tau[int] := int_0^inf ACF(t) as the integrated autocorrelation times.
2184  * The factor `g := 1 + 2*tau[int]` subsequently enters the uncertainty.
2185  */
2186 static void readIntegratedAutocorrelationTimes(t_UmbrellaWindow* window, int nwins, const char* fn)
2187 {
2188     int      nlines, ny, i, ig;
2189     double** iact;
2190
2191     printf("Readging Integrated autocorrelation times from %s ...\n", fn);
2192     nlines = read_xvg(fn, &iact, &ny);
2193     if (nlines != nwins)
2194     {
2195         gmx_fatal(FARGS,
2196                   "Found %d lines with integrated autocorrelation times in %s.\nExpected %d",
2197                   nlines,
2198                   fn,
2199                   nwins);
2200     }
2201     for (i = 0; i < nlines; i++)
2202     {
2203         if (window[i].nPull != ny)
2204         {
2205             gmx_fatal(FARGS,
2206                       "You are providing autocorrelation times with option -iiact and the\n"
2207                       "number of pull groups is different in different simulations. That is not\n"
2208                       "supported yet. Sorry.\n");
2209         }
2210         for (ig = 0; ig < window[i].nPull; ig++)
2211         {
2212             /* compare Kumar et al, J Comp Chem 13, 1011-1021 (1992) */
2213             window[i].g[ig] = 1 + 2 * iact[ig][i] / window[i].dt;
2214
2215             if (iact[ig][i] <= 0.0)
2216             {
2217                 fprintf(stderr, "\nWARNING, IACT = %f (window %d, group %d)\n", iact[ig][i], i, ig);
2218             }
2219         }
2220     }
2221 }
2222
2223
2224 /*! \brief Smooth autocorreltion times along the reaction coordinate.
2225  *
2226  * This is useful
2227  * if the ACT is subject to high uncertainty in case if limited sampling. Note
2228  * that -in case of limited sampling- the ACT may be severely underestimated.
2229  * Note: the g=1+2tau are overwritten.
2230  * If opt->bAllowReduceIact==FALSE, the ACTs are never reduced, only increased
2231  * by the smoothing
2232  */
2233 static void smoothIact(t_UmbrellaWindow* window, int nwins, t_UmbrellaOptions* opt)
2234 {
2235     int    i, ig, j, jg;
2236     double pos, dpos2, siglim, siglim2, gaufact, invtwosig2, w, weight, tausm;
2237
2238     /* only evaluate within +- 3sigma of the Gausian */
2239     siglim  = 3.0 * opt->sigSmoothIact;
2240     siglim2 = gmx::square(siglim);
2241     /* pre-factor of Gaussian */
2242     gaufact    = 1.0 / (std::sqrt(2 * M_PI) * opt->sigSmoothIact);
2243     invtwosig2 = 0.5 / gmx::square(opt->sigSmoothIact);
2244
2245     for (i = 0; i < nwins; i++)
2246     {
2247         snew(window[i].tausmooth, window[i].nPull);
2248         for (ig = 0; ig < window[i].nPull; ig++)
2249         {
2250             tausm  = 0.;
2251             weight = 0;
2252             pos    = window[i].pos[ig];
2253             for (j = 0; j < nwins; j++)
2254             {
2255                 for (jg = 0; jg < window[j].nPull; jg++)
2256                 {
2257                     dpos2 = gmx::square(window[j].pos[jg] - pos);
2258                     if (dpos2 < siglim2)
2259                     {
2260                         w = gaufact * std::exp(-dpos2 * invtwosig2);
2261                         weight += w;
2262                         tausm += w * window[j].tau[jg];
2263                         /*printf("Weight %g dpos2=%g pos=%g gaufact=%g invtwosig2=%g\n",
2264                            w,dpos2,pos,gaufact,invtwosig2); */
2265                     }
2266                 }
2267             }
2268             tausm /= weight;
2269             if (opt->bAllowReduceIact || tausm > window[i].tau[ig])
2270             {
2271                 window[i].tausmooth[ig] = tausm;
2272             }
2273             else
2274             {
2275                 window[i].tausmooth[ig] = window[i].tau[ig];
2276             }
2277             window[i].g[ig] = 1 + 2 * tausm / window[i].dt;
2278         }
2279     }
2280 }
2281
2282 //! Stop integrating autoccorelation function when ACF drops under this value
2283 #define WHAM_AC_ZERO_LIMIT 0.05
2284
2285 /*! \brief Try to compute the autocorrelation time for each umbrealla window
2286  */
2287 static void calcIntegratedAutocorrelationTimes(t_UmbrellaWindow*  window,
2288                                                int                nwins,
2289                                                t_UmbrellaOptions* opt,
2290                                                const char*        fn,
2291                                                const char*        xlabel)
2292 {
2293     int   i, ig, ncorr, ntot, j, k, *count, restart;
2294     real *corr, c0, dt, tmp;
2295     real *ztime, av, tausteps;
2296     FILE *fp, *fpcorr = nullptr;
2297
2298     if (opt->verbose)
2299     {
2300         fpcorr = xvgropen("hist_autocorr.xvg",
2301                           "Autocorrelation functions of umbrella windows",
2302                           "time [ps]",
2303                           "autocorrelation function",
2304                           opt->oenv);
2305     }
2306
2307     printf("\n");
2308     for (i = 0; i < nwins; i++)
2309     {
2310         fprintf(stdout,
2311                 "\rEstimating integrated autocorrelation times ... [%2.0f%%] ...",
2312                 100. * (i + 1) / nwins);
2313         fflush(stdout);
2314         ntot = window[i].Ntot[0];
2315
2316         /* using half the maximum time as length of autocorrelation function */
2317         ncorr = ntot / 2;
2318         if (ntot < 10)
2319         {
2320             gmx_fatal(FARGS,
2321                       "Tryig to estimtate autocorrelation time from only %d"
2322                       " points. Provide more pull data!",
2323                       ntot);
2324         }
2325         snew(corr, ncorr);
2326         /* snew(corrSq,ncorr); */
2327         snew(count, ncorr);
2328         dt = window[i].dt;
2329         snew(window[i].tau, window[i].nPull);
2330         restart = gmx::roundToInt(opt->acTrestart / dt);
2331         if (restart == 0)
2332         {
2333             restart = 1;
2334         }
2335
2336         for (ig = 0; ig < window[i].nPull; ig++)
2337         {
2338             if (ntot != window[i].Ntot[ig])
2339             {
2340                 gmx_fatal(FARGS,
2341                           "Encountered different nr of frames in different pull groups.\n"
2342                           "That should not happen. (%d and %d)\n",
2343                           ntot,
2344                           window[i].Ntot[ig]);
2345             }
2346             ztime = window[i].ztime[ig];
2347
2348             /* calc autocorrelation function C(t) = < [z(tau)-<z>]*[z(tau+t)-<z>]> */
2349             for (j = 0, av = 0; (j < ntot); j++)
2350             {
2351                 av += ztime[j];
2352             }
2353             av /= ntot;
2354             for (k = 0; (k < ncorr); k++)
2355             {
2356                 corr[k]  = 0.;
2357                 count[k] = 0;
2358             }
2359             for (j = 0; (j < ntot); j += restart)
2360             {
2361                 for (k = 0; (k < ncorr) && (j + k < ntot); k++)
2362                 {
2363                     tmp = (ztime[j] - av) * (ztime[j + k] - av);
2364                     corr[k] += tmp;
2365                     /* corrSq[k] += tmp*tmp; */
2366                     count[k]++;
2367                 }
2368             }
2369             /* divide by nr of frames for each time displacement */
2370             for (k = 0; (k < ncorr); k++)
2371             {
2372                 /* count probably = (ncorr-k+(restart-1))/restart; */
2373                 corr[k] = corr[k] / count[k];
2374                 /* variance of autocorrelation function */
2375                 /* corrSq[k]=corrSq[k]/count[k]; */
2376             }
2377             /* normalize such that corr[0] == 0 */
2378             c0 = 1. / corr[0];
2379             for (k = 0; (k < ncorr); k++)
2380             {
2381                 corr[k] *= c0;
2382                 /* corrSq[k]*=c0*c0; */
2383             }
2384
2385             /* write ACFs in verbose mode */
2386             if (fpcorr)
2387             {
2388                 for (k = 0; (k < ncorr); k++)
2389                 {
2390                     fprintf(fpcorr, "%g  %g\n", k * dt, corr[k]);
2391                 }
2392                 fprintf(fpcorr, "%s\n", output_env_get_print_xvgr_codes(opt->oenv) ? "&" : "");
2393             }
2394
2395             /* esimate integrated correlation time, fitting is too unstable */
2396             tausteps = 0.5 * corr[0];
2397             /* consider corr below WHAM_AC_ZERO_LIMIT as noise */
2398             for (j = 1; (j < ncorr) && (corr[j] > WHAM_AC_ZERO_LIMIT); j++)
2399             {
2400                 tausteps += corr[j];
2401             }
2402
2403             /* g = 1+2*tau, see. Ferrenberg/Swendsen, PRL 63:1195 (1989) or
2404                Kumar et al, eq. 28 ff. */
2405             window[i].tau[ig] = tausteps * dt;
2406             window[i].g[ig]   = 1 + 2 * tausteps;
2407             /* printf("win %d, group %d, estimated correlation time = %g ps\n",i,ig,window[i].tau[ig]); */
2408         } /* ig loop */
2409         sfree(corr);
2410         sfree(count);
2411     }
2412     printf(" done\n");
2413     if (fpcorr)
2414     {
2415         xvgrclose(fpcorr);
2416     }
2417
2418     /* plot IACT along reaction coordinate */
2419     fp = xvgropen(fn, "Integrated autocorrelation times", xlabel, "IACT [ps]", opt->oenv);
2420     if (output_env_get_print_xvgr_codes(opt->oenv))
2421     {
2422         fprintf(fp, "@    s0 symbol 1\n@    s0 symbol size 0.5\n@    s0 line linestyle 0\n");
2423         fprintf(fp, "#  WIN   tau(gr1)  tau(gr2) ...\n");
2424         for (i = 0; i < nwins; i++)
2425         {
2426             fprintf(fp, "# %3d   ", i);
2427             for (ig = 0; ig < window[i].nPull; ig++)
2428             {
2429                 fprintf(fp, " %11g", window[i].tau[ig]);
2430             }
2431             fprintf(fp, "\n");
2432         }
2433     }
2434     for (i = 0; i < nwins; i++)
2435     {
2436         for (ig = 0; ig < window[i].nPull; ig++)
2437         {
2438             fprintf(fp, "%8g %8g\n", window[i].pos[ig], window[i].tau[ig]);
2439         }
2440     }
2441     if (opt->sigSmoothIact > 0.0)
2442     {
2443         printf("Smoothing autocorrelation times along reaction coordinate with Gaussian of sig = "
2444                "%g\n",
2445                opt->sigSmoothIact);
2446         /* smooth IACT along reaction coordinate and overwrite g=1+2tau */
2447         smoothIact(window, nwins, opt);
2448         fprintf(fp, "%s\n", output_env_get_print_xvgr_codes(opt->oenv) ? "&" : "");
2449         if (output_env_get_print_xvgr_codes(opt->oenv))
2450         {
2451             fprintf(fp, "@    s1 symbol 1\n@    s1 symbol size 0.5\n@    s1 line linestyle 0\n");
2452             fprintf(fp, "@    s1 symbol color 2\n");
2453         }
2454         for (i = 0; i < nwins; i++)
2455         {
2456             for (ig = 0; ig < window[i].nPull; ig++)
2457             {
2458                 fprintf(fp, "%8g %8g\n", window[i].pos[ig], window[i].tausmooth[ig]);
2459             }
2460         }
2461     }
2462     xvgrclose(fp);
2463     printf("Wrote %s\n", fn);
2464 }
2465
2466 /*! \brief
2467  * compute average and sigma of each umbrella histogram
2468  */
2469 static void averageSigma(t_UmbrellaWindow* window, int nwins)
2470 {
2471     int  i, ig, ntot, k;
2472     real av, sum2, sig, diff, *ztime, nSamplesIndep;
2473
2474     for (i = 0; i < nwins; i++)
2475     {
2476         snew(window[i].aver, window[i].nPull);
2477         snew(window[i].sigma, window[i].nPull);
2478
2479         ntot = window[i].Ntot[0];
2480         for (ig = 0; ig < window[i].nPull; ig++)
2481         {
2482             ztime = window[i].ztime[ig];
2483             for (k = 0, av = 0.; k < ntot; k++)
2484             {
2485                 av += ztime[k];
2486             }
2487             av /= ntot;
2488             for (k = 0, sum2 = 0.; k < ntot; k++)
2489             {
2490                 diff = ztime[k] - av;
2491                 sum2 += diff * diff;
2492             }
2493             sig                = std::sqrt(sum2 / ntot);
2494             window[i].aver[ig] = av;
2495
2496             /* Note: This estimate for sigma is biased from the limited sampling.
2497                Correct sigma by n/(n-1) where n = number of independent
2498                samples. Only possible if IACT is known.
2499              */
2500             if (window[i].tau)
2501             {
2502                 nSamplesIndep       = window[i].N[ig] / (window[i].tau[ig] / window[i].dt);
2503                 window[i].sigma[ig] = sig * nSamplesIndep / (nSamplesIndep - 1);
2504             }
2505             else
2506             {
2507                 window[i].sigma[ig] = sig;
2508             }
2509             printf("win %d, aver = %f  sig = %f\n", i, av, window[i].sigma[ig]);
2510         }
2511     }
2512 }
2513
2514
2515 /*! \brief
2516  * Use histograms to compute average force on pull group.
2517  */
2518 static void computeAverageForce(t_UmbrellaWindow* window, int nWindows, t_UmbrellaOptions* opt)
2519 {
2520     int    i, j, bins = opt->bins, k;
2521     double dz, min = opt->min, max = opt->max, displAv, temp, distance, ztot, ztot_half, w, weight;
2522     double posmirrored;
2523
2524     dz        = (max - min) / bins;
2525     ztot      = opt->max - min;
2526     ztot_half = ztot / 2;
2527
2528     /* Compute average displacement from histograms */
2529     for (j = 0; j < nWindows; ++j)
2530     {
2531         snew(window[j].forceAv, window[j].nPull);
2532         for (k = 0; k < window[j].nPull; ++k)
2533         {
2534             displAv = 0.0;
2535             weight  = 0.0;
2536             for (i = 0; i < opt->bins; ++i)
2537             {
2538                 temp     = (1.0 * i + 0.5) * dz + min;
2539                 distance = temp - window[j].pos[k];
2540                 if (opt->bCycl)
2541                 {                             /* in cyclic wham:             */
2542                     if (distance > ztot_half) /*    |distance| < ztot_half   */
2543                     {
2544                         distance -= ztot;
2545                     }
2546                     else if (distance < -ztot_half)
2547                     {
2548                         distance += ztot;
2549                     }
2550                 }
2551                 w = window[j].Histo[k][i] / window[j].g[k];
2552                 displAv += w * distance;
2553                 weight += w;
2554                 /* Are we near min or max? We are getting wrong forces from the histgrams since
2555                    the histograms are zero outside [min,max). Therefore, assume that the position
2556                    on the other side of the histomgram center is equally likely. */
2557                 if (!opt->bCycl)
2558                 {
2559                     posmirrored = window[j].pos[k] - distance;
2560                     if (posmirrored >= max || posmirrored < min)
2561                     {
2562                         displAv += -w * distance;
2563                         weight += w;
2564                     }
2565                 }
2566             }
2567             displAv /= weight;
2568
2569             /* average force from average displacement */
2570             window[j].forceAv[k] = displAv * window[j].k[k];
2571             /* sigma from average square displacement */
2572             /* window[j].sigma  [k] = sqrt(displAv2); */
2573             /* printf("Win %d, sigma = %f\n",j,sqrt(displAv2)); */
2574         }
2575     }
2576 }
2577
2578 /*! \brief
2579  * Check if the complete reaction coordinate is covered by the histograms
2580  */
2581 static void checkReactionCoordinateCovered(t_UmbrellaWindow* window, int nwins, t_UmbrellaOptions* opt)
2582 {
2583     int  i, ig, j, bins = opt->bins;
2584     bool bBoundary;
2585     real avcount = 0, z, relcount, *count;
2586     snew(count, opt->bins);
2587
2588     for (j = 0; j < opt->bins; ++j)
2589     {
2590         for (i = 0; i < nwins; i++)
2591         {
2592             for (ig = 0; ig < window[i].nPull; ig++)
2593             {
2594                 count[j] += window[i].Histo[ig][j];
2595             }
2596         }
2597         avcount += 1.0 * count[j];
2598     }
2599     avcount /= bins;
2600     for (j = 0; j < bins; ++j)
2601     {
2602         relcount  = count[j] / avcount;
2603         z         = (j + 0.5) * opt->dz + opt->min;
2604         bBoundary = j < bins / 20 || (bins - j) > bins / 20;
2605         /* check for bins with no data */
2606         if (count[j] == 0)
2607         {
2608             fprintf(stderr,
2609                     "\nWARNING, no data point in bin %d (z=%g) !\n"
2610                     "You may not get a reasonable profile. Check your histograms!\n",
2611                     j,
2612                     z);
2613         }
2614         /* and check for poor sampling */
2615         else if (relcount < 0.005 && !bBoundary)
2616         {
2617             fprintf(stderr, "Warning, poor sampling bin %d (z=%g). Check your histograms!\n", j, z);
2618         }
2619     }
2620     sfree(count);
2621 }
2622
2623 /*! \brief Compute initial potential by integrating the average force
2624  *
2625  * This speeds up the convergence by roughly a factor of 2
2626  */
2627 static void guessPotByIntegration(t_UmbrellaWindow* window, int nWindows, t_UmbrellaOptions* opt, const char* xlabel)
2628 {
2629     int    i, j, ig, bins = opt->bins, nHist, winmin, groupmin;
2630     double dz, min = opt->min, *pot, pos, hispos, dist, diff, fAv, distmin, *f;
2631     FILE*  fp;
2632
2633     dz = (opt->max - min) / bins;
2634
2635     printf("Getting initial potential by integration.\n");
2636
2637     /* Compute average displacement from histograms */
2638     computeAverageForce(window, nWindows, opt);
2639
2640     /* Get force for each bin from all histograms in this bin, or, alternatively,
2641        if no histograms are inside this bin, from the closest histogram */
2642     snew(pot, bins);
2643     snew(f, bins);
2644     for (j = 0; j < opt->bins; ++j)
2645     {
2646         pos      = (1.0 * j + 0.5) * dz + min;
2647         nHist    = 0;
2648         fAv      = 0.;
2649         distmin  = 1e20;
2650         groupmin = winmin = 0;
2651         for (i = 0; i < nWindows; i++)
2652         {
2653             for (ig = 0; ig < window[i].nPull; ig++)
2654             {
2655                 hispos = window[i].pos[ig];
2656                 dist   = std::abs(hispos - pos);
2657                 /* average force within bin */
2658                 if (dist < dz / 2)
2659                 {
2660                     nHist++;
2661                     fAv += window[i].forceAv[ig];
2662                 }
2663                 /* at the same time, remember closest histogram */
2664                 if (dist < distmin)
2665                 {
2666                     winmin   = i;
2667                     groupmin = ig;
2668                     distmin  = dist;
2669                 }
2670             }
2671         }
2672         /* if no histogram found in this bin, use closest histogram */
2673         if (nHist > 0)
2674         {
2675             fAv = fAv / nHist;
2676         }
2677         else
2678         {
2679             fAv = window[winmin].forceAv[groupmin];
2680         }
2681         f[j] = fAv;
2682     }
2683     for (j = 1; j < opt->bins; ++j)
2684     {
2685         pot[j] = pot[j - 1] - 0.5 * dz * (f[j - 1] + f[j]);
2686     }
2687
2688     /* cyclic wham: linearly correct possible offset */
2689     if (opt->bCycl)
2690     {
2691         diff = (pot[bins - 1] - pot[0]) / (bins - 1);
2692         for (j = 1; j < opt->bins; ++j)
2693         {
2694             pot[j] -= j * diff;
2695         }
2696     }
2697     if (opt->verbose)
2698     {
2699         fp = xvgropen("pmfintegrated.xvg", "PMF from force integration", xlabel, "PMF (kJ/mol)", opt->oenv);
2700         for (j = 0; j < opt->bins; ++j)
2701         {
2702             fprintf(fp, "%g  %g\n", (j + 0.5) * dz + opt->min, pot[j]);
2703         }
2704         xvgrclose(fp);
2705         printf("verbose mode: wrote %s with PMF from interated forces\n", "pmfintegrated.xvg");
2706     }
2707
2708     /* get initial z=exp(-F[i]/kT) from integrated potential, where F[i] denote the free
2709        energy offsets which are usually determined by wham
2710        First: turn pot into probabilities:
2711      */
2712     for (j = 0; j < opt->bins; ++j)
2713     {
2714         pot[j] = std::exp(-pot[j] / (gmx::c_boltz * opt->Temperature));
2715     }
2716     calc_z(pot, window, nWindows, opt, TRUE);
2717
2718     sfree(pot);
2719     sfree(f);
2720 }
2721
2722 //! Count number of words in an line
2723 static int wordcount(char* ptr)
2724 {
2725     int i, n, is[2];
2726     int cur = 0;
2727
2728     if (std::strlen(ptr) == 0)
2729     {
2730         return 0;
2731     }
2732     /* fprintf(stderr,"ptr='%s'\n",ptr); */
2733     n = 1;
2734     for (i = 0; (ptr[i] != '\0'); i++)
2735     {
2736         is[cur] = isspace(ptr[i]);
2737         if ((i > 0) && (is[cur] && !is[1 - cur]))
2738         {
2739             n++;
2740         }
2741         cur = 1 - cur;
2742     }
2743     return n;
2744 }
2745
2746 /*! \brief Read input file for pull group selection (option -is)
2747  *
2748  * TO DO: ptr=fgets(...) is never freed (small memory leak)
2749  */
2750 static void readPullCoordSelection(t_UmbrellaOptions* opt, char** fnTpr, int nTpr)
2751 {
2752     FILE* fp;
2753     int   i, iline, n, len = STRLEN, temp;
2754     char *ptr = nullptr, *tmpbuf = nullptr;
2755     char  fmt[1024], fmtign[1024];
2756     int   block = 1, sizenow;
2757
2758     fp            = gmx_ffopen(opt->fnCoordSel, "r");
2759     opt->coordsel = nullptr;
2760
2761     snew(tmpbuf, len);
2762     sizenow = 0;
2763     iline   = 0;
2764     while ((ptr = fgets3(fp, tmpbuf, &len)) != nullptr)
2765     {
2766         trim(ptr);
2767         n = wordcount(ptr);
2768
2769         if (iline >= sizenow)
2770         {
2771             sizenow += block;
2772             srenew(opt->coordsel, sizenow);
2773         }
2774         opt->coordsel[iline].n    = n;
2775         opt->coordsel[iline].nUse = 0;
2776         snew(opt->coordsel[iline].bUse, n);
2777
2778         fmtign[0] = '\0';
2779         for (i = 0; i < n; i++)
2780         {
2781             std::strcpy(fmt, fmtign);
2782             std::strcat(fmt, "%d");
2783             if (sscanf(ptr, fmt, &temp))
2784             {
2785                 opt->coordsel[iline].bUse[i] = (temp > 0);
2786                 if (opt->coordsel[iline].bUse[i])
2787                 {
2788                     opt->coordsel[iline].nUse++;
2789                 }
2790             }
2791             std::strcat(fmtign, "%*s");
2792         }
2793         iline++;
2794     }
2795     opt->nCoordsel = iline;
2796     if (nTpr != opt->nCoordsel)
2797     {
2798         gmx_fatal(FARGS, "Found %d tpr files but %d lines in %s\n", nTpr, opt->nCoordsel, opt->fnCoordSel);
2799     }
2800
2801     printf("\nUse only these pull coordinates:\n");
2802     for (iline = 0; iline < nTpr; iline++)
2803     {
2804         printf("%s (%d of %d coordinates):",
2805                fnTpr[iline],
2806                opt->coordsel[iline].nUse,
2807                opt->coordsel[iline].n);
2808         for (i = 0; i < opt->coordsel[iline].n; i++)
2809         {
2810             if (opt->coordsel[iline].bUse[i])
2811             {
2812                 printf(" %d", i + 1);
2813             }
2814         }
2815         printf("\n");
2816     }
2817     printf("\n");
2818
2819     sfree(tmpbuf);
2820 }
2821
2822 //! Boolean XOR
2823 #define WHAMBOOLXOR(a, b) (((!(a)) && (b)) || ((a) && (!(b))))
2824
2825 //! Number of elements in fnm (used for command line parsing)
2826 #define NFILE asize(fnm)
2827
2828 //! The main gmx wham routine
2829 int gmx_wham(int argc, char* argv[])
2830 {
2831     const char* desc[] = {
2832         "[THISMODULE] is an analysis program that implements the Weighted",
2833         "Histogram Analysis Method (WHAM). It is intended to analyze",
2834         "output files generated by umbrella sampling simulations to ",
2835         "compute a potential of mean force (PMF).[PAR]",
2836         "",
2837         "[THISMODULE] is currently not fully up to date. It only supports pull setups",
2838         "where the first pull coordinate(s) is/are umbrella pull coordinates",
2839         "and, if multiple coordinates need to be analyzed, all used the same",
2840         "geometry and dimensions. In most cases this is not an issue.[PAR]",
2841         "At present, three input modes are supported.",
2842         "",
2843         "* With option [TT]-it[tt], the user provides a file which contains the",
2844         "  file names of the umbrella simulation run-input files ([REF].tpr[ref] files),",
2845         "  AND, with option [TT]-ix[tt], a file which contains file names of",
2846         "  the pullx [TT]mdrun[tt] output files. The [REF].tpr[ref] and pullx files must",
2847         "  be in corresponding order, i.e. the first [REF].tpr[ref] created the",
2848         "  first pullx, etc.",
2849         "* Same as the previous input mode, except that the user",
2850         "  provides the pull force output file names ([TT]pullf.xvg[tt]) with option [TT]-if[tt].",
2851         "  From the pull force the position in the umbrella potential is",
2852         "  computed. This does not work with tabulated umbrella potentials.",
2853         "",
2854         "By default, all pull coordinates found in all pullx/pullf files are used in WHAM. If ",
2855         "only ",
2856         "some of the pull coordinates should be used, a pull coordinate selection file (option ",
2857         "[TT]-is[tt]) can ",
2858         "be provided. The selection file must contain one line for each tpr file in tpr-files.dat.",
2859         "Each of these lines must contain one digit (0 or 1) for each pull coordinate in the tpr ",
2860         "file. ",
2861         "Here, 1 indicates that the pull coordinate is used in WHAM, and 0 means it is omitted. ",
2862         "Example:",
2863         "If you have three tpr files, each containing 4 pull coordinates, but only pull ",
2864         "coordinates 1 and 2 should be ",
2865         "used, coordsel.dat looks like this::",
2866         "",
2867         "  1 1 0 0",
2868         "  1 1 0 0",
2869         "  1 1 0 0",
2870         "",
2871         "By default, the output files are::",
2872         "",
2873         "  [TT]-o[tt]      PMF output file",
2874         "  [TT]-hist[tt]   Histograms output file",
2875         "",
2876         "Always check whether the histograms sufficiently overlap.[PAR]",
2877         "The umbrella potential is assumed to be harmonic and the force constants are ",
2878         "read from the [REF].tpr[ref] files. If a non-harmonic umbrella force ",
2879         "was applied ",
2880         "a tabulated potential can be provided with [TT]-tab[tt].",
2881         "",
2882         "WHAM options",
2883         "^^^^^^^^^^^^",
2884         "",
2885         "* [TT]-bins[tt]   Number of bins used in analysis",
2886         "* [TT]-temp[tt]   Temperature in the simulations",
2887         "* [TT]-tol[tt]    Stop iteration if profile (probability) changed less than tolerance",
2888         "* [TT]-auto[tt]   Automatic determination of boundaries",
2889         "* [TT]-min,-max[tt]   Boundaries of the profile",
2890         "",
2891         "The data points that are used to compute the profile",
2892         "can be restricted with options [TT]-b[tt], [TT]-e[tt], and [TT]-dt[tt]. ",
2893         "Adjust [TT]-b[tt] to ensure sufficient equilibration in each ",
2894         "umbrella window.[PAR]",
2895         "With [TT]-log[tt] (default) the profile is written in energy units, otherwise ",
2896         "(with [TT]-nolog[tt]) as probability. The unit can be specified with [TT]-unit[tt]. ",
2897         "With energy output, the energy in the first bin is defined to be zero. ",
2898         "If you want the free energy at a different ",
2899         "position to be zero, set [TT]-zprof0[tt] (useful with bootstrapping, see below).[PAR]",
2900         "For cyclic or periodic reaction coordinates (dihedral angle, channel PMF",
2901         "without osmotic gradient), the option [TT]-cycl[tt] is useful.",
2902         "[THISMODULE] will make use of the",
2903         "periodicity of the system and generate a periodic PMF. The first and the last bin of the",
2904         "reaction coordinate will assumed be be neighbors.[PAR]",
2905         "Option [TT]-sym[tt] symmetrizes the profile around z=0 before output, ",
2906         "which may be useful for, e.g. membranes.",
2907         "",
2908         "Parallelization",
2909         "^^^^^^^^^^^^^^^",
2910         "",
2911         "If available, the number of OpenMP threads used by gmx wham can be controlled by setting",
2912         "the [TT]OMP_NUM_THREADS[tt] environment variable.",
2913         "",
2914         "Autocorrelations",
2915         "^^^^^^^^^^^^^^^^",
2916         "",
2917         "With [TT]-ac[tt], [THISMODULE] estimates the integrated autocorrelation ",
2918         "time (IACT) [GRK]tau[grk] for each umbrella window and weights the respective ",
2919         "window with 1/[1+2*[GRK]tau[grk]/dt]. The IACTs are written ",
2920         "to the file defined with [TT]-oiact[tt]. In verbose mode, all ",
2921         "autocorrelation functions (ACFs) are written to [TT]hist_autocorr.xvg[tt]. ",
2922         "Because the IACTs can be severely underestimated in case of limited ",
2923         "sampling, option [TT]-acsig[tt] allows one to smooth the IACTs along the ",
2924         "reaction coordinate with a Gaussian ([GRK]sigma[grk] provided with [TT]-acsig[tt], ",
2925         "see output in [TT]iact.xvg[tt]). Note that the IACTs are estimated by simple ",
2926         "integration of the ACFs while the ACFs are larger 0.05.",
2927         "If you prefer to compute the IACTs by a more sophisticated (but possibly ",
2928         "less robust) method such as fitting to a double exponential, you can ",
2929         "compute the IACTs with [gmx-analyze] and provide them to [THISMODULE] with the file ",
2930         "[TT]iact-in.dat[tt] (option [TT]-iiact[tt]), which should contain one line per ",
2931         "input file (pullx/pullf file) and one column per pull coordinate in the ",
2932         "respective file.",
2933         "",
2934         "Error analysis",
2935         "^^^^^^^^^^^^^^",
2936         "",
2937         "Statistical errors may be estimated with bootstrap analysis. Use it with care, ",
2938         "otherwise the statistical error may be substantially underestimated. ",
2939         "More background and examples for the bootstrap technique can be found in ",
2940         "Hub, de Groot and Van der Spoel, JCTC (2010) 6: 3713-3720.",
2941         "[TT]-nBootstrap[tt] defines the number of bootstraps (use, e.g., 100). ",
2942         "Four bootstrapping methods are supported and ",
2943         "selected with [TT]-bs-method[tt].",
2944         "",
2945         "* [TT]b-hist[tt]   Default: complete histograms are considered as independent ",
2946         "  data points, and the bootstrap is carried out by assigning random weights to the ",
2947         "  histograms (\"Bayesian bootstrap\"). Note that each point along the reaction coordinate",
2948         "  must be covered by multiple independent histograms (e.g. 10 histograms), otherwise the ",
2949         "  statistical error is underestimated.",
2950         "* [TT]hist[tt]    Complete histograms are considered as independent data points. ",
2951         "  For each bootstrap, N histograms are randomly chosen from the N given histograms ",
2952         "  (allowing duplication, i.e. sampling with replacement).",
2953         "  To avoid gaps without data along the reaction coordinate blocks of histograms ",
2954         "  ([TT]-histbs-block[tt]) may be defined. In that case, the given histograms are ",
2955         "  divided into blocks and only histograms within each block are mixed. Note that ",
2956         "  the histograms within each block must be representative for all possible histograms, ",
2957         "  otherwise the statistical error is underestimated.",
2958         "* [TT]traj[tt]  The given histograms are used to generate new random trajectories,",
2959         "  such that the generated data points are distributed according the given histograms ",
2960         "  and properly autocorrelated. The autocorrelation time (ACT) for each window must be ",
2961         "  known, so use [TT]-ac[tt] or provide the ACT with [TT]-iiact[tt]. If the ACT of all ",
2962         "  windows are identical (and known), you can also provide them with [TT]-bs-tau[tt]. ",
2963         "  Note that this method may severely underestimate the error in case of limited ",
2964         "  sampling, ",
2965         "  that is if individual histograms do not represent the complete phase space at ",
2966         "  the respective positions.",
2967         "* [TT]traj-gauss[tt]  The same as method [TT]traj[tt], but the trajectories are ",
2968         "  not bootstrapped from the umbrella histograms but from Gaussians with the average ",
2969         "  and width of the umbrella histograms. That method yields similar error estimates ",
2970         "  like method [TT]traj[tt].",
2971         "",
2972         "Bootstrapping output:",
2973         "",
2974         "* [TT]-bsres[tt]   Average profile and standard deviations",
2975         "* [TT]-bsprof[tt]  All bootstrapping profiles",
2976         "",
2977         "With [TT]-vbs[tt] (verbose bootstrapping), the histograms of each bootstrap are written, ",
2978         "and, with bootstrap method [TT]traj[tt], the cumulative distribution functions of ",
2979         "the histograms."
2980     };
2981
2982     const char* en_unit[]       = { nullptr, "kJ", "kCal", "kT", nullptr };
2983     const char* en_unit_label[] = { "", "E (kJ mol\\S-1\\N)", "E (kcal mol\\S-1\\N)", "E (kT)", nullptr };
2984     const char* en_bsMethod[] = { nullptr, "b-hist", "hist", "traj", "traj-gauss", nullptr };
2985     static t_UmbrellaOptions opt;
2986
2987     t_pargs pa[] = {
2988         { "-min", FALSE, etREAL, { &opt.min }, "Minimum coordinate in profile" },
2989         { "-max", FALSE, etREAL, { &opt.max }, "Maximum coordinate in profile" },
2990         { "-auto", FALSE, etBOOL, { &opt.bAuto }, "Determine min and max automatically" },
2991         { "-bins", FALSE, etINT, { &opt.bins }, "Number of bins in profile" },
2992         { "-temp", FALSE, etREAL, { &opt.Temperature }, "Temperature" },
2993         { "-tol", FALSE, etREAL, { &opt.Tolerance }, "Tolerance" },
2994         { "-v", FALSE, etBOOL, { &opt.verbose }, "Verbose mode" },
2995         { "-b", FALSE, etREAL, { &opt.tmin }, "First time to analyse (ps)" },
2996         { "-e", FALSE, etREAL, { &opt.tmax }, "Last time to analyse (ps)" },
2997         { "-dt", FALSE, etREAL, { &opt.dt }, "Analyse only every dt ps" },
2998         { "-histonly", FALSE, etBOOL, { &opt.bHistOnly }, "Write histograms and exit" },
2999         { "-boundsonly",
3000           FALSE,
3001           etBOOL,
3002           { &opt.bBoundsOnly },
3003           "Determine min and max and exit (with [TT]-auto[tt])" },
3004         { "-log", FALSE, etBOOL, { &opt.bLog }, "Calculate the log of the profile before printing" },
3005         { "-unit", FALSE, etENUM, { en_unit }, "Energy unit in case of log output" },
3006         { "-zprof0",
3007           FALSE,
3008           etREAL,
3009           { &opt.zProf0 },
3010           "Define profile to 0.0 at this position (with [TT]-log[tt])" },
3011         { "-cycl",
3012           FALSE,
3013           etBOOL,
3014           { &opt.bCycl },
3015           "Create cyclic/periodic profile. Assumes min and max are the same point." },
3016         { "-sym", FALSE, etBOOL, { &opt.bSym }, "Symmetrize profile around z=0" },
3017         { "-hist-eq",
3018           FALSE,
3019           etBOOL,
3020           { &opt.bHistEq },
3021           "HIDDENEnforce equal weight for all histograms. (Non-Weighed-HAM)" },
3022         { "-ac",
3023           FALSE,
3024           etBOOL,
3025           { &opt.bCalcTauInt },
3026           "Calculate integrated autocorrelation times and use in wham" },
3027         { "-acsig",
3028           FALSE,
3029           etREAL,
3030           { &opt.sigSmoothIact },
3031           "Smooth autocorrelation times along reaction coordinate with Gaussian of this "
3032           "[GRK]sigma[grk]" },
3033         { "-ac-trestart",
3034           FALSE,
3035           etREAL,
3036           { &opt.acTrestart },
3037           "When computing autocorrelation functions, restart computing every .. (ps)" },
3038         { "-acred",
3039           FALSE,
3040           etBOOL,
3041           { &opt.bAllowReduceIact },
3042           "HIDDENWhen smoothing the ACTs, allows one to reduce ACTs. Otherwise, only increase ACTs "
3043           "during smoothing" },
3044         { "-nBootstrap",
3045           FALSE,
3046           etINT,
3047           { &opt.nBootStrap },
3048           "nr of bootstraps to estimate statistical uncertainty (e.g., 200)" },
3049         { "-bs-method", FALSE, etENUM, { en_bsMethod }, "Bootstrap method" },
3050         { "-bs-tau",
3051           FALSE,
3052           etREAL,
3053           { &opt.tauBootStrap },
3054           "Autocorrelation time (ACT) assumed for all histograms. Use option [TT]-ac[tt] if ACT is "
3055           "unknown." },
3056         { "-bs-seed", FALSE, etINT, { &opt.bsSeed }, "Seed for bootstrapping. (-1 = use time)" },
3057         { "-histbs-block",
3058           FALSE,
3059           etINT,
3060           { &opt.histBootStrapBlockLength },
3061           "When mixing histograms only mix within blocks of [TT]-histbs-block[tt]." },
3062         { "-vbs",
3063           FALSE,
3064           etBOOL,
3065           { &opt.bs_verbose },
3066           "Verbose bootstrapping. Print the CDFs and a histogram file for each bootstrap." },
3067         { "-stepout",
3068           FALSE,
3069           etINT,
3070           { &opt.stepchange },
3071           "HIDDENWrite maximum change every ... (set to 1 with [TT]-v[tt])" },
3072         { "-updateContr",
3073           FALSE,
3074           etINT,
3075           { &opt.stepUpdateContrib },
3076           "HIDDENUpdate table with significan contributions to WHAM every ... iterations" },
3077     };
3078
3079     t_filenm fnm[] = {
3080         { efDAT, "-ix", "pullx-files", ffOPTRD }, /* wham input: pullf.xvg's and tprs           */
3081         { efDAT, "-if", "pullf-files", ffOPTRD }, /* wham input: pullf.xvg's and tprs           */
3082         { efDAT, "-it", "tpr-files", ffOPTRD },   /* wham input: tprs                           */
3083         { efDAT, "-is", "coordsel", ffOPTRD },    /* input: select pull coords to use           */
3084         { efXVG, "-o", "profile", ffWRITE },      /* output file for profile                     */
3085         { efXVG, "-hist", "histo", ffWRITE },     /* output file for histograms                  */
3086         { efXVG, "-oiact", "iact", ffOPTWR },     /* writing integrated autocorrelation times    */
3087         { efDAT, "-iiact", "iact-in", ffOPTRD },  /* reading integrated autocorrelation times   */
3088         { efXVG, "-bsres", "bsResult", ffOPTWR }, /* average and errors of bootstrap analysis    */
3089         { efXVG, "-bsprof", "bsProfs", ffOPTWR }, /* output file for bootstrap profiles          */
3090         { efDAT, "-tab", "umb-pot", ffOPTRD }, /* Tabulated umbrella potential (if not harmonic) */
3091     };
3092
3093     int               i, j, l, nfiles, nwins, nfiles2;
3094     t_UmbrellaHeader  header;
3095     t_UmbrellaWindow* window = nullptr;
3096     double *          profile, maxchange = 1e20;
3097     gmx_bool          bMinSet, bMaxSet, bAutoSet, bExact = FALSE;
3098     char **           fninTpr, **fninPull;
3099     const char*       fnPull;
3100     FILE *            histout, *profout;
3101     char              xlabel[STRLEN], ylabel[256], title[256];
3102
3103     opt.bins      = 200;
3104     opt.verbose   = FALSE;
3105     opt.bHistOnly = FALSE;
3106     opt.bCycl     = FALSE;
3107     opt.tmin      = 50;
3108     opt.tmax      = 1e20;
3109     opt.dt        = 0.0;
3110     opt.min       = 0;
3111     opt.max       = 0;
3112     opt.bAuto     = TRUE;
3113     opt.nCoordsel = 0;
3114     opt.coordsel  = nullptr;
3115
3116     /* bootstrapping stuff */
3117     opt.nBootStrap               = 0;
3118     opt.bsMethod                 = bsMethod_hist;
3119     opt.tauBootStrap             = 0.0;
3120     opt.bsSeed                   = -1;
3121     opt.histBootStrapBlockLength = 8;
3122     opt.bs_verbose               = FALSE;
3123
3124     opt.bLog                  = TRUE;
3125     opt.unit                  = en_kJ;
3126     opt.zProf0                = 0.;
3127     opt.Temperature           = 298;
3128     opt.Tolerance             = 1e-6;
3129     opt.bBoundsOnly           = FALSE;
3130     opt.bSym                  = FALSE;
3131     opt.bCalcTauInt           = FALSE;
3132     opt.sigSmoothIact         = 0.0;
3133     opt.bAllowReduceIact      = TRUE;
3134     opt.bInitPotByIntegration = TRUE;
3135     opt.acTrestart            = 1.0;
3136     opt.stepchange            = 100;
3137     opt.stepUpdateContrib     = 100;
3138
3139     if (!parse_common_args(
3140                 &argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &opt.oenv))
3141     {
3142         return 0;
3143     }
3144
3145     opt.unit     = nenum(en_unit);
3146     opt.bsMethod = nenum(en_bsMethod);
3147
3148     opt.bProf0Set = opt2parg_bSet("-zprof0", asize(pa), pa);
3149
3150     opt.bTab         = opt2bSet("-tab", NFILE, fnm);
3151     opt.bTpr         = opt2bSet("-it", NFILE, fnm);
3152     opt.bPullx       = opt2bSet("-ix", NFILE, fnm);
3153     opt.bPullf       = opt2bSet("-if", NFILE, fnm);
3154     opt.bTauIntGiven = opt2bSet("-iiact", NFILE, fnm);
3155     if (opt.bTab && opt.bPullf)
3156     {
3157         gmx_fatal(FARGS,
3158                   "Force input does not work with tabulated potentials. "
3159                   "Provide pullx.xvg files!");
3160     }
3161
3162     if (!WHAMBOOLXOR(opt.bPullx, opt.bPullf))
3163     {
3164         gmx_fatal(FARGS, "Give either pullx (-ix) OR pullf (-if) data. Not both.");
3165     }
3166
3167     opt.fnTpr      = opt2fn("-it", NFILE, fnm);
3168     opt.fnPullf    = opt2fn("-if", NFILE, fnm);
3169     opt.fnPullx    = opt2fn("-ix", NFILE, fnm);
3170     opt.fnCoordSel = opt2fn_null("-is", NFILE, fnm);
3171
3172     bMinSet  = opt2parg_bSet("-min", asize(pa), pa);
3173     bMaxSet  = opt2parg_bSet("-max", asize(pa), pa);
3174     bAutoSet = opt2parg_bSet("-auto", asize(pa), pa);
3175     if ((bMinSet || bMaxSet) && bAutoSet)
3176     {
3177         gmx_fatal(FARGS, "With -auto, do not give -min or -max\n");
3178     }
3179
3180     if ((bMinSet && !bMaxSet) || (!bMinSet && bMaxSet))
3181     {
3182         gmx_fatal(FARGS, "When giving -min, you must give -max (and vice versa), too\n");
3183     }
3184
3185     if (bMinSet && opt.bAuto)
3186     {
3187         printf("Note: min and max given, switching off -auto.\n");
3188         opt.bAuto = FALSE;
3189     }
3190
3191     if (opt.bTauIntGiven && opt.bCalcTauInt)
3192     {
3193         gmx_fatal(FARGS,
3194                   "Either read (option -iiact) or calculate (option -ac) the\n"
3195                   "the autocorrelation times. Not both.");
3196     }
3197
3198     if (opt.tauBootStrap > 0.0 && opt2parg_bSet("-ac", asize(pa), pa))
3199     {
3200         gmx_fatal(FARGS,
3201                   "Either compute autocorrelation times (ACTs) (option -ac) or "
3202                   "provide it with -bs-tau for bootstrapping. Not Both.\n");
3203     }
3204     if (opt.tauBootStrap > 0.0 && opt2bSet("-iiact", NFILE, fnm))
3205     {
3206         gmx_fatal(FARGS,
3207                   "Either provide autocorrelation times (ACTs) with file iact-in.dat "
3208                   "(option -iiact) or define all ACTs with -bs-tau for bootstrapping\n. Not Both.");
3209     }
3210
3211     /* Reading gmx4/gmx5 pull output and tpr files */
3212     read_wham_in(opt.fnTpr, &fninTpr, &nfiles, &opt);
3213
3214     fnPull = opt.bPullf ? opt.fnPullf : opt.fnPullx;
3215     read_wham_in(fnPull, &fninPull, &nfiles2, &opt);
3216     printf("Found %d tpr and %d pull %s files in %s and %s, respectively\n",
3217            nfiles,
3218            nfiles2,
3219            opt.bPullf ? "force" : "position",
3220            opt.fnTpr,
3221            fnPull);
3222     if (nfiles != nfiles2)
3223     {
3224         gmx_fatal(FARGS, "Found %d file names in %s, but %d in %s\n", nfiles, opt.fnTpr, nfiles2, fnPull);
3225     }
3226
3227     /* Read file that selects the pull group to be used */
3228     if (opt.fnCoordSel != nullptr)
3229     {
3230         readPullCoordSelection(&opt, fninTpr, nfiles);
3231     }
3232
3233     window = initUmbrellaWindows(nfiles);
3234     read_tpr_pullxf_files(fninTpr, fninPull, nfiles, &header, window, &opt);
3235
3236     /* It is currently assumed that all pull coordinates have the same geometry, so they also have the same coordinate units.
3237        We can therefore get the units for the xlabel from the first coordinate. */
3238     sprintf(xlabel, "\\xx\\f{} (%s)", header.pcrd[0].coord_unit);
3239
3240     nwins = nfiles;
3241
3242     /* enforce equal weight for all histograms? */
3243     if (opt.bHistEq)
3244     {
3245         enforceEqualWeights(window, nwins);
3246     }
3247
3248     /* write histograms */
3249     histout = xvgropen(opt2fn("-hist", NFILE, fnm), "Umbrella histograms", xlabel, "count", opt.oenv);
3250     for (l = 0; l < opt.bins; ++l)
3251     {
3252         fprintf(histout, "%e\t", (l + 0.5) / opt.bins * (opt.max - opt.min) + opt.min);
3253         for (i = 0; i < nwins; ++i)
3254         {
3255             for (j = 0; j < window[i].nPull; ++j)
3256             {
3257                 fprintf(histout, "%e\t", window[i].Histo[j][l]);
3258             }
3259         }
3260         fprintf(histout, "\n");
3261     }
3262     xvgrclose(histout);
3263     printf("Wrote %s\n", opt2fn("-hist", NFILE, fnm));
3264     if (opt.bHistOnly)
3265     {
3266         printf("Wrote histograms to %s, now exiting.\n", opt2fn("-hist", NFILE, fnm));
3267         return 0;
3268     }
3269
3270     /* Using tabulated umbrella potential */
3271     if (opt.bTab)
3272     {
3273         setup_tab(opt2fn("-tab", NFILE, fnm), &opt);
3274     }
3275
3276     /* Integrated autocorrelation times provided ? */
3277     if (opt.bTauIntGiven)
3278     {
3279         readIntegratedAutocorrelationTimes(window, nwins, opt2fn("-iiact", NFILE, fnm));
3280     }
3281
3282     /* Compute integrated autocorrelation times */
3283     if (opt.bCalcTauInt)
3284     {
3285         calcIntegratedAutocorrelationTimes(window, nwins, &opt, opt2fn("-oiact", NFILE, fnm), xlabel);
3286     }
3287
3288     /* calc average and sigma for each histogram
3289        (maybe required for bootstrapping. If not, this is fast anyhow) */
3290     if (opt.nBootStrap && opt.bsMethod == bsMethod_trajGauss)
3291     {
3292         averageSigma(window, nwins);
3293     }
3294
3295     /* Get initial potential by simple integration */
3296     if (opt.bInitPotByIntegration)
3297     {
3298         guessPotByIntegration(window, nwins, &opt, xlabel);
3299     }
3300
3301     /* Check if complete reaction coordinate is covered */
3302     checkReactionCoordinateCovered(window, nwins, &opt);
3303
3304     /* Calculate profile */
3305     snew(profile, opt.bins);
3306     if (opt.verbose)
3307     {
3308         opt.stepchange = 1;
3309     }
3310     i = 0;
3311     do
3312     {
3313         if ((i % opt.stepUpdateContrib) == 0)
3314         {
3315             setup_acc_wham(profile, window, nwins, &opt);
3316         }
3317         if (maxchange < opt.Tolerance)
3318         {
3319             bExact = TRUE;
3320             /* if (opt.verbose) */
3321             printf("Switched to exact iteration in iteration %d\n", i);
3322         }
3323         calc_profile(profile, window, nwins, &opt, bExact);
3324         if (((i % opt.stepchange) == 0 || i == 1) && i != 0)
3325         {
3326             printf("\t%4d) Maximum change %e\n", i, maxchange);
3327         }
3328         i++;
3329     } while ((maxchange = calc_z(profile, window, nwins, &opt, bExact)) > opt.Tolerance || !bExact);
3330     printf("Converged in %d iterations. Final maximum change %g\n", i, maxchange);
3331
3332     /* calc error from Kumar's formula */
3333     /* Unclear how the error propagates along reaction coordinate, therefore
3334        commented out  */
3335     /* calc_error_kumar(profile,window, nwins,&opt); */
3336
3337     /* Write profile in energy units? */
3338     if (opt.bLog)
3339     {
3340         prof_normalization_and_unit(profile, &opt);
3341         std::strcpy(ylabel, en_unit_label[opt.unit]);
3342         std::strcpy(title, "Umbrella potential");
3343     }
3344     else
3345     {
3346         std::strcpy(ylabel, "Density of states");
3347         std::strcpy(title, "Density of states");
3348     }
3349
3350     /* symmetrize profile around z=0? */
3351     if (opt.bSym)
3352     {
3353         symmetrizeProfile(profile, &opt);
3354     }
3355
3356     /* write profile or density of states */
3357     profout = xvgropen(opt2fn("-o", NFILE, fnm), title, xlabel, ylabel, opt.oenv);
3358     for (i = 0; i < opt.bins; ++i)
3359     {
3360         fprintf(profout, "%e\t%e\n", (i + 0.5) / opt.bins * (opt.max - opt.min) + opt.min, profile[i]);
3361     }
3362     xvgrclose(profout);
3363     printf("Wrote %s\n", opt2fn("-o", NFILE, fnm));
3364
3365     /* Bootstrap Method */
3366     if (opt.nBootStrap)
3367     {
3368         do_bootstrapping(opt2fn("-bsres", NFILE, fnm),
3369                          opt2fn("-bsprof", NFILE, fnm),
3370                          opt2fn("-hist", NFILE, fnm),
3371                          xlabel,
3372                          ylabel,
3373                          profile,
3374                          window,
3375                          nwins,
3376                          &opt);
3377     }
3378
3379     sfree(profile);
3380     freeUmbrellaWindows(window, nfiles);
3381
3382     printf("\nIn case you use results from gmx wham for a publication, please cite:\n");
3383     please_cite(stdout, "Hub2010");
3384
3385     return 0;
3386 }