Remove unused code detected by PGI compiler
[gromacs.git] / src / gromacs / gmxana / gmx_potential.cpp
blob82007565ae9e7033a4e6450c24e701b2b62e5123
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, 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 <cctype>
40 #include <cmath>
41 #include <cstring>
43 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/commandline/viewit.h"
45 #include "gromacs/fileio/trxio.h"
46 #include "gromacs/fileio/xvgr.h"
47 #include "gromacs/gmxana/gmx_ana.h"
48 #include "gromacs/gmxana/princ.h"
49 #include "gromacs/math/vec.h"
50 #include "gromacs/pbcutil/rmpbc.h"
51 #include "gromacs/topology/index.h"
52 #include "gromacs/topology/topology.h"
53 #include "gromacs/utility/arraysize.h"
54 #include "gromacs/utility/cstringutil.h"
55 #include "gromacs/utility/fatalerror.h"
56 #include "gromacs/utility/futil.h"
57 #include "gromacs/utility/smalloc.h"
59 #define EPS0 8.85419E-12
60 #define ELC 1.60219E-19
62 /****************************************************************************/
63 /* This program calculates the electrostatic potential across the box by */
64 /* determining the charge density in slices of the box and integrating these*/
65 /* twice. */
66 /* Peter Tieleman, April 1995 */
67 /* It now also calculates electrostatic potential in spherical micelles, */
68 /* using \frac{1}{r}\frac{d^2r\Psi}{r^2} = - \frac{\rho}{\epsilon_0} */
69 /* This probably sucks but it seems to work. */
70 /****************************************************************************/
72 static int ce = 0, cb = 0;
74 /* this routine integrates the array data and returns the resulting array */
75 /* routine uses simple trapezoid rule */
76 void p_integrate(double *result, double data[], int ndata, double slWidth)
78 int i, slice;
79 double sum;
81 if (ndata <= 2)
83 fprintf(stderr, "Warning: nr of slices very small. This will result"
84 "in nonsense.\n");
87 fprintf(stderr, "Integrating from slice %d to slice %d\n", cb, ndata-ce);
89 for (slice = cb; slice < (ndata-ce); slice++)
91 sum = 0;
92 for (i = cb; i < slice; i++)
94 sum += slWidth * (data[i] + 0.5 * (data[i+1] - data[i]));
96 result[slice] = sum;
98 return;
101 void calc_potential(const char *fn, int **index, int gnx[],
102 double ***slPotential, double ***slCharge,
103 double ***slField, int *nslices,
104 t_topology *top, int ePBC,
105 int axis, int nr_grps, double *slWidth,
106 double fudge_z, gmx_bool bSpherical, gmx_bool bCorrect,
107 const gmx_output_env_t *oenv)
109 rvec *x0; /* coordinates without pbc */
110 matrix box; /* box (3x3) */
111 int natoms; /* nr. atoms in trj */
112 t_trxstatus *status;
113 int i, n, /* loop indices */
114 teller = 0,
115 ax1 = 0, ax2 = 0,
116 nr_frames = 0, /* number of frames */
117 slice; /* current slice */
118 double slVolume; /* volume of slice for spherical averaging */
119 double qsum, nn;
120 real t;
121 double z;
122 rvec xcm;
123 gmx_rmpbc_t gpbc = NULL;
125 switch (axis)
127 case 0:
128 ax1 = 1; ax2 = 2;
129 break;
130 case 1:
131 ax1 = 0; ax2 = 2;
132 break;
133 case 2:
134 ax1 = 0; ax2 = 1;
135 break;
136 default:
137 gmx_fatal(FARGS, "Invalid axes. Terminating\n");
140 if ((natoms = read_first_x(oenv, &status, fn, &t, &x0, box)) == 0)
142 gmx_fatal(FARGS, "Could not read coordinates from statusfile\n");
145 if (!*nslices)
147 *nslices = static_cast<int>(box[axis][axis] * 10.0); /* default value */
150 fprintf(stderr, "\nDividing the box in %d slices\n", *nslices);
152 snew(*slField, nr_grps);
153 snew(*slCharge, nr_grps);
154 snew(*slPotential, nr_grps);
156 for (i = 0; i < nr_grps; i++)
158 snew((*slField)[i], *nslices);
159 snew((*slCharge)[i], *nslices);
160 snew((*slPotential)[i], *nslices);
164 gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms);
166 /*********** Start processing trajectory ***********/
169 *slWidth = box[axis][axis]/(*nslices);
170 teller++;
171 gmx_rmpbc(gpbc, natoms, box, x0);
173 /* calculate position of center of mass based on group 1 */
174 calc_xcm(x0, gnx[0], index[0], top->atoms.atom, xcm, FALSE);
175 svmul(-1, xcm, xcm);
177 for (n = 0; n < nr_grps; n++)
179 /* Check whether we actually have all positions of the requested index
180 * group in the trajectory file */
181 if (gnx[n] > natoms)
183 gmx_fatal(FARGS, "You selected a group with %d atoms, but only %d atoms\n"
184 "were found in the trajectory.\n", gnx[n], natoms);
186 for (i = 0; i < gnx[n]; i++) /* loop over all atoms in index file */
188 if (bSpherical)
190 rvec_add(x0[index[n][i]], xcm, x0[index[n][i]]);
191 /* only distance from origin counts, not sign */
192 slice = static_cast<int>(norm(x0[index[n][i]])/(*slWidth));
194 /* this is a nice check for spherical groups but not for
195 all water in a cubic box since a lot will fall outside
196 the sphere
197 if (slice > (*nslices))
199 fprintf(stderr,"Warning: slice = %d\n",slice);
202 (*slCharge)[n][slice] += top->atoms.atom[index[n][i]].q;
204 else
206 z = x0[index[n][i]][axis];
207 z = z + fudge_z;
208 if (z < 0)
210 z += box[axis][axis];
212 if (z > box[axis][axis])
214 z -= box[axis][axis];
216 /* determine which slice atom is in */
217 slice = static_cast<int>((z / (*slWidth)));
218 (*slCharge)[n][slice] += top->atoms.atom[index[n][i]].q;
222 nr_frames++;
224 while (read_next_x(oenv, status, &t, x0, box));
226 gmx_rmpbc_done(gpbc);
228 /*********** done with status file **********/
229 close_trj(status);
231 /* slCharge now contains the total charge per slice, summed over all
232 frames. Now divide by nr_frames and integrate twice
236 if (bSpherical)
238 fprintf(stderr, "\n\nRead %d frames from trajectory. Calculating potential"
239 "in spherical coordinates\n", nr_frames);
241 else
243 fprintf(stderr, "\n\nRead %d frames from trajectory. Calculating potential\n",
244 nr_frames);
247 for (n = 0; n < nr_grps; n++)
249 for (i = 0; i < *nslices; i++)
251 if (bSpherical)
253 /* charge per volume is now the summed charge, divided by the nr
254 of frames and by the volume of the slice it's in, 4pi r^2 dr
256 slVolume = 4*M_PI * sqr(i) * sqr(*slWidth) * *slWidth;
257 if (slVolume == 0)
259 (*slCharge)[n][i] = 0;
261 else
263 (*slCharge)[n][i] = (*slCharge)[n][i] / (nr_frames * slVolume);
266 else
268 /* get charge per volume */
269 (*slCharge)[n][i] = (*slCharge)[n][i] * (*nslices) /
270 (nr_frames * box[axis][axis] * box[ax1][ax1] * box[ax2][ax2]);
273 /* Now we have charge densities */
276 if (bCorrect && !bSpherical)
278 for (n = 0; n < nr_grps; n++)
280 nn = 0;
281 qsum = 0;
282 for (i = 0; i < *nslices; i++)
284 if (std::abs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN)
286 nn++;
287 qsum += (*slCharge)[n][i];
290 qsum /= nn;
291 for (i = 0; i < *nslices; i++)
293 if (std::abs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN)
295 (*slCharge)[n][i] -= qsum;
301 for (n = 0; n < nr_grps; n++)
303 /* integrate twice to get field and potential */
304 p_integrate((*slField)[n], (*slCharge)[n], *nslices, *slWidth);
308 if (bCorrect && !bSpherical)
310 for (n = 0; n < nr_grps; n++)
312 nn = 0;
313 qsum = 0;
314 for (i = 0; i < *nslices; i++)
316 if (std::abs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN)
318 nn++;
319 qsum += (*slField)[n][i];
322 qsum /= nn;
323 for (i = 0; i < *nslices; i++)
325 if (std::abs((*slCharge)[n][i]) >= GMX_DOUBLE_MIN)
327 (*slField)[n][i] -= qsum;
333 for (n = 0; n < nr_grps; n++)
335 p_integrate((*slPotential)[n], (*slField)[n], *nslices, *slWidth);
338 /* Now correct for eps0 and in spherical case for r*/
339 for (n = 0; n < nr_grps; n++)
341 for (i = 0; i < *nslices; i++)
343 if (bSpherical)
345 (*slPotential)[n][i] = ELC * (*slPotential)[n][i] * -1.0E9 /
346 (EPS0 * i * (*slWidth));
347 (*slField)[n][i] = ELC * (*slField)[n][i] * 1E18 /
348 (EPS0 * i * (*slWidth));
350 else
352 (*slPotential)[n][i] = ELC * (*slPotential)[n][i] * -1.0E9 / EPS0;
353 (*slField)[n][i] = ELC * (*slField)[n][i] * 1E18 / EPS0;
358 sfree(x0); /* free memory used by coordinate array */
361 void plot_potential(double *potential[], double *charge[], double *field[],
362 const char *afile, const char *bfile, const char *cfile,
363 int nslices, int nr_grps, const char *grpname[], double slWidth,
364 const gmx_output_env_t *oenv)
366 FILE *pot, /* xvgr file with potential */
367 *cha, /* xvgr file with charges */
368 *fie; /* xvgr files with fields */
369 char buf[256]; /* for xvgr title */
370 int slice, n;
372 sprintf(buf, "Electrostatic Potential");
373 pot = xvgropen(afile, buf, "Box (nm)", "Potential (V)", oenv);
374 xvgr_legend(pot, nr_grps, grpname, oenv);
376 sprintf(buf, "Charge Distribution");
377 cha = xvgropen(bfile, buf, "Box (nm)", "Charge density (q/nm\\S3\\N)", oenv);
378 xvgr_legend(cha, nr_grps, grpname, oenv);
380 sprintf(buf, "Electric Field");
381 fie = xvgropen(cfile, buf, "Box (nm)", "Field (V/nm)", oenv);
382 xvgr_legend(fie, nr_grps, grpname, oenv);
384 for (slice = cb; slice < (nslices - ce); slice++)
386 fprintf(pot, "%20.16g ", slice * slWidth);
387 fprintf(cha, "%20.16g ", slice * slWidth);
388 fprintf(fie, "%20.16g ", slice * slWidth);
389 for (n = 0; n < nr_grps; n++)
391 fprintf(pot, " %20.16g", potential[n][slice]);
392 fprintf(fie, " %20.16g", field[n][slice]/1e9); /* convert to V/nm */
393 fprintf(cha, " %20.16g", charge[n][slice]);
395 fprintf(pot, "\n");
396 fprintf(cha, "\n");
397 fprintf(fie, "\n");
400 xvgrclose(pot);
401 xvgrclose(cha);
402 xvgrclose(fie);
405 int gmx_potential(int argc, char *argv[])
407 const char *desc[] = {
408 "[THISMODULE] computes the electrostatical potential across the box. The potential is",
409 "calculated by first summing the charges per slice and then integrating",
410 "twice of this charge distribution. Periodic boundaries are not taken",
411 "into account. Reference of potential is taken to be the left side of",
412 "the box. It is also possible to calculate the potential in spherical",
413 "coordinates as function of r by calculating a charge distribution in",
414 "spherical slices and twice integrating them. epsilon_r is taken as 1,",
415 "but 2 is more appropriate in many cases."
417 gmx_output_env_t *oenv;
418 static int axis = 2; /* normal to memb. default z */
419 static const char *axtitle = "Z";
420 static int nslices = 10; /* nr of slices defined */
421 static int ngrps = 1;
422 static gmx_bool bSpherical = FALSE; /* default is bilayer types */
423 static real fudge_z = 0; /* translate coordinates */
424 static gmx_bool bCorrect = 0;
425 t_pargs pa [] = {
426 { "-d", FALSE, etSTR, {&axtitle},
427 "Take the normal on the membrane in direction X, Y or Z." },
428 { "-sl", FALSE, etINT, {&nslices},
429 "Calculate potential as function of boxlength, dividing the box"
430 " in this number of slices." },
431 { "-cb", FALSE, etINT, {&cb},
432 "Discard this number of first slices of box for integration" },
433 { "-ce", FALSE, etINT, {&ce},
434 "Discard this number of last slices of box for integration" },
435 { "-tz", FALSE, etREAL, {&fudge_z},
436 "Translate all coordinates by this distance in the direction of the box" },
437 { "-spherical", FALSE, etBOOL, {&bSpherical},
438 "Calculate spherical thingie" },
439 { "-ng", FALSE, etINT, {&ngrps},
440 "Number of groups to consider" },
441 { "-correct", FALSE, etBOOL, {&bCorrect},
442 "Assume net zero charge of groups to improve accuracy" }
444 const char *bugs[] = {
445 "Discarding slices for integration should not be necessary."
448 double **potential, /* potential per slice */
449 **charge, /* total charge per slice */
450 **field, /* field per slice */
451 slWidth; /* width of one slice */
452 char **grpname; /* groupnames */
453 int *ngx; /* sizes of groups */
454 t_topology *top; /* topology */
455 int ePBC;
456 int **index; /* indices for all groups */
457 t_filenm fnm[] = { /* files for g_order */
458 { efTRX, "-f", NULL, ffREAD }, /* trajectory file */
459 { efNDX, NULL, NULL, ffREAD }, /* index file */
460 { efTPR, NULL, NULL, ffREAD }, /* topology file */
461 { efXVG, "-o", "potential", ffWRITE }, /* xvgr output file */
462 { efXVG, "-oc", "charge", ffWRITE }, /* xvgr output file */
463 { efXVG, "-of", "field", ffWRITE }, /* xvgr output file */
466 #define NFILE asize(fnm)
468 if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME,
469 NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs,
470 &oenv))
472 return 0;
475 /* Calculate axis */
476 axis = toupper(axtitle[0]) - 'X';
478 top = read_top(ftp2fn(efTPR, NFILE, fnm), &ePBC); /* read topology file */
480 snew(grpname, ngrps);
481 snew(index, ngrps);
482 snew(ngx, ngrps);
484 rd_index(ftp2fn(efNDX, NFILE, fnm), ngrps, ngx, index, grpname);
487 calc_potential(ftp2fn(efTRX, NFILE, fnm), index, ngx,
488 &potential, &charge, &field,
489 &nslices, top, ePBC, axis, ngrps, &slWidth, fudge_z,
490 bSpherical, bCorrect, oenv);
492 plot_potential(potential, charge, field, opt2fn("-o", NFILE, fnm),
493 opt2fn("-oc", NFILE, fnm), opt2fn("-of", NFILE, fnm),
494 nslices, ngrps, (const char**)grpname, slWidth, oenv);
496 do_view(oenv, opt2fn("-o", NFILE, fnm), NULL); /* view xvgr file */
497 do_view(oenv, opt2fn("-oc", NFILE, fnm), NULL); /* view xvgr file */
498 do_view(oenv, opt2fn("-of", NFILE, fnm), NULL); /* view xvgr file */
500 return 0;