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, 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/vec.h"
56 #include "gromacs/topology/topology.h"
57 #include "gromacs/utility/arraysize.h"
58 #include "gromacs/utility/fatalerror.h"
59 #include "gromacs/utility/futil.h"
60 #include "gromacs/utility/smalloc.h"
63 static int index2(const int* ibox, int x, int y)
65 return (ibox[1] * x + y);
68 static int index3(const int* ibox, int x, int y, int z)
70 return (ibox[2] * (ibox[1] * x + y) + z);
73 static int64_t indexn(int ndim, const int* ibox, const int* nxyz)
78 /* Compute index in 1-D array */
80 for (k = 0; (k < ndim); k++)
83 for (kk = k + 1; (kk < ndim); kk++)
94 int Nx; /* x grid points in unit cell */
95 int Ny; /* y grid points in unit cell */
96 int Nz; /* z grid points in unit cell */
97 int dmin[3]; /* starting point x,y,z*/
98 int dmax[3]; /* ending point x,y,z */
99 real cell[6]; /* usual cell parameters */
103 static void lo_write_xplor(XplorMap* map, const char* file)
108 fp = gmx_ffopen(file, "w");
109 /* The REMARKS part is the worst part of the XPLOR format
110 * and may cause problems with some programs
112 fprintf(fp, "\n 2 !NTITLE\n");
113 fprintf(fp, " REMARKS Energy Landscape from GROMACS\n");
114 fprintf(fp, " REMARKS DATE: 2004-12-21 \n");
115 fprintf(fp, " %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", map->Nx, map->dmin[0], map->dmax[0],
116 map->Ny, map->dmin[1], map->dmax[1], map->Nz, map->dmin[2], map->dmax[2]);
117 fprintf(fp, "%12.5E%12.5E%12.5E%12.5E%12.5E%12.5E\n", map->cell[0], map->cell[1], map->cell[2],
118 map->cell[3], map->cell[4], map->cell[5]);
119 fprintf(fp, "ZYX\n");
122 for (n = 0; n < map->Nz; n++, z++)
124 fprintf(fp, "%8d\n", z);
125 for (i = 0; i < map->Nx * map->Ny; i += 6)
127 for (j = 0; j < 6; j++)
129 if (i + j < map->Nx * map->Ny)
131 fprintf(fp, "%12.5E", map->ed[n * map->Nx * map->Ny + i + j]);
137 fprintf(fp, " -9999\n");
141 static void write_xplor(const char* file, const real* data, int* ibox, const real dmin[], const real dmax[])
150 snew(xm->ed, xm->Nx * xm->Ny * xm->Nz);
152 for (k = 0; (k < xm->Nz); k++)
154 for (j = 0; (j < xm->Ny); j++)
156 for (i = 0; (i < xm->Nx); i++)
158 xm->ed[n++] = data[index3(ibox, i, j, k)];
162 xm->cell[0] = dmax[XX] - dmin[XX];
163 xm->cell[1] = dmax[YY] - dmin[YY];
164 xm->cell[2] = dmax[ZZ] - dmin[ZZ];
165 xm->cell[3] = xm->cell[4] = xm->cell[5] = 90;
167 clear_ivec(xm->dmin);
168 xm->dmax[XX] = ibox[XX] - 1;
169 xm->dmax[YY] = ibox[YY] - 1;
170 xm->dmax[ZZ] = ibox[ZZ] - 1;
172 lo_write_xplor(xm, file);
178 static void normalize_p_e(int len, double* P, const int* nbin, real* E, real pmin)
183 for (i = 0; (i < len); i++)
188 E[i] = E[i] / nbin[i];
191 printf("Ptot = %g\n", Ptot);
192 for (i = 0; (i < len); i++)
195 /* Have to check for pmin after normalizing to prevent "stretching"
211 static int comp_minima(const void* a, const void* b)
213 const t_minimum* ma = reinterpret_cast<const t_minimum*>(a);
214 const t_minimum* mb = reinterpret_cast<const t_minimum*>(b);
217 if (ma->ener < mb->ener)
221 else if (ma->ener > mb->ener)
231 static inline void print_minimum(FILE* fp, int num, const t_minimum* min)
234 "Minimum %d at index "
235 "%" PRId64 " energy %10.3f\n",
236 num, min->index, min->ener);
239 static inline void add_minimum(FILE* fp, int num, const t_minimum* min, t_minimum* mm)
241 print_minimum(fp, num, min);
242 mm[num].index = min->index;
243 mm[num].ener = min->ener;
246 static inline gmx_bool is_local_minimum_from_below(const t_minimum* this_min,
252 return ((dimension_index == dimension_min)
253 || ((dimension_index > dimension_min) && (this_min->ener < W[neighbour_index])));
254 /* Note over/underflow within W cannot occur. */
257 static inline gmx_bool is_local_minimum_from_above(const t_minimum* this_min,
263 return ((dimension_index == dimension_max)
264 || ((dimension_index < dimension_max) && (this_min->ener < W[neighbour_index])));
265 /* Note over/underflow within W cannot occur. */
268 static void pick_minima(const char* logfile, int* ibox, int ndim, int len, real W[])
272 t_minimum *mm, this_min;
274 int loopmax, loopcounter;
278 fp = gmx_ffopen(logfile, "w");
279 /* Loop over each element in the array of dimenion ndim seeking
280 * minima with respect to every dimension. Specialized loops for
281 * speed with ndim == 2 and ndim == 3. */
285 /* This is probably impossible to reach anyway. */
288 for (i = 0; (i < ibox[0]); i++)
290 for (j = 0; (j < ibox[1]); j++)
292 /* Get the index of this point in the flat array */
293 this_min.index = index2(ibox, i, j);
294 this_min.ener = W[this_min.index];
295 if (is_local_minimum_from_below(&this_min, i, 0, index2(ibox, i - 1, j), W)
296 && is_local_minimum_from_above(&this_min, i, ibox[0] - 1, index2(ibox, i + 1, j), W)
297 && is_local_minimum_from_below(&this_min, j, 0, index2(ibox, i, j - 1), W)
298 && is_local_minimum_from_above(&this_min, j, ibox[1] - 1, index2(ibox, i, j + 1), W))
300 add_minimum(fp, nmin, &this_min, mm);
307 for (i = 0; (i < ibox[0]); i++)
309 for (j = 0; (j < ibox[1]); j++)
311 for (k = 0; (k < ibox[2]); k++)
313 /* Get the index of this point in the flat array */
314 this_min.index = index3(ibox, i, j, k);
315 this_min.ener = W[this_min.index];
316 if (is_local_minimum_from_below(&this_min, i, 0, index3(ibox, i - 1, j, k), W)
317 && is_local_minimum_from_above(&this_min, i, ibox[0] - 1,
318 index3(ibox, i + 1, j, k), W)
319 && is_local_minimum_from_below(&this_min, j, 0, index3(ibox, i, j - 1, k), W)
320 && is_local_minimum_from_above(&this_min, j, ibox[1] - 1,
321 index3(ibox, i, j + 1, k), W)
322 && is_local_minimum_from_below(&this_min, k, 0, index3(ibox, i, j, k - 1), W)
323 && is_local_minimum_from_above(&this_min, k, ibox[2] - 1,
324 index3(ibox, i, j, k + 1), W))
326 add_minimum(fp, nmin, &this_min, mm);
334 /* Note this treats ndim == 1 and ndim > 3 */
336 /* Set up an ndim-dimensional vector to loop over the points
337 * on the grid. (0,0,0, ... 0) is an acceptable place to
339 snew(this_point, ndim);
341 /* Determine the number of points of the ndim-dimensional
344 for (i = 1; i < ndim; i++)
350 while (loopmax > loopcounter)
352 gmx_bool bMin = TRUE;
354 /* Get the index of this_point in the flat array */
355 this_min.index = indexn(ndim, ibox, this_point);
356 this_min.ener = W[this_min.index];
358 /* Is this_point a minimum from above and below in each
360 for (i = 0; bMin && (i < ndim); i++)
362 /* Save the index of this_point within the curent
363 * dimension so we can change that index in the
364 * this_point array for use with indexn(). */
365 int index = this_point[i];
368 && is_local_minimum_from_below(&this_min, index, 0,
369 indexn(ndim, ibox, this_point), W);
372 && is_local_minimum_from_above(&this_min, index, ibox[i] - 1,
373 indexn(ndim, ibox, this_point), W);
378 add_minimum(fp, nmin, &this_min, mm);
382 /* update global loop counter */
385 /* Avoid underflow of this_point[i] */
386 if (loopmax > loopcounter)
388 /* update this_point non-recursively */
391 while (ibox[i] == this_point[i])
395 /* this_point[i] cannot underflow because
396 * loopmax > loopcounter. */
405 qsort(mm, nmin, sizeof(mm[0]), comp_minima);
406 fprintf(fp, "Minima sorted after energy\n");
407 for (i = 0; (i < nmin); i++)
409 print_minimum(fp, i, &mm[i]);
415 static void do_sham(const char* fn,
444 real * min_eig, *max_eig;
445 real * axis_x, *axis_y, *axis_z, *axis = nullptr;
447 real ** PP, *W, *E, **WW, **EE, *S, **SS, *M, *bE;
450 double * bfac, efac, bref, Pmax, Wmin, Wmax, Winf, Emin, Emax, Einf, Smin, Smax, Sinf;
452 int i, j, k, imin, len, index, *nbin, *bindex, bi;
457 t_rgb rlo = { 0, 0, 0 };
458 t_rgb rhi = { 1, 1, 1 };
460 /* Determine extremes for the eigenvectors */
467 for (i = 0; (i < neig); i++)
469 /* Check for input constraints */
470 min_eig[i] = max_eig[i] = eig[i][0];
471 for (j = 0; (j < n); j++)
473 min_eig[i] = std::min(min_eig[i], eig[i][j]);
474 max_eig[i] = std::max(max_eig[i], eig[i][j]);
475 delta[i] = (max_eig[i] - min_eig[i]) / (2.0 * ibox[i]);
477 /* Add some extra space, half a bin on each side, unless the
478 * user has set the limits.
482 if (max_eig[i] > xmax[i])
484 gmx_warning("Your xmax[%d] value %f is smaller than the largest data point %f", i,
485 xmax[i], max_eig[i]);
487 max_eig[i] = xmax[i];
491 max_eig[i] += delta[i];
496 if (min_eig[i] < xmin[i])
498 gmx_warning("Your xmin[%d] value %f is larger than the smallest data point %f", i,
499 xmin[i], min_eig[i]);
501 min_eig[i] = xmin[i];
505 min_eig[i] -= delta[i];
507 bfac[i] = ibox[i] / (max_eig[i] - min_eig[i]);
510 bref = 1 / (BOLTZ * Tref);
512 if (bGE || nenerT == 2)
516 for (j = 0; (j < n); j++)
520 bE[j] = bref * enerT[0][j];
524 bE[j] = (bref - 1 / (BOLTZ * enerT[1][j])) * enerT[0][j];
526 Emin = std::min(Emin, static_cast<double>(bE[j]));
534 for (i = 0; (i < neig); i++)
538 printf("There are %d bins in the %d-dimensional histogram. Beta-Emin = %g\n", len, neig, Emin);
548 /* Loop over projections */
549 for (j = 0; (j < n); j++)
551 /* Loop over dimensions */
553 for (i = 0; (i < neig); i++)
555 nxyz[i] = static_cast<int>(bfac[i] * (eig[i][j] - min_eig[i]));
556 if (nxyz[i] < 0 || nxyz[i] >= ibox[i])
563 index = indexn(neig, ibox, nxyz);
564 range_check(index, 0, len);
565 /* Compute the exponential factor */
568 efac = std::exp(-bE[j] + Emin);
574 /* Apply the bin volume correction for a multi-dimensional distance */
575 for (i = 0; i < neig; i++)
581 else if (idim[i] == 3)
583 efac /= gmx::square(eig[i][j]);
585 else if (idim[i] == -1)
587 efac /= std::sin(DEG2RAD * eig[i][j]);
590 /* Update the probability */
592 /* Update the energy */
595 E[index] += enerT[0][j];
597 /* Statistics: which "structure" in which bin */
602 /* Normalize probability */
603 normalize_p_e(len, P, nbin, E, pmin);
605 /* Compute boundaries for the Free energy */
609 /* Recompute Emin: it may have changed due to averaging */
612 for (i = 0; (i < len); i++)
616 Pmax = std::max(P[i], Pmax);
617 W[i] = -BOLTZ * Tref * std::log(P[i]);
623 Emin = std::min(static_cast<double>(E[i]), Emin);
624 Emax = std::max(static_cast<double>(E[i]), Emax);
625 Wmax = std::max(static_cast<double>(W[i]), Wmax);
645 /* Write out the free energy as a function of bin index */
646 fp = gmx_ffopen(fn, "w");
647 for (i = 0; (i < len); i++)
652 S[i] = E[i] - W[i] - Smin;
653 fprintf(fp, "%5d %10.5e %10.5e %10.5e\n", i, W[i], E[i], S[i]);
663 /* Organize the structures in the bins */
665 snew(b->index, len + 1);
668 for (i = 0; (i < len); i++)
670 b->index[i + 1] = b->index[i] + nbin[i];
673 for (i = 0; (i < n); i++)
676 b->a[b->index[bi] + nbin[bi]] = i;
679 /* Consistency check */
680 /* This no longer applies when we allow the plot to be smaller
681 than the sampled space.
682 for(i=0; (i<len); i++) {
683 if (nbin[i] != (b->index[i+1] - b->index[i]))
684 gmx_fatal(FARGS,"nbin[%d] = %d, should be %d",i,nbin[i],
685 b->index[i+1] - b->index[i]);
688 /* Write the index file */
689 fp = gmx_ffopen(ndx, "w");
690 for (i = 0; (i < len); i++)
694 fprintf(fp, "[ %d ]\n", i);
695 for (j = b->index[i]; (j < b->index[i + 1]); j++)
697 fprintf(fp, "%d\n", b->a[j] + 1);
702 snew(axis_x, ibox[0] + 1);
703 snew(axis_y, ibox[1] + 1);
704 snew(axis_z, ibox[2] + 1);
705 maxbox = std::max(ibox[0], std::max(ibox[1], ibox[2]));
706 snew(PP, maxbox * maxbox);
707 snew(WW, maxbox * maxbox);
708 snew(EE, maxbox * maxbox);
709 snew(SS, maxbox * maxbox);
710 for (i = 0; (i < std::min(neig, 3)); i++)
714 case 0: axis = axis_x; break;
715 case 1: axis = axis_y; break;
716 case 2: axis = axis_z; break;
719 for (j = 0; j <= ibox[i]; j++)
721 axis[j] = min_eig[i] + j / bfac[i];
725 pick_minima(logf, ibox, neig, len, W);
730 flags = MAT_SPATIAL_X | MAT_SPATIAL_Y;
733 /* Dump to XPM file */
735 for (i = 0; (i < ibox[0]); i++)
737 snew(PP[i], ibox[1]);
738 for (j = 0; j < ibox[1]; j++)
740 PP[i][j] = P[i * ibox[1] + j];
742 WW[i] = &(W[i * ibox[1]]);
743 EE[i] = &(E[i * ibox[1]]);
744 SS[i] = &(S[i * ibox[1]]);
746 fp = gmx_ffopen(xpmP, "w");
747 write_xpm(fp, flags, "Probability Distribution", "", "PC1", "PC2", ibox[0], ibox[1], axis_x,
748 axis_y, PP, 0, Pmax, rlo, rhi, &nlevels);
750 fp = gmx_ffopen(xpm, "w");
751 write_xpm(fp, flags, "Gibbs Energy Landscape", "G (kJ/mol)", "PC1", "PC2", ibox[0], ibox[1],
752 axis_x, axis_y, WW, 0, gmax, rlo, rhi, &nlevels);
754 fp = gmx_ffopen(xpm2, "w");
755 write_xpm(fp, flags, "Enthalpy Landscape", "H (kJ/mol)", "PC1", "PC2", ibox[0], ibox[1],
756 axis_x, axis_y, EE, emin ? *emin : Emin, emax ? *emax : Einf, rlo, rhi, &nlevels);
758 fp = gmx_ffopen(xpm3, "w");
759 write_xpm(fp, flags, "Entropy Landscape", "TDS (kJ/mol)", "PC1", "PC2", ibox[0], ibox[1],
760 axis_x, axis_y, SS, 0, Sinf, rlo, rhi, &nlevels);
765 /* Dump to PDB file */
766 fp = gmx_ffopen(pdb, "w");
767 for (i = 0; (i < ibox[0]); i++)
769 xxx[XX] = 3 * i + 1.5 * (1 - ibox[0]);
770 for (j = 0; (j < ibox[1]); j++)
772 xxx[YY] = 3 * j + 1.5 * (1 - ibox[1]);
773 for (k = 0; (k < ibox[2]); k++)
775 xxx[ZZ] = 3 * k + 1.5 * (1 - ibox[2]);
776 index = index3(ibox, i, j, k);
779 fprintf(fp, "%-6s%5d %-4.4s%3.3s %4d %8.3f%8.3f%8.3f%6.2f%6.2f\n",
780 "ATOM", (index + 1) % 10000, "H", "H", (index + 1) % 10000, xxx[XX],
781 xxx[YY], xxx[ZZ], 1.0, W[index]);
787 write_xplor("out.xplor", W, ibox, min_eig, max_eig);
788 nxyz[XX] = imin / (ibox[1] * ibox[2]);
789 nxyz[YY] = (imin - nxyz[XX] * ibox[1] * ibox[2]) / ibox[2];
790 nxyz[ZZ] = imin % ibox[2];
791 for (i = 0; (i < ibox[0]); i++)
794 for (j = 0; (j < ibox[1]); j++)
796 WW[i][j] = W[index3(ibox, i, j, nxyz[ZZ])];
799 snew(buf, std::strlen(xpm) + 4);
800 sprintf(buf, "%s", xpm);
801 sprintf(&buf[std::strlen(xpm) - 4], "12.xpm");
802 fp = gmx_ffopen(buf, "w");
803 write_xpm(fp, flags, "Gibbs Energy Landscape", "W (kJ/mol)", "PC1", "PC2", ibox[0], ibox[1],
804 axis_x, axis_y, WW, 0, gmax, rlo, rhi, &nlevels);
806 for (i = 0; (i < ibox[0]); i++)
808 for (j = 0; (j < ibox[2]); j++)
810 WW[i][j] = W[index3(ibox, i, nxyz[YY], j)];
813 sprintf(&buf[std::strlen(xpm) - 4], "13.xpm");
814 fp = gmx_ffopen(buf, "w");
815 write_xpm(fp, flags, "SHAM Energy Landscape", "kJ/mol", "PC1", "PC3", ibox[0], ibox[2],
816 axis_x, axis_z, WW, 0, gmax, rlo, rhi, &nlevels);
818 for (i = 0; (i < ibox[1]); i++)
820 for (j = 0; (j < ibox[2]); j++)
822 WW[i][j] = W[index3(ibox, nxyz[XX], i, j)];
825 sprintf(&buf[std::strlen(xpm) - 4], "23.xpm");
826 fp = gmx_ffopen(buf, "w");
827 write_xpm(fp, flags, "SHAM Energy Landscape", "kJ/mol", "PC2", "PC3", ibox[1], ibox[2],
828 axis_y, axis_z, WW, 0, gmax, rlo, rhi, &nlevels);
834 static void ehisto(const char* fh, int n, real** enerT, const gmx_output_env_t* oenv)
837 int i, j, k, nbin, blength;
839 real *T, bmin, bmax, bwidth;
847 for (j = 1; (j < n); j++)
849 for (k = 0; (k < nbin); k++)
851 if (T[k] == enerT[1][j])
860 T[nbin] = enerT[1][j];
863 bmin = std::min(enerT[0][j], bmin);
864 bmax = std::max(enerT[0][j], bmax);
867 blength = static_cast<int>((bmax - bmin) / bwidth + 2);
869 for (i = 0; (i < nbin); i++)
871 snew(histo[i], blength);
873 for (j = 0; (j < n); j++)
875 k = static_cast<int>((enerT[0][j] - bmin) / bwidth);
876 histo[bindex[j]][k]++;
878 fp = xvgropen(fh, "Energy distribution", "E (kJ/mol)", "", oenv);
879 for (j = 0; (j < blength); j++)
881 fprintf(fp, "%8.3f", bmin + j * bwidth);
882 for (k = 0; (k < nbin); k++)
884 fprintf(fp, " %6d", histo[k][j]);
891 int gmx_sham(int argc, char* argv[])
893 const char* desc[] = {
894 "[THISMODULE] makes multi-dimensional free-energy, enthalpy and entropy plots.",
895 "[THISMODULE] reads one or more [REF].xvg[ref] files and analyzes data sets.",
896 "The basic purpose of [THISMODULE] is to plot Gibbs free energy landscapes",
897 "(option [TT]-ls[tt])",
898 "by Bolzmann inverting multi-dimensional histograms (option [TT]-lp[tt]),",
900 "make enthalpy (option [TT]-lsh[tt]) and entropy (option [TT]-lss[tt])",
901 "plots. The histograms can be made for any quantities the user supplies.",
902 "A line in the input file may start with a time",
903 "(see option [TT]-time[tt]) and any number of [IT]y[it]-values may follow.",
904 "Multiple sets can also be",
905 "read when they are separated by & (option [TT]-n[tt]),",
906 "in this case only one [IT]y[it]-value is read from each line.",
907 "All lines starting with # and @ are skipped.",
909 "Option [TT]-ge[tt] can be used to supply a file with free energies",
910 "when the ensemble is not a Boltzmann ensemble, but needs to be biased",
911 "by this free energy. One free energy value is required for each",
912 "(multi-dimensional) data point in the [TT]-f[tt] input.",
914 "Option [TT]-ene[tt] can be used to supply a file with energies.",
915 "These energies are used as a weighting function in the single",
916 "histogram analysis method by Kumar et al. When temperatures",
917 "are supplied (as a second column in the file), an experimental",
918 "weighting scheme is applied. In addition the vales",
919 "are used for making enthalpy and entropy plots.",
921 "With option [TT]-dim[tt], dimensions can be gives for distances.",
922 "When a distance is 2- or 3-dimensional, the circumference or surface",
923 "sampled by two particles increases with increasing distance.",
924 "Depending on what one would like to show, one can choose to correct",
925 "the histogram and free-energy for this volume effect.",
926 "The probability is normalized by r and r^2 for dimensions of 2 and 3, ",
928 "A value of -1 is used to indicate an angle in degrees between two",
929 "vectors: a sin(angle) normalization will be applied.",
930 "[BB]Note[bb] that for angles between vectors the inner-product or cosine",
931 "is the natural quantity to use, as it will produce bins of the same",
934 static real tb = -1, te = -1;
935 static gmx_bool bHaveT = TRUE, bDer = FALSE;
936 static gmx_bool bSham = TRUE;
937 static real Tref = 298.15, pmin = 0, ttol = 0, pmax = 0, gmax = 0, emin = 0, emax = 0;
938 static rvec nrdim = { 1, 1, 1 };
939 static rvec nrbox = { 32, 32, 32 };
940 static rvec xmin = { 0, 0, 0 }, xmax = { 1, 1, 1 };
941 static int nsets_in = 1, nlevels = 25;
943 { "-time", FALSE, etBOOL, { &bHaveT }, "Expect a time in the input" },
944 { "-b", FALSE, etREAL, { &tb }, "First time to read from set" },
945 { "-e", FALSE, etREAL, { &te }, "Last time to read from set" },
946 { "-ttol", FALSE, etREAL, { &ttol }, "Tolerance on time in appropriate units (usually ps)" },
951 "Read this number of sets separated by lines containing only an ampersand" },
952 { "-d", FALSE, etBOOL, { &bDer }, "Use the derivative" },
957 "Turn off energy weighting even if energies are given" },
958 { "-tsham", FALSE, etREAL, { &Tref }, "Temperature for single histogram analysis" },
963 "Minimum probability. Anything lower than this will be set to zero" },
968 "Dimensions for distances, used for volume correction (max 3 values, dimensions > 3 will "
969 "get the same value as the last)" },
974 "Number of bins for energy landscapes (max 3 values, dimensions > 3 will get the same "
975 "value as the last)" },
980 "Minimum for the axes in energy landscape (see above for > 3 dimensions)" },
985 "Maximum for the axes in energy landscape (see above for > 3 dimensions)" },
986 { "-pmax", FALSE, etREAL, { &pmax }, "Maximum probability in output, default is calculate" },
987 { "-gmax", FALSE, etREAL, { &gmax }, "Maximum free energy in output, default is calculate" },
988 { "-emin", FALSE, etREAL, { &emin }, "Minimum enthalpy in output, default is calculate" },
989 { "-emax", FALSE, etREAL, { &emax }, "Maximum enthalpy in output, default is calculate" },
990 { "-nlevels", FALSE, etINT, { &nlevels }, "Number of levels for energy landscape" },
992 #define NPA asize(pa)
994 int n, e_n, nset, e_nset = 0, i, *idim, *ibox;
995 real ** val, **et_val, *t, *e_t, e_dt, dt;
997 const char * fn_ge, *fn_ene;
998 gmx_output_env_t* oenv;
999 int64_t num_grid_points;
1002 { efXVG, "-f", "graph", ffREAD }, { efXVG, "-ge", "gibbs", ffOPTRD },
1003 { efXVG, "-ene", "esham", ffOPTRD }, { efXVG, "-dist", "ener", ffOPTWR },
1004 { efXVG, "-histo", "edist", ffOPTWR }, { efNDX, "-bin", "bindex", ffOPTWR },
1005 { efXPM, "-lp", "prob", ffOPTWR }, { efXPM, "-ls", "gibbs", ffOPTWR },
1006 { efXPM, "-lsh", "enthalpy", ffOPTWR }, { efXPM, "-lss", "entropy", ffOPTWR },
1007 { efPDB, "-ls3", "gibbs3", ffOPTWR }, { efLOG, "-g", "shamlog", ffOPTWR }
1009 #define NFILE asize(fnm)
1014 if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, npargs, pa, asize(desc), desc, 0,
1020 val = read_xvg_time(opt2fn("-f", NFILE, fnm), bHaveT, opt2parg_bSet("-b", npargs, pa), tb - ttol,
1021 opt2parg_bSet("-e", npargs, pa), te + ttol, nsets_in, &nset, &n, &dt, &t);
1022 printf("Read %d sets of %d points, dt = %g\n\n", nset, n, dt);
1024 fn_ge = opt2fn_null("-ge", NFILE, fnm);
1025 fn_ene = opt2fn_null("-ene", NFILE, fnm);
1027 if (fn_ge && fn_ene)
1029 gmx_fatal(FARGS, "Can not do free energy and energy corrections at the same time");
1032 if (fn_ge || fn_ene)
1034 et_val = read_xvg_time(fn_ge ? fn_ge : fn_ene, bHaveT, opt2parg_bSet("-b", npargs, pa),
1035 tb - ttol, opt2parg_bSet("-e", npargs, pa), te + ttol, 1, &e_nset,
1041 gmx_fatal(FARGS, "Can only handle one free energy component in %s", fn_ge);
1046 if (e_nset != 1 && e_nset != 2)
1049 "Can only handle one energy component or one energy and one T in %s", fn_ene);
1054 gmx_fatal(FARGS, "Number of energies (%d) does not match number of entries (%d) in %s",
1055 e_n, n, opt2fn("-f", NFILE, fnm));
1063 if (fn_ene && et_val)
1065 ehisto(opt2fn("-histo", NFILE, fnm), e_n, et_val, oenv);
1068 snew(idim, std::max(3, nset));
1069 snew(ibox, std::max(3, nset));
1070 snew(rmin, std::max(3, nset));
1071 snew(rmax, std::max(3, nset));
1072 for (i = 0; (i < std::min(3, nset)); i++)
1074 idim[i] = static_cast<int>(nrdim[i]);
1075 ibox[i] = static_cast<int>(nrbox[i]);
1079 for (; (i < nset); i++)
1081 idim[i] = static_cast<int>(nrdim[2]);
1082 ibox[i] = static_cast<int>(nrbox[2]);
1087 /* Check that the grid size is manageable. */
1088 num_grid_points = ibox[0];
1089 for (i = 1; i < nset; i++)
1092 if (!check_int_multiply_for_overflow(num_grid_points, ibox[i], &result))
1095 "The number of dimensions and grid points is too large for this tool.\n");
1097 num_grid_points = result;
1099 /* The number of grid points fits in a int64_t. */
1101 do_sham(opt2fn("-dist", NFILE, fnm), opt2fn("-bin", NFILE, fnm), opt2fn("-lp", NFILE, fnm),
1102 opt2fn("-ls", NFILE, fnm), opt2fn("-lsh", NFILE, fnm), opt2fn("-lss", NFILE, fnm),
1103 opt2fn("-ls3", NFILE, fnm), opt2fn("-g", NFILE, fnm), n, nset, val, fn_ge != nullptr,
1104 e_nset, et_val, Tref, pmax, gmax, opt2parg_bSet("-emin", NPA, pa) ? &emin : nullptr,
1105 opt2parg_bSet("-emax", NPA, pa) ? &emax : nullptr, nlevels, pmin, idim, ibox,
1106 opt2parg_bSet("-xmin", NPA, pa), rmin, opt2parg_bSet("-xmax", NPA, pa), rmax);