2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
46 #include "gromacs/commandline/pargs.h"
47 #include "gromacs/commandline/viewit.h"
48 #include "gromacs/correlationfunctions/autocorr.h"
49 #include "gromacs/fileio/enxio.h"
50 #include "gromacs/fileio/gmxfio.h"
51 #include "gromacs/fileio/tpxio.h"
52 #include "gromacs/fileio/trxio.h"
53 #include "gromacs/fileio/xvgr.h"
54 #include "gromacs/gmxana/gmx_ana.h"
55 #include "gromacs/gmxana/gstat.h"
56 #include "gromacs/math/functions.h"
57 #include "gromacs/math/units.h"
58 #include "gromacs/math/vec.h"
59 #include "gromacs/mdlib/energyoutput.h"
60 #include "gromacs/mdtypes/inputrec.h"
61 #include "gromacs/mdtypes/md_enums.h"
62 #include "gromacs/topology/ifunc.h"
63 #include "gromacs/topology/mtop_lookup.h"
64 #include "gromacs/topology/mtop_util.h"
65 #include "gromacs/topology/topology.h"
66 #include "gromacs/trajectory/energyframe.h"
67 #include "gromacs/utility/arraysize.h"
68 #include "gromacs/utility/cstringutil.h"
69 #include "gromacs/utility/fatalerror.h"
70 #include "gromacs/utility/gmxassert.h"
71 #include "gromacs/utility/pleasecite.h"
72 #include "gromacs/utility/smalloc.h"
73 #include "gromacs/utility/strconvert.h"
75 static const int NOTSET = -23451;
106 static void done_enerdata_t(int nset, enerdata_t* edat)
111 for (int i = 0; i < nset; i++)
113 sfree(edat->s[i].ener);
114 sfree(edat->s[i].es);
119 static void chomp(char* buf)
121 int len = std::strlen(buf);
123 while ((len > 0) && (buf[len - 1] == '\n'))
130 static int* select_by_name(int nre, gmx_enxnm_t* nm, int* nset)
133 int k, kk, j, i, nmatch, nind, nss;
135 gmx_bool bEOF, bVerbose = TRUE, bLong = FALSE;
136 char * ptr, buf[STRLEN];
137 const char* fm4 = "%3d %-14s";
138 const char* fm2 = "%3d %-34s";
139 char** newnm = nullptr;
141 if ((getenv("GMX_ENER_VERBOSE")) != nullptr)
146 fprintf(stderr, "\n");
147 fprintf(stderr, "Select the terms you want from the following list by\n");
148 fprintf(stderr, "selecting either (part of) the name or the number or a combination.\n");
149 fprintf(stderr, "End your selection with an empty line or a zero.\n");
150 fprintf(stderr, "-------------------------------------------------------------------\n");
154 for (k = 0; k < nre; k++)
156 newnm[k] = gmx_strdup(nm[k].name);
157 /* Insert dashes in all the names */
158 while ((ptr = std::strchr(newnm[k], ' ')) != nullptr)
168 fprintf(stderr, "\n");
171 for (kk = k; kk < k + 4; kk++)
173 if (kk < nre && std::strlen(nm[kk].name) > 14)
181 fprintf(stderr, " ");
185 fprintf(stderr, fm4, k + 1, newnm[k]);
194 fprintf(stderr, fm2, k + 1, newnm[k]);
205 fprintf(stderr, "\n\n");
211 while (!bEOF && (fgets2(buf, STRLEN - 1, stdin)))
213 /* Remove newlines */
219 /* Empty line means end of input */
220 bEOF = (std::strlen(buf) == 0);
228 /* First try to read an integer */
229 nss = sscanf(ptr, "%d", &nind);
232 /* Zero means end of input */
237 else if ((1 <= nind) && (nind <= nre))
243 fprintf(stderr, "number %d is out of range\n", nind);
248 /* Now try to read a string */
250 for (nind = 0; nind < nre; nind++)
252 if (gmx_strcasecmp(newnm[nind], ptr) == 0)
260 i = std::strlen(ptr);
262 for (nind = 0; nind < nre; nind++)
264 if (gmx_strncasecmp(newnm[nind], ptr, i) == 0)
272 fprintf(stderr, "String '%s' does not match anything\n", ptr);
277 /* Look for the first space, and remove spaces from there */
278 if ((ptr = std::strchr(ptr, ' ')) != nullptr)
282 } while (!bEOF && ((ptr != nullptr) && (std::strlen(ptr) > 0)));
287 for (i = (*nset) = 0; (i < nre); i++)
299 gmx_fatal(FARGS, "No energy terms selected");
302 for (i = 0; (i < nre); i++)
311 static void get_dhdl_parms(const char* topnm, t_inputrec* ir)
317 /* all we need is the ir to be able to write the label */
318 read_tpx(topnm, ir, box, &natoms, nullptr, nullptr, &mtop);
321 static void einstein_visco(const char* fn,
329 const gmx_output_env_t* oenv)
332 double av[4], avold[4];
338 for (i = 0; i <= nsets; i++)
342 fp0 = xvgropen(fni, "Shear viscosity integral", "Time (ps)", "(kg m\\S-1\\N s\\S-1\\N ps)", oenv);
344 fn, "Shear viscosity using Einstein relation", "Time (ps)", "(kg m\\S-1\\N s\\S-1\\N)", oenv);
345 for (i = 0; i < nf4; i++)
347 for (m = 0; m <= nsets; m++)
351 for (j = 0; j < nint - i; j++)
353 for (m = 0; m < nsets; m++)
355 di = gmx::square(eneint[m][j + i] - eneint[m][j]);
358 av[nsets] += di / nsets;
361 /* Convert to SI for the viscosity */
362 fac = (V * gmx::c_nano * gmx::c_nano * gmx::c_nano * gmx::c_pico * 1e10)
363 / (2 * gmx::c_boltzmann * T) / (nint - i);
364 fprintf(fp0, "%10g", i * dt);
365 for (m = 0; (m <= nsets); m++)
368 fprintf(fp0, " %10g", av[m]);
371 fprintf(fp1, "%10g", (i + 0.5) * dt);
372 for (m = 0; (m <= nsets); m++)
374 fprintf(fp1, " %10g", (av[m] - avold[m]) / dt);
399 static void clear_ee_sum(ee_sum_t* ees)
407 static void add_ee_sum(ee_sum_t* ees, double sum, int np)
413 static void add_ee_av(ee_sum_t* ees)
417 av = ees->sum / ees->np;
419 ees->sav2 += av * av;
424 static double calc_ee2(int nb, ee_sum_t* ees)
426 return (ees->sav2 / nb - gmx::square(ees->sav / nb)) / (nb - 1);
429 static void set_ee_av(ener_ee_t* eee)
433 char buf[STEPSTRSIZE];
434 fprintf(debug, "Storing average for err.est.: %s steps\n", gmx_step_str(eee->nst, buf));
436 add_ee_av(&eee->sum);
438 if (eee->b == 1 || eee->nst < eee->nst_min)
440 eee->nst_min = eee->nst;
445 static void calc_averages(int nset, enerdata_t* edat, int nbmin, int nbmax)
448 double sum, sum2, sump, see2;
449 int64_t np, p, bound_nb;
453 double x, sx, sy, sxx, sxy;
456 /* Check if we have exact statistics over all points */
457 for (i = 0; i < nset; i++)
460 ed->bExactStat = FALSE;
463 /* All energy file sum entries 0 signals no exact sums.
464 * But if all energy values are 0, we still have exact sums.
467 for (f = 0; f < edat->nframes && !ed->bExactStat; f++)
469 if (ed->ener[i] != 0)
473 ed->bExactStat = (ed->es[f].sum != 0);
477 ed->bExactStat = TRUE;
482 snew(eee, nbmax + 1);
483 for (i = 0; i < nset; i++)
494 for (nb = nbmin; nb <= nbmax; nb++)
497 clear_ee_sum(&eee[nb].sum);
501 for (f = 0; f < edat->nframes; f++)
507 /* Add the sum and the sum of variances to the totals. */
513 sum2 += gmx::square(sum / np - (sum + es->sum) / (np + p)) * np * (np + p) / p;
518 /* Add a single value to the sum and sum of squares. */
521 sum2 += gmx::square(sump);
524 /* sum has to be increased after sum2 */
528 /* For the linear regression use variance 1/p.
529 * Note that sump is the sum, not the average, so we don't need p*.
531 x = edat->step[f] - 0.5 * (edat->steps[f] - 1);
537 for (nb = nbmin; nb <= nbmax; nb++)
539 /* Check if the current end step is closer to the desired
540 * block boundary than the next end step.
542 bound_nb = (edat->step[0] - 1) * nb + edat->nsteps * (eee[nb].b + 1);
543 if (eee[nb].nst > 0 && bound_nb - edat->step[f - 1] * nb < edat->step[f] * nb - bound_nb)
553 eee[nb].nst += edat->step[f] - edat->step[f - 1];
557 add_ee_sum(&eee[nb].sum, es->sum, edat->points[f]);
561 add_ee_sum(&eee[nb].sum, edat->s[i].ener[f], 1);
563 bound_nb = (edat->step[0] - 1) * nb + edat->nsteps * (eee[nb].b + 1);
564 if (edat->step[f] * nb >= bound_nb)
571 edat->s[i].av = sum / np;
574 edat->s[i].rmsd = std::sqrt(sum2 / np);
578 edat->s[i].rmsd = std::sqrt(sum2 / np - gmx::square(edat->s[i].av));
581 if (edat->nframes > 1)
583 edat->s[i].slope = (np * sxy - sx * sy) / (np * sxx - sx * sx);
587 edat->s[i].slope = 0;
592 for (nb = nbmin; nb <= nbmax; nb++)
594 /* Check if we actually got nb blocks and if the smallest
595 * block is not shorter than 80% of the average.
599 char buf1[STEPSTRSIZE], buf2[STEPSTRSIZE];
601 "Requested %d blocks, we have %d blocks, min %s nsteps %s\n",
604 gmx_step_str(eee[nb].nst_min, buf1),
605 gmx_step_str(edat->nsteps, buf2));
607 if (eee[nb].b == nb && 5 * nb * eee[nb].nst_min >= 4 * edat->nsteps)
609 see2 += calc_ee2(nb, &eee[nb].sum);
615 edat->s[i].ee = std::sqrt(see2 / nee);
625 static enerdata_t* calc_sum(int nset, enerdata_t* edat, int nbmin, int nbmax)
636 snew(s->ener, esum->nframes);
637 snew(s->es, esum->nframes);
639 s->bExactStat = TRUE;
641 for (i = 0; i < nset; i++)
643 if (!edat->s[i].bExactStat)
645 s->bExactStat = FALSE;
647 s->slope += edat->s[i].slope;
650 for (f = 0; f < edat->nframes; f++)
653 for (i = 0; i < nset; i++)
655 sum += edat->s[i].ener[f];
659 for (i = 0; i < nset; i++)
661 sum += edat->s[i].es[f].sum;
667 calc_averages(1, esum, nbmin, nbmax);
672 static void ee_pr(double ee, int buflen, char* buf)
674 snprintf(buf, buflen, "%s", "--");
677 /* Round to two decimals by printing. */
679 snprintf(tmp, sizeof(tmp), "%.1e", ee);
680 double rnd = gmx::doubleFromString(tmp);
681 snprintf(buf, buflen, "%g", rnd);
685 static void remove_drift(int nset, int nbmin, int nbmax, real dt, enerdata_t* edat)
687 /* Remove the drift by performing a fit to y = ax+b.
688 Uses 5 iterations. */
692 edat->npoints = edat->nframes;
693 edat->nsteps = edat->nframes;
695 for (k = 0; (k < 5); k++)
697 for (i = 0; (i < nset); i++)
699 delta = edat->s[i].slope * dt;
701 if (nullptr != debug)
703 fprintf(debug, "slope for set %d is %g\n", i, edat->s[i].slope);
706 for (j = 0; (j < edat->nframes); j++)
708 edat->s[i].ener[j] -= j * delta;
709 edat->s[i].es[j].sum = 0;
710 edat->s[i].es[j].sum2 = 0;
713 calc_averages(nset, edat, nbmin, nbmax);
717 static void calc_fluctuation_props(FILE* fp,
728 double vv, v, h, varv, hh, varh, tt, cv, cp, alpha, kappa, dcp, varet;
738 const char* my_ener[] = { "Volume", "Enthalpy", "Temperature", "Total Energy" };
741 NANO3 = gmx::c_nano * gmx::c_nano * gmx::c_nano;
745 "\nYou may want to use the -driftcorr flag in order to correct\n"
746 "for spurious drift in the graphs. Note that this is not\n"
747 "a substitute for proper equilibration and sampling!\n");
751 remove_drift(nset, nbmin, nbmax, dt, edat);
753 for (i = 0; (i < eNR); i++)
755 for (ii[i] = 0; (ii[i] < nset && (gmx_strcasecmp(leg[ii[i]], my_ener[i]) != 0)); ii[i]++) {}
757 fprintf(fp,"Found %s data.\n",my_ener[i]);
759 /* Compute it all! */
760 alpha = kappa = cp = dcp = cv = NOTSET;
764 if (ii[eTemp] < nset)
766 tt = edat->s[ii[eTemp]].av;
770 if ((ii[eVol] < nset) && (ii[eTemp] < nset))
772 vv = edat->s[ii[eVol]].av * NANO3;
773 varv = gmx::square(edat->s[ii[eVol]].rmsd * NANO3);
774 kappa = (varv / vv) / (gmx::c_boltzmann * tt);
778 if ((ii[eEnth] < nset) && (ii[eTemp] < nset))
780 hh = gmx::c_kilo * edat->s[ii[eEnth]].av / gmx::c_avogadro;
781 varh = gmx::square(gmx::c_kilo * edat->s[ii[eEnth]].rmsd / gmx::c_avogadro);
782 cp = gmx::c_avogadro * ((varh / nmol) / (gmx::c_boltzmann * tt * tt));
785 if ((ii[eEtot] < nset) && (hh == NOTSET) && (tt != NOTSET))
787 /* Only compute cv in constant volume runs, which we can test
788 by checking whether the enthalpy was computed.
790 varet = gmx::square(edat->s[ii[eEtot]].rmsd);
791 cv = gmx::c_kilo * ((varet / nmol) / (gmx::c_boltz * tt * tt));
794 if ((ii[eVol] < nset) && (ii[eEnth] < nset) && (ii[eTemp] < nset))
796 double v_sum, h_sum, vh_sum, v_aver, h_aver, vh_aver;
797 vh_sum = v_sum = h_sum = 0;
798 for (j = 0; (j < edat->nframes); j++)
800 v = edat->s[ii[eVol]].ener[j] * NANO3;
801 h = gmx::c_kilo * edat->s[ii[eEnth]].ener[j] / gmx::c_avogadro;
806 vh_aver = vh_sum / edat->nframes;
807 v_aver = v_sum / edat->nframes;
808 h_aver = h_sum / edat->nframes;
809 alpha = (vh_aver - v_aver * h_aver) / (v_aver * gmx::c_boltzmann * tt * tt);
810 dcp = (v_aver * gmx::c_avogadro / nmol) * tt * gmx::square(alpha) / (kappa);
817 fprintf(fp, "\nWARNING: nmol = %d, this may not be what you want.\n", nmol);
819 fprintf(fp, "\nTemperature dependent fluctuation properties at T = %g.\n", tt);
820 fprintf(fp, "\nHeat capacities obtained from fluctuations do *not* include\n");
821 fprintf(fp, "quantum corrections. If you want to get a more accurate estimate\n");
822 fprintf(fp, "please use the g_dos program.\n\n");
824 "WARNING: Please verify that your simulations are converged and perform\n"
825 "a block-averaging error analysis (not implemented in g_energy yet)\n");
827 if (debug != nullptr)
831 fprintf(fp, "varv = %10g (m^6)\n", varv * gmx::c_avogadro / nmol);
836 fprintf(fp, "Volume = %10g m^3/mol\n", vv * gmx::c_avogadro / nmol);
841 "Enthalpy = %10g kJ/mol\n",
842 hh * gmx::c_avogadro / (gmx::c_kilo * nmol));
846 fprintf(fp, "Coefficient of Thermal Expansion Alpha_P = %10g (1/K)\n", alpha);
850 fprintf(fp, "Isothermal Compressibility Kappa = %10g (m^3/J)\n", kappa);
851 fprintf(fp, "Adiabatic bulk modulus = %10g (J/m^3)\n", 1.0 / kappa);
855 fprintf(fp, "Heat capacity at constant pressure Cp = %10g J/(mol K)\n", cp);
859 fprintf(fp, "Heat capacity at constant volume Cv = %10g J/(mol K)\n", cv);
863 fprintf(fp, "Cp-Cv = %10g J/(mol K)\n", dcp);
865 please_cite(fp, "Allen1987a");
869 fprintf(fp, "You should select the temperature in order to obtain fluctuation properties.\n");
873 static void analyse_ener(gmx_bool bCorr,
875 const char* eviscofn,
876 const char* eviscoifn,
891 const gmx_bool* bIsEner,
898 const gmx_output_env_t* oenv)
901 /* Check out the printed manual for equations! */
902 double Dt, aver, stddev, errest, delta_t, totaldrift;
903 enerdata_t* esum = nullptr;
904 real integral, intBulk, Temp = 0, Pres = 0;
905 real pr_aver, pr_stddev, pr_errest;
906 double beta = 0, expE, expEtot, *fee = nullptr;
908 int nexact, nnotexact;
910 char buf[256], eebuf[100];
912 nsteps = step - start_step + 1;
915 fprintf(stdout, "Not enough steps (%s) for statistics\n", gmx_step_str(nsteps, buf));
919 /* Calculate the time difference */
920 delta_t = t - start_t;
923 "\nStatistics over %s steps [ %.4f through %.4f ps ], %d data sets\n",
924 gmx_step_str(nsteps, buf),
929 calc_averages(nset, edat, nbmin, nbmax);
933 esum = calc_sum(nset, edat, nbmin, nbmax);
936 if (!edat->bHaveSums)
945 for (i = 0; (i < nset); i++)
947 if (edat->s[i].bExactStat)
960 fprintf(stdout, "All statistics are over %s points\n", gmx_step_str(edat->npoints, buf));
962 else if (nexact == 0 || edat->npoints == edat->nframes)
964 fprintf(stdout, "All statistics are over %d points (frames)\n", edat->nframes);
968 fprintf(stdout, "The term%s", nnotexact == 1 ? "" : "s");
969 for (i = 0; (i < nset); i++)
971 if (!edat->s[i].bExactStat)
973 fprintf(stdout, " '%s'", leg[i]);
977 " %s has statistics over %d points (frames)\n",
978 nnotexact == 1 ? "is" : "are",
980 fprintf(stdout, "All other statistics are over %s points\n", gmx_step_str(edat->npoints, buf));
982 fprintf(stdout, "\n");
985 "%-24s %10s %10s %10s %10s",
993 fprintf(stdout, " %10s\n", "-kT ln<e^(E/kT)>");
997 fprintf(stdout, "\n");
1000 "-------------------------------------------------------------------------------"
1003 /* Initiate locals, only used with -sum */
1007 beta = 1.0 / (gmx::c_boltz * reftemp);
1010 for (i = 0; (i < nset); i++)
1012 aver = edat->s[i].av;
1013 stddev = edat->s[i].rmsd;
1014 errest = edat->s[i].ee;
1019 for (j = 0; (j < edat->nframes); j++)
1021 expE += std::exp(beta * (edat->s[i].ener[j] - aver) / nmol);
1025 expEtot += expE / edat->nframes;
1028 fee[i] = std::log(expE / edat->nframes) / beta + aver / nmol;
1030 if (std::strstr(leg[i], "empera") != nullptr)
1034 else if (std::strstr(leg[i], "olum") != nullptr)
1038 else if (std::strstr(leg[i], "essure") != nullptr)
1044 pr_aver = aver / nmol - ezero;
1045 pr_stddev = stddev / nmol;
1046 pr_errest = errest / nmol;
1055 /* Multiply the slope in steps with the number of steps taken */
1056 totaldrift = (edat->nsteps - 1) * edat->s[i].slope;
1062 ee_pr(pr_errest, sizeof(eebuf), eebuf);
1063 fprintf(stdout, "%-24s %10g %10s %10g %10g", leg[i], pr_aver, eebuf, pr_stddev, totaldrift);
1066 fprintf(stdout, " %10g", fee[i]);
1069 fprintf(stdout, " (%s)\n", enm[set[i]].unit);
1073 for (j = 0; (j < edat->nframes); j++)
1075 edat->s[i].ener[j] -= aver;
1081 totaldrift = (edat->nsteps - 1) * esum->s[0].slope;
1082 ee_pr(esum->s[0].ee / nmol, sizeof(eebuf), eebuf);
1084 "%-24s %10g %10s %10s %10g (%s)",
1086 esum->s[0].av / nmol,
1091 /* pr_aver,pr_stddev,a,totaldrift */
1096 std::log(expEtot) / beta + esum->s[0].av / nmol,
1097 std::log(expEtot) / beta);
1101 fprintf(stdout, "\n");
1105 /* Do correlation function */
1106 if (edat->nframes > 1)
1108 Dt = delta_t / (edat->nframes - 1);
1116 const char* leg[] = { "Shear", "Bulk" };
1121 /* Assume pressure tensor is in Pxx Pxy Pxz Pyx Pyy Pyz Pzx Pzy Pzz */
1123 /* Symmetrise tensor! (and store in first three elements)
1124 * And subtract average pressure!
1127 for (i = 0; i < 12; i++)
1129 snew(eneset[i], edat->nframes);
1131 for (i = 0; (i < edat->nframes); i++)
1133 eneset[0][i] = 0.5 * (edat->s[1].ener[i] + edat->s[3].ener[i]);
1134 eneset[1][i] = 0.5 * (edat->s[2].ener[i] + edat->s[6].ener[i]);
1135 eneset[2][i] = 0.5 * (edat->s[5].ener[i] + edat->s[7].ener[i]);
1136 for (j = 3; j <= 11; j++)
1138 eneset[j][i] = edat->s[j].ener[i];
1140 eneset[11][i] -= Pres;
1143 /* Determine integrals of the off-diagonal pressure elements */
1145 for (i = 0; i < 3; i++)
1147 snew(eneint[i], edat->nframes + 1);
1152 for (i = 0; i < edat->nframes; i++)
1156 + 0.5 * (edat->s[1].es[i].sum + edat->s[3].es[i].sum) * Dt / edat->points[i];
1159 + 0.5 * (edat->s[2].es[i].sum + edat->s[6].es[i].sum) * Dt / edat->points[i];
1162 + 0.5 * (edat->s[5].es[i].sum + edat->s[7].es[i].sum) * Dt / edat->points[i];
1165 einstein_visco(eviscofn, eviscoifn, 3, edat->nframes + 1, eneint, Vaver, Temp, Dt, oenv);
1167 for (i = 0; i < 3; i++)
1173 /*do_autocorr(corrfn,buf,nenergy,3,eneset,Dt,eacNormal,TRUE);*/
1174 /* Do it for shear viscosity */
1175 std::strcpy(buf, "Shear Viscosity");
1176 low_do_autocorr(corrfn,
1181 (edat->nframes + 1) / 2,
1193 /* Now for bulk viscosity */
1194 std::strcpy(buf, "Bulk Viscosity");
1195 low_do_autocorr(corrfn,
1200 (edat->nframes + 1) / 2,
1212 factor = (Vaver * 1e-26 / (gmx::c_boltzmann * Temp)) * Dt;
1213 fp = xvgropen(visfn, buf, "Time (ps)", "\\8h\\4 (cp)", oenv);
1214 xvgr_legend(fp, asize(leg), leg, oenv);
1216 /* Use trapezium rule for integration */
1219 nout = get_acfnout();
1220 if ((nout < 2) || (nout >= edat->nframes / 2))
1222 nout = edat->nframes / 2;
1224 for (i = 1; (i < nout); i++)
1226 integral += 0.5 * (eneset[0][i - 1] + eneset[0][i]) * factor;
1227 intBulk += 0.5 * (eneset[11][i - 1] + eneset[11][i]) * factor;
1228 fprintf(fp, "%10g %10g %10g\n", (i * Dt), integral, intBulk);
1232 for (i = 0; i < 12; i++)
1242 std::strcpy(buf, "Autocorrelation of Energy Fluctuations");
1246 std::strcpy(buf, "Energy Autocorrelation");
1249 do_autocorr(corrfn, oenv, buf, edat->nframes,
1251 bSum ? &edat->s[nset-1].energyGroupPairTerms : eneset,
1252 (delta_t/edat->nframes), eacNormal, FALSE);
1258 static void print_time(FILE* fp, double t)
1260 fprintf(fp, "%12.6f", t);
1263 static void print1(FILE* fp, gmx_bool bDp, real e)
1267 fprintf(fp, " %16.12f", e);
1271 fprintf(fp, " %10.6f", e);
1275 static void fec(const char* ene2fn,
1276 const char* runavgfn,
1283 const gmx_output_env_t* oenv)
1285 const char* ravgleg[] = { "\\8D\\4E = E\\sB\\N-E\\sA\\N", "<e\\S-\\8D\\4E/kT\\N>\\s0..t\\N" };
1288 int timecheck, nenergy, nenergy2, maxenergy;
1294 gmx_enxnm_t* enm = nullptr;
1298 /* read second energy file */
1301 enx = open_enx(ene2fn, "r");
1302 do_enxnms(enx, &(fr->nre), &enm);
1304 snew(eneset2, nset + 1);
1310 /* This loop searches for the first frame (when -b option is given),
1311 * or when this has been found it reads just one energy frame
1315 bCont = do_enx(enx, fr);
1319 timecheck = check_times(fr->t);
1322 } while (bCont && (timecheck < 0));
1324 /* Store energies for analysis afterwards... */
1325 if ((timecheck == 0) && bCont)
1329 if (nenergy2 >= maxenergy)
1332 for (i = 0; i <= nset; i++)
1334 srenew(eneset2[i], maxenergy);
1337 GMX_RELEASE_ASSERT(time != nullptr, "trying to dereference NULL time pointer");
1339 if (fr->t != time[nenergy2])
1342 "\nWARNING time mismatch %g!=%g at frame %s\n",
1345 gmx_step_str(fr->step, buf));
1347 for (i = 0; i < nset; i++)
1349 eneset2[i][nenergy2] = fr->ener[set[i]].e;
1354 } while (bCont && (timecheck == 0));
1357 if (edat->nframes != nenergy2)
1359 fprintf(stderr, "\nWARNING file length mismatch %d!=%d\n", edat->nframes, nenergy2);
1361 nenergy = std::min(edat->nframes, nenergy2);
1363 /* calculate fe difference dF = -kT ln < exp(-(E_B-E_A)/kT) >_A */
1367 fp = xvgropen(runavgfn,
1368 "Running average free energy difference",
1369 "Time (" unit_time ")",
1370 "\\8D\\4E (" unit_energy ")",
1372 xvgr_legend(fp, asize(ravgleg), ravgleg, oenv);
1374 fprintf(stdout, "\n%-24s %10s\n", "Energy", "dF = -kT ln < exp(-(EB-EA)/kT) >A");
1376 beta = 1.0 / (gmx::c_boltz * reftemp);
1377 for (i = 0; i < nset; i++)
1379 if (gmx_strcasecmp(leg[i], enm[set[i]].name) != 0)
1381 fprintf(stderr, "\nWARNING energy set name mismatch %s!=%s\n", leg[i], enm[set[i]].name);
1383 for (j = 0; j < nenergy; j++)
1385 dE = eneset2[i][j] - edat->s[i].ener[j];
1386 sum += std::exp(-dE * beta);
1389 fprintf(fp, "%10g %10g %10g\n", time[j], dE, -gmx::c_boltz * reftemp * std::log(sum / (j + 1)));
1392 aver = -gmx::c_boltz * reftemp * std::log(sum / nenergy);
1393 fprintf(stdout, "%-24s %10g\n", leg[i], aver);
1403 static void do_dhdl(t_enxframe* fr,
1404 const t_inputrec* ir,
1406 const char* filename,
1412 const gmx_output_env_t* oenv)
1414 const char *dhdl = "dH/d\\lambda", *deltag = "\\DeltaH", *lambda = "\\lambda";
1415 char title[STRLEN], label_x[STRLEN], label_y[STRLEN], legend[STRLEN];
1417 int nblock_hist = 0, nblock_dh = 0, nblock_dhcoll = 0;
1420 double temp = 0, start_time = 0, delta_time = 0, start_lambda = 0;
1421 static int setnr = 0;
1422 double* native_lambda_vec = nullptr;
1423 const char** lambda_components = nullptr;
1424 int n_lambda_vec = 0;
1425 bool firstPass = true;
1427 /* now count the blocks & handle the global dh data */
1428 for (i = 0; i < fr->nblock; i++)
1430 if (fr->block[i].id == enxDHHIST)
1434 else if (fr->block[i].id == enxDH)
1438 else if (fr->block[i].id == enxDHCOLL)
1441 if ((fr->block[i].nsub < 1) || (fr->block[i].sub[0].type != xdr_datatype_double)
1442 || (fr->block[i].sub[0].nr < 5))
1444 gmx_fatal(FARGS, "Unexpected block data");
1447 /* read the data from the DHCOLL block */
1448 temp = fr->block[i].sub[0].dval[0];
1449 start_time = fr->block[i].sub[0].dval[1];
1450 delta_time = fr->block[i].sub[0].dval[2];
1451 start_lambda = fr->block[i].sub[0].dval[3];
1452 if (fr->block[i].nsub > 1)
1456 n_lambda_vec = fr->block[i].sub[1].ival[1];
1457 snew(lambda_components, n_lambda_vec);
1458 snew(native_lambda_vec, n_lambda_vec);
1463 if (n_lambda_vec != fr->block[i].sub[1].ival[1])
1465 gmx_fatal(FARGS, "Unexpected change of basis set in lambda");
1468 for (j = 0; j < n_lambda_vec; j++)
1470 native_lambda_vec[j] = fr->block[i].sub[0].dval[5 + j];
1471 lambda_components[j] =
1472 enumValueToStringSingular(static_cast<FreeEnergyPerturbationCouplingType>(
1473 fr->block[i].sub[1].ival[2 + j]));
1479 sfree(native_lambda_vec);
1480 sfree(lambda_components);
1481 if (nblock_hist == 0 && nblock_dh == 0)
1483 /* don't do anything */
1486 if (nblock_hist > 0 && nblock_dh > 0)
1489 "This energy file contains both histogram dhdl data and non-histogram dhdl data. "
1490 "Don't know what to do.");
1496 /* we have standard, non-histogram data --
1497 call open_dhdl to open the file */
1498 /* TODO this is an ugly hack that needs to be fixed: this will only
1499 work if the order of data is always the same and if we're
1500 only using the g_energy compiled with the mdrun that produced
1502 *fp_dhdl = open_dhdl(filename, ir, oenv);
1506 sprintf(title, "N(%s)", deltag);
1507 sprintf(label_x, "%s (%s)", deltag, unit_energy);
1508 sprintf(label_y, "Samples");
1509 *fp_dhdl = xvgropen_type(filename, title, label_x, label_y, exvggtXNY, oenv);
1510 sprintf(buf, "T = %g (K), %s = %g", temp, lambda, start_lambda);
1511 xvgr_subtitle(*fp_dhdl, buf, oenv);
1515 (*hists) += nblock_hist;
1516 (*blocks) += nblock_dh;
1517 (*nlambdas) = nblock_hist + nblock_dh;
1519 /* write the data */
1520 if (nblock_hist > 0)
1524 for (i = 0; i < fr->nblock; i++)
1526 t_enxblock* blk = &(fr->block[i]);
1527 if (blk->id == enxDHHIST)
1529 double foreign_lambda, dx;
1531 int nhist, derivative;
1533 /* check the block types etc. */
1534 if ((blk->nsub < 2) || (blk->sub[0].type != xdr_datatype_double)
1535 || (blk->sub[1].type != xdr_datatype_int64) || (blk->sub[0].nr < 2)
1536 || (blk->sub[1].nr < 2))
1538 gmx_fatal(FARGS, "Unexpected block data in file");
1540 foreign_lambda = blk->sub[0].dval[0];
1541 dx = blk->sub[0].dval[1];
1542 nhist = blk->sub[1].lval[0];
1543 derivative = blk->sub[1].lval[1];
1544 for (j = 0; j < nhist; j++)
1547 x0 = blk->sub[1].lval[2 + j];
1551 sprintf(legend, "N(%s(%s=%g) | %s=%g)", deltag, lambda, foreign_lambda, lambda, start_lambda);
1555 sprintf(legend, "N(%s | %s=%g)", dhdl, lambda, start_lambda);
1559 xvgr_new_dataset(*fp_dhdl, setnr, 1, lg, oenv);
1561 for (k = 0; k < blk->sub[j + 2].nr; k++)
1566 hist = blk->sub[j + 2].ival[k];
1567 xmin = (x0 + k) * dx;
1568 xmax = (x0 + k + 1) * dx;
1569 fprintf(*fp_dhdl, "%g %d\n%g %d\n", xmin, hist, xmax, hist);
1572 /* multiple histogram data blocks in one histogram
1573 mean that the second one is the reverse of the first one:
1574 for dhdl derivatives, it's important to know both the
1575 maximum and minimum values */
1580 (*samples) += static_cast<int>(sum / nblock_hist);
1587 for (i = 0; i < fr->nblock; i++)
1589 t_enxblock* blk = &(fr->block[i]);
1590 if (blk->id == enxDH)
1594 len = blk->sub[2].nr;
1598 if (len != blk->sub[2].nr)
1600 gmx_fatal(FARGS, "Length inconsistency in dhdl data");
1607 for (i = 0; i < len; i++)
1609 double time = start_time + delta_time * i;
1611 fprintf(*fp_dhdl, "%.4f ", time);
1613 for (j = 0; j < fr->nblock; j++)
1615 t_enxblock* blk = &(fr->block[j]);
1616 if (blk->id == enxDH)
1619 if (blk->sub[2].type == xdr_datatype_float)
1621 value = blk->sub[2].fval[i];
1625 value = blk->sub[2].dval[i];
1627 /* we need to decide which data type it is based on the count*/
1629 if (j == 1 && ir->bExpanded)
1631 fprintf(*fp_dhdl, "%4d", static_cast<int>(value)); /* if expanded ensembles and zero, this is a state value, it's an integer. We need a cleaner conditional than if j==1! */
1637 fprintf(*fp_dhdl, " %#.12g", value); /* print normal precision */
1641 fprintf(*fp_dhdl, " %#.8g", value); /* print normal precision */
1646 fprintf(*fp_dhdl, "\n");
1652 int gmx_energy(int argc, char* argv[])
1654 const char* desc[] = {
1655 "[THISMODULE] extracts energy components",
1656 "from an energy file. The user is prompted to interactively",
1657 "select the desired energy terms.[PAR]",
1659 "Average, RMSD, and drift are calculated with full precision from the",
1660 "simulation (see printed manual). Drift is calculated by performing",
1661 "a least-squares fit of the data to a straight line. The reported total drift",
1662 "is the difference of the fit at the first and last point.",
1663 "An error estimate of the average is given based on a block averages",
1664 "over 5 blocks using the full-precision averages. The error estimate",
1665 "can be performed over multiple block lengths with the options",
1666 "[TT]-nbmin[tt] and [TT]-nbmax[tt].",
1667 "[BB]Note[bb] that in most cases the energy files contains averages over all",
1668 "MD steps, or over many more points than the number of frames in",
1669 "energy file. This makes the [THISMODULE] statistics output more accurate",
1670 "than the [REF].xvg[ref] output. When exact averages are not present in the energy",
1671 "file, the statistics mentioned above are simply over the single, per-frame",
1672 "energy values.[PAR]",
1674 "The term fluctuation gives the RMSD around the least-squares fit.[PAR]",
1676 "Some fluctuation-dependent properties can be calculated provided",
1677 "the correct energy terms are selected, and that the command line option",
1678 "[TT]-fluct_props[tt] is given. The following properties",
1679 "will be computed:",
1681 "=============================== ===================",
1682 "Property Energy terms needed",
1683 "=============================== ===================",
1684 "Heat capacity C[SUB]p[sub] (NPT sims): Enthalpy, Temp",
1685 "Heat capacity C[SUB]v[sub] (NVT sims): Etot, Temp",
1686 "Thermal expansion coeff. (NPT): Enthalpy, Vol, Temp",
1687 "Isothermal compressibility: Vol, Temp",
1688 "Adiabatic bulk modulus: Vol, Temp",
1689 "=============================== ===================",
1691 "You always need to set the number of molecules [TT]-nmol[tt].",
1692 "The C[SUB]p[sub]/C[SUB]v[sub] computations do [BB]not[bb] include any corrections",
1693 "for quantum effects. Use the [gmx-dos] program if you need that (and you do).[PAR]",
1695 "Option [TT]-odh[tt] extracts and plots the free energy data",
1696 "(Hamiltoian differences and/or the Hamiltonian derivative dhdl)",
1697 "from the [TT]ener.edr[tt] file.[PAR]",
1699 "With [TT]-fee[tt] an estimate is calculated for the free-energy",
1700 "difference with an ideal gas state::",
1702 " [GRK]Delta[grk] A = A(N,V,T) - A[SUB]idealgas[sub](N,V,T) = kT ",
1703 " [LN][CHEVRON][EXP]U[SUB]pot[sub]/kT[exp][chevron][ln]",
1704 " [GRK]Delta[grk] G = G(N,p,T) - G[SUB]idealgas[sub](N,p,T) = kT ",
1705 " [LN][CHEVRON][EXP]U[SUB]pot[sub]/kT[exp][chevron][ln]",
1707 "where k is Boltzmann's constant, T is set by [TT]-fetemp[tt] and",
1708 "the average is over the ensemble (or time in a trajectory).",
1709 "Note that this is in principle",
1710 "only correct when averaging over the whole (Boltzmann) ensemble",
1711 "and using the potential energy. This also allows for an entropy",
1714 " [GRK]Delta[grk] S(N,V,T) = S(N,V,T) - S[SUB]idealgas[sub](N,V,T) = ",
1715 " ([CHEVRON]U[SUB]pot[sub][chevron] - [GRK]Delta[grk] A)/T",
1716 " [GRK]Delta[grk] S(N,p,T) = S(N,p,T) - S[SUB]idealgas[sub](N,p,T) = ",
1717 " ([CHEVRON]U[SUB]pot[sub][chevron] + pV - [GRK]Delta[grk] G)/T",
1720 "When a second energy file is specified ([TT]-f2[tt]), a free energy",
1721 "difference is calculated::",
1724 " [LN][CHEVRON][EXP]-(E[SUB]B[sub]-E[SUB]A[sub]) / ",
1725 " kT[exp][chevron][SUB]A[sub][ln],",
1727 "where E[SUB]A[sub] and E[SUB]B[sub] are the energies from the first and second energy",
1728 "files, and the average is over the ensemble A. The running average",
1729 "of the free energy difference is printed to a file specified by [TT]-ravg[tt].",
1730 "[BB]Note[bb] that the energies must both be calculated from the same trajectory."
1733 static gmx_bool bSum = FALSE, bFee = FALSE, bPrAll = FALSE, bFluct = FALSE, bDriftCorr = FALSE;
1734 static gmx_bool bDp = FALSE, bMutot = FALSE, bOrinst = FALSE, bOvec = FALSE, bFluctProps = FALSE;
1735 static int nmol = 1, nbmin = 5, nbmax = 5;
1736 static real reftemp = 300.0, ezero = 0;
1738 { "-fee", FALSE, etBOOL, { &bFee }, "Do a free energy estimate" },
1743 "Reference temperature for free energy calculation" },
1744 { "-zero", FALSE, etREAL, { &ezero }, "Subtract a zero-point energy" },
1749 "Sum the energy terms selected rather than display them all" },
1750 { "-dp", FALSE, etBOOL, { &bDp }, "Print energies in high precision" },
1751 { "-nbmin", FALSE, etINT, { &nbmin }, "Minimum number of blocks for error estimate" },
1752 { "-nbmax", FALSE, etINT, { &nbmax }, "Maximum number of blocks for error estimate" },
1757 "Compute the total dipole moment from the components" },
1762 "Also print the exact average and rmsd stored in the energy frames (only when 1 term is "
1768 "Number of molecules in your sample: the energies are divided by this number" },
1773 "Compute properties based on energy fluctuations, like heat capacity" },
1778 "Useful only for calculations of fluctuation properties. The drift in the observables "
1779 "will be subtracted before computing the fluctuation properties." },
1784 "Calculate autocorrelation of energy fluctuations rather than energy itself" },
1785 { "-orinst", FALSE, etBOOL, { &bOrinst }, "Analyse instantaneous orientation data" },
1786 { "-ovec", FALSE, etBOOL, { &bOvec }, "Also plot the eigenvectors with [TT]-oten[tt]" }
1788 static const char* setnm[] = { "Pres-XX", "Pres-XY", "Pres-XZ", "Pres-YX",
1789 "Pres-YY", "Pres-YZ", "Pres-ZX", "Pres-ZY",
1790 "Pres-ZZ", "Temperature", "Volume", "Pressure" };
1792 FILE* out = nullptr;
1793 FILE* fp_dhdl = nullptr;
1797 gmx_enxnm_t* enm = nullptr;
1798 t_enxframe * frame, *fr = nullptr;
1800 #define NEXT (1 - cur)
1805 gmx_bool bFoundStart, bCont, bVisco;
1807 double* time = nullptr;
1809 int * set = nullptr, i, j, nset, sss;
1810 gmx_bool* bIsEner = nullptr;
1811 char** leg = nullptr;
1813 gmx_output_env_t* oenv;
1814 int dh_blocks = 0, dh_hists = 0, dh_samples = 0, dh_lambdas = 0;
1817 { efEDR, "-f", nullptr, ffREAD }, { efEDR, "-f2", nullptr, ffOPTRD },
1818 { efTPR, "-s", nullptr, ffOPTRD }, { efXVG, "-o", "energy", ffWRITE },
1819 { efXVG, "-viol", "violaver", ffOPTWR }, { efXVG, "-pairs", "pairs", ffOPTWR },
1820 { efXVG, "-corr", "enecorr", ffOPTWR }, { efXVG, "-vis", "visco", ffOPTWR },
1821 { efXVG, "-evisco", "evisco", ffOPTWR }, { efXVG, "-eviscoi", "eviscoi", ffOPTWR },
1822 { efXVG, "-ravg", "runavgdf", ffOPTWR }, { efXVG, "-odh", "dhdl", ffOPTWR }
1824 #define NFILE asize(fnm)
1829 ppa = add_acf_pargs(&npargs, pa);
1830 if (!parse_common_args(
1831 &argc, argv, PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
1837 bDHDL = opt2bSet("-odh", NFILE, fnm);
1842 fp = open_enx(ftp2fn(efEDR, NFILE, fnm), "r");
1843 do_enxnms(fp, &nre, &enm);
1847 bVisco = opt2bSet("-vis", NFILE, fnm);
1849 t_inputrec irInstance;
1850 t_inputrec* ir = &irInstance;
1856 nset = asize(setnm);
1858 /* This is nasty code... To extract Pres tensor, Volume and Temperature */
1859 for (j = 0; j < nset; j++)
1861 for (i = 0; i < nre; i++)
1863 if (std::strstr(enm[i].name, setnm[j]))
1871 if (gmx_strcasecmp(setnm[j], "Volume") == 0)
1873 printf("Enter the box volume (" unit_volume "): ");
1874 if (1 != scanf("%lf", &dbl))
1876 gmx_fatal(FARGS, "Error reading user input");
1882 gmx_fatal(FARGS, "Could not find term %s for viscosity calculation", setnm[j]);
1889 set = select_by_name(nre, enm, &nset);
1891 /* Print all the different units once */
1892 sprintf(buf, "(%s)", enm[set[0]].unit);
1893 for (i = 1; i < nset; i++)
1895 for (j = 0; j < i; j++)
1897 if (std::strcmp(enm[set[i]].unit, enm[set[j]].unit) == 0)
1904 std::strcat(buf, ", (");
1905 std::strcat(buf, enm[set[i]].unit);
1906 std::strcat(buf, ")");
1909 out = xvgropen(opt2fn("-o", NFILE, fnm), "GROMACS Energies", "Time (ps)", buf, oenv);
1911 snew(leg, nset + 1);
1912 for (i = 0; (i < nset); i++)
1914 leg[i] = enm[set[i]].name;
1918 leg[nset] = gmx_strdup("Sum");
1919 xvgr_legend(out, nset + 1, leg, oenv);
1923 xvgr_legend(out, nset, leg, oenv);
1926 snew(bIsEner, nset);
1927 for (i = 0; (i < nset); i++)
1930 for (j = 0; (j <= F_ETOT); j++)
1932 bIsEner[i] = bIsEner[i]
1933 || (gmx_strcasecmp(interaction_function[j].longname, leg[i]) == 0);
1936 if (bPrAll && nset > 1)
1938 gmx_fatal(FARGS, "Printing averages can only be done when a single set is selected");
1943 get_dhdl_parms(ftp2fn(efTPR, NFILE, fnm), ir);
1946 /* Initiate energies and set them to zero */
1950 edat.step = nullptr;
1951 edat.steps = nullptr;
1952 edat.points = nullptr;
1953 edat.bHaveSums = TRUE;
1956 /* Initiate counters */
1957 bFoundStart = FALSE;
1962 /* This loop searches for the first frame (when -b option is given),
1963 * or when this has been found it reads just one energy frame
1967 bCont = do_enx(fp, &(frame[NEXT]));
1970 timecheck = check_times(frame[NEXT].t);
1972 } while (bCont && (timecheck < 0));
1974 if ((timecheck == 0) && bCont)
1976 /* We read a valid frame, so we can use it */
1977 fr = &(frame[NEXT]);
1981 /* The frame contains energies, so update cur */
1984 if (edat.nframes % 1000 == 0)
1986 srenew(edat.step, edat.nframes + 1000);
1987 std::memset(&(edat.step[edat.nframes]), 0, 1000 * sizeof(edat.step[0]));
1988 srenew(edat.steps, edat.nframes + 1000);
1989 std::memset(&(edat.steps[edat.nframes]), 0, 1000 * sizeof(edat.steps[0]));
1990 srenew(edat.points, edat.nframes + 1000);
1991 std::memset(&(edat.points[edat.nframes]), 0, 1000 * sizeof(edat.points[0]));
1993 for (i = 0; i < nset; i++)
1995 srenew(edat.s[i].ener, edat.nframes + 1000);
1996 std::memset(&(edat.s[i].ener[edat.nframes]), 0, 1000 * sizeof(edat.s[i].ener[0]));
1997 srenew(edat.s[i].es, edat.nframes + 1000);
1998 std::memset(&(edat.s[i].es[edat.nframes]), 0, 1000 * sizeof(edat.s[i].es[0]));
2003 edat.step[nfr] = fr->step;
2008 /* Initiate the previous step data */
2009 start_step = fr->step;
2011 /* Initiate the energy sums */
2012 edat.steps[nfr] = 1;
2013 edat.points[nfr] = 1;
2014 for (i = 0; i < nset; i++)
2017 edat.s[i].es[nfr].sum = fr->ener[sss].e;
2018 edat.s[i].es[nfr].sum2 = 0;
2025 edat.steps[nfr] = fr->nsteps;
2029 /* mdrun only calculated the energy at energy output
2030 * steps. We don't need to check step intervals.
2032 edat.points[nfr] = 1;
2033 for (i = 0; i < nset; i++)
2036 edat.s[i].es[nfr].sum = fr->ener[sss].e;
2037 edat.s[i].es[nfr].sum2 = 0;
2040 edat.bHaveSums = FALSE;
2042 else if (fr->step - start_step + 1 == edat.nsteps + fr->nsteps)
2044 /* We have statistics to the previous frame */
2045 edat.points[nfr] = fr->nsum;
2046 for (i = 0; i < nset; i++)
2049 edat.s[i].es[nfr].sum = fr->ener[sss].esum;
2050 edat.s[i].es[nfr].sum2 = fr->ener[sss].eav;
2052 edat.npoints += fr->nsum;
2056 /* The interval does not match fr->nsteps:
2057 * can not do exact averages.
2059 edat.bHaveSums = FALSE;
2062 edat.nsteps = fr->step - start_step + 1;
2064 for (i = 0; i < nset; i++)
2066 edat.s[i].ener[nfr] = fr->ener[set[i]].e;
2070 * Store energies for analysis afterwards...
2072 if (!bDHDL && (fr->nre > 0))
2074 if (edat.nframes % 1000 == 0)
2076 srenew(time, edat.nframes + 1000);
2078 time[edat.nframes] = fr->t;
2083 do_dhdl(fr, ir, &fp_dhdl, opt2fn("-odh", NFILE, fnm), bDp, &dh_blocks, &dh_hists, &dh_samples, &dh_lambdas, oenv);
2086 /*******************************************
2088 *******************************************/
2095 /* We skip frames with single points (usually only the first frame),
2096 * since they would result in an average plot with outliers.
2100 print_time(out, fr->t);
2101 print1(out, bDp, fr->ener[set[0]].e);
2102 print1(out, bDp, fr->ener[set[0]].esum / fr->nsum);
2103 print1(out, bDp, std::sqrt(fr->ener[set[0]].eav / fr->nsum));
2109 print_time(out, fr->t);
2113 for (i = 0; i < nset; i++)
2115 sum += fr->ener[set[i]].e;
2117 print1(out, bDp, sum / nmol - ezero);
2121 for (i = 0; (i < nset); i++)
2125 print1(out, bDp, (fr->ener[set[i]].e) / nmol - ezero);
2129 print1(out, bDp, fr->ener[set[i]].e);
2138 } while (bCont && (timecheck == 0));
2140 fprintf(stderr, "\n");
2151 gmx_fio_fclose(fp_dhdl);
2152 printf("\n\nWrote %d lambda values with %d samples as ", dh_lambdas, dh_samples);
2155 printf("%d dH histograms ", dh_hists);
2159 printf("%d dH data blocks ", dh_blocks);
2161 printf("to %s\n", opt2fn("-odh", NFILE, fnm));
2165 gmx_fatal(FARGS, "No dH data in %s\n", opt2fn("-f", NFILE, fnm));
2170 double dt = (frame[cur].t - start_t) / (edat.nframes - 1);
2171 analyse_ener(opt2bSet("-corr", NFILE, fnm),
2172 opt2fn("-corr", NFILE, fnm),
2173 opt2fn("-evisco", NFILE, fnm),
2174 opt2fn("-eviscoi", NFILE, fnm),
2179 opt2fn("-vis", NFILE, fnm),
2199 calc_fluctuation_props(stdout, bDriftCorr, dt, nset, nmol, leg, &edat, nbmin, nbmax);
2202 if (opt2bSet("-f2", NFILE, fnm))
2204 fec(opt2fn("-f2", NFILE, fnm), opt2fn("-ravg", NFILE, fnm), reftemp, nset, set, leg, &edat, time, oenv);
2207 done_enerdata_t(nset, &edat);
2209 free_enxframe(&frame[0]);
2210 free_enxframe(&frame[1]);
2212 free_enxnms(nre, enm);
2218 const char* nxy = "-nxy";
2220 do_view(oenv, opt2fn("-o", NFILE, fnm), nxy);
2221 do_view(oenv, opt2fn_null("-ravg", NFILE, fnm), nxy);
2222 do_view(oenv, opt2fn_null("-odh", NFILE, fnm), nxy);
2224 output_env_done(oenv);