Convert gmx_mtop_t to C++
[gromacs.git] / src / gromacs / gmxana / gmx_energy.cpp
blob77de9a322276b520d18fd9f480a8495f9fab2745
1 /*
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.
37 #include "gmxpre.h"
39 #include <cmath>
40 #include <cstdlib>
41 #include <cstring>
43 #include <algorithm>
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;
75 typedef struct {
76 real sum;
77 real sum2;
78 } exactsum_t;
80 typedef struct {
81 real *ener;
82 exactsum_t *es;
83 gmx_bool bExactStat;
84 double av;
85 double rmsd;
86 double ee;
87 double slope;
88 } enerdat_t;
90 typedef struct {
91 gmx_int64_t nsteps;
92 gmx_int64_t npoints;
93 int nframes;
94 int *step;
95 int *steps;
96 int *points;
97 enerdat_t *s;
98 gmx_bool bHaveSums;
99 } enerdata_t;
101 static void done_enerdata_t(int nset, enerdata_t *edat)
103 sfree(edat->step);
104 sfree(edat->steps);
105 sfree(edat->points);
106 for (int i = 0; i < nset; i++)
108 sfree(edat->s[i].ener);
109 sfree(edat->s[i].es);
111 sfree(edat->s);
114 static void chomp(char *buf)
116 int len = std::strlen(buf);
118 while ((len > 0) && (buf[len-1] == '\n'))
120 buf[len-1] = '\0';
121 len--;
125 static int *select_by_name(int nre, gmx_enxnm_t *nm, int *nset)
127 gmx_bool *bE;
128 int k, kk, j, i, nmatch, nind, nss;
129 int *set;
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)
138 bVerbose = FALSE;
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");
147 snew(newnm, nre);
148 j = 0;
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)
155 *ptr = '-';
157 if (bVerbose)
159 if (j == 0)
161 if (k > 0)
163 fprintf(stderr, "\n");
165 bLong = FALSE;
166 for (kk = k; kk < k+4; kk++)
168 if (kk < nre && std::strlen(nm[kk].name) > 14)
170 bLong = TRUE;
174 else
176 fprintf(stderr, " ");
178 if (!bLong)
180 fprintf(stderr, fm4, k+1, newnm[k]);
181 j++;
182 if (j == 4)
184 j = 0;
187 else
189 fprintf(stderr, fm2, k+1, newnm[k]);
190 j++;
191 if (j == 2)
193 j = 0;
198 if (bVerbose)
200 fprintf(stderr, "\n\n");
203 snew(bE, nre);
205 bEOF = FALSE;
206 while (!bEOF && (fgets2(buf, STRLEN-1, stdin)))
208 /* Remove newlines */
209 chomp(buf);
211 /* Remove spaces */
212 trim(buf);
214 /* Empty line means end of input */
215 bEOF = (std::strlen(buf) == 0);
216 if (!bEOF)
218 ptr = buf;
221 if (!bEOF)
223 /* First try to read an integer */
224 nss = sscanf(ptr, "%d", &nind);
225 if (nss == 1)
227 /* Zero means end of input */
228 if (nind == 0)
230 bEOF = TRUE;
232 else if ((1 <= nind) && (nind <= nre))
234 bE[nind-1] = TRUE;
236 else
238 fprintf(stderr, "number %d is out of range\n", nind);
241 else
243 /* Now try to read a string */
244 nmatch = 0;
245 for (nind = 0; nind < nre; nind++)
247 if (gmx_strcasecmp(newnm[nind], ptr) == 0)
249 bE[nind] = TRUE;
250 nmatch++;
253 if (nmatch == 0)
255 i = std::strlen(ptr);
256 nmatch = 0;
257 for (nind = 0; nind < nre; nind++)
259 if (gmx_strncasecmp(newnm[nind], ptr, i) == 0)
261 bE[nind] = TRUE;
262 nmatch++;
265 if (nmatch == 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)
275 trim(ptr);
278 while (!bEOF && (ptr && (std::strlen(ptr) > 0)));
282 snew(set, nre);
283 for (i = (*nset) = 0; (i < nre); i++)
285 if (bE[i])
287 set[(*nset)++] = i;
291 sfree(bE);
293 if (*nset == 0)
295 gmx_fatal(FARGS, "No energy terms selected");
298 for (i = 0; (i < nre); i++)
300 sfree(newnm[i]);
302 sfree(newnm);
304 return set;
307 static void get_dhdl_parms(const char *topnm, t_inputrec *ir)
309 gmx_mtop_t mtop;
310 int natoms;
311 matrix box;
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)
322 FILE *fp0, *fp1;
323 double av[4], avold[4];
324 double fac, di;
325 int i, j, m, nf4;
327 nf4 = nint/4 + 1;
329 for (i = 0; i <= nsets; i++)
331 avold[i] = 0;
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++)
341 av[m] = 0;
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]);
349 av[m] += di;
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++)
358 av[m] = fac*av[m];
359 fprintf(fp0, " %10g", av[m]);
361 fprintf(fp0, "\n");
362 fprintf(fp1, "%10g", (i + 0.5)*dt);
363 for (m = 0; (m <= nsets); m++)
365 fprintf(fp1, " %10g", (av[m]-avold[m])/dt);
366 avold[m] = av[m];
368 fprintf(fp1, "\n");
370 xvgrclose(fp0);
371 xvgrclose(fp1);
374 typedef struct {
375 gmx_int64_t np;
376 double sum;
377 double sav;
378 double sav2;
379 } ee_sum_t;
381 typedef struct {
382 int b;
383 ee_sum_t sum;
384 gmx_int64_t nst;
385 gmx_int64_t nst_min;
386 } ener_ee_t;
388 static void clear_ee_sum(ee_sum_t *ees)
390 ees->sav = 0;
391 ees->sav2 = 0;
392 ees->np = 0;
393 ees->sum = 0;
396 static void add_ee_sum(ee_sum_t *ees, double sum, int np)
398 ees->np += np;
399 ees->sum += sum;
402 static void add_ee_av(ee_sum_t *ees)
404 double av;
406 av = ees->sum/ees->np;
407 ees->sav += av;
408 ees->sav2 += av*av;
409 ees->np = 0;
410 ees->sum = 0;
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)
420 if (debug)
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);
427 eee->b++;
428 if (eee->b == 1 || eee->nst < eee->nst_min)
430 eee->nst_min = eee->nst;
432 eee->nst = 0;
435 static void calc_averages(int nset, enerdata_t *edat, int nbmin, int nbmax)
437 int nb, i, f, nee;
438 double sum, sum2, sump, see2;
439 gmx_int64_t np, p, bound_nb;
440 enerdat_t *ed;
441 exactsum_t *es;
442 gmx_bool bAllZero;
443 double x, sx, sy, sxx, sxy;
444 ener_ee_t *eee;
446 /* Check if we have exact statistics over all points */
447 for (i = 0; i < nset; i++)
449 ed = &edat->s[i];
450 ed->bExactStat = FALSE;
451 if (edat->bHaveSums)
453 /* All energy file sum entries 0 signals no exact sums.
454 * But if all energy values are 0, we still have exact sums.
456 bAllZero = TRUE;
457 for (f = 0; f < edat->nframes && !ed->bExactStat; f++)
459 if (ed->ener[i] != 0)
461 bAllZero = FALSE;
463 ed->bExactStat = (ed->es[f].sum != 0);
465 if (bAllZero)
467 ed->bExactStat = TRUE;
472 snew(eee, nbmax+1);
473 for (i = 0; i < nset; i++)
475 ed = &edat->s[i];
477 sum = 0;
478 sum2 = 0;
479 np = 0;
480 sx = 0;
481 sy = 0;
482 sxx = 0;
483 sxy = 0;
484 for (nb = nbmin; nb <= nbmax; nb++)
486 eee[nb].b = 0;
487 clear_ee_sum(&eee[nb].sum);
488 eee[nb].nst = 0;
489 eee[nb].nst_min = 0;
491 for (f = 0; f < edat->nframes; f++)
493 es = &ed->es[f];
495 if (ed->bExactStat)
497 /* Add the sum and the sum of variances to the totals. */
498 p = edat->points[f];
499 sump = es->sum;
500 sum2 += es->sum2;
501 if (np > 0)
503 sum2 += gmx::square(sum/np - (sum + es->sum)/(np + p))
504 *np*(np + p)/p;
507 else
509 /* Add a single value to the sum and sum of squares. */
510 p = 1;
511 sump = ed->ener[f];
512 sum2 += gmx::square(sump);
515 /* sum has to be increased after sum2 */
516 np += p;
517 sum += sump;
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);
523 sx += p*x;
524 sy += sump;
525 sxx += p*x*x;
526 sxy += x*sump;
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)
537 set_ee_av(&eee[nb]);
539 if (f == 0)
541 eee[nb].nst = 1;
543 else
545 eee[nb].nst += edat->step[f] - edat->step[f-1];
547 if (ed->bExactStat)
549 add_ee_sum(&eee[nb].sum, es->sum, edat->points[f]);
551 else
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)
558 set_ee_av(&eee[nb]);
563 edat->s[i].av = sum/np;
564 if (ed->bExactStat)
566 edat->s[i].rmsd = std::sqrt(sum2/np);
568 else
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);
577 else
579 edat->s[i].slope = 0;
582 nee = 0;
583 see2 = 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.
589 if (debug)
591 char buf1[STEPSTRSIZE], buf2[STEPSTRSIZE];
592 fprintf(debug, "Requested %d blocks, we have %d blocks, min %s nsteps %s\n",
593 nb, eee[nb].b,
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);
600 nee++;
603 if (nee > 0)
605 edat->s[i].ee = std::sqrt(see2/nee);
607 else
609 edat->s[i].ee = -1;
612 sfree(eee);
615 static enerdata_t *calc_sum(int nset, enerdata_t *edat, int nbmin, int nbmax)
617 enerdata_t *esum;
618 enerdat_t *s;
619 int f, i;
620 double sum;
622 snew(esum, 1);
623 *esum = *edat;
624 snew(esum->s, 1);
625 s = &esum->s[0];
626 snew(s->ener, esum->nframes);
627 snew(s->es, esum->nframes);
629 s->bExactStat = TRUE;
630 s->slope = 0;
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++)
642 sum = 0;
643 for (i = 0; i < nset; i++)
645 sum += edat->s[i].ener[f];
647 s->ener[f] = sum;
648 sum = 0;
649 for (i = 0; i < nset; i++)
651 sum += edat->s[i].es[f].sum;
653 s->es[f].sum = sum;
654 s->es[f].sum2 = 0;
657 calc_averages(1, esum, nbmin, nbmax);
659 return esum;
662 static void ee_pr(double ee, int buflen, char *buf)
664 snprintf(buf, buflen, "%s", "--");
665 if (ee >= 0)
667 /* Round to two decimals by printing. */
668 char tmp[100];
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. */
679 int i, j, k;
680 double delta;
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,
709 int nset, int nmol,
710 char **leg, enerdata_t *edat,
711 int nbmin, int nbmax)
713 int i, j;
714 double vv, v, h, varv, hh, varh, tt, cv, cp, alpha, kappa, dcp, varet;
715 double NANO3;
716 enum {
717 eVol, eEnth, eTemp, eEtot, eNR
719 const char *my_ener[] = { "Volume", "Enthalpy", "Temperature", "Total Energy" };
720 int ii[eNR];
722 NANO3 = NANO*NANO*NANO;
723 if (!bDriftCorr)
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");
729 else
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]++)
740 /* if (ii[i] < nset)
741 fprintf(fp,"Found %s data.\n",my_ener[i]);
742 */ }
743 /* Compute it all! */
744 alpha = kappa = cp = dcp = cv = NOTSET;
746 /* Temperature */
747 tt = NOTSET;
748 if (ii[eTemp] < nset)
750 tt = edat->s[ii[eTemp]].av;
752 /* Volume */
753 vv = varv = NOTSET;
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);
760 /* Enthalpy */
761 hh = varh = NOTSET;
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));
768 /* Total energy */
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));
777 /* Alpha, dcp */
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;
786 v_sum += v;
787 h_sum += h;
788 vh_sum += (v*h);
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);
797 if (tt != NOTSET)
799 if (nmol < 2)
801 fprintf(fp, "\nWARNING: nmol = %d, this may not be what you want.\n",
802 nmol);
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)
813 if (varv != NOTSET)
815 fprintf(fp, "varv = %10g (m^6)\n", varv*AVOGADRO/nmol);
818 if (vv != NOTSET)
820 fprintf(fp, "Volume = %10g m^3/mol\n",
821 vv*AVOGADRO/nmol);
823 if (varh != NOTSET)
825 fprintf(fp, "Enthalpy = %10g kJ/mol\n",
826 hh*AVOGADRO/(KILO*nmol));
828 if (alpha != NOTSET)
830 fprintf(fp, "Coefficient of Thermal Expansion Alpha_P = %10g (1/K)\n",
831 alpha);
833 if (kappa != NOTSET)
835 fprintf(fp, "Isothermal Compressibility Kappa = %10g (m^3/J)\n",
836 kappa);
837 fprintf(fp, "Adiabatic bulk modulus = %10g (J/m^3)\n",
838 1.0/kappa);
840 if (cp != NOTSET)
842 fprintf(fp, "Heat capacity at constant pressure Cp = %10g J/(mol K)\n",
843 cp);
845 if (cv != NOTSET)
847 fprintf(fp, "Heat capacity at constant volume Cv = %10g J/(mol K)\n",
848 cv);
850 if (dcp != NOTSET)
852 fprintf(fp, "Cp-Cv = %10g J/(mol K)\n",
853 dcp);
855 please_cite(fp, "Allen1987a");
857 else
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,
869 real reftemp,
870 enerdata_t *edat,
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)
877 FILE *fp;
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;
884 gmx_int64_t nsteps;
885 int nexact, nnotexact;
886 int i, j, nout;
887 char buf[256], eebuf[100];
889 nsteps = step - start_step + 1;
890 if (nsteps < 1)
892 fprintf(stdout, "Not enough steps (%s) for statistics\n",
893 gmx_step_str(nsteps, buf));
895 else
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);
905 if (bSum)
907 esum = calc_sum(nset, edat, nbmin, nbmax);
910 if (!edat->bHaveSums)
912 nexact = 0;
913 nnotexact = nset;
915 else
917 nexact = 0;
918 nnotexact = 0;
919 for (i = 0; (i < nset); i++)
921 if (edat->s[i].bExactStat)
923 nexact++;
925 else
927 nnotexact++;
932 if (nnotexact == 0)
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",
940 edat->nframes);
942 else
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");
961 if (bFee)
963 fprintf(stdout, " %10s\n", "-kT ln<e^(E/kT)>");
965 else
967 fprintf(stdout, "\n");
969 fprintf(stdout, "-------------------------------------------------------------------------------\n");
971 /* Initiate locals, only used with -sum */
972 expEtot = 0;
973 if (bFee)
975 beta = 1.0/(BOLTZ*reftemp);
976 snew(fee, nset);
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;
984 if (bFee)
986 expE = 0;
987 for (j = 0; (j < edat->nframes); j++)
989 expE += std::exp(beta*(edat->s[i].ener[j] - aver)/nmol);
991 if (bSum)
993 expEtot += expE/edat->nframes;
996 fee[i] = std::log(expE/edat->nframes)/beta + aver/nmol;
998 if (std::strstr(leg[i], "empera") != nullptr)
1000 Temp = aver;
1002 else if (std::strstr(leg[i], "olum") != nullptr)
1004 Vaver = aver;
1006 else if (std::strstr(leg[i], "essure") != nullptr)
1008 Pres = aver;
1010 if (bIsEner[i])
1012 pr_aver = aver/nmol-ezero;
1013 pr_stddev = stddev/nmol;
1014 pr_errest = errest/nmol;
1016 else
1018 pr_aver = aver;
1019 pr_stddev = stddev;
1020 pr_errest = errest;
1023 /* Multiply the slope in steps with the number of steps taken */
1024 totaldrift = (edat->nsteps - 1)*edat->s[i].slope;
1025 if (bIsEner[i])
1027 totaldrift /= nmol;
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);
1033 if (bFee)
1035 fprintf(stdout, " %10g", fee[i]);
1038 fprintf(stdout, " (%s)\n", enm[set[i]].unit);
1040 if (bFluct)
1042 for (j = 0; (j < edat->nframes); j++)
1044 edat->s[i].ener[j] -= aver;
1048 if (bSum)
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 */
1056 if (bFee)
1058 fprintf(stdout, " %10g %10g\n",
1059 std::log(expEtot)/beta + esum->s[0].av/nmol, std::log(expEtot)/beta);
1061 else
1063 fprintf(stdout, "\n");
1067 /* Do correlation function */
1068 if (edat->nframes > 1)
1070 Dt = delta_t/(edat->nframes - 1);
1072 else
1074 Dt = 0;
1076 if (bVisco)
1078 const char* leg[] = { "Shear", "Bulk" };
1079 real factor;
1080 real **eneset;
1081 real **eneint;
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!
1088 snew(eneset, 12);
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 */
1106 snew(eneint, 3);
1107 for (i = 0; i < 3; i++)
1109 snew(eneint[i], edat->nframes + 1);
1111 eneint[0][0] = 0;
1112 eneint[1][0] = 0;
1113 eneint[2][0] = 0;
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++)
1126 sfree(eneint[i]);
1128 sfree(eneint);
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 */
1148 integral = 0;
1149 intBulk = 0;
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);
1161 xvgrclose(fp);
1163 for (i = 0; i < 12; i++)
1165 sfree(eneset[i]);
1167 sfree(eneset);
1169 else if (bCorr)
1171 if (bFluct)
1173 std::strcpy(buf, "Autocorrelation of Energy Fluctuations");
1175 else
1177 std::strcpy(buf, "Energy Autocorrelation");
1179 #if 0
1180 do_autocorr(corrfn, oenv, buf, edat->nframes,
1181 bSum ? 1 : nset,
1182 bSum ? &edat->s[nset-1].ener : eneset,
1183 (delta_t/edat->nframes), eacNormal, FALSE);
1184 #endif
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)
1196 if (bDp)
1198 fprintf(fp, " %16.12f", e);
1200 else
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"
1215 FILE *fp;
1216 ener_file_t enx;
1217 int timecheck, nenergy, nenergy2, maxenergy;
1218 int i, j;
1219 gmx_bool bCont;
1220 real aver, beta;
1221 real **eneset2;
1222 double dE, sum;
1223 gmx_enxnm_t *enm = nullptr;
1224 t_enxframe *fr;
1225 char buf[22];
1227 /* read second energy file */
1228 snew(fr, 1);
1229 enm = nullptr;
1230 enx = open_enx(ene2fn, "r");
1231 do_enxnms(enx, &(fr->nre), &enm);
1233 snew(eneset2, nset+1);
1234 nenergy2 = 0;
1235 maxenergy = 0;
1236 timecheck = 0;
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);
1246 if (bCont)
1248 timecheck = check_times(fr->t);
1252 while (bCont && (timecheck < 0));
1254 /* Store energies for analysis afterwards... */
1255 if ((timecheck == 0) && bCont)
1257 if (fr->nre > 0)
1259 if (nenergy2 >= maxenergy)
1261 maxenergy += 1000;
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;
1278 nenergy2++;
1282 while (bCont && (timecheck == 0));
1284 /* check */
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 */
1293 fp = nullptr;
1294 if (runavgfn)
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");
1302 sum = 0;
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);
1315 if (fp)
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);
1324 if (fp)
1326 xvgrclose(fp);
1328 sfree(fr);
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];
1339 char buf[STRLEN];
1340 int nblock_hist = 0, nblock_dh = 0, nblock_dhcoll = 0;
1341 int i, j, k;
1342 /* coll data */
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)
1355 nblock_hist++;
1357 else if (fr->block[i].id == enxDH)
1359 nblock_dh++;
1361 else if (fr->block[i].id == enxDHCOLL)
1363 nblock_dhcoll++;
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)
1378 if (firstPass)
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);
1383 firstPass = false;
1385 else
1387 if (n_lambda_vec != fr->block[i].sub[1].ival[1])
1389 gmx_fatal(FARGS,
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]];
1402 // Clean up!
1403 sfree(native_lambda_vec);
1404 sfree(lambda_components);
1405 if (nblock_hist == 0 && nblock_dh == 0)
1407 /* don't do anything */
1408 return;
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.");
1414 if (!*fp_dhdl)
1416 if (nblock_dh > 0)
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
1423 the ener.edr. */
1424 *fp_dhdl = open_dhdl(filename, ir, oenv);
1426 else
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;
1445 /* histograms */
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;
1452 gmx_int64_t x0;
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++)
1470 const char *lg[1];
1471 x0 = blk->sub[1].lval[2+j];
1473 if (!derivative)
1475 sprintf(legend, "N(%s(%s=%g) | %s=%g)",
1476 deltag, lambda, foreign_lambda,
1477 lambda, start_lambda);
1479 else
1481 sprintf(legend, "N(%s | %s=%g)",
1482 dhdl, lambda, start_lambda);
1485 lg[0] = legend;
1486 xvgr_new_dataset(*fp_dhdl, setnr, 1, lg, oenv);
1487 setnr++;
1488 for (k = 0; k < blk->sub[j+2].nr; k++)
1490 int hist;
1491 double xmin, xmax;
1493 hist = blk->sub[j+2].ival[k];
1494 xmin = (x0+k)*dx;
1495 xmax = (x0+k+1)*dx;
1496 fprintf(*fp_dhdl, "%g %d\n%g %d\n", xmin, hist,
1497 xmax, hist);
1498 sum += 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 */
1504 dx = -dx;
1508 (*samples) += static_cast<int>(sum/nblock_hist);
1510 else
1512 /* raw dh */
1513 int len = 0;
1515 for (i = 0; i < fr->nblock; i++)
1517 t_enxblock *blk = &(fr->block[i]);
1518 if (blk->id == enxDH)
1520 if (len == 0)
1522 len = blk->sub[2].nr;
1524 else
1526 if (len != blk->sub[2].nr)
1528 gmx_fatal(FARGS, "Length inconsistency in dhdl data");
1533 (*samples) += len;
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)
1546 double value;
1547 if (blk->sub[2].type == xdr_datatype_float)
1549 value = blk->sub[2].fval[i];
1551 else
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! */
1561 else
1563 if (bDp)
1565 fprintf(*fp_dhdl, " %#.12g", value); /* print normal precision */
1567 else
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",
1638 "estimate using::",
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;
1659 t_pargs pa[] = {
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;
1699 ener_file_t fp;
1700 int timecheck = 0;
1701 enerdata_t edat;
1702 gmx_enxnm_t *enm = nullptr;
1703 t_enxframe *frame, *fr = nullptr;
1704 int cur = 0;
1705 #define NEXT (1-cur)
1706 int nre, nfr;
1707 gmx_int64_t start_step;
1708 real start_t;
1709 gmx_bool bDHDL;
1710 gmx_bool bFoundStart, bCont, bVisco;
1711 double sum, dbl;
1712 double *time = nullptr;
1713 real Vaver;
1714 int *set = nullptr, i, j, nset, sss;
1715 gmx_bool *bIsEner = nullptr;
1716 char **leg = nullptr;
1717 char buf[256];
1718 gmx_output_env_t *oenv;
1719 int dh_blocks = 0, dh_hists = 0, dh_samples = 0, dh_lambdas = 0;
1721 t_filenm fnm[] = {
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)
1736 int npargs;
1737 t_pargs *ppa;
1739 npargs = asize(pa);
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))
1745 sfree(ppa);
1746 return 0;
1749 bDHDL = opt2bSet("-odh", NFILE, fnm);
1751 nset = 0;
1753 snew(frame, 2);
1754 fp = open_enx(ftp2fn(efEDR, NFILE, fnm), "r");
1755 do_enxnms(fp, &nre, &enm);
1757 Vaver = -1;
1759 bVisco = opt2bSet("-vis", NFILE, fnm);
1761 t_inputrec irInstance;
1762 t_inputrec *ir = &irInstance;
1764 if (!bDHDL)
1766 if (bVisco)
1768 nset = asize(setnm);
1769 snew(set, nset);
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]))
1777 set[j] = i;
1778 break;
1781 if (i == nre)
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");
1790 Vaver = dbl;
1792 else
1794 gmx_fatal(FARGS, "Could not find term %s for viscosity calculation",
1795 setnm[j]);
1800 else
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)
1812 break;
1815 if (j == i)
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,
1823 oenv);
1825 snew(leg, nset+1);
1826 for (i = 0; (i < nset); i++)
1828 leg[i] = enm[set[i]].name;
1830 if (bSum)
1832 leg[nset] = gmx_strdup("Sum");
1833 xvgr_legend(out, nset+1, (const char**)leg, oenv);
1835 else
1837 xvgr_legend(out, nset, (const char**)leg, oenv);
1840 snew(bIsEner, nset);
1841 for (i = 0; (i < nset); i++)
1843 bIsEner[i] = FALSE;
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");
1856 else if (bDHDL)
1858 get_dhdl_parms(ftp2fn(efTPR, NFILE, fnm), ir);
1861 /* Initiate energies and set them to zero */
1862 edat.nsteps = 0;
1863 edat.npoints = 0;
1864 edat.nframes = 0;
1865 edat.step = nullptr;
1866 edat.steps = nullptr;
1867 edat.points = nullptr;
1868 edat.bHaveSums = TRUE;
1869 snew(edat.s, nset);
1871 /* Initiate counters */
1872 bFoundStart = FALSE;
1873 start_step = 0;
1874 start_t = 0;
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]));
1883 if (bCont)
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]);
1895 if (fr->nre > 0)
1897 /* The frame contains energies, so update cur */
1898 cur = NEXT;
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]));
1920 nfr = edat.nframes;
1921 edat.step[nfr] = fr->step;
1923 if (!bFoundStart)
1925 bFoundStart = TRUE;
1926 /* Initiate the previous step data */
1927 start_step = fr->step;
1928 start_t = fr->t;
1929 /* Initiate the energy sums */
1930 edat.steps[nfr] = 1;
1931 edat.points[nfr] = 1;
1932 for (i = 0; i < nset; i++)
1934 sss = set[i];
1935 edat.s[i].es[nfr].sum = fr->ener[sss].e;
1936 edat.s[i].es[nfr].sum2 = 0;
1938 edat.nsteps = 1;
1939 edat.npoints = 1;
1941 else
1943 edat.steps[nfr] = fr->nsteps;
1945 if (fr->nsum <= 1)
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++)
1953 sss = set[i];
1954 edat.s[i].es[nfr].sum = fr->ener[sss].e;
1955 edat.s[i].es[nfr].sum2 = 0;
1957 edat.npoints += 1;
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++)
1966 sss = set[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;
1972 else
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;
1997 edat.nframes++;
1999 if (bDHDL)
2001 do_dhdl(fr, ir, &fp_dhdl, opt2fn("-odh", NFILE, fnm), bDp, &dh_blocks, &dh_hists, &dh_samples, &dh_lambdas, oenv);
2004 /*******************************************
2005 * E N E R G I E S
2006 *******************************************/
2007 else
2009 if (fr->nre > 0)
2011 if (bPrAll)
2013 /* We skip frames with single points (usually only the first frame),
2014 * since they would result in an average plot with outliers.
2016 if (fr->nsum > 1)
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));
2022 fprintf(out, "\n");
2025 else
2027 print_time(out, fr->t);
2028 if (bSum)
2030 sum = 0;
2031 for (i = 0; i < nset; i++)
2033 sum += fr->ener[set[i]].e;
2035 print1(out, bDp, sum/nmol-ezero);
2037 else
2039 for (i = 0; (i < nset); i++)
2041 if (bIsEner[i])
2043 print1(out, bDp, (fr->ener[set[i]].e)/nmol-ezero);
2045 else
2047 print1(out, bDp, fr->ener[set[i]].e);
2051 fprintf(out, "\n");
2057 while (bCont && (timecheck == 0));
2059 fprintf(stderr, "\n");
2060 done_ener_file(fp);
2061 if (out)
2063 xvgrclose(out);
2066 if (bDHDL)
2068 if (fp_dhdl)
2070 gmx_fio_fclose(fp_dhdl);
2071 printf("\n\nWrote %d lambda values with %d samples as ",
2072 dh_lambdas, dh_samples);
2073 if (dh_hists > 0)
2075 printf("%d dH histograms ", dh_hists);
2077 if (dh_blocks > 0)
2079 printf("%d dH data blocks ", dh_blocks);
2081 printf("to %s\n", opt2fn("-odh", NFILE, fnm));
2084 else
2086 gmx_fatal(FARGS, "No dH data in %s\n", opt2fn("-f", NFILE, fnm));
2090 else
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),
2095 bFee, bSum, bFluct,
2096 bVisco, opt2fn("-vis", NFILE, fnm),
2097 nmol,
2098 start_step, start_t, frame[cur].step, frame[cur].t,
2099 reftemp, &edat,
2100 nset, set, bIsEner, leg, enm, Vaver, ezero, nbmin, nbmax,
2101 oenv);
2102 if (bFluctProps)
2104 calc_fluctuation_props(stdout, bDriftCorr, dt, nset, nmol, leg, &edat,
2105 nbmin, nbmax);
2108 if (opt2bSet("-f2", NFILE, fnm))
2110 fec(opt2fn("-f2", NFILE, fnm), opt2fn("-ravg", NFILE, fnm),
2111 reftemp, nset, set, leg, &edat, time, oenv);
2113 // Clean up!
2114 done_enerdata_t(nset, &edat);
2115 sfree(time);
2116 free_enxframe(&frame[0]);
2117 free_enxframe(&frame[1]);
2118 sfree(frame);
2119 free_enxnms(nre, enm);
2120 sfree(ppa);
2121 sfree(set);
2122 sfree(leg);
2123 sfree(bIsEner);
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);
2133 return 0;