2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
47 #include "gromacs/commandline/pargs.h"
48 #include "gromacs/fileio/matio.h"
49 #include "gromacs/fileio/pdbio.h"
50 #include "gromacs/fileio/xvgr.h"
51 #include "gromacs/gmxana/gmx_ana.h"
52 #include "gromacs/gmxana/gstat.h"
53 #include "gromacs/math/functions.h"
54 #include "gromacs/math/units.h"
55 #include "gromacs/math/utilities.h"
56 #include "gromacs/math/vec.h"
57 #include "gromacs/topology/topology.h"
58 #include "gromacs/utility/arraysize.h"
59 #include "gromacs/utility/fatalerror.h"
60 #include "gromacs/utility/futil.h"
61 #include "gromacs/utility/smalloc.h"
64 static int index2(const int* ibox, int x, int y)
66 return (ibox[1] * x + y);
69 static int index3(const int* ibox, int x, int y, int z)
71 return (ibox[2] * (ibox[1] * x + y) + z);
74 static int64_t indexn(int ndim, const int* ibox, const int* nxyz)
79 /* Compute index in 1-D array */
81 for (k = 0; (k < ndim); k++)
84 for (kk = k + 1; (kk < ndim); kk++)
95 int Nx; /* x grid points in unit cell */
96 int Ny; /* y grid points in unit cell */
97 int Nz; /* z grid points in unit cell */
98 int dmin[3]; /* starting point x,y,z*/
99 int dmax[3]; /* ending point x,y,z */
100 real cell[6]; /* usual cell parameters */
104 static void lo_write_xplor(XplorMap* map, const char* file)
109 fp = gmx_ffopen(file, "w");
110 /* The REMARKS part is the worst part of the XPLOR format
111 * and may cause problems with some programs
113 fprintf(fp, "\n 2 !NTITLE\n");
114 fprintf(fp, " REMARKS Energy Landscape from GROMACS\n");
115 fprintf(fp, " REMARKS DATE: 2004-12-21 \n");
117 " %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
128 "%12.5E%12.5E%12.5E%12.5E%12.5E%12.5E\n",
135 fprintf(fp, "ZYX\n");
138 for (n = 0; n < map->Nz; n++, z++)
140 fprintf(fp, "%8d\n", z);
141 for (i = 0; i < map->Nx * map->Ny; i += 6)
143 for (j = 0; j < 6; j++)
145 if (i + j < map->Nx * map->Ny)
147 fprintf(fp, "%12.5E", map->ed[n * map->Nx * map->Ny + i + j]);
153 fprintf(fp, " -9999\n");
157 static void write_xplor(const char* file, const real* data, int* ibox, const real dmin[], const real dmax[])
166 snew(xm->ed, xm->Nx * xm->Ny * xm->Nz);
168 for (k = 0; (k < xm->Nz); k++)
170 for (j = 0; (j < xm->Ny); j++)
172 for (i = 0; (i < xm->Nx); i++)
174 xm->ed[n++] = data[index3(ibox, i, j, k)];
178 xm->cell[0] = dmax[XX] - dmin[XX];
179 xm->cell[1] = dmax[YY] - dmin[YY];
180 xm->cell[2] = dmax[ZZ] - dmin[ZZ];
181 xm->cell[3] = xm->cell[4] = xm->cell[5] = 90;
183 clear_ivec(xm->dmin);
184 xm->dmax[XX] = ibox[XX] - 1;
185 xm->dmax[YY] = ibox[YY] - 1;
186 xm->dmax[ZZ] = ibox[ZZ] - 1;
188 lo_write_xplor(xm, file);
194 static void normalize_p_e(int len, double* P, const int* nbin, real* E, real pmin)
199 for (i = 0; (i < len); i++)
204 E[i] = E[i] / nbin[i];
207 printf("Ptot = %g\n", Ptot);
208 for (i = 0; (i < len); i++)
211 /* Have to check for pmin after normalizing to prevent "stretching"
227 static int comp_minima(const void* a, const void* b)
229 const t_minimum* ma = reinterpret_cast<const t_minimum*>(a);
230 const t_minimum* mb = reinterpret_cast<const t_minimum*>(b);
233 if (ma->ener < mb->ener)
237 else if (ma->ener > mb->ener)
247 static inline void print_minimum(FILE* fp, int num, const t_minimum* min)
250 "Minimum %d at index "
251 "%" PRId64 " energy %10.3f\n",
257 static inline void add_minimum(FILE* fp, int num, const t_minimum* min, t_minimum* mm)
259 print_minimum(fp, num, min);
260 mm[num].index = min->index;
261 mm[num].ener = min->ener;
264 static inline gmx_bool is_local_minimum_from_below(const t_minimum* this_min,
270 return ((dimension_index == dimension_min)
271 || ((dimension_index > dimension_min) && (this_min->ener < W[neighbour_index])));
272 /* Note over/underflow within W cannot occur. */
275 static inline gmx_bool is_local_minimum_from_above(const t_minimum* this_min,
281 return ((dimension_index == dimension_max)
282 || ((dimension_index < dimension_max) && (this_min->ener < W[neighbour_index])));
283 /* Note over/underflow within W cannot occur. */
286 static void pick_minima(const char* logfile, int* ibox, int ndim, int len, real W[])
290 t_minimum *mm, this_min;
292 int loopmax, loopcounter;
296 fp = gmx_ffopen(logfile, "w");
297 /* Loop over each element in the array of dimenion ndim seeking
298 * minima with respect to every dimension. Specialized loops for
299 * speed with ndim == 2 and ndim == 3. */
303 /* This is probably impossible to reach anyway. */
306 for (i = 0; (i < ibox[0]); i++)
308 for (j = 0; (j < ibox[1]); j++)
310 /* Get the index of this point in the flat array */
311 this_min.index = index2(ibox, i, j);
312 this_min.ener = W[this_min.index];
313 if (is_local_minimum_from_below(&this_min, i, 0, index2(ibox, i - 1, j), W)
314 && is_local_minimum_from_above(&this_min, i, ibox[0] - 1, index2(ibox, i + 1, j), W)
315 && is_local_minimum_from_below(&this_min, j, 0, index2(ibox, i, j - 1), W)
316 && is_local_minimum_from_above(&this_min, j, ibox[1] - 1, index2(ibox, i, j + 1), W))
318 add_minimum(fp, nmin, &this_min, mm);
325 for (i = 0; (i < ibox[0]); i++)
327 for (j = 0; (j < ibox[1]); j++)
329 for (k = 0; (k < ibox[2]); k++)
331 /* Get the index of this point in the flat array */
332 this_min.index = index3(ibox, i, j, k);
333 this_min.ener = W[this_min.index];
334 if (is_local_minimum_from_below(&this_min, i, 0, index3(ibox, i - 1, j, k), W)
335 && is_local_minimum_from_above(
336 &this_min, i, ibox[0] - 1, index3(ibox, i + 1, j, k), W)
337 && is_local_minimum_from_below(&this_min, j, 0, index3(ibox, i, j - 1, k), W)
338 && is_local_minimum_from_above(
339 &this_min, j, ibox[1] - 1, index3(ibox, i, j + 1, k), W)
340 && is_local_minimum_from_below(&this_min, k, 0, index3(ibox, i, j, k - 1), W)
341 && is_local_minimum_from_above(
342 &this_min, k, ibox[2] - 1, index3(ibox, i, j, k + 1), W))
344 add_minimum(fp, nmin, &this_min, mm);
352 /* Note this treats ndim == 1 and ndim > 3 */
354 /* Set up an ndim-dimensional vector to loop over the points
355 * on the grid. (0,0,0, ... 0) is an acceptable place to
357 snew(this_point, ndim);
359 /* Determine the number of points of the ndim-dimensional
362 for (i = 1; i < ndim; i++)
368 while (loopmax > loopcounter)
370 gmx_bool bMin = TRUE;
372 /* Get the index of this_point in the flat array */
373 this_min.index = indexn(ndim, ibox, this_point);
374 this_min.ener = W[this_min.index];
376 /* Is this_point a minimum from above and below in each
378 for (i = 0; bMin && (i < ndim); i++)
380 /* Save the index of this_point within the curent
381 * dimension so we can change that index in the
382 * this_point array for use with indexn(). */
383 int index = this_point[i];
386 && is_local_minimum_from_below(
387 &this_min, index, 0, indexn(ndim, ibox, this_point), W);
390 && is_local_minimum_from_above(
391 &this_min, index, ibox[i] - 1, indexn(ndim, ibox, this_point), W);
396 add_minimum(fp, nmin, &this_min, mm);
400 /* update global loop counter */
403 /* Avoid underflow of this_point[i] */
404 if (loopmax > loopcounter)
406 /* update this_point non-recursively */
409 while (ibox[i] == this_point[i])
413 /* this_point[i] cannot underflow because
414 * loopmax > loopcounter. */
423 qsort(mm, nmin, sizeof(mm[0]), comp_minima);
424 fprintf(fp, "Minima sorted after energy\n");
425 for (i = 0; (i < nmin); i++)
427 print_minimum(fp, i, &mm[i]);
433 static void do_sham(const char* fn,
462 real * min_eig, *max_eig;
463 real * axis_x, *axis_y, *axis_z, *axis = nullptr;
465 real ** PP, *W, *E, **WW, **EE, *S, **SS, *M, *bE;
468 double * bfac, efac, bref, Pmax, Wmin, Wmax, Winf, Emin, Emax, Einf, Smin, Smax, Sinf;
470 int i, j, k, imin, len, index, *nbin, *bindex, bi;
475 t_rgb rlo = { 0, 0, 0 };
476 t_rgb rhi = { 1, 1, 1 };
478 /* Determine extremes for the eigenvectors */
485 for (i = 0; (i < neig); i++)
487 /* Check for input constraints */
488 min_eig[i] = max_eig[i] = eig[i][0];
489 for (j = 0; (j < n); j++)
491 min_eig[i] = std::min(min_eig[i], eig[i][j]);
492 max_eig[i] = std::max(max_eig[i], eig[i][j]);
493 delta[i] = (max_eig[i] - min_eig[i]) / (2.0 * ibox[i]);
495 /* Add some extra space, half a bin on each side, unless the
496 * user has set the limits.
500 if (max_eig[i] > xmax[i])
502 gmx_warning("Your xmax[%d] value %f is smaller than the largest data point %f",
507 max_eig[i] = xmax[i];
511 max_eig[i] += delta[i];
516 if (min_eig[i] < xmin[i])
518 gmx_warning("Your xmin[%d] value %f is larger than the smallest data point %f",
523 min_eig[i] = xmin[i];
527 min_eig[i] -= delta[i];
529 bfac[i] = ibox[i] / (max_eig[i] - min_eig[i]);
532 bref = 1 / (gmx::c_boltz * Tref);
534 if (bGE || nenerT == 2)
538 for (j = 0; (j < n); j++)
542 bE[j] = bref * enerT[0][j];
546 bE[j] = (bref - 1 / (gmx::c_boltz * enerT[1][j])) * enerT[0][j];
548 Emin = std::min(Emin, static_cast<double>(bE[j]));
556 for (i = 0; (i < neig); i++)
560 printf("There are %d bins in the %d-dimensional histogram. Beta-Emin = %g\n", len, neig, Emin);
570 /* Loop over projections */
571 for (j = 0; (j < n); j++)
573 /* Loop over dimensions */
575 for (i = 0; (i < neig); i++)
577 nxyz[i] = static_cast<int>(bfac[i] * (eig[i][j] - min_eig[i]));
578 if (nxyz[i] < 0 || nxyz[i] >= ibox[i])
585 index = indexn(neig, ibox, nxyz);
586 range_check(index, 0, len);
587 /* Compute the exponential factor */
590 efac = std::exp(-bE[j] + Emin);
596 /* Apply the bin volume correction for a multi-dimensional distance */
597 for (i = 0; i < neig; i++)
603 else if (idim[i] == 3)
605 efac /= gmx::square(eig[i][j]);
607 else if (idim[i] == -1)
609 efac /= std::sin(gmx::c_deg2Rad * eig[i][j]);
612 /* Update the probability */
614 /* Update the energy */
617 E[index] += enerT[0][j];
619 /* Statistics: which "structure" in which bin */
624 /* Normalize probability */
625 normalize_p_e(len, P, nbin, E, pmin);
627 /* Compute boundaries for the Free energy */
631 /* Recompute Emin: it may have changed due to averaging */
634 for (i = 0; (i < len); i++)
638 Pmax = std::max(P[i], Pmax);
639 W[i] = -gmx::c_boltz * Tref * std::log(P[i]);
645 Emin = std::min(static_cast<double>(E[i]), Emin);
646 Emax = std::max(static_cast<double>(E[i]), Emax);
647 Wmax = std::max(static_cast<double>(W[i]), Wmax);
667 /* Write out the free energy as a function of bin index */
668 fp = gmx_ffopen(fn, "w");
669 for (i = 0; (i < len); i++)
674 S[i] = E[i] - W[i] - Smin;
675 fprintf(fp, "%5d %10.5e %10.5e %10.5e\n", i, W[i], E[i], S[i]);
685 /* Organize the structures in the bins */
687 snew(b->index, len + 1);
690 for (i = 0; (i < len); i++)
692 b->index[i + 1] = b->index[i] + nbin[i];
695 for (i = 0; (i < n); i++)
698 b->a[b->index[bi] + nbin[bi]] = i;
701 /* Consistency check */
702 /* This no longer applies when we allow the plot to be smaller
703 than the sampled space.
704 for(i=0; (i<len); i++) {
705 if (nbin[i] != (b->index[i+1] - b->index[i]))
706 gmx_fatal(FARGS,"nbin[%d] = %d, should be %d",i,nbin[i],
707 b->index[i+1] - b->index[i]);
710 /* Write the index file */
711 fp = gmx_ffopen(ndx, "w");
712 for (i = 0; (i < len); i++)
716 fprintf(fp, "[ %d ]\n", i);
717 for (j = b->index[i]; (j < b->index[i + 1]); j++)
719 fprintf(fp, "%d\n", b->a[j] + 1);
724 snew(axis_x, ibox[0] + 1);
725 snew(axis_y, ibox[1] + 1);
726 snew(axis_z, ibox[2] + 1);
727 maxbox = std::max(ibox[0], std::max(ibox[1], ibox[2]));
728 snew(PP, maxbox * maxbox);
729 snew(WW, maxbox * maxbox);
730 snew(EE, maxbox * maxbox);
731 snew(SS, maxbox * maxbox);
732 for (i = 0; (i < std::min(neig, 3)); i++)
736 case 0: axis = axis_x; break;
737 case 1: axis = axis_y; break;
738 case 2: axis = axis_z; break;
741 for (j = 0; j <= ibox[i]; j++)
743 axis[j] = min_eig[i] + j / bfac[i];
747 pick_minima(logf, ibox, neig, len, W);
752 flags = MAT_SPATIAL_X | MAT_SPATIAL_Y;
755 /* Dump to XPM file */
757 for (i = 0; (i < ibox[0]); i++)
759 snew(PP[i], ibox[1]);
760 for (j = 0; j < ibox[1]; j++)
762 PP[i][j] = P[i * ibox[1] + j];
764 WW[i] = &(W[i * ibox[1]]);
765 EE[i] = &(E[i * ibox[1]]);
766 SS[i] = &(S[i * ibox[1]]);
768 fp = gmx_ffopen(xpmP, "w");
771 "Probability Distribution",
786 fp = gmx_ffopen(xpm, "w");
789 "Gibbs Energy Landscape",
804 fp = gmx_ffopen(xpm2, "w");
807 "Enthalpy Landscape",
822 fp = gmx_ffopen(xpm3, "w");
843 /* Dump to PDB file */
844 fp = gmx_ffopen(pdb, "w");
845 for (i = 0; (i < ibox[0]); i++)
847 xxx[XX] = 3 * i + 1.5 * (1 - ibox[0]);
848 for (j = 0; (j < ibox[1]); j++)
850 xxx[YY] = 3 * j + 1.5 * (1 - ibox[1]);
851 for (k = 0; (k < ibox[2]); k++)
853 xxx[ZZ] = 3 * k + 1.5 * (1 - ibox[2]);
854 index = index3(ibox, i, j, k);
858 "%-6s%5d %-4.4s%3.3s %4d %8.3f%8.3f%8.3f%6.2f%6.2f\n",
874 write_xplor("out.xplor", W, ibox, min_eig, max_eig);
875 nxyz[XX] = imin / (ibox[1] * ibox[2]);
876 nxyz[YY] = (imin - nxyz[XX] * ibox[1] * ibox[2]) / ibox[2];
877 nxyz[ZZ] = imin % ibox[2];
878 for (i = 0; (i < ibox[0]); i++)
881 for (j = 0; (j < ibox[1]); j++)
883 WW[i][j] = W[index3(ibox, i, j, nxyz[ZZ])];
886 snew(buf, std::strlen(xpm) + 4);
887 sprintf(buf, "%s", xpm);
888 sprintf(&buf[std::strlen(xpm) - 4], "12.xpm");
889 fp = gmx_ffopen(buf, "w");
892 "Gibbs Energy Landscape",
907 for (i = 0; (i < ibox[0]); i++)
909 for (j = 0; (j < ibox[2]); j++)
911 WW[i][j] = W[index3(ibox, i, nxyz[YY], j)];
914 sprintf(&buf[std::strlen(xpm) - 4], "13.xpm");
915 fp = gmx_ffopen(buf, "w");
918 "SHAM Energy Landscape",
933 for (i = 0; (i < ibox[1]); i++)
935 for (j = 0; (j < ibox[2]); j++)
937 WW[i][j] = W[index3(ibox, nxyz[XX], i, j)];
940 sprintf(&buf[std::strlen(xpm) - 4], "23.xpm");
941 fp = gmx_ffopen(buf, "w");
944 "SHAM Energy Landscape",
963 static void ehisto(const char* fh, int n, real** enerT, const gmx_output_env_t* oenv)
966 int i, j, k, nbin, blength;
968 real *T, bmin, bmax, bwidth;
976 for (j = 1; (j < n); j++)
978 for (k = 0; (k < nbin); k++)
980 if (T[k] == enerT[1][j])
989 T[nbin] = enerT[1][j];
992 bmin = std::min(enerT[0][j], bmin);
993 bmax = std::max(enerT[0][j], bmax);
996 blength = static_cast<int>((bmax - bmin) / bwidth + 2);
998 for (i = 0; (i < nbin); i++)
1000 snew(histo[i], blength);
1002 for (j = 0; (j < n); j++)
1004 k = static_cast<int>((enerT[0][j] - bmin) / bwidth);
1005 histo[bindex[j]][k]++;
1007 fp = xvgropen(fh, "Energy distribution", "E (kJ/mol)", "", oenv);
1008 for (j = 0; (j < blength); j++)
1010 fprintf(fp, "%8.3f", bmin + j * bwidth);
1011 for (k = 0; (k < nbin); k++)
1013 fprintf(fp, " %6d", histo[k][j]);
1020 int gmx_sham(int argc, char* argv[])
1022 const char* desc[] = {
1023 "[THISMODULE] makes multi-dimensional free-energy, enthalpy and entropy plots.",
1024 "[THISMODULE] reads one or more [REF].xvg[ref] files and analyzes data sets.",
1025 "The basic purpose of [THISMODULE] is to plot Gibbs free energy landscapes",
1026 "(option [TT]-ls[tt])",
1027 "by Bolzmann inverting multi-dimensional histograms (option [TT]-lp[tt]),",
1029 "make enthalpy (option [TT]-lsh[tt]) and entropy (option [TT]-lss[tt])",
1030 "plots. The histograms can be made for any quantities the user supplies.",
1031 "A line in the input file may start with a time",
1032 "(see option [TT]-time[tt]) and any number of [IT]y[it]-values may follow.",
1033 "Multiple sets can also be",
1034 "read when they are separated by & (option [TT]-n[tt]),",
1035 "in this case only one [IT]y[it]-value is read from each line.",
1036 "All lines starting with # and @ are skipped.",
1038 "Option [TT]-ge[tt] can be used to supply a file with free energies",
1039 "when the ensemble is not a Boltzmann ensemble, but needs to be biased",
1040 "by this free energy. One free energy value is required for each",
1041 "(multi-dimensional) data point in the [TT]-f[tt] input.",
1043 "Option [TT]-ene[tt] can be used to supply a file with energies.",
1044 "These energies are used as a weighting function in the single",
1045 "histogram analysis method by Kumar et al. When temperatures",
1046 "are supplied (as a second column in the file), an experimental",
1047 "weighting scheme is applied. In addition the vales",
1048 "are used for making enthalpy and entropy plots.",
1050 "With option [TT]-dim[tt], dimensions can be gives for distances.",
1051 "When a distance is 2- or 3-dimensional, the circumference or surface",
1052 "sampled by two particles increases with increasing distance.",
1053 "Depending on what one would like to show, one can choose to correct",
1054 "the histogram and free-energy for this volume effect.",
1055 "The probability is normalized by r and r^2 for dimensions of 2 and 3, ",
1057 "A value of -1 is used to indicate an angle in degrees between two",
1058 "vectors: a sin(angle) normalization will be applied.",
1059 "[BB]Note[bb] that for angles between vectors the inner-product or cosine",
1060 "is the natural quantity to use, as it will produce bins of the same",
1063 static real tb = -1, te = -1;
1064 static gmx_bool bHaveT = TRUE, bDer = FALSE;
1065 static gmx_bool bSham = TRUE;
1066 static real Tref = 298.15, pmin = 0, ttol = 0, pmax = 0, gmax = 0, emin = 0, emax = 0;
1067 static rvec nrdim = { 1, 1, 1 };
1068 static rvec nrbox = { 32, 32, 32 };
1069 static rvec xmin = { 0, 0, 0 }, xmax = { 1, 1, 1 };
1070 static int nsets_in = 1, nlevels = 25;
1072 { "-time", FALSE, etBOOL, { &bHaveT }, "Expect a time in the input" },
1073 { "-b", FALSE, etREAL, { &tb }, "First time to read from set" },
1074 { "-e", FALSE, etREAL, { &te }, "Last time to read from set" },
1075 { "-ttol", FALSE, etREAL, { &ttol }, "Tolerance on time in appropriate units (usually ps)" },
1080 "Read this number of sets separated by lines containing only an ampersand" },
1081 { "-d", FALSE, etBOOL, { &bDer }, "Use the derivative" },
1086 "Turn off energy weighting even if energies are given" },
1087 { "-tsham", FALSE, etREAL, { &Tref }, "Temperature for single histogram analysis" },
1092 "Minimum probability. Anything lower than this will be set to zero" },
1097 "Dimensions for distances, used for volume correction (max 3 values, dimensions > 3 will "
1098 "get the same value as the last)" },
1103 "Number of bins for energy landscapes (max 3 values, dimensions > 3 will get the same "
1104 "value as the last)" },
1109 "Minimum for the axes in energy landscape (see above for > 3 dimensions)" },
1114 "Maximum for the axes in energy landscape (see above for > 3 dimensions)" },
1115 { "-pmax", FALSE, etREAL, { &pmax }, "Maximum probability in output, default is calculate" },
1116 { "-gmax", FALSE, etREAL, { &gmax }, "Maximum free energy in output, default is calculate" },
1117 { "-emin", FALSE, etREAL, { &emin }, "Minimum enthalpy in output, default is calculate" },
1118 { "-emax", FALSE, etREAL, { &emax }, "Maximum enthalpy in output, default is calculate" },
1119 { "-nlevels", FALSE, etINT, { &nlevels }, "Number of levels for energy landscape" },
1121 #define NPA asize(pa)
1123 int n, e_n, nset, e_nset = 0, i, *idim, *ibox;
1124 real ** val, **et_val, *t, *e_t, e_dt, dt;
1126 const char * fn_ge, *fn_ene;
1127 gmx_output_env_t* oenv;
1128 int64_t num_grid_points;
1131 { efXVG, "-f", "graph", ffREAD }, { efXVG, "-ge", "gibbs", ffOPTRD },
1132 { efXVG, "-ene", "esham", ffOPTRD }, { efXVG, "-dist", "ener", ffOPTWR },
1133 { efXVG, "-histo", "edist", ffOPTWR }, { efNDX, "-bin", "bindex", ffOPTWR },
1134 { efXPM, "-lp", "prob", ffOPTWR }, { efXPM, "-ls", "gibbs", ffOPTWR },
1135 { efXPM, "-lsh", "enthalpy", ffOPTWR }, { efXPM, "-lss", "entropy", ffOPTWR },
1136 { efPDB, "-ls3", "gibbs3", ffOPTWR }, { efLOG, "-g", "shamlog", ffOPTWR }
1138 #define NFILE asize(fnm)
1143 if (!parse_common_args(
1144 &argc, argv, PCA_CAN_VIEW, NFILE, fnm, npargs, pa, asize(desc), desc, 0, nullptr, &oenv))
1149 val = read_xvg_time(opt2fn("-f", NFILE, fnm),
1151 opt2parg_bSet("-b", npargs, pa),
1153 opt2parg_bSet("-e", npargs, pa),
1160 printf("Read %d sets of %d points, dt = %g\n\n", nset, n, dt);
1162 fn_ge = opt2fn_null("-ge", NFILE, fnm);
1163 fn_ene = opt2fn_null("-ene", NFILE, fnm);
1165 if (fn_ge && fn_ene)
1167 gmx_fatal(FARGS, "Can not do free energy and energy corrections at the same time");
1170 if (fn_ge || fn_ene)
1172 et_val = read_xvg_time(fn_ge ? fn_ge : fn_ene,
1174 opt2parg_bSet("-b", npargs, pa),
1176 opt2parg_bSet("-e", npargs, pa),
1187 gmx_fatal(FARGS, "Can only handle one free energy component in %s", fn_ge);
1192 if (e_nset != 1 && e_nset != 2)
1195 "Can only handle one energy component or one energy and one T in %s",
1202 "Number of energies (%d) does not match number of entries (%d) in %s",
1205 opt2fn("-f", NFILE, fnm));
1213 if (fn_ene && et_val)
1215 ehisto(opt2fn("-histo", NFILE, fnm), e_n, et_val, oenv);
1218 snew(idim, std::max(3, nset));
1219 snew(ibox, std::max(3, nset));
1220 snew(rmin, std::max(3, nset));
1221 snew(rmax, std::max(3, nset));
1222 for (i = 0; (i < std::min(3, nset)); i++)
1224 idim[i] = static_cast<int>(nrdim[i]);
1225 ibox[i] = static_cast<int>(nrbox[i]);
1229 for (; (i < nset); i++)
1231 idim[i] = static_cast<int>(nrdim[2]);
1232 ibox[i] = static_cast<int>(nrbox[2]);
1237 /* Check that the grid size is manageable. */
1238 num_grid_points = ibox[0];
1239 for (i = 1; i < nset; i++)
1242 if (!check_int_multiply_for_overflow(num_grid_points, ibox[i], &result))
1245 "The number of dimensions and grid points is too large for this tool.\n");
1247 num_grid_points = result;
1249 /* The number of grid points fits in a int64_t. */
1251 do_sham(opt2fn("-dist", NFILE, fnm),
1252 opt2fn("-bin", NFILE, fnm),
1253 opt2fn("-lp", NFILE, fnm),
1254 opt2fn("-ls", NFILE, fnm),
1255 opt2fn("-lsh", NFILE, fnm),
1256 opt2fn("-lss", NFILE, fnm),
1257 opt2fn("-ls3", NFILE, fnm),
1258 opt2fn("-g", NFILE, fnm),
1268 opt2parg_bSet("-emin", NPA, pa) ? &emin : nullptr,
1269 opt2parg_bSet("-emax", NPA, pa) ? &emax : nullptr,
1274 opt2parg_bSet("-xmin", NPA, pa),
1276 opt2parg_bSet("-xmax", NPA, pa),