Merge release-5-0 into master
[gromacs.git] / src / gromacs / gmxana / gmx_h2order.c
blob96ab2b82f26d44b05f253fe39b088976ee146185
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, 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 "config.h"
41 #include <math.h>
42 #include <string.h>
44 #include "gromacs/legacyheaders/typedefs.h"
45 #include "gromacs/utility/smalloc.h"
46 #include "gromacs/legacyheaders/macros.h"
47 #include "princ.h"
48 #include "gromacs/pbcutil/rmpbc.h"
49 #include "gromacs/math/vec.h"
50 #include "gromacs/fileio/xvgr.h"
51 #include "gromacs/legacyheaders/viewit.h"
52 #include "gromacs/utility/futil.h"
53 #include "gromacs/commandline/pargs.h"
54 #include "gromacs/topology/index.h"
55 #include "gmx_ana.h"
56 #include "gromacs/fileio/trxio.h"
58 #include "gromacs/utility/fatalerror.h"
60 /****************************************************************************/
61 /* This program calculates the ordering of water molecules across a box, as */
62 /* function of the z-coordinate. This implies averaging over slices and over*/
63 /* time. Output is the average cos of the angle of the dipole with the */
64 /* normal, per slice. */
65 /* In addition, it calculates the average dipole moment itself in three */
66 /* directions. */
67 /****************************************************************************/
69 void calc_h2order(const char *fn, atom_id index[], int ngx, rvec **slDipole,
70 real **slOrder, real *slWidth, int *nslices,
71 t_topology *top, int ePBC,
72 int axis, gmx_bool bMicel, atom_id micel[], int nmic,
73 const output_env_t oenv)
75 rvec *x0, /* coordinates with pbc */
76 dipole, /* dipole moment due to one molecules */
77 normal,
78 com; /* center of mass of micel, with bMicel */
79 rvec *dip; /* sum of dipoles, unnormalized */
80 matrix box; /* box (3x3) */
81 t_trxstatus *status;
82 real t, /* time from trajectory */
83 *sum, /* sum of all cosines of dipoles, per slice */
84 *frame; /* order over one frame */
85 int natoms, /* nr. atoms in trj */
86 i, j, teller = 0,
87 slice = 0, /* current slice number */
88 *count; /* nr. of atoms in one slice */
89 gmx_rmpbc_t gpbc = NULL;
91 if ((natoms = read_first_x(oenv, &status, fn, &t, &x0, box)) == 0)
93 gmx_fatal(FARGS, "Could not read coordinates from statusfile\n");
96 if (!*nslices)
98 *nslices = (int)(box[axis][axis] * 10); /* default value */
102 switch (axis)
104 case 0:
105 normal[0] = 1; normal[1] = 0; normal[2] = 0;
106 break;
107 case 1:
108 normal[0] = 0; normal[1] = 1; normal[2] = 0;
109 break;
110 case 2:
111 normal[0] = 0; normal[1] = 0; normal[2] = 1;
112 break;
113 default:
114 gmx_fatal(FARGS, "No valid value for -axis-. Exiting.\n");
115 /* make compiler happy */
116 normal[0] = 1; normal[1] = 0; normal[2] = 0;
119 clear_rvec(dipole);
120 snew(count, *nslices);
121 snew(sum, *nslices);
122 snew(dip, *nslices);
123 snew(frame, *nslices);
125 *slWidth = box[axis][axis]/(*nslices);
126 fprintf(stderr, "Box divided in %d slices. Initial width of slice: %f\n",
127 *nslices, *slWidth);
129 teller = 0;
131 gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms);
132 /*********** Start processing trajectory ***********/
135 *slWidth = box[axis][axis]/(*nslices);
136 teller++;
138 gmx_rmpbc(gpbc, natoms, box, x0);
140 if (bMicel)
142 calc_xcm(x0, nmic, micel, top->atoms.atom, com, FALSE);
145 for (i = 0; i < ngx/3; i++)
147 /* put all waters in box */
148 for (j = 0; j < DIM; j++)
150 if (x0[index[3*i]][j] < 0)
152 x0[index[3*i]][j] += box[j][j];
153 x0[index[3*i+1]][j] += box[j][j];
154 x0[index[3*i+2]][j] += box[j][j];
156 if (x0[index[3*i]][j] > box[j][j])
158 x0[index[3*i]][j] -= box[j][j];
159 x0[index[3*i+1]][j] -= box[j][j];
160 x0[index[3*i+2]][j] -= box[j][j];
164 for (j = 0; j < DIM; j++)
166 dipole[j] =
167 x0[index[3*i]][j] * top->atoms.atom[index[3*i]].q +
168 x0[index[3*i+1]][j] * top->atoms.atom[index[3*i+1]].q +
169 x0[index[3*i+2]][j] * top->atoms.atom[index[3*i+2]].q;
172 /* now we have a dipole vector. Might as well safe it. Then the
173 rest depends on whether we're dealing with
174 a flat or a spherical interface.
177 if (bMicel)
178 { /* this is for spherical interfaces */
179 rvec_sub(com, x0[index[3*i]], normal); /* vector from Oxygen to COM */
180 slice = norm(normal)/(*slWidth); /* spherical slice */
182 sum[slice] += iprod(dipole, normal) / (norm(dipole) * norm(normal));
183 frame[slice] += iprod(dipole, normal) / (norm(dipole) * norm(normal));
184 count[slice]++;
187 else
189 /* this is for flat interfaces */
191 /* determine which slice atom is in */
192 slice = (x0[index[3*i]][axis] / (*slWidth));
193 if (slice < 0 || slice >= *nslices)
195 fprintf(stderr, "Coordinate: %f ", x0[index[3*i]][axis]);
196 fprintf(stderr, "HELP PANIC! slice = %d, OUT OF RANGE!\n", slice);
198 else
200 rvec_add(dipole, dip[slice], dip[slice]);
201 /* Add dipole to total. mag[slice] is total dipole in axis direction */
202 sum[slice] += iprod(dipole, normal)/norm(dipole);
203 frame[slice] += iprod(dipole, normal)/norm(dipole);
204 /* increase count for that slice */
205 count[slice]++;
211 while (read_next_x(oenv, status, &t, x0, box));
212 /*********** done with status file **********/
214 fprintf(stderr, "\nRead trajectory. Printing parameters to file\n");
215 gmx_rmpbc_done(gpbc);
217 for (i = 0; i < *nslices; i++) /* average over frames */
219 fprintf(stderr, "%d waters in slice %d\n", count[i], i);
220 if (count[i] > 0) /* divide by number of molecules in each slice */
222 sum[i] = sum[i] / count[i];
223 dip[i][XX] = dip[i][XX] / count[i];
224 dip[i][YY] = dip[i][YY] / count[i];
225 dip[i][ZZ] = dip[i][ZZ] / count[i];
227 else
229 fprintf(stderr, "No water in slice %d\n", i);
233 *slOrder = sum; /* copy a pointer, I hope */
234 *slDipole = dip;
235 sfree(x0); /* free memory used by coordinate arrays */
238 void h2order_plot(rvec dipole[], real order[], const char *afile,
239 int nslices, real slWidth, const output_env_t oenv)
241 FILE *ord; /* xvgr files with order parameters */
242 int slice; /* loop index */
243 char buf[256]; /* for xvgr title */
244 real factor; /* conversion to Debye from electron*nm */
246 /* factor = 1e-9*1.60217733e-19/3.336e-30 */
247 factor = 1.60217733/3.336e-2;
248 fprintf(stderr, "%d slices\n", nslices);
249 sprintf(buf, "Water orientation with respect to normal");
250 ord = xvgropen(afile, buf,
251 "box (nm)", "mu_x, mu_y, mu_z (D), cosine with normal", oenv);
253 for (slice = 0; slice < nslices; slice++)
255 fprintf(ord, "%8.3f %8.3f %8.3f %8.3f %e\n", slWidth*slice,
256 factor*dipole[slice][XX], factor*dipole[slice][YY],
257 factor*dipole[slice][ZZ], order[slice]);
260 gmx_ffclose(ord);
263 int gmx_h2order(int argc, char *argv[])
265 const char *desc[] = {
266 "[THISMODULE] computes the orientation of water molecules with respect to the normal",
267 "of the box. The program determines the average cosine of the angle",
268 "between the dipole moment of water and an axis of the box. The box is",
269 "divided in slices and the average orientation per slice is printed.",
270 "Each water molecule is assigned to a slice, per time frame, based on the",
271 "position of the oxygen. When [TT]-nm[tt] is used, the angle between the water",
272 "dipole and the axis from the center of mass to the oxygen is calculated",
273 "instead of the angle between the dipole and a box axis."
275 static int axis = 2; /* normal to memb. default z */
276 static const char *axtitle = "Z";
277 static int nslices = 0; /* nr of slices defined */
278 t_pargs pa[] = {
279 { "-d", FALSE, etSTR, {&axtitle},
280 "Take the normal on the membrane in direction X, Y or Z." },
281 { "-sl", FALSE, etINT, {&nslices},
282 "Calculate order parameter as function of boxlength, dividing the box"
283 " in this number of slices."}
285 const char *bugs[] = {
286 "The program assigns whole water molecules to a slice, based on the first "
287 "atom of three in the index file group. It assumes an order O,H,H. "
288 "Name is not important, but the order is. If this demand is not met, "
289 "assigning molecules to slices is different."
292 output_env_t oenv;
293 real *slOrder, /* av. cosine, per slice */
294 slWidth = 0.0; /* width of a slice */
295 rvec *slDipole;
296 char *grpname, /* groupnames */
297 *micname;
298 int ngx, /* nr. of atomsin sol group */
299 nmic = 0; /* nr. of atoms in micelle */
300 t_topology *top; /* topology */
301 int ePBC;
302 atom_id *index, /* indices for solvent group */
303 *micelle = NULL;
304 gmx_bool bMicel = FALSE; /* think we're a micel */
305 t_filenm fnm[] = { /* files for g_order */
306 { efTRX, "-f", NULL, ffREAD }, /* trajectory file */
307 { efNDX, NULL, NULL, ffREAD }, /* index file */
308 { efNDX, "-nm", NULL, ffOPTRD }, /* index with micelle atoms */
309 { efTPX, NULL, NULL, ffREAD }, /* topology file */
310 { efXVG, "-o", "order", ffWRITE }, /* xvgr output file */
313 #define NFILE asize(fnm)
315 if (!parse_common_args(&argc, argv,
316 PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE, NFILE,
317 fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
319 return 0;
321 bMicel = opt2bSet("-nm", NFILE, fnm);
323 top = read_top(ftp2fn(efTPX, NFILE, fnm), &ePBC); /* read topology file */
325 rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &ngx, &index, &grpname);
327 if (bMicel)
329 rd_index(opt2fn("-nm", NFILE, fnm), 1, &nmic, &micelle, &micname);
332 calc_h2order(ftp2fn(efTRX, NFILE, fnm), index, ngx, &slDipole, &slOrder,
333 &slWidth, &nslices, top, ePBC, axis, bMicel, micelle, nmic,
334 oenv);
336 h2order_plot(slDipole, slOrder, opt2fn("-o", NFILE, fnm), nslices,
337 slWidth, oenv);
339 do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); /* view xvgr file */
341 return 0;