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,2018, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
45 #include "gromacs/commandline/pargs.h"
46 #include "gromacs/commandline/viewit.h"
47 #include "gromacs/correlationfunctions/autocorr.h"
48 #include "gromacs/fileio/enxio.h"
49 #include "gromacs/fileio/gmxfio.h"
50 #include "gromacs/fileio/tpxio.h"
51 #include "gromacs/fileio/trxio.h"
52 #include "gromacs/fileio/xvgr.h"
53 #include "gromacs/gmxana/gmx_ana.h"
54 #include "gromacs/gmxana/gstat.h"
55 #include "gromacs/math/functions.h"
56 #include "gromacs/math/units.h"
57 #include "gromacs/math/vec.h"
58 #include "gromacs/mdlib/mdebin.h"
59 #include "gromacs/mdtypes/inputrec.h"
60 #include "gromacs/mdtypes/md_enums.h"
61 #include "gromacs/topology/ifunc.h"
62 #include "gromacs/topology/mtop_lookup.h"
63 #include "gromacs/topology/mtop_util.h"
64 #include "gromacs/topology/topology.h"
65 #include "gromacs/utility/arraysize.h"
66 #include "gromacs/utility/cstringutil.h"
67 #include "gromacs/utility/fatalerror.h"
68 #include "gromacs/utility/gmxassert.h"
69 #include "gromacs/utility/pleasecite.h"
70 #include "gromacs/utility/smalloc.h"
71 #include "gromacs/utility/strconvert.h"
73 static const int NOTSET = -23451;
101 static void done_enerdata_t(int nset, enerdata_t *edat)
106 for (int i = 0; i < nset; i++)
108 sfree(edat->s[i].ener);
109 sfree(edat->s[i].es);
114 static void chomp(char *buf)
116 int len = std::strlen(buf);
118 while ((len > 0) && (buf[len-1] == '\n'))
125 static int *select_by_name(int nre, gmx_enxnm_t *nm, int *nset)
128 int k, kk, j, i, nmatch, nind, nss;
130 gmx_bool bEOF, bVerbose = TRUE, bLong = FALSE;
131 char *ptr, buf[STRLEN];
132 const char *fm4 = "%3d %-14s";
133 const char *fm2 = "%3d %-34s";
134 char **newnm = nullptr;
136 if ((getenv("GMX_ENER_VERBOSE")) != nullptr)
141 fprintf(stderr, "\n");
142 fprintf(stderr, "Select the terms you want from the following list by\n");
143 fprintf(stderr, "selecting either (part of) the name or the number or a combination.\n");
144 fprintf(stderr, "End your selection with an empty line or a zero.\n");
145 fprintf(stderr, "-------------------------------------------------------------------\n");
149 for (k = 0; k < nre; k++)
151 newnm[k] = gmx_strdup(nm[k].name);
152 /* Insert dashes in all the names */
153 while ((ptr = std::strchr(newnm[k], ' ')) != nullptr)
163 fprintf(stderr, "\n");
166 for (kk = k; kk < k+4; kk++)
168 if (kk < nre && std::strlen(nm[kk].name) > 14)
176 fprintf(stderr, " ");
180 fprintf(stderr, fm4, k+1, newnm[k]);
189 fprintf(stderr, fm2, k+1, newnm[k]);
200 fprintf(stderr, "\n\n");
206 while (!bEOF && (fgets2(buf, STRLEN-1, stdin)))
208 /* Remove newlines */
214 /* Empty line means end of input */
215 bEOF = (std::strlen(buf) == 0);
223 /* First try to read an integer */
224 nss = sscanf(ptr, "%d", &nind);
227 /* Zero means end of input */
232 else if ((1 <= nind) && (nind <= nre))
238 fprintf(stderr, "number %d is out of range\n", nind);
243 /* Now try to read a string */
245 for (nind = 0; nind < nre; nind++)
247 if (gmx_strcasecmp(newnm[nind], ptr) == 0)
255 i = std::strlen(ptr);
257 for (nind = 0; nind < nre; nind++)
259 if (gmx_strncasecmp(newnm[nind], ptr, i) == 0)
267 fprintf(stderr, "String '%s' does not match anything\n", ptr);
272 /* Look for the first space, and remove spaces from there */
273 if ((ptr = std::strchr(ptr, ' ')) != nullptr)
278 while (!bEOF && (ptr && (std::strlen(ptr) > 0)));
283 for (i = (*nset) = 0; (i < nre); i++)
295 gmx_fatal(FARGS, "No energy terms selected");
298 for (i = 0; (i < nre); i++)
307 static void get_dhdl_parms(const char *topnm, t_inputrec *ir)
313 /* all we need is the ir to be able to write the label */
314 read_tpx(topnm, ir, box, &natoms, nullptr, nullptr, &mtop);
317 static void einstein_visco(const char *fn, const char *fni, int nsets,
318 int nint, real **eneint,
319 real V, real T, double dt,
320 const gmx_output_env_t *oenv)
323 double av[4], avold[4];
329 for (i = 0; i <= nsets; i++)
333 fp0 = xvgropen(fni, "Shear viscosity integral",
334 "Time (ps)", "(kg m\\S-1\\N s\\S-1\\N ps)", oenv);
335 fp1 = xvgropen(fn, "Shear viscosity using Einstein relation",
336 "Time (ps)", "(kg m\\S-1\\N s\\S-1\\N)", oenv);
337 for (i = 0; i < nf4; i++)
339 for (m = 0; m <= nsets; m++)
343 for (j = 0; j < nint - i; j++)
345 for (m = 0; m < nsets; m++)
347 di = gmx::square(eneint[m][j+i] - eneint[m][j]);
350 av[nsets] += di/nsets;
353 /* Convert to SI for the viscosity */
354 fac = (V*NANO*NANO*NANO*PICO*1e10)/(2*BOLTZMANN*T)/(nint - i);
355 fprintf(fp0, "%10g", i*dt);
356 for (m = 0; (m <= nsets); m++)
359 fprintf(fp0, " %10g", av[m]);
362 fprintf(fp1, "%10g", (i + 0.5)*dt);
363 for (m = 0; (m <= nsets); m++)
365 fprintf(fp1, " %10g", (av[m]-avold[m])/dt);
388 static void clear_ee_sum(ee_sum_t *ees)
396 static void add_ee_sum(ee_sum_t *ees, double sum, int np)
402 static void add_ee_av(ee_sum_t *ees)
406 av = ees->sum/ees->np;
413 static double calc_ee2(int nb, ee_sum_t *ees)
415 return (ees->sav2/nb - gmx::square(ees->sav/nb))/(nb - 1);
418 static void set_ee_av(ener_ee_t *eee)
422 char buf[STEPSTRSIZE];
423 fprintf(debug, "Storing average for err.est.: %s steps\n",
424 gmx_step_str(eee->nst, buf));
426 add_ee_av(&eee->sum);
428 if (eee->b == 1 || eee->nst < eee->nst_min)
430 eee->nst_min = eee->nst;
435 static void calc_averages(int nset, enerdata_t *edat, int nbmin, int nbmax)
438 double sum, sum2, sump, see2;
439 gmx_int64_t np, p, bound_nb;
443 double x, sx, sy, sxx, sxy;
446 /* Check if we have exact statistics over all points */
447 for (i = 0; i < nset; i++)
450 ed->bExactStat = FALSE;
453 /* All energy file sum entries 0 signals no exact sums.
454 * But if all energy values are 0, we still have exact sums.
457 for (f = 0; f < edat->nframes && !ed->bExactStat; f++)
459 if (ed->ener[i] != 0)
463 ed->bExactStat = (ed->es[f].sum != 0);
467 ed->bExactStat = TRUE;
473 for (i = 0; i < nset; i++)
484 for (nb = nbmin; nb <= nbmax; nb++)
487 clear_ee_sum(&eee[nb].sum);
491 for (f = 0; f < edat->nframes; f++)
497 /* Add the sum and the sum of variances to the totals. */
503 sum2 += gmx::square(sum/np - (sum + es->sum)/(np + p))
509 /* Add a single value to the sum and sum of squares. */
512 sum2 += gmx::square(sump);
515 /* sum has to be increased after sum2 */
519 /* For the linear regression use variance 1/p.
520 * Note that sump is the sum, not the average, so we don't need p*.
522 x = edat->step[f] - 0.5*(edat->steps[f] - 1);
528 for (nb = nbmin; nb <= nbmax; nb++)
530 /* Check if the current end step is closer to the desired
531 * block boundary than the next end step.
533 bound_nb = (edat->step[0]-1)*nb + edat->nsteps*(eee[nb].b+1);
534 if (eee[nb].nst > 0 &&
535 bound_nb - edat->step[f-1]*nb < edat->step[f]*nb - bound_nb)
545 eee[nb].nst += edat->step[f] - edat->step[f-1];
549 add_ee_sum(&eee[nb].sum, es->sum, edat->points[f]);
553 add_ee_sum(&eee[nb].sum, edat->s[i].ener[f], 1);
555 bound_nb = (edat->step[0]-1)*nb + edat->nsteps*(eee[nb].b+1);
556 if (edat->step[f]*nb >= bound_nb)
563 edat->s[i].av = sum/np;
566 edat->s[i].rmsd = std::sqrt(sum2/np);
570 edat->s[i].rmsd = std::sqrt(sum2/np - gmx::square(edat->s[i].av));
573 if (edat->nframes > 1)
575 edat->s[i].slope = (np*sxy - sx*sy)/(np*sxx - sx*sx);
579 edat->s[i].slope = 0;
584 for (nb = nbmin; nb <= nbmax; nb++)
586 /* Check if we actually got nb blocks and if the smallest
587 * block is not shorter than 80% of the average.
591 char buf1[STEPSTRSIZE], buf2[STEPSTRSIZE];
592 fprintf(debug, "Requested %d blocks, we have %d blocks, min %s nsteps %s\n",
594 gmx_step_str(eee[nb].nst_min, buf1),
595 gmx_step_str(edat->nsteps, buf2));
597 if (eee[nb].b == nb && 5*nb*eee[nb].nst_min >= 4*edat->nsteps)
599 see2 += calc_ee2(nb, &eee[nb].sum);
605 edat->s[i].ee = std::sqrt(see2/nee);
615 static enerdata_t *calc_sum(int nset, enerdata_t *edat, int nbmin, int nbmax)
626 snew(s->ener, esum->nframes);
627 snew(s->es, esum->nframes);
629 s->bExactStat = TRUE;
631 for (i = 0; i < nset; i++)
633 if (!edat->s[i].bExactStat)
635 s->bExactStat = FALSE;
637 s->slope += edat->s[i].slope;
640 for (f = 0; f < edat->nframes; f++)
643 for (i = 0; i < nset; i++)
645 sum += edat->s[i].ener[f];
649 for (i = 0; i < nset; i++)
651 sum += edat->s[i].es[f].sum;
657 calc_averages(1, esum, nbmin, nbmax);
662 static void ee_pr(double ee, int buflen, char *buf)
664 snprintf(buf, buflen, "%s", "--");
667 /* Round to two decimals by printing. */
669 snprintf(tmp, sizeof(tmp), "%.1e", ee);
670 double rnd = gmx::doubleFromString(tmp);
671 snprintf(buf, buflen, "%g", rnd);
675 static void remove_drift(int nset, int nbmin, int nbmax, real dt, enerdata_t *edat)
677 /* Remove the drift by performing a fit to y = ax+b.
678 Uses 5 iterations. */
682 edat->npoints = edat->nframes;
683 edat->nsteps = edat->nframes;
685 for (k = 0; (k < 5); k++)
687 for (i = 0; (i < nset); i++)
689 delta = edat->s[i].slope*dt;
691 if (nullptr != debug)
693 fprintf(debug, "slope for set %d is %g\n", i, edat->s[i].slope);
696 for (j = 0; (j < edat->nframes); j++)
698 edat->s[i].ener[j] -= j*delta;
699 edat->s[i].es[j].sum = 0;
700 edat->s[i].es[j].sum2 = 0;
703 calc_averages(nset, edat, nbmin, nbmax);
707 static void calc_fluctuation_props(FILE *fp,
708 gmx_bool bDriftCorr, real dt,
710 char **leg, enerdata_t *edat,
711 int nbmin, int nbmax)
714 double vv, v, h, varv, hh, varh, tt, cv, cp, alpha, kappa, dcp, varet;
717 eVol, eEnth, eTemp, eEtot, eNR
719 const char *my_ener[] = { "Volume", "Enthalpy", "Temperature", "Total Energy" };
722 NANO3 = NANO*NANO*NANO;
725 fprintf(fp, "\nYou may want to use the -driftcorr flag in order to correct\n"
726 "for spurious drift in the graphs. Note that this is not\n"
727 "a substitute for proper equilibration and sampling!\n");
731 remove_drift(nset, nbmin, nbmax, dt, edat);
733 for (i = 0; (i < eNR); i++)
735 for (ii[i] = 0; (ii[i] < nset &&
736 (gmx_strcasecmp(leg[ii[i]], my_ener[i]) != 0)); ii[i]++)
741 fprintf(fp,"Found %s data.\n",my_ener[i]);
743 /* Compute it all! */
744 alpha = kappa = cp = dcp = cv = NOTSET;
748 if (ii[eTemp] < nset)
750 tt = edat->s[ii[eTemp]].av;
754 if ((ii[eVol] < nset) && (ii[eTemp] < nset))
756 vv = edat->s[ii[eVol]].av*NANO3;
757 varv = gmx::square(edat->s[ii[eVol]].rmsd*NANO3);
758 kappa = (varv/vv)/(BOLTZMANN*tt);
762 if ((ii[eEnth] < nset) && (ii[eTemp] < nset))
764 hh = KILO*edat->s[ii[eEnth]].av/AVOGADRO;
765 varh = gmx::square(KILO*edat->s[ii[eEnth]].rmsd/AVOGADRO);
766 cp = AVOGADRO*((varh/nmol)/(BOLTZMANN*tt*tt));
769 if ((ii[eEtot] < nset) && (hh == NOTSET) && (tt != NOTSET))
771 /* Only compute cv in constant volume runs, which we can test
772 by checking whether the enthalpy was computed.
774 varet = gmx::square(edat->s[ii[eEtot]].rmsd);
775 cv = KILO*((varet/nmol)/(BOLTZ*tt*tt));
778 if ((ii[eVol] < nset) && (ii[eEnth] < nset) && (ii[eTemp] < nset))
780 double v_sum, h_sum, vh_sum, v_aver, h_aver, vh_aver;
781 vh_sum = v_sum = h_sum = 0;
782 for (j = 0; (j < edat->nframes); j++)
784 v = edat->s[ii[eVol]].ener[j]*NANO3;
785 h = KILO*edat->s[ii[eEnth]].ener[j]/AVOGADRO;
790 vh_aver = vh_sum / edat->nframes;
791 v_aver = v_sum / edat->nframes;
792 h_aver = h_sum / edat->nframes;
793 alpha = (vh_aver-v_aver*h_aver)/(v_aver*BOLTZMANN*tt*tt);
794 dcp = (v_aver*AVOGADRO/nmol)*tt*gmx::square(alpha)/(kappa);
801 fprintf(fp, "\nWARNING: nmol = %d, this may not be what you want.\n",
804 fprintf(fp, "\nTemperature dependent fluctuation properties at T = %g.\n", tt);
805 fprintf(fp, "\nHeat capacities obtained from fluctuations do *not* include\n");
806 fprintf(fp, "quantum corrections. If you want to get a more accurate estimate\n");
807 fprintf(fp, "please use the g_dos program.\n\n");
808 fprintf(fp, "WARNING: Please verify that your simulations are converged and perform\n"
809 "a block-averaging error analysis (not implemented in g_energy yet)\n");
811 if (debug != nullptr)
815 fprintf(fp, "varv = %10g (m^6)\n", varv*AVOGADRO/nmol);
820 fprintf(fp, "Volume = %10g m^3/mol\n",
825 fprintf(fp, "Enthalpy = %10g kJ/mol\n",
826 hh*AVOGADRO/(KILO*nmol));
830 fprintf(fp, "Coefficient of Thermal Expansion Alpha_P = %10g (1/K)\n",
835 fprintf(fp, "Isothermal Compressibility Kappa = %10g (m^3/J)\n",
837 fprintf(fp, "Adiabatic bulk modulus = %10g (J/m^3)\n",
842 fprintf(fp, "Heat capacity at constant pressure Cp = %10g J/(mol K)\n",
847 fprintf(fp, "Heat capacity at constant volume Cv = %10g J/(mol K)\n",
852 fprintf(fp, "Cp-Cv = %10g J/(mol K)\n",
855 please_cite(fp, "Allen1987a");
859 fprintf(fp, "You should select the temperature in order to obtain fluctuation properties.\n");
863 static void analyse_ener(gmx_bool bCorr, const char *corrfn,
864 const char *eviscofn, const char *eviscoifn,
865 gmx_bool bFee, gmx_bool bSum, gmx_bool bFluct,
866 gmx_bool bVisco, const char *visfn, int nmol,
867 gmx_int64_t start_step, double start_t,
868 gmx_int64_t step, double t,
871 int nset, int set[], gmx_bool *bIsEner,
872 char **leg, gmx_enxnm_t *enm,
873 real Vaver, real ezero,
874 int nbmin, int nbmax,
875 const gmx_output_env_t *oenv)
878 /* Check out the printed manual for equations! */
879 double Dt, aver, stddev, errest, delta_t, totaldrift;
880 enerdata_t *esum = nullptr;
881 real integral, intBulk, Temp = 0, Pres = 0;
882 real pr_aver, pr_stddev, pr_errest;
883 double beta = 0, expE, expEtot, *fee = nullptr;
885 int nexact, nnotexact;
887 char buf[256], eebuf[100];
889 nsteps = step - start_step + 1;
892 fprintf(stdout, "Not enough steps (%s) for statistics\n",
893 gmx_step_str(nsteps, buf));
897 /* Calculate the time difference */
898 delta_t = t - start_t;
900 fprintf(stdout, "\nStatistics over %s steps [ %.4f through %.4f ps ], %d data sets\n",
901 gmx_step_str(nsteps, buf), start_t, t, nset);
903 calc_averages(nset, edat, nbmin, nbmax);
907 esum = calc_sum(nset, edat, nbmin, nbmax);
910 if (!edat->bHaveSums)
919 for (i = 0; (i < nset); i++)
921 if (edat->s[i].bExactStat)
934 fprintf(stdout, "All statistics are over %s points\n",
935 gmx_step_str(edat->npoints, buf));
937 else if (nexact == 0 || edat->npoints == edat->nframes)
939 fprintf(stdout, "All statistics are over %d points (frames)\n",
944 fprintf(stdout, "The term%s", nnotexact == 1 ? "" : "s");
945 for (i = 0; (i < nset); i++)
947 if (!edat->s[i].bExactStat)
949 fprintf(stdout, " '%s'", leg[i]);
952 fprintf(stdout, " %s has statistics over %d points (frames)\n",
953 nnotexact == 1 ? "is" : "are", edat->nframes);
954 fprintf(stdout, "All other statistics are over %s points\n",
955 gmx_step_str(edat->npoints, buf));
957 fprintf(stdout, "\n");
959 fprintf(stdout, "%-24s %10s %10s %10s %10s",
960 "Energy", "Average", "Err.Est.", "RMSD", "Tot-Drift");
963 fprintf(stdout, " %10s\n", "-kT ln<e^(E/kT)>");
967 fprintf(stdout, "\n");
969 fprintf(stdout, "-------------------------------------------------------------------------------\n");
971 /* Initiate locals, only used with -sum */
975 beta = 1.0/(BOLTZ*reftemp);
978 for (i = 0; (i < nset); i++)
980 aver = edat->s[i].av;
981 stddev = edat->s[i].rmsd;
982 errest = edat->s[i].ee;
987 for (j = 0; (j < edat->nframes); j++)
989 expE += std::exp(beta*(edat->s[i].ener[j] - aver)/nmol);
993 expEtot += expE/edat->nframes;
996 fee[i] = std::log(expE/edat->nframes)/beta + aver/nmol;
998 if (std::strstr(leg[i], "empera") != nullptr)
1002 else if (std::strstr(leg[i], "olum") != nullptr)
1006 else if (std::strstr(leg[i], "essure") != nullptr)
1012 pr_aver = aver/nmol-ezero;
1013 pr_stddev = stddev/nmol;
1014 pr_errest = errest/nmol;
1023 /* Multiply the slope in steps with the number of steps taken */
1024 totaldrift = (edat->nsteps - 1)*edat->s[i].slope;
1030 ee_pr(pr_errest, sizeof(eebuf), eebuf);
1031 fprintf(stdout, "%-24s %10g %10s %10g %10g",
1032 leg[i], pr_aver, eebuf, pr_stddev, totaldrift);
1035 fprintf(stdout, " %10g", fee[i]);
1038 fprintf(stdout, " (%s)\n", enm[set[i]].unit);
1042 for (j = 0; (j < edat->nframes); j++)
1044 edat->s[i].ener[j] -= aver;
1050 totaldrift = (edat->nsteps - 1)*esum->s[0].slope;
1051 ee_pr(esum->s[0].ee/nmol, sizeof(eebuf), eebuf);
1052 fprintf(stdout, "%-24s %10g %10s %10s %10g (%s)",
1053 "Total", esum->s[0].av/nmol, eebuf,
1054 "--", totaldrift/nmol, enm[set[0]].unit);
1055 /* pr_aver,pr_stddev,a,totaldrift */
1058 fprintf(stdout, " %10g %10g\n",
1059 std::log(expEtot)/beta + esum->s[0].av/nmol, std::log(expEtot)/beta);
1063 fprintf(stdout, "\n");
1067 /* Do correlation function */
1068 if (edat->nframes > 1)
1070 Dt = delta_t/(edat->nframes - 1);
1078 const char* leg[] = { "Shear", "Bulk" };
1083 /* Assume pressure tensor is in Pxx Pxy Pxz Pyx Pyy Pyz Pzx Pzy Pzz */
1085 /* Symmetrise tensor! (and store in first three elements)
1086 * And subtract average pressure!
1089 for (i = 0; i < 12; i++)
1091 snew(eneset[i], edat->nframes);
1093 for (i = 0; (i < edat->nframes); i++)
1095 eneset[0][i] = 0.5*(edat->s[1].ener[i]+edat->s[3].ener[i]);
1096 eneset[1][i] = 0.5*(edat->s[2].ener[i]+edat->s[6].ener[i]);
1097 eneset[2][i] = 0.5*(edat->s[5].ener[i]+edat->s[7].ener[i]);
1098 for (j = 3; j <= 11; j++)
1100 eneset[j][i] = edat->s[j].ener[i];
1102 eneset[11][i] -= Pres;
1105 /* Determine integrals of the off-diagonal pressure elements */
1107 for (i = 0; i < 3; i++)
1109 snew(eneint[i], edat->nframes + 1);
1114 for (i = 0; i < edat->nframes; i++)
1116 eneint[0][i+1] = eneint[0][i] + 0.5*(edat->s[1].es[i].sum + edat->s[3].es[i].sum)*Dt/edat->points[i];
1117 eneint[1][i+1] = eneint[1][i] + 0.5*(edat->s[2].es[i].sum + edat->s[6].es[i].sum)*Dt/edat->points[i];
1118 eneint[2][i+1] = eneint[2][i] + 0.5*(edat->s[5].es[i].sum + edat->s[7].es[i].sum)*Dt/edat->points[i];
1121 einstein_visco(eviscofn, eviscoifn,
1122 3, edat->nframes+1, eneint, Vaver, Temp, Dt, oenv);
1124 for (i = 0; i < 3; i++)
1130 /*do_autocorr(corrfn,buf,nenergy,3,eneset,Dt,eacNormal,TRUE);*/
1131 /* Do it for shear viscosity */
1132 std::strcpy(buf, "Shear Viscosity");
1133 low_do_autocorr(corrfn, oenv, buf, edat->nframes, 3,
1134 (edat->nframes+1)/2, eneset, Dt,
1135 eacNormal, 1, TRUE, FALSE, FALSE, 0.0, 0.0, 0);
1137 /* Now for bulk viscosity */
1138 std::strcpy(buf, "Bulk Viscosity");
1139 low_do_autocorr(corrfn, oenv, buf, edat->nframes, 1,
1140 (edat->nframes+1)/2, &(eneset[11]), Dt,
1141 eacNormal, 1, TRUE, FALSE, FALSE, 0.0, 0.0, 0);
1143 factor = (Vaver*1e-26/(BOLTZMANN*Temp))*Dt;
1144 fp = xvgropen(visfn, buf, "Time (ps)", "\\8h\\4 (cp)", oenv);
1145 xvgr_legend(fp, asize(leg), leg, oenv);
1147 /* Use trapezium rule for integration */
1150 nout = get_acfnout();
1151 if ((nout < 2) || (nout >= edat->nframes/2))
1153 nout = edat->nframes/2;
1155 for (i = 1; (i < nout); i++)
1157 integral += 0.5*(eneset[0][i-1] + eneset[0][i])*factor;
1158 intBulk += 0.5*(eneset[11][i-1] + eneset[11][i])*factor;
1159 fprintf(fp, "%10g %10g %10g\n", (i*Dt), integral, intBulk);
1163 for (i = 0; i < 12; i++)
1173 std::strcpy(buf, "Autocorrelation of Energy Fluctuations");
1177 std::strcpy(buf, "Energy Autocorrelation");
1180 do_autocorr(corrfn, oenv, buf, edat->nframes,
1182 bSum ? &edat->s[nset-1].ener : eneset,
1183 (delta_t/edat->nframes), eacNormal, FALSE);
1189 static void print_time(FILE *fp, double t)
1191 fprintf(fp, "%12.6f", t);
1194 static void print1(FILE *fp, gmx_bool bDp, real e)
1198 fprintf(fp, " %16.12f", e);
1202 fprintf(fp, " %10.6f", e);
1206 static void fec(const char *ene2fn, const char *runavgfn,
1207 real reftemp, int nset, int set[], char *leg[],
1208 enerdata_t *edat, double time[],
1209 const gmx_output_env_t *oenv)
1211 const char * ravgleg[] = {
1212 "\\8D\\4E = E\\sB\\N-E\\sA\\N",
1213 "<e\\S-\\8D\\4E/kT\\N>\\s0..t\\N"
1217 int timecheck, nenergy, nenergy2, maxenergy;
1223 gmx_enxnm_t *enm = nullptr;
1227 /* read second energy file */
1230 enx = open_enx(ene2fn, "r");
1231 do_enxnms(enx, &(fr->nre), &enm);
1233 snew(eneset2, nset+1);
1239 /* This loop searches for the first frame (when -b option is given),
1240 * or when this has been found it reads just one energy frame
1244 bCont = do_enx(enx, fr);
1248 timecheck = check_times(fr->t);
1252 while (bCont && (timecheck < 0));
1254 /* Store energies for analysis afterwards... */
1255 if ((timecheck == 0) && bCont)
1259 if (nenergy2 >= maxenergy)
1262 for (i = 0; i <= nset; i++)
1264 srenew(eneset2[i], maxenergy);
1267 GMX_RELEASE_ASSERT(time != nullptr, "trying to dereference NULL time pointer");
1269 if (fr->t != time[nenergy2])
1271 fprintf(stderr, "\nWARNING time mismatch %g!=%g at frame %s\n",
1272 fr->t, time[nenergy2], gmx_step_str(fr->step, buf));
1274 for (i = 0; i < nset; i++)
1276 eneset2[i][nenergy2] = fr->ener[set[i]].e;
1282 while (bCont && (timecheck == 0));
1285 if (edat->nframes != nenergy2)
1287 fprintf(stderr, "\nWARNING file length mismatch %d!=%d\n",
1288 edat->nframes, nenergy2);
1290 nenergy = std::min(edat->nframes, nenergy2);
1292 /* calculate fe difference dF = -kT ln < exp(-(E_B-E_A)/kT) >_A */
1296 fp = xvgropen(runavgfn, "Running average free energy difference",
1297 "Time (" unit_time ")", "\\8D\\4E (" unit_energy ")", oenv);
1298 xvgr_legend(fp, asize(ravgleg), ravgleg, oenv);
1300 fprintf(stdout, "\n%-24s %10s\n",
1301 "Energy", "dF = -kT ln < exp(-(EB-EA)/kT) >A");
1303 beta = 1.0/(BOLTZ*reftemp);
1304 for (i = 0; i < nset; i++)
1306 if (gmx_strcasecmp(leg[i], enm[set[i]].name) != 0)
1308 fprintf(stderr, "\nWARNING energy set name mismatch %s!=%s\n",
1309 leg[i], enm[set[i]].name);
1311 for (j = 0; j < nenergy; j++)
1313 dE = eneset2[i][j] - edat->s[i].ener[j];
1314 sum += std::exp(-dE*beta);
1317 fprintf(fp, "%10g %10g %10g\n",
1318 time[j], dE, -BOLTZ*reftemp*std::log(sum/(j+1)) );
1321 aver = -BOLTZ*reftemp*std::log(sum/nenergy);
1322 fprintf(stdout, "%-24s %10g\n", leg[i], aver);
1332 static void do_dhdl(t_enxframe *fr, const t_inputrec *ir, FILE **fp_dhdl,
1333 const char *filename, gmx_bool bDp,
1334 int *blocks, int *hists, int *samples, int *nlambdas,
1335 const gmx_output_env_t *oenv)
1337 const char *dhdl = "dH/d\\lambda", *deltag = "\\DeltaH", *lambda = "\\lambda";
1338 char title[STRLEN], label_x[STRLEN], label_y[STRLEN], legend[STRLEN];
1340 int nblock_hist = 0, nblock_dh = 0, nblock_dhcoll = 0;
1343 double temp = 0, start_time = 0, delta_time = 0, start_lambda = 0;
1344 static int setnr = 0;
1345 double *native_lambda_vec = nullptr;
1346 const char **lambda_components = nullptr;
1347 int n_lambda_vec = 0;
1348 bool firstPass = true;
1350 /* now count the blocks & handle the global dh data */
1351 for (i = 0; i < fr->nblock; i++)
1353 if (fr->block[i].id == enxDHHIST)
1357 else if (fr->block[i].id == enxDH)
1361 else if (fr->block[i].id == enxDHCOLL)
1364 if ( (fr->block[i].nsub < 1) ||
1365 (fr->block[i].sub[0].type != xdr_datatype_double) ||
1366 (fr->block[i].sub[0].nr < 5))
1368 gmx_fatal(FARGS, "Unexpected block data");
1371 /* read the data from the DHCOLL block */
1372 temp = fr->block[i].sub[0].dval[0];
1373 start_time = fr->block[i].sub[0].dval[1];
1374 delta_time = fr->block[i].sub[0].dval[2];
1375 start_lambda = fr->block[i].sub[0].dval[3];
1376 if (fr->block[i].nsub > 1)
1380 n_lambda_vec = fr->block[i].sub[1].ival[1];
1381 snew(lambda_components, n_lambda_vec);
1382 snew(native_lambda_vec, n_lambda_vec);
1387 if (n_lambda_vec != fr->block[i].sub[1].ival[1])
1390 "Unexpected change of basis set in lambda");
1393 for (j = 0; j < n_lambda_vec; j++)
1395 native_lambda_vec[j] = fr->block[i].sub[0].dval[5+j];
1396 lambda_components[j] =
1397 efpt_singular_names[fr->block[i].sub[1].ival[2+j]];
1403 sfree(native_lambda_vec);
1404 sfree(lambda_components);
1405 if (nblock_hist == 0 && nblock_dh == 0)
1407 /* don't do anything */
1410 if (nblock_hist > 0 && nblock_dh > 0)
1412 gmx_fatal(FARGS, "This energy file contains both histogram dhdl data and non-histogram dhdl data. Don't know what to do.");
1418 /* we have standard, non-histogram data --
1419 call open_dhdl to open the file */
1420 /* TODO this is an ugly hack that needs to be fixed: this will only
1421 work if the order of data is always the same and if we're
1422 only using the g_energy compiled with the mdrun that produced
1424 *fp_dhdl = open_dhdl(filename, ir, oenv);
1428 sprintf(title, "N(%s)", deltag);
1429 sprintf(label_x, "%s (%s)", deltag, unit_energy);
1430 sprintf(label_y, "Samples");
1431 *fp_dhdl = xvgropen_type(filename, title, label_x, label_y, exvggtXNY, oenv);
1432 sprintf(buf, "T = %g (K), %s = %g", temp, lambda, start_lambda);
1433 xvgr_subtitle(*fp_dhdl, buf, oenv);
1437 (*hists) += nblock_hist;
1438 (*blocks) += nblock_dh;
1439 (*nlambdas) = nblock_hist+nblock_dh;
1441 /* write the data */
1442 if (nblock_hist > 0)
1444 gmx_int64_t sum = 0;
1446 for (i = 0; i < fr->nblock; i++)
1448 t_enxblock *blk = &(fr->block[i]);
1449 if (blk->id == enxDHHIST)
1451 double foreign_lambda, dx;
1453 int nhist, derivative;
1455 /* check the block types etc. */
1456 if ( (blk->nsub < 2) ||
1457 (blk->sub[0].type != xdr_datatype_double) ||
1458 (blk->sub[1].type != xdr_datatype_int64) ||
1459 (blk->sub[0].nr < 2) ||
1460 (blk->sub[1].nr < 2) )
1462 gmx_fatal(FARGS, "Unexpected block data in file");
1464 foreign_lambda = blk->sub[0].dval[0];
1465 dx = blk->sub[0].dval[1];
1466 nhist = blk->sub[1].lval[0];
1467 derivative = blk->sub[1].lval[1];
1468 for (j = 0; j < nhist; j++)
1471 x0 = blk->sub[1].lval[2+j];
1475 sprintf(legend, "N(%s(%s=%g) | %s=%g)",
1476 deltag, lambda, foreign_lambda,
1477 lambda, start_lambda);
1481 sprintf(legend, "N(%s | %s=%g)",
1482 dhdl, lambda, start_lambda);
1486 xvgr_new_dataset(*fp_dhdl, setnr, 1, lg, oenv);
1488 for (k = 0; k < blk->sub[j+2].nr; k++)
1493 hist = blk->sub[j+2].ival[k];
1496 fprintf(*fp_dhdl, "%g %d\n%g %d\n", xmin, hist,
1500 /* multiple histogram data blocks in one histogram
1501 mean that the second one is the reverse of the first one:
1502 for dhdl derivatives, it's important to know both the
1503 maximum and minimum values */
1508 (*samples) += static_cast<int>(sum/nblock_hist);
1515 for (i = 0; i < fr->nblock; i++)
1517 t_enxblock *blk = &(fr->block[i]);
1518 if (blk->id == enxDH)
1522 len = blk->sub[2].nr;
1526 if (len != blk->sub[2].nr)
1528 gmx_fatal(FARGS, "Length inconsistency in dhdl data");
1535 for (i = 0; i < len; i++)
1537 double time = start_time + delta_time*i;
1539 fprintf(*fp_dhdl, "%.4f ", time);
1541 for (j = 0; j < fr->nblock; j++)
1543 t_enxblock *blk = &(fr->block[j]);
1544 if (blk->id == enxDH)
1547 if (blk->sub[2].type == xdr_datatype_float)
1549 value = blk->sub[2].fval[i];
1553 value = blk->sub[2].dval[i];
1555 /* we need to decide which data type it is based on the count*/
1557 if (j == 1 && ir->bExpanded)
1559 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! */
1565 fprintf(*fp_dhdl, " %#.12g", value); /* print normal precision */
1569 fprintf(*fp_dhdl, " %#.8g", value); /* print normal precision */
1574 fprintf(*fp_dhdl, "\n");
1580 int gmx_energy(int argc, char *argv[])
1582 const char *desc[] = {
1583 "[THISMODULE] extracts energy components",
1584 "from an energy file. The user is prompted to interactively",
1585 "select the desired energy terms.[PAR]",
1587 "Average, RMSD, and drift are calculated with full precision from the",
1588 "simulation (see printed manual). Drift is calculated by performing",
1589 "a least-squares fit of the data to a straight line. The reported total drift",
1590 "is the difference of the fit at the first and last point.",
1591 "An error estimate of the average is given based on a block averages",
1592 "over 5 blocks using the full-precision averages. The error estimate",
1593 "can be performed over multiple block lengths with the options",
1594 "[TT]-nbmin[tt] and [TT]-nbmax[tt].",
1595 "[BB]Note[bb] that in most cases the energy files contains averages over all",
1596 "MD steps, or over many more points than the number of frames in",
1597 "energy file. This makes the [THISMODULE] statistics output more accurate",
1598 "than the [REF].xvg[ref] output. When exact averages are not present in the energy",
1599 "file, the statistics mentioned above are simply over the single, per-frame",
1600 "energy values.[PAR]",
1602 "The term fluctuation gives the RMSD around the least-squares fit.[PAR]",
1604 "Some fluctuation-dependent properties can be calculated provided",
1605 "the correct energy terms are selected, and that the command line option",
1606 "[TT]-fluct_props[tt] is given. The following properties",
1607 "will be computed:",
1609 "=============================== ===================",
1610 "Property Energy terms needed",
1611 "=============================== ===================",
1612 "Heat capacity C[SUB]p[sub] (NPT sims): Enthalpy, Temp",
1613 "Heat capacity C[SUB]v[sub] (NVT sims): Etot, Temp",
1614 "Thermal expansion coeff. (NPT): Enthalpy, Vol, Temp",
1615 "Isothermal compressibility: Vol, Temp",
1616 "Adiabatic bulk modulus: Vol, Temp",
1617 "=============================== ===================",
1619 "You always need to set the number of molecules [TT]-nmol[tt].",
1620 "The C[SUB]p[sub]/C[SUB]v[sub] computations do [BB]not[bb] include any corrections",
1621 "for quantum effects. Use the [gmx-dos] program if you need that (and you do).[PAR]"
1623 "Option [TT]-odh[tt] extracts and plots the free energy data",
1624 "(Hamiltoian differences and/or the Hamiltonian derivative dhdl)",
1625 "from the [TT]ener.edr[tt] file.[PAR]",
1627 "With [TT]-fee[tt] an estimate is calculated for the free-energy",
1628 "difference with an ideal gas state::",
1630 " [GRK]Delta[grk] A = A(N,V,T) - A[SUB]idealgas[sub](N,V,T) = kT [LN][CHEVRON][EXP]U[SUB]pot[sub]/kT[exp][chevron][ln]",
1631 " [GRK]Delta[grk] G = G(N,p,T) - G[SUB]idealgas[sub](N,p,T) = kT [LN][CHEVRON][EXP]U[SUB]pot[sub]/kT[exp][chevron][ln]",
1633 "where k is Boltzmann's constant, T is set by [TT]-fetemp[tt] and",
1634 "the average is over the ensemble (or time in a trajectory).",
1635 "Note that this is in principle",
1636 "only correct when averaging over the whole (Boltzmann) ensemble",
1637 "and using the potential energy. This also allows for an entropy",
1640 " [GRK]Delta[grk] S(N,V,T) = S(N,V,T) - S[SUB]idealgas[sub](N,V,T) = ([CHEVRON]U[SUB]pot[sub][chevron] - [GRK]Delta[grk] A)/T",
1641 " [GRK]Delta[grk] S(N,p,T) = S(N,p,T) - S[SUB]idealgas[sub](N,p,T) = ([CHEVRON]U[SUB]pot[sub][chevron] + pV - [GRK]Delta[grk] G)/T",
1644 "When a second energy file is specified ([TT]-f2[tt]), a free energy",
1645 "difference is calculated::",
1647 " dF = -kT [LN][CHEVRON][EXP]-(E[SUB]B[sub]-E[SUB]A[sub])/kT[exp][chevron][SUB]A[sub][ln] ,",
1649 "where E[SUB]A[sub] and E[SUB]B[sub] are the energies from the first and second energy",
1650 "files, and the average is over the ensemble A. The running average",
1651 "of the free energy difference is printed to a file specified by [TT]-ravg[tt].",
1652 "[BB]Note[bb] that the energies must both be calculated from the same trajectory."
1655 static gmx_bool bSum = FALSE, bFee = FALSE, bPrAll = FALSE, bFluct = FALSE, bDriftCorr = FALSE;
1656 static gmx_bool bDp = FALSE, bMutot = FALSE, bOrinst = FALSE, bOvec = FALSE, bFluctProps = FALSE;
1657 static int nmol = 1, nbmin = 5, nbmax = 5;
1658 static real reftemp = 300.0, ezero = 0;
1660 { "-fee", FALSE, etBOOL, {&bFee},
1661 "Do a free energy estimate" },
1662 { "-fetemp", FALSE, etREAL, {&reftemp},
1663 "Reference temperature for free energy calculation" },
1664 { "-zero", FALSE, etREAL, {&ezero},
1665 "Subtract a zero-point energy" },
1666 { "-sum", FALSE, etBOOL, {&bSum},
1667 "Sum the energy terms selected rather than display them all" },
1668 { "-dp", FALSE, etBOOL, {&bDp},
1669 "Print energies in high precision" },
1670 { "-nbmin", FALSE, etINT, {&nbmin},
1671 "Minimum number of blocks for error estimate" },
1672 { "-nbmax", FALSE, etINT, {&nbmax},
1673 "Maximum number of blocks for error estimate" },
1674 { "-mutot", FALSE, etBOOL, {&bMutot},
1675 "Compute the total dipole moment from the components" },
1676 { "-aver", FALSE, etBOOL, {&bPrAll},
1677 "Also print the exact average and rmsd stored in the energy frames (only when 1 term is requested)" },
1678 { "-nmol", FALSE, etINT, {&nmol},
1679 "Number of molecules in your sample: the energies are divided by this number" },
1680 { "-fluct_props", FALSE, etBOOL, {&bFluctProps},
1681 "Compute properties based on energy fluctuations, like heat capacity" },
1682 { "-driftcorr", FALSE, etBOOL, {&bDriftCorr},
1683 "Useful only for calculations of fluctuation properties. The drift in the observables will be subtracted before computing the fluctuation properties."},
1684 { "-fluc", FALSE, etBOOL, {&bFluct},
1685 "Calculate autocorrelation of energy fluctuations rather than energy itself" },
1686 { "-orinst", FALSE, etBOOL, {&bOrinst},
1687 "Analyse instantaneous orientation data" },
1688 { "-ovec", FALSE, etBOOL, {&bOvec},
1689 "Also plot the eigenvectors with [TT]-oten[tt]" }
1691 static const char *setnm[] = {
1692 "Pres-XX", "Pres-XY", "Pres-XZ", "Pres-YX", "Pres-YY",
1693 "Pres-YZ", "Pres-ZX", "Pres-ZY", "Pres-ZZ", "Temperature",
1694 "Volume", "Pressure"
1697 FILE *out = nullptr;
1698 FILE *fp_dhdl = nullptr;
1702 gmx_enxnm_t *enm = nullptr;
1703 t_enxframe *frame, *fr = nullptr;
1705 #define NEXT (1-cur)
1707 gmx_int64_t start_step;
1710 gmx_bool bFoundStart, bCont, bVisco;
1712 double *time = nullptr;
1714 int *set = nullptr, i, j, nset, sss;
1715 gmx_bool *bIsEner = nullptr;
1716 char **leg = nullptr;
1718 gmx_output_env_t *oenv;
1719 int dh_blocks = 0, dh_hists = 0, dh_samples = 0, dh_lambdas = 0;
1722 { efEDR, "-f", nullptr, ffREAD },
1723 { efEDR, "-f2", nullptr, ffOPTRD },
1724 { efTPR, "-s", nullptr, ffOPTRD },
1725 { efXVG, "-o", "energy", ffWRITE },
1726 { efXVG, "-viol", "violaver", ffOPTWR },
1727 { efXVG, "-pairs", "pairs", ffOPTWR },
1728 { efXVG, "-corr", "enecorr", ffOPTWR },
1729 { efXVG, "-vis", "visco", ffOPTWR },
1730 { efXVG, "-evisco", "evisco", ffOPTWR },
1731 { efXVG, "-eviscoi", "eviscoi", ffOPTWR },
1732 { efXVG, "-ravg", "runavgdf", ffOPTWR },
1733 { efXVG, "-odh", "dhdl", ffOPTWR }
1735 #define NFILE asize(fnm)
1740 ppa = add_acf_pargs(&npargs, pa);
1741 if (!parse_common_args(&argc, argv,
1742 PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END,
1743 NFILE, fnm, npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
1749 bDHDL = opt2bSet("-odh", NFILE, fnm);
1754 fp = open_enx(ftp2fn(efEDR, NFILE, fnm), "r");
1755 do_enxnms(fp, &nre, &enm);
1759 bVisco = opt2bSet("-vis", NFILE, fnm);
1761 t_inputrec irInstance;
1762 t_inputrec *ir = &irInstance;
1768 nset = asize(setnm);
1770 /* This is nasty code... To extract Pres tensor, Volume and Temperature */
1771 for (j = 0; j < nset; j++)
1773 for (i = 0; i < nre; i++)
1775 if (std::strstr(enm[i].name, setnm[j]))
1783 if (gmx_strcasecmp(setnm[j], "Volume") == 0)
1785 printf("Enter the box volume (" unit_volume "): ");
1786 if (1 != scanf("%lf", &dbl))
1788 gmx_fatal(FARGS, "Error reading user input");
1794 gmx_fatal(FARGS, "Could not find term %s for viscosity calculation",
1802 set = select_by_name(nre, enm, &nset);
1804 /* Print all the different units once */
1805 sprintf(buf, "(%s)", enm[set[0]].unit);
1806 for (i = 1; i < nset; i++)
1808 for (j = 0; j < i; j++)
1810 if (std::strcmp(enm[set[i]].unit, enm[set[j]].unit) == 0)
1817 std::strcat(buf, ", (");
1818 std::strcat(buf, enm[set[i]].unit);
1819 std::strcat(buf, ")");
1822 out = xvgropen(opt2fn("-o", NFILE, fnm), "GROMACS Energies", "Time (ps)", buf,
1826 for (i = 0; (i < nset); i++)
1828 leg[i] = enm[set[i]].name;
1832 leg[nset] = gmx_strdup("Sum");
1833 xvgr_legend(out, nset+1, (const char**)leg, oenv);
1837 xvgr_legend(out, nset, (const char**)leg, oenv);
1840 snew(bIsEner, nset);
1841 for (i = 0; (i < nset); i++)
1844 for (j = 0; (j <= F_ETOT); j++)
1846 bIsEner[i] = bIsEner[i] ||
1847 (gmx_strcasecmp(interaction_function[j].longname, leg[i]) == 0);
1850 if (bPrAll && nset > 1)
1852 gmx_fatal(FARGS, "Printing averages can only be done when a single set is selected");
1858 get_dhdl_parms(ftp2fn(efTPR, NFILE, fnm), ir);
1861 /* Initiate energies and set them to zero */
1865 edat.step = nullptr;
1866 edat.steps = nullptr;
1867 edat.points = nullptr;
1868 edat.bHaveSums = TRUE;
1871 /* Initiate counters */
1872 bFoundStart = FALSE;
1877 /* This loop searches for the first frame (when -b option is given),
1878 * or when this has been found it reads just one energy frame
1882 bCont = do_enx(fp, &(frame[NEXT]));
1885 timecheck = check_times(frame[NEXT].t);
1888 while (bCont && (timecheck < 0));
1890 if ((timecheck == 0) && bCont)
1892 /* We read a valid frame, so we can use it */
1893 fr = &(frame[NEXT]);
1897 /* The frame contains energies, so update cur */
1900 if (edat.nframes % 1000 == 0)
1902 srenew(edat.step, edat.nframes+1000);
1903 std::memset(&(edat.step[edat.nframes]), 0, 1000*sizeof(edat.step[0]));
1904 srenew(edat.steps, edat.nframes+1000);
1905 std::memset(&(edat.steps[edat.nframes]), 0, 1000*sizeof(edat.steps[0]));
1906 srenew(edat.points, edat.nframes+1000);
1907 std::memset(&(edat.points[edat.nframes]), 0, 1000*sizeof(edat.points[0]));
1909 for (i = 0; i < nset; i++)
1911 srenew(edat.s[i].ener, edat.nframes+1000);
1912 std::memset(&(edat.s[i].ener[edat.nframes]), 0,
1913 1000*sizeof(edat.s[i].ener[0]));
1914 srenew(edat.s[i].es, edat.nframes+1000);
1915 std::memset(&(edat.s[i].es[edat.nframes]), 0,
1916 1000*sizeof(edat.s[i].es[0]));
1921 edat.step[nfr] = fr->step;
1926 /* Initiate the previous step data */
1927 start_step = fr->step;
1929 /* Initiate the energy sums */
1930 edat.steps[nfr] = 1;
1931 edat.points[nfr] = 1;
1932 for (i = 0; i < nset; i++)
1935 edat.s[i].es[nfr].sum = fr->ener[sss].e;
1936 edat.s[i].es[nfr].sum2 = 0;
1943 edat.steps[nfr] = fr->nsteps;
1947 /* mdrun only calculated the energy at energy output
1948 * steps. We don't need to check step intervals.
1950 edat.points[nfr] = 1;
1951 for (i = 0; i < nset; i++)
1954 edat.s[i].es[nfr].sum = fr->ener[sss].e;
1955 edat.s[i].es[nfr].sum2 = 0;
1958 edat.bHaveSums = FALSE;
1960 else if (fr->step - start_step + 1 == edat.nsteps + fr->nsteps)
1962 /* We have statistics to the previous frame */
1963 edat.points[nfr] = fr->nsum;
1964 for (i = 0; i < nset; i++)
1967 edat.s[i].es[nfr].sum = fr->ener[sss].esum;
1968 edat.s[i].es[nfr].sum2 = fr->ener[sss].eav;
1970 edat.npoints += fr->nsum;
1974 /* The interval does not match fr->nsteps:
1975 * can not do exact averages.
1977 edat.bHaveSums = FALSE;
1980 edat.nsteps = fr->step - start_step + 1;
1982 for (i = 0; i < nset; i++)
1984 edat.s[i].ener[nfr] = fr->ener[set[i]].e;
1988 * Store energies for analysis afterwards...
1990 if (!bDHDL && (fr->nre > 0))
1992 if (edat.nframes % 1000 == 0)
1994 srenew(time, edat.nframes+1000);
1996 time[edat.nframes] = fr->t;
2001 do_dhdl(fr, ir, &fp_dhdl, opt2fn("-odh", NFILE, fnm), bDp, &dh_blocks, &dh_hists, &dh_samples, &dh_lambdas, oenv);
2004 /*******************************************
2006 *******************************************/
2013 /* We skip frames with single points (usually only the first frame),
2014 * since they would result in an average plot with outliers.
2018 print_time(out, fr->t);
2019 print1(out, bDp, fr->ener[set[0]].e);
2020 print1(out, bDp, fr->ener[set[0]].esum/fr->nsum);
2021 print1(out, bDp, std::sqrt(fr->ener[set[0]].eav/fr->nsum));
2027 print_time(out, fr->t);
2031 for (i = 0; i < nset; i++)
2033 sum += fr->ener[set[i]].e;
2035 print1(out, bDp, sum/nmol-ezero);
2039 for (i = 0; (i < nset); i++)
2043 print1(out, bDp, (fr->ener[set[i]].e)/nmol-ezero);
2047 print1(out, bDp, fr->ener[set[i]].e);
2057 while (bCont && (timecheck == 0));
2059 fprintf(stderr, "\n");
2070 gmx_fio_fclose(fp_dhdl);
2071 printf("\n\nWrote %d lambda values with %d samples as ",
2072 dh_lambdas, dh_samples);
2075 printf("%d dH histograms ", dh_hists);
2079 printf("%d dH data blocks ", dh_blocks);
2081 printf("to %s\n", opt2fn("-odh", NFILE, fnm));
2086 gmx_fatal(FARGS, "No dH data in %s\n", opt2fn("-f", NFILE, fnm));
2092 double dt = (frame[cur].t-start_t)/(edat.nframes-1);
2093 analyse_ener(opt2bSet("-corr", NFILE, fnm), opt2fn("-corr", NFILE, fnm),
2094 opt2fn("-evisco", NFILE, fnm), opt2fn("-eviscoi", NFILE, fnm),
2096 bVisco, opt2fn("-vis", NFILE, fnm),
2098 start_step, start_t, frame[cur].step, frame[cur].t,
2100 nset, set, bIsEner, leg, enm, Vaver, ezero, nbmin, nbmax,
2104 calc_fluctuation_props(stdout, bDriftCorr, dt, nset, nmol, leg, &edat,
2108 if (opt2bSet("-f2", NFILE, fnm))
2110 fec(opt2fn("-f2", NFILE, fnm), opt2fn("-ravg", NFILE, fnm),
2111 reftemp, nset, set, leg, &edat, time, oenv);
2114 done_enerdata_t(nset, &edat);
2116 free_enxframe(&frame[0]);
2117 free_enxframe(&frame[1]);
2119 free_enxnms(nre, enm);
2125 const char *nxy = "-nxy";
2127 do_view(oenv, opt2fn("-o", NFILE, fnm), nxy);
2128 do_view(oenv, opt2fn_null("-ravg", NFILE, fnm), nxy);
2129 do_view(oenv, opt2fn_null("-odh", NFILE, fnm), nxy);
2131 output_env_done(oenv);