8dd13887554f0f3ab39c0266b6ec9e7632e7c45e
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_analyze.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, 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 #include "gmxpre.h"
39
40 #include <cmath>
41 #include <cstdlib>
42 #include <cstring>
43
44 #include "gromacs/commandline/pargs.h"
45 #include "gromacs/commandline/viewit.h"
46 #include "gromacs/correlationfunctions/autocorr.h"
47 #include "gromacs/correlationfunctions/expfit.h"
48 #include "gromacs/correlationfunctions/integrate.h"
49 #include "gromacs/fileio/xvgr.h"
50 #include "gromacs/gmxana/gmx_ana.h"
51 #include "gromacs/gmxana/gstat.h"
52 #include "gromacs/linearalgebra/matrix.h"
53 #include "gromacs/math/functions.h"
54 #include "gromacs/math/utilities.h"
55 #include "gromacs/math/vec.h"
56 #include "gromacs/statistics/statistics.h"
57 #include "gromacs/utility/arraysize.h"
58 #include "gromacs/utility/fatalerror.h"
59 #include "gromacs/utility/futil.h"
60 #include "gromacs/utility/pleasecite.h"
61 #include "gromacs/utility/smalloc.h"
62 #include "gromacs/utility/snprintf.h"
63
64 /* must correspond to char *avbar_opt[] declared in main() */
65 enum
66 {
67     avbarSEL,
68     avbarNONE,
69     avbarSTDDEV,
70     avbarERROR,
71     avbar90,
72     avbarNR
73 };
74
75 static void power_fit(int n, int nset, real** val, real* t)
76 {
77     real *x, *y, quality, a, b, r;
78     int   s, i;
79
80     snew(x, n);
81     snew(y, n);
82
83     if (t[0] > 0)
84     {
85         for (i = 0; i < n; i++)
86         {
87             if (t[0] > 0)
88             {
89                 x[i] = std::log(t[i]);
90             }
91         }
92     }
93     else
94     {
95         fprintf(stdout,
96                 "First time is not larger than 0, using index number as time for power fit\n");
97         for (i = 0; i < n; i++)
98         {
99             x[i] = std::log1p(static_cast<real>(i));
100         }
101     }
102
103     for (s = 0; s < nset; s++)
104     {
105         for (i = 0; i < n && val[s][i] >= 0; i++)
106         {
107             y[i] = std::log(val[s][i]);
108         }
109         if (i < n)
110         {
111             fprintf(stdout, "Will power fit up to point %d, since it is not larger than 0\n", i);
112         }
113         lsq_y_ax_b(i, x, y, &a, &b, &r, &quality);
114         fprintf(stdout, "Power fit set %3d:  error %.3f  a %g  b %g\n", s + 1, quality, a, std::exp(b));
115     }
116
117     sfree(y);
118     sfree(x);
119 }
120
121 static real cosine_content(int nhp, int n, const real* y)
122 /* Assumes n equidistant points */
123 {
124     double fac, cosyint, yyint;
125     int    i;
126
127     if (n < 2)
128     {
129         return 0;
130     }
131
132     fac = M_PI * nhp / (n - 1);
133
134     cosyint = 0;
135     yyint   = 0;
136     for (i = 0; i < n; i++)
137     {
138         cosyint += std::cos(fac * i) * y[i];
139         yyint += y[i] * y[i];
140     }
141
142     return 2 * cosyint * cosyint / (n * yyint);
143 }
144
145 static void plot_coscont(const char* ccfile, int n, int nset, real** val, const gmx_output_env_t* oenv)
146 {
147     FILE* fp;
148     int   s;
149     real  cc;
150
151     fp = xvgropen(ccfile, "Cosine content", "set / half periods", "cosine content", oenv);
152
153     for (s = 0; s < nset; s++)
154     {
155         cc = cosine_content(s + 1, n, val[s]);
156         fprintf(fp, " %d %g\n", s + 1, cc);
157         fprintf(stdout, "Cosine content of set %d with %.1f periods: %g\n", s + 1, 0.5 * (s + 1), cc);
158     }
159     fprintf(stdout, "\n");
160
161     xvgrclose(fp);
162 }
163
164 static void regression_analysis(int n, gmx_bool bXYdy, real* x, int nset, real** val)
165 {
166     real S, chi2, a, b, da, db, r = 0;
167     int  ok;
168
169     if (bXYdy || (nset == 1))
170     {
171         printf("Fitting data to a function f(x) = ax + b\n");
172         printf("Minimizing residual chi2 = Sum_i w_i [f(x_i) - y_i]2\n");
173         printf("Error estimates will be given if w_i (sigma) values are given\n");
174         printf("(use option -xydy).\n\n");
175         if (bXYdy)
176         {
177             if ((ok = lsq_y_ax_b_error(n, x, val[0], val[1], &a, &b, &da, &db, &r, &S)) != estatsOK)
178             {
179                 gmx_fatal(FARGS, "Error fitting the data: %s", gmx_stats_message(ok));
180             }
181         }
182         else
183         {
184             if ((ok = lsq_y_ax_b(n, x, val[0], &a, &b, &r, &S)) != estatsOK)
185             {
186                 gmx_fatal(FARGS, "Error fitting the data: %s", gmx_stats_message(ok));
187             }
188         }
189         chi2 = gmx::square((n - 2) * S);
190         printf("Chi2                    = %g\n", chi2);
191         printf("S (Sqrt(Chi2/(n-2))     = %g\n", S);
192         printf("Correlation coefficient = %.1f%%\n", 100 * r);
193         printf("\n");
194         if (bXYdy)
195         {
196             printf("a    = %g +/- %g\n", a, da);
197             printf("b    = %g +/- %g\n", b, db);
198         }
199         else
200         {
201             printf("a    = %g\n", a);
202             printf("b    = %g\n", b);
203         }
204     }
205     else
206     {
207         double chi2, *a, **xx, *y;
208         int    i, j;
209
210         snew(y, n);
211         snew(xx, nset - 1);
212         for (j = 0; (j < nset - 1); j++)
213         {
214             snew(xx[j], n);
215         }
216         for (i = 0; (i < n); i++)
217         {
218             y[i] = val[0][i];
219             for (j = 1; (j < nset); j++)
220             {
221                 xx[j - 1][i] = val[j][i];
222             }
223         }
224         snew(a, nset - 1);
225         chi2 = multi_regression(nullptr, n, y, nset - 1, xx, a);
226         printf("Fitting %d data points in %d sets\n", n, nset - 1);
227         printf("chi2 = %g\n", chi2);
228         printf("A =");
229         for (i = 0; (i < nset - 1); i++)
230         {
231             printf("  %g", a[i]);
232             sfree(xx[i]);
233         }
234         printf("\n");
235         sfree(xx);
236         sfree(y);
237         sfree(a);
238     }
239 }
240
241 static void histogram(const char* distfile, real binwidth, int n, int nset, real** val, const gmx_output_env_t* oenv)
242 {
243     FILE*    fp;
244     int      i, s;
245     double   minval, maxval;
246     int      nbin;
247     int64_t* histo;
248
249     minval = val[0][0];
250     maxval = val[0][0];
251     for (s = 0; s < nset; s++)
252     {
253         for (i = 0; i < n; i++)
254         {
255             if (val[s][i] < minval)
256             {
257                 minval = val[s][i];
258             }
259             else if (val[s][i] > maxval)
260             {
261                 maxval = val[s][i];
262             }
263         }
264     }
265
266     minval = binwidth * std::floor(minval / binwidth);
267     maxval = binwidth * std::ceil(maxval / binwidth);
268     if (minval != 0)
269     {
270         minval -= binwidth;
271     }
272     maxval += binwidth;
273
274     nbin = gmx::roundToInt(((maxval - minval) / binwidth) + 1);
275     fprintf(stderr, "Making distributions with %d bins\n", nbin);
276     snew(histo, nbin);
277     fp = xvgropen(distfile, "Distribution", "", "", oenv);
278     for (s = 0; s < nset; s++)
279     {
280         for (i = 0; i < nbin; i++)
281         {
282             histo[i] = 0;
283         }
284         for (i = 0; i < n; i++)
285         {
286             histo[gmx::roundToInt((val[s][i] - minval) / binwidth)]++;
287         }
288         for (i = 0; i < nbin; i++)
289         {
290             fprintf(fp, " %g  %g\n", minval + i * binwidth, static_cast<double>(histo[i]) / (n * binwidth));
291         }
292         if (s < nset - 1)
293         {
294             fprintf(fp, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
295         }
296     }
297     xvgrclose(fp);
298 }
299
300 static int real_comp(const void* a, const void* b)
301 {
302     real dif = *reinterpret_cast<const real*>(a) - *reinterpret_cast<const real*>(b);
303
304     if (dif < 0)
305     {
306         return -1;
307     }
308     else if (dif > 0)
309     {
310         return 1;
311     }
312     else
313     {
314         return 0;
315     }
316 }
317
318 static void average(const char* avfile, int avbar_opt, int n, int nset, real** val, real* t)
319 {
320     FILE*  fp;
321     int    i, s, edge = 0;
322     double av, var, err;
323     real*  tmp = nullptr;
324
325     fp = gmx_ffopen(avfile, "w");
326     if ((avbar_opt == avbarERROR) && (nset == 1))
327     {
328         avbar_opt = avbarNONE;
329     }
330     if (avbar_opt != avbarNONE)
331     {
332         if (avbar_opt == avbar90)
333         {
334             snew(tmp, nset);
335             fprintf(fp, "@TYPE xydydy\n");
336             edge = gmx::roundToInt(nset * 0.05);
337             fprintf(stdout,
338                     "Errorbars: discarding %d points on both sides: %d%%"
339                     " interval\n",
340                     edge, gmx::roundToInt(100. * (nset - 2 * edge) / nset));
341         }
342         else
343         {
344             fprintf(fp, "@TYPE xydy\n");
345         }
346     }
347
348     for (i = 0; i < n; i++)
349     {
350         av = 0;
351         for (s = 0; s < nset; s++)
352         {
353             av += val[s][i];
354         }
355         av /= nset;
356         fprintf(fp, " %g %g", t[i], av);
357         var = 0;
358         if (avbar_opt != avbarNONE)
359         {
360             if (avbar_opt == avbar90)
361             {
362                 for (s = 0; s < nset; s++)
363                 {
364                     tmp[s] = val[s][i];
365                 }
366                 qsort(tmp, nset, sizeof(tmp[0]), real_comp);
367                 fprintf(fp, " %g %g", tmp[nset - 1 - edge] - av, av - tmp[edge]);
368             }
369             else
370             {
371                 for (s = 0; s < nset; s++)
372                 {
373                     var += gmx::square(val[s][i] - av);
374                 }
375                 if (avbar_opt == avbarSTDDEV)
376                 {
377                     err = std::sqrt(var / nset);
378                 }
379                 else
380                 {
381                     err = std::sqrt(var / (nset * (nset - 1)));
382                 }
383                 fprintf(fp, " %g", err);
384             }
385         }
386         fprintf(fp, "\n");
387     }
388     gmx_ffclose(fp);
389
390     if (avbar_opt == avbar90)
391     {
392         sfree(tmp);
393     }
394 }
395
396 /*! \brief Compute final error estimate.
397  *
398  * See Eqn A17, Hess, JCP 116 (2002) 209-217 for details.
399  */
400 static real optimal_error_estimate(double sigma, const double fitparm[], real tTotal)
401 {
402     // When sigma is zero, the fitparm data can be uninitialized
403     if (sigma == 0.0)
404     {
405         return 0;
406     }
407     double ss = fitparm[1] * fitparm[0] + (1 - fitparm[1]) * fitparm[2];
408     if ((tTotal <= 0) || (ss <= 0))
409     {
410         fprintf(stderr, "Problem in error estimate: T = %g, ss = %g\n", tTotal, ss);
411         return 0;
412     }
413
414     return sigma * std::sqrt(2 * ss / tTotal);
415 }
416
417 static void estimate_error(const char*             eefile,
418                            int                     nb_min,
419                            int                     resol,
420                            int                     n,
421                            int                     nset,
422                            double*                 av,
423                            double*                 sig,
424                            real**                  val,
425                            real                    dt,
426                            gmx_bool                bFitAc,
427                            gmx_bool                bSingleExpFit,
428                            gmx_bool                bAllowNegLTCorr,
429                            const gmx_output_env_t* oenv)
430 {
431     FILE*  fp;
432     int    bs, prev_bs, nbs, nb;
433     real   spacing, nbr;
434     int    s, i, j;
435     double blav, var;
436     char** leg;
437     real * tbs, *ybs, rtmp, dens, *fitsig, twooe, tau1_est, tau_sig;
438     double fitparm[3];
439     real   ee, a, tau1, tau2;
440
441     if (n < 4)
442     {
443         fprintf(stdout, "The number of points is smaller than 4, can not make an error estimate\n");
444
445         return;
446     }
447
448     fp = xvgropen(eefile, "Error estimates", "Block size (time)", "Error estimate", oenv);
449     if (output_env_get_print_xvgr_codes(oenv))
450     {
451         fprintf(fp, "@ subtitle \"using block averaging, total time %g (%d points)\"\n", (n - 1) * dt, n);
452     }
453     snew(leg, 2 * nset);
454     xvgr_legend(fp, 2 * nset, leg, oenv);
455     sfree(leg);
456
457     spacing = std::pow(2.0, 1.0 / resol);
458     snew(tbs, n);
459     snew(ybs, n);
460     snew(fitsig, n);
461     for (s = 0; s < nset; s++)
462     {
463         nbs     = 0;
464         prev_bs = 0;
465         nbr     = nb_min;
466         while (nbr <= n)
467         {
468             bs = n / static_cast<int>(nbr);
469             if (bs != prev_bs)
470             {
471                 nb  = n / bs;
472                 var = 0;
473                 for (i = 0; i < nb; i++)
474                 {
475                     blav = 0;
476                     for (j = 0; j < bs; j++)
477                     {
478                         blav += val[s][bs * i + j];
479                     }
480                     var += gmx::square(av[s] - blav / bs);
481                 }
482                 tbs[nbs] = bs * dt;
483                 if (sig[s] == 0)
484                 {
485                     ybs[nbs] = 0;
486                 }
487                 else
488                 {
489                     ybs[nbs] = var / (nb * (nb - 1.0)) * (n * dt) / (sig[s] * sig[s]);
490                 }
491                 nbs++;
492             }
493             nbr *= spacing;
494             prev_bs = bs;
495         }
496         if (sig[s] == 0)
497         {
498             ee         = 0;
499             a          = 1;
500             tau1       = 0;
501             tau2       = 0;
502             fitparm[0] = 0;
503             fitparm[1] = 0;
504             fitparm[2] = 0;
505         }
506         else
507         {
508             for (i = 0; i < nbs / 2; i++)
509             {
510                 rtmp             = tbs[i];
511                 tbs[i]           = tbs[nbs - 1 - i];
512                 tbs[nbs - 1 - i] = rtmp;
513                 rtmp             = ybs[i];
514                 ybs[i]           = ybs[nbs - 1 - i];
515                 ybs[nbs - 1 - i] = rtmp;
516             }
517             /* The initial slope of the normalized ybs^2 is 1.
518              * For a single exponential autocorrelation: ybs(tau1) = 2/e tau1
519              * From this we take our initial guess for tau1.
520              */
521             twooe = 2.0 / std::exp(1.0);
522             i     = -1;
523             do
524             {
525                 i++;
526                 tau1_est = tbs[i];
527             } while (i < nbs - 1 && (ybs[i] > ybs[i + 1] || ybs[i] > twooe * tau1_est));
528
529             if (ybs[0] > ybs[1])
530             {
531                 fprintf(stdout,
532                         "Data set %d has strange time correlations:\n"
533                         "the std. error using single points is larger than that of blocks of 2 "
534                         "points\n"
535                         "The error estimate might be inaccurate, check the fit\n",
536                         s + 1);
537                 /* Use the total time as tau for the fitting weights */
538                 tau_sig = (n - 1) * dt;
539             }
540             else
541             {
542                 tau_sig = tau1_est;
543             }
544
545             if (debug)
546             {
547                 fprintf(debug, "set %d tau1 estimate %f\n", s + 1, tau1_est);
548             }
549
550             /* Generate more or less appropriate sigma's,
551              * also taking the density of points into account.
552              */
553             for (i = 0; i < nbs; i++)
554             {
555                 if (i == 0)
556                 {
557                     dens = tbs[1] / tbs[0] - 1;
558                 }
559                 else if (i == nbs - 1)
560                 {
561                     dens = tbs[nbs - 1] / tbs[nbs - 2] - 1;
562                 }
563                 else
564                 {
565                     dens = 0.5 * (tbs[i + 1] / tbs[i - 1] - 1);
566                 }
567                 fitsig[i] = std::sqrt((tau_sig + tbs[i]) / dens);
568             }
569
570             if (!bSingleExpFit)
571             {
572                 fitparm[0] = tau1_est;
573                 fitparm[1] = 0.95;
574                 /* We set the initial guess for tau2
575                  * to halfway between tau1_est and the total time (on log scale).
576                  */
577                 fitparm[2] = std::sqrt(tau1_est * (n - 1) * dt);
578                 do_lmfit(nbs, ybs, fitsig, 0, tbs, 0, dt * n, oenv, bDebugMode(), effnERREST,
579                          fitparm, 0, nullptr);
580             }
581             if (bSingleExpFit || fitparm[0] < 0 || fitparm[2] < 0 || fitparm[1] < 0
582                 || (fitparm[1] > 1 && !bAllowNegLTCorr) || fitparm[2] > (n - 1) * dt)
583             {
584                 if (!bSingleExpFit)
585                 {
586                     if (fitparm[2] > (n - 1) * dt)
587                     {
588                         fprintf(stdout,
589                                 "Warning: tau2 is longer than the length of the data (%g)\n"
590                                 "         the statistics might be bad\n",
591                                 (n - 1) * dt);
592                     }
593                     else
594                     {
595                         fprintf(stdout, "a fitted parameter is negative\n");
596                     }
597                     fprintf(stdout, "invalid fit:  e.e. %g  a %g  tau1 %g  tau2 %g\n",
598                             optimal_error_estimate(sig[s], fitparm, n * dt), fitparm[1], fitparm[0],
599                             fitparm[2]);
600                     /* Do a fit with tau2 fixed at the total time.
601                      * One could also choose any other large value for tau2.
602                      */
603                     fitparm[0] = tau1_est;
604                     fitparm[1] = 0.95;
605                     fitparm[2] = (n - 1) * dt;
606                     fprintf(stdout, "Will fix tau2 at the total time: %g\n", fitparm[2]);
607                     do_lmfit(nbs, ybs, fitsig, 0, tbs, 0, dt * n, oenv, bDebugMode(), effnERREST,
608                              fitparm, 4, nullptr);
609                 }
610                 if (bSingleExpFit || fitparm[0] < 0 || fitparm[1] < 0 || (fitparm[1] > 1 && !bAllowNegLTCorr))
611                 {
612                     if (!bSingleExpFit)
613                     {
614                         fprintf(stdout, "a fitted parameter is negative\n");
615                         fprintf(stdout, "invalid fit:  e.e. %g  a %g  tau1 %g  tau2 %g\n",
616                                 optimal_error_estimate(sig[s], fitparm, n * dt), fitparm[1],
617                                 fitparm[0], fitparm[2]);
618                     }
619                     /* Do a single exponential fit */
620                     fprintf(stderr, "Will use a single exponential fit for set %d\n", s + 1);
621                     fitparm[0] = tau1_est;
622                     fitparm[1] = 1.0;
623                     fitparm[2] = 0.0;
624                     do_lmfit(nbs, ybs, fitsig, 0, tbs, 0, dt * n, oenv, bDebugMode(), effnERREST,
625                              fitparm, 6, nullptr);
626                 }
627             }
628             ee   = optimal_error_estimate(sig[s], fitparm, n * dt);
629             a    = fitparm[1];
630             tau1 = fitparm[0];
631             tau2 = fitparm[2];
632         }
633         fprintf(stdout, "Set %3d:  err.est. %g  a %g  tau1 %g  tau2 %g\n", s + 1, ee, a, tau1, tau2);
634         if (output_env_get_xvg_format(oenv) == exvgXMGR)
635         {
636             fprintf(fp, "@ legend string %d \"av %f\"\n", 2 * s, av[s]);
637             fprintf(fp, "@ legend string %d \"ee %6g\"\n", 2 * s + 1,
638                     optimal_error_estimate(sig[s], fitparm, n * dt));
639         }
640         else if (output_env_get_xvg_format(oenv) == exvgXMGRACE)
641         {
642             fprintf(fp, "@ s%d legend \"av %f\"\n", 2 * s, av[s]);
643             fprintf(fp, "@ s%d legend \"ee %6g\"\n", 2 * s + 1,
644                     optimal_error_estimate(sig[s], fitparm, n * dt));
645         }
646         for (i = 0; i < nbs; i++)
647         {
648             fprintf(fp, "%g %g %g\n", tbs[i], sig[s] * std::sqrt(ybs[i] / (n * dt)),
649                     sig[s] * std::sqrt(fit_function(effnERREST, fitparm, tbs[i]) / (n * dt)));
650         }
651
652         if (bFitAc)
653         {
654             int    fitlen;
655             real * ac, acint;
656             double ac_fit[4];
657
658             snew(ac, n);
659             for (i = 0; i < n; i++)
660             {
661                 ac[i] = val[s][i] - av[s];
662                 if (i > 0)
663                 {
664                     fitsig[i] = std::sqrt(static_cast<real>(i));
665                 }
666                 else
667                 {
668                     fitsig[i] = 1;
669                 }
670             }
671             low_do_autocorr(nullptr, oenv, nullptr, n, 1, -1, &ac, dt, eacNormal, 1, FALSE, TRUE,
672                             FALSE, 0, 0, effnNONE);
673
674             fitlen = n / nb_min;
675
676             /* Integrate ACF only up to fitlen/2 to avoid integrating noise */
677             acint = 0.5 * ac[0];
678             for (i = 1; i <= fitlen / 2; i++)
679             {
680                 acint += ac[i];
681             }
682             acint *= dt;
683
684             /* Generate more or less appropriate sigma's */
685             for (i = 0; i <= fitlen; i++)
686             {
687                 fitsig[i] = std::sqrt(acint + dt * i);
688             }
689
690             ac_fit[0] = 0.5 * acint;
691             ac_fit[1] = 0.95;
692             ac_fit[2] = 10 * acint;
693             do_lmfit(n / nb_min, ac, fitsig, dt, nullptr, 0, fitlen * dt, oenv, bDebugMode(),
694                      effnEXPEXP, ac_fit, 0, nullptr);
695             ac_fit[3] = 1 - ac_fit[1];
696
697             fprintf(stdout, "Set %3d:  ac erest %g  a %g  tau1 %g  tau2 %g\n", s + 1,
698                     optimal_error_estimate(sig[s], ac_fit, n * dt), ac_fit[1], ac_fit[0], ac_fit[2]);
699
700             fprintf(fp, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
701             for (i = 0; i < nbs; i++)
702             {
703                 fprintf(fp, "%g %g\n", tbs[i],
704                         sig[s] * std::sqrt(fit_function(effnERREST, ac_fit, tbs[i])) / (n * dt));
705             }
706
707             sfree(ac);
708         }
709         if (s < nset - 1)
710         {
711             fprintf(fp, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
712         }
713     }
714     sfree(fitsig);
715     sfree(ybs);
716     sfree(tbs);
717     xvgrclose(fp);
718 }
719
720 static void luzar_correl(int nn, real* time, int nset, real** val, real temp, gmx_bool bError, real fit_start)
721 {
722     real* kt;
723     real  d2;
724     int   j;
725
726     please_cite(stdout, "Spoel2006b");
727
728     /* Compute negative derivative k(t) = -dc(t)/dt */
729     if (!bError)
730     {
731         snew(kt, nn);
732         compute_derivative(nn, time, val[0], kt);
733         for (j = 0; (j < nn); j++)
734         {
735             kt[j] = -kt[j];
736         }
737         if (debug)
738         {
739             d2 = 0;
740             for (j = 0; (j < nn); j++)
741             {
742                 d2 += gmx::square(kt[j] - val[3][j]);
743             }
744             fprintf(debug, "RMS difference in derivatives is %g\n", std::sqrt(d2 / nn));
745         }
746         analyse_corr(nn, time, val[0], val[2], kt, nullptr, nullptr, nullptr, fit_start, temp);
747         sfree(kt);
748     }
749     else if (nset == 6)
750     {
751         analyse_corr(nn, time, val[0], val[2], val[4], val[1], val[3], val[5], fit_start, temp);
752     }
753     else
754     {
755         printf("Inconsistent input. I need c(t) sigma_c(t) n(t) sigma_n(t) K(t) sigma_K(t)\n");
756         printf("Not doing anything. Sorry.\n");
757     }
758 }
759
760 static void filter(real flen, int n, int nset, real** val, real dt)
761 {
762     int     f, s, i, j;
763     double *filt, sum, vf, fluc, fluctot;
764
765     f = static_cast<int>(flen / (2 * dt));
766     snew(filt, f + 1);
767     filt[0] = 1;
768     sum     = 1;
769     for (i = 1; i <= f; i++)
770     {
771         filt[i] = std::cos(M_PI * dt * i / flen);
772         sum += 2 * filt[i];
773     }
774     for (i = 0; i <= f; i++)
775     {
776         filt[i] /= sum;
777     }
778     fprintf(stdout, "Will calculate the fluctuation over %d points\n", n - 2 * f);
779     fprintf(stdout, "  using a filter of length %g of %d points\n", flen, 2 * f + 1);
780     fluctot = 0;
781     for (s = 0; s < nset; s++)
782     {
783         fluc = 0;
784         for (i = f; i < n - f; i++)
785         {
786             vf = filt[0] * val[s][i];
787             for (j = 1; j <= f; j++)
788             {
789                 vf += filt[j] * (val[s][i - f] + val[s][i + f]);
790             }
791             fluc += gmx::square(val[s][i] - vf);
792         }
793         fluc /= n - 2 * f;
794         fluctot += fluc;
795         fprintf(stdout, "Set %3d filtered fluctuation: %12.6e\n", s + 1, std::sqrt(fluc));
796     }
797     fprintf(stdout, "Overall filtered fluctuation: %12.6e\n", std::sqrt(fluctot / nset));
798     fprintf(stdout, "\n");
799
800     sfree(filt);
801 }
802
803 static void do_fit(FILE*                   out,
804                    int                     n,
805                    gmx_bool                bYdy,
806                    int                     ny,
807                    real*                   x0,
808                    real**                  val,
809                    int                     npargs,
810                    t_pargs*                ppa,
811                    const gmx_output_env_t* oenv,
812                    const char*             fn_fitted)
813 {
814     real *  c1 = nullptr, *sig = nullptr;
815     double* fitparm;
816     real    tendfit, tbeginfit;
817     int     i, efitfn, nparm;
818
819     efitfn = get_acffitfn();
820     nparm  = effnNparams(efitfn);
821     fprintf(out, "Will fit to the following function:\n");
822     fprintf(out, "%s\n", effnDescription(efitfn));
823     c1 = val[n];
824     if (bYdy)
825     {
826         c1  = val[n];
827         sig = val[n + 1];
828         fprintf(out, "Using two columns as y and sigma values\n");
829     }
830     else
831     {
832         snew(sig, ny);
833     }
834     if (opt2parg_bSet("-beginfit", npargs, ppa))
835     {
836         tbeginfit = opt2parg_real("-beginfit", npargs, ppa);
837     }
838     else
839     {
840         tbeginfit = x0[0];
841     }
842     if (opt2parg_bSet("-endfit", npargs, ppa))
843     {
844         tendfit = opt2parg_real("-endfit", npargs, ppa);
845     }
846     else
847     {
848         tendfit = x0[ny - 1];
849     }
850
851     snew(fitparm, nparm);
852     switch (efitfn)
853     {
854         case effnEXP1: fitparm[0] = 0.5; break;
855         case effnEXP2:
856             fitparm[0] = 0.5;
857             fitparm[1] = c1[0];
858             break;
859         case effnEXPEXP:
860             fitparm[0] = 1.0;
861             fitparm[1] = 0.5 * c1[0];
862             fitparm[2] = 10.0;
863             break;
864         case effnEXP5:
865             fitparm[0] = fitparm[2] = 0.5 * c1[0];
866             fitparm[1]              = 10;
867             fitparm[3]              = 40;
868             fitparm[4]              = 0;
869             break;
870         case effnEXP7:
871             fitparm[0] = fitparm[2] = fitparm[4] = 0.33 * c1[0];
872             fitparm[1]                           = 1;
873             fitparm[3]                           = 10;
874             fitparm[5]                           = 100;
875             fitparm[6]                           = 0;
876             break;
877         case effnEXP9:
878             fitparm[0] = fitparm[2] = fitparm[4] = fitparm[6] = 0.25 * c1[0];
879             fitparm[1]                                        = 0.1;
880             fitparm[3]                                        = 1;
881             fitparm[5]                                        = 10;
882             fitparm[7]                                        = 100;
883             fitparm[8]                                        = 0;
884             break;
885         default:
886             fprintf(out, "Warning: don't know how to initialize the parameters\n");
887             for (i = 0; (i < nparm); i++)
888             {
889                 fitparm[i] = 1;
890             }
891     }
892     fprintf(out, "Starting parameters:\n");
893     for (i = 0; (i < nparm); i++)
894     {
895         fprintf(out, "a%-2d = %12.5e\n", i + 1, fitparm[i]);
896     }
897     if (do_lmfit(ny, c1, sig, 0, x0, tbeginfit, tendfit, oenv, bDebugMode(), efitfn, fitparm, 0, fn_fitted) > 0)
898     {
899         for (i = 0; (i < nparm); i++)
900         {
901             fprintf(out, "a%-2d = %12.5e\n", i + 1, fitparm[i]);
902         }
903     }
904     else
905     {
906         fprintf(out, "No solution was found\n");
907     }
908 }
909
910 static void print_fitted_function(const char*       fitfile,
911                                   const char*       fn_fitted,
912                                   gmx_bool          bXYdy,
913                                   int               nset,
914                                   int               n,
915                                   real*             t,
916                                   real**            val,
917                                   int               npargs,
918                                   t_pargs*          ppa,
919                                   gmx_output_env_t* oenv)
920 {
921     FILE* out_fit = gmx_ffopen(fitfile, "w");
922     if (bXYdy && nset >= 2)
923     {
924         do_fit(out_fit, 0, TRUE, n, t, val, npargs, ppa, oenv, fn_fitted);
925     }
926     else
927     {
928         char* buf2 = nullptr;
929         int   s, buflen = 0;
930         if (nullptr != fn_fitted)
931         {
932             buflen = std::strlen(fn_fitted) + 32;
933             snew(buf2, buflen);
934             std::strncpy(buf2, fn_fitted, buflen);
935             buf2[std::strlen(buf2) - 4] = '\0';
936         }
937         for (s = 0; s < nset; s++)
938         {
939             char* buf = nullptr;
940             if (nullptr != fn_fitted)
941             {
942                 snew(buf, buflen);
943                 snprintf(buf, n, "%s_%d.xvg", buf2, s);
944             }
945             do_fit(out_fit, s, FALSE, n, t, val, npargs, ppa, oenv, buf);
946             sfree(buf);
947         }
948         sfree(buf2);
949     }
950     gmx_ffclose(out_fit);
951 }
952
953 int gmx_analyze(int argc, char* argv[])
954 {
955     static const char* desc[] = {
956         "[THISMODULE] reads an ASCII file and analyzes data sets.",
957         "A line in the input file may start with a time",
958         "(see option [TT]-time[tt]) and any number of [IT]y[it]-values may follow.",
959         "Multiple sets can also be",
960         "read when they are separated by & (option [TT]-n[tt]);",
961         "in this case only one [IT]y[it]-value is read from each line.",
962         "All lines starting with # and @ are skipped.",
963         "All analyses can also be done for the derivative of a set",
964         "(option [TT]-d[tt]).[PAR]",
965
966         "All options, except for [TT]-av[tt] and [TT]-power[tt], assume that the",
967         "points are equidistant in time.[PAR]",
968
969         "[THISMODULE] always shows the average and standard deviation of each",
970         "set, as well as the relative deviation of the third",
971         "and fourth cumulant from those of a Gaussian distribution with the same",
972         "standard deviation.[PAR]",
973
974         "Option [TT]-ac[tt] produces the autocorrelation function(s).",
975         "Be sure that the time interval between data points is",
976         "much shorter than the time scale of the autocorrelation.[PAR]",
977
978         "Option [TT]-cc[tt] plots the resemblance of set i with a cosine of",
979         "i/2 periods. The formula is::",
980         "",
981         "  [MATH]2 ([INT][FROM]0[from][TO]T[to][int] y(t) [COS]i [GRK]pi[grk] t[cos] dt)^2 ",
982         "  / [INT][FROM]0[from][TO]T[to][int] y^2(t) dt[math]",
983         "",
984         "This is useful for principal components obtained from covariance",
985         "analysis, since the principal components of random diffusion are",
986         "pure cosines.[PAR]",
987
988         "Option [TT]-msd[tt] produces the mean square displacement(s).[PAR]",
989
990         "Option [TT]-dist[tt] produces distribution plot(s).[PAR]",
991
992         "Option [TT]-av[tt] produces the average over the sets.",
993         "Error bars can be added with the option [TT]-errbar[tt].",
994         "The errorbars can represent the standard deviation, the error",
995         "(assuming the points are independent) or the interval containing",
996         "90% of the points, by discarding 5% of the points at the top and",
997         "the bottom.[PAR]",
998
999         "Option [TT]-ee[tt] produces error estimates using block averaging.",
1000         "A set is divided in a number of blocks and averages are calculated for",
1001         "each block. The error for the total average is calculated from",
1002         "the variance between averages of the m blocks B[SUB]i[sub] as follows:",
1003         "error^2 = [SUM][sum] (B[SUB]i[sub] - [CHEVRON]B[chevron])^2 / (m*(m-1)).",
1004         "These errors are plotted as a function of the block size.",
1005         "Also an analytical block average curve is plotted, assuming",
1006         "that the autocorrelation is a sum of two exponentials.",
1007         "The analytical curve for the block average is::",
1008         "",
1009         "  [MATH]f(t) = [GRK]sigma[grk][TT]*[tt][SQRT]2/T (  [GRK]alpha[grk]   ",
1010         "  ([GRK]tau[grk][SUB]1[sub] (([EXP]-t/[GRK]tau[grk][SUB]1[sub][exp] - 1) ",
1011         "  [GRK]tau[grk][SUB]1[sub]/t + 1)) +",
1012         "  (1-[GRK]alpha[grk]) ([GRK]tau[grk][SUB]2[sub] ",
1013         "  (([EXP]-t/[GRK]tau[grk][SUB]2[sub][exp] - 1) [GRK]tau[grk][SUB]2[sub]/t + ",
1014         "  1)))[sqrt][math],",
1015         "",
1016         "where T is the total time.",
1017         "[GRK]alpha[grk], [GRK]tau[grk][SUB]1[sub] and [GRK]tau[grk][SUB]2[sub] are ",
1018         "obtained by fitting f^2(t) to error^2.",
1019         "When the actual block average is very close to the analytical curve,",
1020         "the error is [MATH][GRK]sigma[grk][TT]*[tt][SQRT]2/T (a [GRK]tau[grk][SUB]1[sub] ",
1021         "+ (1-a) [GRK]tau[grk][SUB]2[sub])[sqrt][math].",
1022         "The complete derivation is given in",
1023         "B. Hess, J. Chem. Phys. 116:209-217, 2002.[PAR]",
1024
1025         "Option [TT]-filter[tt] prints the RMS high-frequency fluctuation",
1026         "of each set and over all sets with respect to a filtered average.",
1027         "The filter is proportional to cos([GRK]pi[grk] t/len) where t goes from -len/2",
1028         "to len/2. len is supplied with the option [TT]-filter[tt].",
1029         "This filter reduces oscillations with period len/2 and len by a factor",
1030         "of 0.79 and 0.33 respectively.[PAR]",
1031
1032         "Option [TT]-g[tt] fits the data to the function given with option",
1033         "[TT]-fitfn[tt].[PAR]",
1034
1035         "Option [TT]-power[tt] fits the data to [MATH]b t^a[math], which is accomplished",
1036         "by fitting to [MATH]a t + b[math] on log-log scale. All points after the first",
1037         "zero or with a negative value are ignored.[PAR]",
1038
1039         "Option [TT]-luzar[tt] performs a Luzar & Chandler kinetics analysis",
1040         "on output from [gmx-hbond]. The input file can be taken directly",
1041         "from [TT]gmx hbond -ac[tt], and then the same result should be produced.[PAR]",
1042         "Option [TT]-fitfn[tt] performs curve fitting to a number of different",
1043         "curves that make sense in the context of molecular dynamics, mainly",
1044         "exponential curves. More information is in the manual. To check the output",
1045         "of the fitting procedure the option [TT]-fitted[tt] will print both the",
1046         "original data and the fitted function to a new data file. The fitting",
1047         "parameters are stored as comment in the output file."
1048     };
1049     static real     tb = -1, te = -1, frac = 0.5, filtlen = 0, binwidth = 0.1, aver_start = 0;
1050     static gmx_bool bHaveT = TRUE, bDer = FALSE, bSubAv = TRUE, bAverCorr = FALSE, bXYdy = FALSE;
1051     static gmx_bool bEESEF = FALSE, bEENLC = FALSE, bEeFitAc = FALSE, bPower = FALSE;
1052     static gmx_bool bIntegrate = FALSE, bRegression = FALSE, bLuzar = FALSE;
1053     static int      nsets_in = 1, d = 1, nb_min = 4, resol = 10;
1054     static real     temp = 298.15, fit_start = 1, fit_end = 60;
1055
1056     /* must correspond to enum avbar* declared at beginning of file */
1057     static const char* avbar_opt[avbarNR + 1] = { nullptr, "none", "stddev", "error", "90", nullptr };
1058
1059     t_pargs pa[] = {
1060         { "-time", FALSE, etBOOL, { &bHaveT }, "Expect a time in the input" },
1061         { "-b", FALSE, etREAL, { &tb }, "First time to read from set" },
1062         { "-e", FALSE, etREAL, { &te }, "Last time to read from set" },
1063         { "-n", FALSE, etINT, { &nsets_in }, "Read this number of sets separated by &" },
1064         { "-d", FALSE, etBOOL, { &bDer }, "Use the derivative" },
1065         { "-dp",
1066           FALSE,
1067           etINT,
1068           { &d },
1069           "HIDDENThe derivative is the difference over this number of points" },
1070         { "-bw", FALSE, etREAL, { &binwidth }, "Binwidth for the distribution" },
1071         { "-errbar", FALSE, etENUM, { avbar_opt }, "Error bars for [TT]-av[tt]" },
1072         { "-integrate",
1073           FALSE,
1074           etBOOL,
1075           { &bIntegrate },
1076           "Integrate data function(s) numerically using trapezium rule" },
1077         { "-aver_start", FALSE, etREAL, { &aver_start }, "Start averaging the integral from here" },
1078         { "-xydy",
1079           FALSE,
1080           etBOOL,
1081           { &bXYdy },
1082           "Interpret second data set as error in the y values for integrating" },
1083         { "-regression",
1084           FALSE,
1085           etBOOL,
1086           { &bRegression },
1087           "Perform a linear regression analysis on the data. If [TT]-xydy[tt] is set a second set "
1088           "will be interpreted as the error bar in the Y value. Otherwise, if multiple data sets "
1089           "are present a multilinear regression will be performed yielding the constant A that "
1090           "minimize [MATH][GRK]chi[grk]^2 = (y - A[SUB]0[sub] x[SUB]0[sub] - A[SUB]1[sub] "
1091           "x[SUB]1[sub] - ... - A[SUB]N[sub] x[SUB]N[sub])^2[math] where now Y is the first data "
1092           "set in the input file and x[SUB]i[sub] the others. Do read the information at the "
1093           "option [TT]-time[tt]." },
1094         { "-luzar",
1095           FALSE,
1096           etBOOL,
1097           { &bLuzar },
1098           "Do a Luzar and Chandler analysis on a correlation function and "
1099           "related as produced by [gmx-hbond]. When in addition the "
1100           "[TT]-xydy[tt] flag is given the second and fourth column will be "
1101           "interpreted as errors in c(t) and n(t)." },
1102         { "-temp",
1103           FALSE,
1104           etREAL,
1105           { &temp },
1106           "Temperature for the Luzar hydrogen bonding kinetics analysis (K)" },
1107         { "-fitstart",
1108           FALSE,
1109           etREAL,
1110           { &fit_start },
1111           "Time (ps) from which to start fitting the correlation functions in order to obtain the "
1112           "forward and backward rate constants for HB breaking and formation" },
1113         { "-fitend",
1114           FALSE,
1115           etREAL,
1116           { &fit_end },
1117           "Time (ps) where to stop fitting the correlation functions in order to obtain the "
1118           "forward and backward rate constants for HB breaking and formation. Only with "
1119           "[TT]-gem[tt]" },
1120         { "-nbmin",
1121           FALSE,
1122           etINT,
1123           { &nb_min },
1124           "HIDDENMinimum number of blocks for block averaging" },
1125         { "-resol",
1126           FALSE,
1127           etINT,
1128           { &resol },
1129           "HIDDENResolution for the block averaging, block size increases with"
1130           " a factor 2^(1/resol)" },
1131         { "-eeexpfit",
1132           FALSE,
1133           etBOOL,
1134           { &bEESEF },
1135           "HIDDENAlways use a single exponential fit for the error estimate" },
1136         { "-eenlc", FALSE, etBOOL, { &bEENLC }, "HIDDENAllow a negative long-time correlation" },
1137         { "-eefitac",
1138           FALSE,
1139           etBOOL,
1140           { &bEeFitAc },
1141           "HIDDENAlso plot analytical block average using a autocorrelation fit" },
1142         { "-filter",
1143           FALSE,
1144           etREAL,
1145           { &filtlen },
1146           "Print the high-frequency fluctuation after filtering with a cosine filter of this "
1147           "length" },
1148         { "-power", FALSE, etBOOL, { &bPower }, "Fit data to: b t^a" },
1149         { "-subav", FALSE, etBOOL, { &bSubAv }, "Subtract the average before autocorrelating" },
1150         { "-oneacf", FALSE, etBOOL, { &bAverCorr }, "Calculate one ACF over all sets" },
1151     };
1152 #define NPA asize(pa)
1153
1154     FILE*             out;
1155     int               n, nlast, s, nset, i, j = 0;
1156     real **           val, *t, dt, tot, error;
1157     double *          av, *sig, cum1, cum2, cum3, cum4, db;
1158     const char *      acfile, *msdfile, *ccfile, *distfile, *avfile, *eefile, *fitfile;
1159     gmx_output_env_t* oenv;
1160
1161     t_filenm fnm[] = {
1162         { efXVG, "-f", "graph", ffREAD },     { efXVG, "-ac", "autocorr", ffOPTWR },
1163         { efXVG, "-msd", "msd", ffOPTWR },    { efXVG, "-cc", "coscont", ffOPTWR },
1164         { efXVG, "-dist", "distr", ffOPTWR }, { efXVG, "-av", "average", ffOPTWR },
1165         { efXVG, "-ee", "errest", ffOPTWR },  { efXVG, "-fitted", "fitted", ffOPTWR },
1166         { efLOG, "-g", "fitlog", ffOPTWR }
1167     };
1168 #define NFILE asize(fnm)
1169
1170     int      npargs;
1171     t_pargs* ppa;
1172
1173     npargs = asize(pa);
1174     ppa    = add_acf_pargs(&npargs, pa);
1175
1176     if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, npargs, ppa, asize(desc), desc, 0,
1177                            nullptr, &oenv))
1178     {
1179         sfree(ppa);
1180         return 0;
1181     }
1182
1183     acfile   = opt2fn_null("-ac", NFILE, fnm);
1184     msdfile  = opt2fn_null("-msd", NFILE, fnm);
1185     ccfile   = opt2fn_null("-cc", NFILE, fnm);
1186     distfile = opt2fn_null("-dist", NFILE, fnm);
1187     avfile   = opt2fn_null("-av", NFILE, fnm);
1188     eefile   = opt2fn_null("-ee", NFILE, fnm);
1189     if (opt2parg_bSet("-fitfn", npargs, ppa) && acfile == nullptr)
1190     {
1191         fitfile = opt2fn("-g", NFILE, fnm);
1192     }
1193     else
1194     {
1195         fitfile = opt2fn_null("-g", NFILE, fnm);
1196     }
1197
1198     val = read_xvg_time(opt2fn("-f", NFILE, fnm), bHaveT, opt2parg_bSet("-b", npargs, ppa), tb,
1199                         opt2parg_bSet("-e", npargs, ppa), te, nsets_in, &nset, &n, &dt, &t);
1200     printf("Read %d sets of %d points, dt = %g\n\n", nset, n, dt);
1201
1202     if (bDer)
1203     {
1204         printf("Calculating the derivative as (f[i+%d]-f[i])/(%d*dt)\n\n", d, d);
1205         n -= d;
1206         for (s = 0; s < nset; s++)
1207         {
1208             for (i = 0; (i < n); i++)
1209             {
1210                 val[s][i] = (val[s][i + d] - val[s][i]) / (d * dt);
1211             }
1212         }
1213     }
1214
1215     if (bIntegrate)
1216     {
1217         real sum, stddev;
1218
1219         printf("Calculating the integral using the trapezium rule\n");
1220
1221         if (bXYdy)
1222         {
1223             sum = evaluate_integral(n, t, val[0], val[1], aver_start, &stddev);
1224             printf("Integral %10.3f +/- %10.5f\n", sum, stddev);
1225         }
1226         else
1227         {
1228             for (s = 0; s < nset; s++)
1229             {
1230                 sum = evaluate_integral(n, t, val[s], nullptr, aver_start, &stddev);
1231                 printf("Integral %d  %10.5f  +/- %10.5f\n", s + 1, sum, stddev);
1232             }
1233         }
1234     }
1235
1236     if (fitfile != nullptr)
1237     {
1238         print_fitted_function(fitfile, opt2fn_null("-fitted", NFILE, fnm), bXYdy, nset, n, t, val,
1239                               npargs, ppa, oenv);
1240     }
1241
1242     printf("                                      std. dev.    relative deviation of\n");
1243     printf("                       standard       ---------   cumulants from those of\n");
1244     printf("set      average       deviation      sqrt(n-1)   a Gaussian distribition\n");
1245     printf("                                                      cum. 3   cum. 4\n");
1246     snew(av, nset);
1247     snew(sig, nset);
1248     for (s = 0; (s < nset); s++)
1249     {
1250         cum1 = 0;
1251         cum2 = 0;
1252         cum3 = 0;
1253         cum4 = 0;
1254         for (i = 0; (i < n); i++)
1255         {
1256             cum1 += val[s][i];
1257         }
1258         cum1 /= n;
1259         for (i = 0; (i < n); i++)
1260         {
1261             db = val[s][i] - cum1;
1262             cum2 += db * db;
1263             cum3 += db * db * db;
1264             cum4 += db * db * db * db;
1265         }
1266         cum2 /= n;
1267         cum3 /= n;
1268         cum4 /= n;
1269         av[s]  = cum1;
1270         sig[s] = std::sqrt(cum2);
1271         if (n > 1)
1272         {
1273             error = std::sqrt(cum2 / (n - 1));
1274         }
1275         else
1276         {
1277             error = 0;
1278         }
1279         printf("SS%d  %13.6e   %12.6e   %12.6e      %6.3f   %6.3f\n", s + 1, av[s], sig[s], error,
1280                sig[s] != 0.0 ? cum3 / (sig[s] * sig[s] * sig[s] * std::sqrt(8 / M_PI)) : 0,
1281                sig[s] != 0.0 ? cum4 / (sig[s] * sig[s] * sig[s] * sig[s] * 3) - 1 : 0);
1282     }
1283     printf("\n");
1284
1285     if (filtlen != 0.0F)
1286     {
1287         filter(filtlen, n, nset, val, dt);
1288     }
1289
1290     if (msdfile)
1291     {
1292         out   = xvgropen(msdfile, "Mean square displacement", "time", "MSD (nm\\S2\\N)", oenv);
1293         nlast = static_cast<int>(n * frac);
1294         for (s = 0; s < nset; s++)
1295         {
1296             for (j = 0; j <= nlast; j++)
1297             {
1298                 if (j % 100 == 0)
1299                 {
1300                     fprintf(stderr, "\r%d", j);
1301                     fflush(stderr);
1302                 }
1303                 tot = 0;
1304                 for (i = 0; i < n - j; i++)
1305                 {
1306                     tot += gmx::square(val[s][i] - val[s][i + j]);
1307                 }
1308                 tot /= (n - j);
1309                 fprintf(out, " %g %8g\n", dt * j, tot);
1310             }
1311             if (s < nset - 1)
1312             {
1313                 fprintf(out, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
1314             }
1315         }
1316         xvgrclose(out);
1317         fprintf(stderr, "\r%d, time=%g\n", j - 1, (j - 1) * dt);
1318         fflush(stderr);
1319     }
1320     if (ccfile)
1321     {
1322         plot_coscont(ccfile, n, nset, val, oenv);
1323     }
1324
1325     if (distfile)
1326     {
1327         histogram(distfile, binwidth, n, nset, val, oenv);
1328     }
1329     if (avfile)
1330     {
1331         average(avfile, nenum(avbar_opt), n, nset, val, t);
1332     }
1333     if (eefile)
1334     {
1335         estimate_error(eefile, nb_min, resol, n, nset, av, sig, val, dt, bEeFitAc, bEESEF, bEENLC, oenv);
1336     }
1337     if (bPower)
1338     {
1339         power_fit(n, nset, val, t);
1340     }
1341
1342     if (acfile != nullptr)
1343     {
1344         if (bSubAv)
1345         {
1346             for (s = 0; s < nset; s++)
1347             {
1348                 for (i = 0; i < n; i++)
1349                 {
1350                     val[s][i] -= av[s];
1351                 }
1352             }
1353         }
1354         do_autocorr(acfile, oenv, "Autocorrelation", n, nset, val, dt, eacNormal, bAverCorr);
1355     }
1356
1357     if (bRegression)
1358     {
1359         regression_analysis(n, bXYdy, t, nset, val);
1360     }
1361
1362     if (bLuzar)
1363     {
1364         luzar_correl(n, t, nset, val, temp, bXYdy, fit_start);
1365     }
1366
1367     view_all(oenv, NFILE, fnm);
1368
1369     return 0;
1370 }