/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2014,2015,2017, by the GROMACS development team, led by
+ * Copyright (c) 2007,2008,2009,2010,2011 by the GROMACS development team.
+ * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
#include "gromacs/utility/arraysize.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/futil.h"
+#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/smalloc.h"
-static const double bohr = 0.529177249; /* conversion factor to compensate for VMD plugin conversion... */
+static const double bohr =
+ 0.529177249; /* conversion factor to compensate for VMD plugin conversion... */
-int gmx_spatial(int argc, char *argv[])
+int gmx_spatial(int argc, char* argv[])
{
- const char *desc[] = {
+ const char* desc[] = {
"[THISMODULE] calculates the spatial distribution function and",
"outputs it in a form that can be read by VMD as Gaussian98 cube format.",
"For a system of 32,000 atoms and a 50 ns trajectory, the SDF can be generated",
"in about 30 minutes, with most of the time dedicated to the two runs through",
"[TT]trjconv[tt] that are required to center everything properly.",
"This also takes a whole bunch of space (3 copies of the trajectory file).",
- "Still, the pictures are pretty and very informative when the fitted selection is properly made.",
+ "Still, the pictures are pretty and very informative when the fitted selection is ",
+ "properly ",
+ "made.",
"3-4 atoms in a widely mobile group (like a free amino acid in solution) works",
"well, or select the protein backbone in a stable folded structure to get the SDF",
"of solvent and look at the time-averaged solvation shell.",
"",
"Usage:",
"",
- "1. Use [gmx-make_ndx] to create a group containing the atoms around which you want the SDF",
+ "1. Use [gmx-make_ndx] to create a group containing the atoms around which you want the ",
+ "SDF",
"2. [TT]gmx trjconv -s a.tpr -f a.tng -o b.tng -boxcenter tric -ur compact -pbc none[tt]",
"3. [TT]gmx trjconv -s a.tpr -f b.tng -o c.tng -fit rot+trans[tt]",
"4. run [THISMODULE] on the [TT]c.tng[tt] output of step #3.",
"5. Load [TT]grid.cube[tt] into VMD and view as an isosurface.",
"",
- "[BB]Note[bb] that systems such as micelles will require [TT]gmx trjconv -pbc cluster[tt] between steps 1 and 2.",
+ "[BB]Note[bb] that systems such as micelles will require [TT]gmx trjconv -pbc cluster[tt] ",
+ "between steps 1 and 2.",
"",
"Warnings",
"^^^^^^^^",
"",
- "The SDF will be generated for a cube that contains all bins that have some non-zero occupancy.",
- "However, the preparatory [TT]-fit rot+trans[tt] option to [gmx-trjconv] implies that your system will be rotating",
- "and translating in space (in order that the selected group does not). Therefore the values that are",
- "returned will only be valid for some region around your central group/coordinate that has full overlap",
- "with system volume throughout the entire translated/rotated system over the course of the trajectory.",
+ "The SDF will be generated for a cube that contains all bins that have some non-zero ",
+ "occupancy.",
+ "However, the preparatory [TT]-fit rot+trans[tt] option to [gmx-trjconv] implies that ",
+ "your system will be rotating",
+ "and translating in space (in order that the selected group does not). Therefore the ",
+ "values that are",
+ "returned will only be valid for some region around your central group/coordinate that ",
+ "has full overlap",
+ "with system volume throughout the entire translated/rotated system over the course of ",
+ "the trajectory.",
"It is up to the user to ensure that this is the case.",
"",
"Risky options",
"memory is allocated for cube bins based on the initial coordinates and the [TT]-nab[tt]",
"option value."
};
- const char *bugs[] = {
- "When the allocated memory is not large enough, a segmentation fault may occur. This is usually detected "
- "and the program is halted prior to the fault while displaying a warning message suggesting the use of the [TT]-nab[tt] (Number of Additional Bins) "
- "option. However, the program does not detect all such events. If you encounter a segmentation fault, run it again "
+ const char* bugs[] = {
+ "When the allocated memory is not large enough, a segmentation fault may occur. ",
+ "This is usually detected ",
+ "and the program is halted prior to the fault while displaying a warning message ",
+ "suggesting the use of the [TT]-nab[tt] (Number of Additional Bins) ",
+ "option. However, the program does not detect all such events. If you encounter a ",
+ "segmentation fault, run it again ",
"with an increased [TT]-nab[tt] value."
};
- static gmx_bool bPBC = FALSE;
- static int iIGNOREOUTER = -1; /*Positive values may help if the surface is spikey */
- static gmx_bool bCUTDOWN = TRUE;
- static real rBINWIDTH = 0.05; /* nm */
- static gmx_bool bCALCDIV = TRUE;
- static int iNAB = 4;
+ static gmx_bool bPBC = FALSE;
+ static int iIGNOREOUTER = -1; /*Positive values may help if the surface is spikey */
+ static gmx_bool bCUTDOWN = TRUE;
+ static real rBINWIDTH = 0.05; /* nm */
+ static gmx_bool bCALCDIV = TRUE;
+ static int iNAB = 4;
- t_pargs pa[] = {
- { "-pbc", FALSE, etBOOL, {&bPBC},
- "Use periodic boundary conditions for computing distances" },
- { "-div", FALSE, etBOOL, {&bCALCDIV},
- "Calculate and apply the divisor for bin occupancies based on atoms/minimal cube size. Set as TRUE for visualization and as FALSE ([TT]-nodiv[tt]) to get accurate counts per frame" },
- { "-ign", FALSE, etINT, {&iIGNOREOUTER},
- "Do not display this number of outer cubes (positive values may reduce boundary speckles; -1 ensures outer surface is visible)" },
- /* { "-cut", bCUTDOWN, etBOOL, {&bCUTDOWN},*/
- /* "Display a total cube that is of minimal size" }, */
- { "-bin", FALSE, etREAL, {&rBINWIDTH},
- "Width of the bins (nm)" },
- { "-nab", FALSE, etINT, {&iNAB},
- "Number of additional bins to ensure proper memory allocation" }
- };
+ t_pargs pa[] = { { "-pbc",
+ FALSE,
+ etBOOL,
+ { &bPBC },
+ "Use periodic boundary conditions for computing distances" },
+ { "-div",
+ FALSE,
+ etBOOL,
+ { &bCALCDIV },
+ "Calculate and apply the divisor for bin occupancies based on atoms/minimal "
+ "cube size. Set as TRUE for visualization and as FALSE ([TT]-nodiv[tt]) to "
+ "get accurate counts per frame" },
+ { "-ign",
+ FALSE,
+ etINT,
+ { &iIGNOREOUTER },
+ "Do not display this number of outer cubes (positive values may reduce "
+ "boundary speckles; -1 ensures outer surface is visible)" },
+ /* { "-cut", bCUTDOWN, etBOOL, {&bCUTDOWN},*/
+ /* "Display a total cube that is of minimal size" }, */
+ { "-bin", FALSE, etREAL, { &rBINWIDTH }, "Width of the bins (nm)" },
+ { "-nab",
+ FALSE,
+ etINT,
+ { &iNAB },
+ "Number of additional bins to ensure proper memory allocation" } };
double MINBIN[3];
double MAXBIN[3];
t_topology top;
- int ePBC;
+ PbcType pbcType;
t_trxframe fr;
- rvec *xtop;
+ rvec* xtop;
matrix box, box_pbc;
- t_trxstatus *status;
+ t_trxstatus* status;
int flags = TRX_READ_X;
t_pbc pbc;
- t_atoms *atoms;
+ t_atoms* atoms;
int natoms;
- char *grpnm, *grpnmp;
- int *index, *indexp;
+ char * grpnm, *grpnmp;
+ int * index, *indexp;
int i, nidx, nidxp;
int v;
int j, k;
- int ***bin = nullptr;
+ int*** bin = nullptr;
int nbin[3];
- FILE *flp;
+ FILE* flp;
int x, y, z, minx, miny, minz, maxx, maxy, maxz;
int numfr, numcu;
int tot, maxval, minval;
double norm;
- gmx_output_env_t *oenv;
+ gmx_output_env_t* oenv;
gmx_rmpbc_t gpbc = nullptr;
- t_filenm fnm[] = {
- { efTPS, nullptr, nullptr, ffREAD }, /* this is for the topology */
- { efTRX, "-f", nullptr, ffREAD }, /* and this for the trajectory */
- { efNDX, nullptr, nullptr, ffOPTRD }
- };
+ t_filenm fnm[] = { { efTPS, nullptr, nullptr, ffREAD }, /* this is for the topology */
+ { efTRX, "-f", nullptr, ffREAD }, /* and this for the trajectory */
+ { efNDX, nullptr, nullptr, ffOPTRD } };
#define NFILE asize(fnm)
/* This is the routine responsible for adding default options,
* calling the X/motif interface, etc. */
- if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW,
- NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
+ if (!parse_common_args(
+ &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
{
return 0;
}
- read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, &xtop, nullptr, box, TRUE);
+ read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &pbcType, &xtop, nullptr, box, TRUE);
sfree(xtop);
atoms = &(top.atoms);
}
for (i = ZZ; i >= XX; --i)
{
- MAXBIN[i] = (std::ceil((MAXBIN[i]-MINBIN[i])/rBINWIDTH)+iNAB)*rBINWIDTH+MINBIN[i];
- MINBIN[i] -= iNAB*rBINWIDTH;
- nbin[i] = static_cast<int>(std::ceil((MAXBIN[i]-MINBIN[i])/rBINWIDTH));
+ MAXBIN[i] = (std::ceil((MAXBIN[i] - MINBIN[i]) / rBINWIDTH) + iNAB) * rBINWIDTH + MINBIN[i];
+ MINBIN[i] -= iNAB * rBINWIDTH;
+ nbin[i] = static_cast<int>(std::ceil((MAXBIN[i] - MINBIN[i]) / rBINWIDTH));
}
snew(bin, nbin[XX]);
for (i = 0; i < nbin[XX]; ++i)
}
copy_mat(box, box_pbc);
numfr = 0;
- minx = miny = minz = 999;
- maxx = maxy = maxz = 0;
+ minx = miny = minz = 999;
+ maxx = maxy = maxz = 0;
if (bPBC)
{
- gpbc = gmx_rmpbc_init(&top.idef, ePBC, natoms);
+ gpbc = gmx_rmpbc_init(&top.idef, pbcType, natoms);
}
/* This is the main loop over frames */
do
if (bPBC)
{
gmx_rmpbc_trxfr(gpbc, &fr);
- set_pbc(&pbc, ePBC, box_pbc);
+ set_pbc(&pbc, pbcType, box_pbc);
}
for (i = 0; i < nidx; i++)
{
- if (fr.x[index[i]][XX] < MINBIN[XX] || fr.x[index[i]][XX] > MAXBIN[XX] ||
- fr.x[index[i]][YY] < MINBIN[YY] || fr.x[index[i]][YY] > MAXBIN[YY] ||
- fr.x[index[i]][ZZ] < MINBIN[ZZ] || fr.x[index[i]][ZZ] > MAXBIN[ZZ])
+ if (fr.x[index[i]][XX] < MINBIN[XX] || fr.x[index[i]][XX] > MAXBIN[XX]
+ || fr.x[index[i]][YY] < MINBIN[YY] || fr.x[index[i]][YY] > MAXBIN[YY]
+ || fr.x[index[i]][ZZ] < MINBIN[ZZ] || fr.x[index[i]][ZZ] > MAXBIN[ZZ])
{
- printf("There was an item outside of the allocated memory. Increase the value given with the -nab option.\n");
- printf("Memory was allocated for [%f,%f,%f]\tto\t[%f,%f,%f]\n", MINBIN[XX], MINBIN[YY], MINBIN[ZZ], MAXBIN[XX], MAXBIN[YY], MAXBIN[ZZ]);
- printf("Memory was required for [%f,%f,%f]\n", fr.x[index[i]][XX], fr.x[index[i]][YY], fr.x[index[i]][ZZ]);
+ printf("There was an item outside of the allocated memory. Increase the value "
+ "given with the -nab option.\n");
+ printf("Memory was allocated for [%f,%f,%f]\tto\t[%f,%f,%f]\n",
+ MINBIN[XX],
+ MINBIN[YY],
+ MINBIN[ZZ],
+ MAXBIN[XX],
+ MAXBIN[YY],
+ MAXBIN[ZZ]);
+ printf("Memory was required for [%f,%f,%f]\n",
+ fr.x[index[i]][XX],
+ fr.x[index[i]][YY],
+ fr.x[index[i]][ZZ]);
exit(1);
}
- x = static_cast<int>(std::ceil((fr.x[index[i]][XX]-MINBIN[XX])/rBINWIDTH));
- y = static_cast<int>(std::ceil((fr.x[index[i]][YY]-MINBIN[YY])/rBINWIDTH));
- z = static_cast<int>(std::ceil((fr.x[index[i]][ZZ]-MINBIN[ZZ])/rBINWIDTH));
+ x = static_cast<int>(std::ceil((fr.x[index[i]][XX] - MINBIN[XX]) / rBINWIDTH));
+ y = static_cast<int>(std::ceil((fr.x[index[i]][YY] - MINBIN[YY]) / rBINWIDTH));
+ z = static_cast<int>(std::ceil((fr.x[index[i]][ZZ] - MINBIN[ZZ]) / rBINWIDTH));
++bin[x][y][z];
if (x < minx)
{
numfr++;
/* printf("%f\t%f\t%f\n",box[XX][XX],box[YY][YY],box[ZZ][ZZ]); */
- }
- while (read_next_frame(oenv, status, &fr));
+ } while (read_next_frame(oenv, status, &fr));
if (bPBC)
{
if (!bCUTDOWN)
{
minx = miny = minz = 0;
- maxx = nbin[XX];
- maxy = nbin[YY];
- maxz = nbin[ZZ];
+ maxx = nbin[XX];
+ maxy = nbin[YY];
+ maxz = nbin[ZZ];
}
/* OUTPUT */
flp = gmx_ffopen("grid.cube", "w");
fprintf(flp, "Spatial Distribution Function\n");
fprintf(flp, "test\n");
- fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", nidxp, (MINBIN[XX]+(minx+iIGNOREOUTER)*rBINWIDTH)*10./bohr, (MINBIN[YY]+(miny+iIGNOREOUTER)*rBINWIDTH)*10./bohr, (MINBIN[ZZ]+(minz+iIGNOREOUTER)*rBINWIDTH)*10./bohr);
- fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxx-minx+1-(2*iIGNOREOUTER), rBINWIDTH*10./bohr, 0., 0.);
- fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxy-miny+1-(2*iIGNOREOUTER), 0., rBINWIDTH*10./bohr, 0.);
- fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxz-minz+1-(2*iIGNOREOUTER), 0., 0., rBINWIDTH*10./bohr);
+ fprintf(flp,
+ "%5d%12.6f%12.6f%12.6f\n",
+ nidxp,
+ (MINBIN[XX] + (minx + iIGNOREOUTER) * rBINWIDTH) * 10. / bohr,
+ (MINBIN[YY] + (miny + iIGNOREOUTER) * rBINWIDTH) * 10. / bohr,
+ (MINBIN[ZZ] + (minz + iIGNOREOUTER) * rBINWIDTH) * 10. / bohr);
+ fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxx - minx + 1 - (2 * iIGNOREOUTER), rBINWIDTH * 10. / bohr, 0., 0.);
+ fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxy - miny + 1 - (2 * iIGNOREOUTER), 0., rBINWIDTH * 10. / bohr, 0.);
+ fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxz - minz + 1 - (2 * iIGNOREOUTER), 0., 0., rBINWIDTH * 10. / bohr);
for (i = 0; i < nidxp; i++)
{
v = 2;
{
v = 16;
}
- fprintf(flp, "%5d%12.6f%12.6f%12.6f%12.6f\n", v, 0., fr.x[indexp[i]][XX]*10.0/bohr, fr.x[indexp[i]][YY]*10.0/bohr, fr.x[indexp[i]][ZZ]*10.0/bohr);
+ fprintf(flp,
+ "%5d%12.6f%12.6f%12.6f%12.6f\n",
+ v,
+ 0.,
+ fr.x[indexp[i]][XX] * 10.0 / bohr,
+ fr.x[indexp[i]][YY] * 10.0 / bohr,
+ fr.x[indexp[i]][ZZ] * 10.0 / bohr);
}
tot = 0;
}
if (bin[k][j][i] != 0)
{
- printf("A bin was not empty when it should have been empty. Programming error.\n");
+ printf("A bin was not empty when it should have been empty. Programming "
+ "error.\n");
printf("bin[%d][%d][%d] was = %d\n", k, j, i, bin[k][j][i]);
exit(1);
}
maxval = 0;
for (k = 0; k < nbin[XX]; k++)
{
- if (k < minx+iIGNOREOUTER || k > maxx-iIGNOREOUTER)
+ if (k < minx + iIGNOREOUTER || k > maxx - iIGNOREOUTER)
{
continue;
}
for (j = 0; j < nbin[YY]; j++)
{
- if (j < miny+iIGNOREOUTER || j > maxy-iIGNOREOUTER)
+ if (j < miny + iIGNOREOUTER || j > maxy - iIGNOREOUTER)
{
continue;
}
for (i = 0; i < nbin[ZZ]; i++)
{
- if (i < minz+iIGNOREOUTER || i > maxz-iIGNOREOUTER)
+ if (i < minz + iIGNOREOUTER || i > maxz - iIGNOREOUTER)
{
continue;
}
}
}
- numcu = (maxx-minx+1-(2*iIGNOREOUTER))*(maxy-miny+1-(2*iIGNOREOUTER))*(maxz-minz+1-(2*iIGNOREOUTER));
+ numcu = (maxx - minx + 1 - (2 * iIGNOREOUTER)) * (maxy - miny + 1 - (2 * iIGNOREOUTER))
+ * (maxz - minz + 1 - (2 * iIGNOREOUTER));
if (bCALCDIV)
{
- norm = static_cast<double>(numcu*numfr)/tot;
+ norm = double(numcu) * numfr / tot;
+ GMX_ASSERT(norm >= 0, "The norm should be non-negative.");
}
else
{
for (k = 0; k < nbin[XX]; k++)
{
- if (k < minx+iIGNOREOUTER || k > maxx-iIGNOREOUTER)
+ if (k < minx + iIGNOREOUTER || k > maxx - iIGNOREOUTER)
{
continue;
}
for (j = 0; j < nbin[YY]; j++)
{
- if (j < miny+iIGNOREOUTER || j > maxy-iIGNOREOUTER)
+ if (j < miny + iIGNOREOUTER || j > maxy - iIGNOREOUTER)
{
continue;
}
for (i = 0; i < nbin[ZZ]; i++)
{
- if (i < minz+iIGNOREOUTER || i > maxz-iIGNOREOUTER)
+ if (i < minz + iIGNOREOUTER || i > maxz - iIGNOREOUTER)
{
continue;
}
- fprintf(flp, "%12.6f ", static_cast<double>(norm*bin[k][j][i])/numfr);
+ fprintf(flp, "%12.6f ", static_cast<double>(norm * bin[k][j][i]) / numfr);
}
fprintf(flp, "\n");
}
if (bCALCDIV)
{
- printf("Counts per frame in all %d cubes divided by %le\n", numcu, 1.0/norm);
- printf("Normalized data: average %le, min %le, max %le\n", 1.0, minval*norm/numfr, maxval*norm/numfr);
+ printf("Counts per frame in all %d cubes divided by %le\n", numcu, 1.0 / norm);
+ printf("Normalized data: average %le, min %le, max %le\n",
+ 1.0,
+ minval * norm / numfr,
+ maxval * norm / numfr);
}
else
{
printf("grid.cube contains counts per frame in all %d cubes\n", numcu);
- printf("Raw data: average %le, min %le, max %le\n", 1.0/norm, static_cast<double>(minval)/numfr, static_cast<double>(maxval)/numfr);
+ printf("Raw data: average %le, min %le, max %le\n",
+ 1.0 / norm,
+ static_cast<double>(minval) / numfr,
+ static_cast<double>(maxval) / numfr);
}
return 0;