ca338f90151ff0fd02c621b997afda93adf7ee79
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_h2order.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
10  *
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.
15  *
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.
20  *
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.
25  *
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.
33  *
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.
36  */
37 #include "gmxpre.h"
38
39 #include "config.h"
40
41 #include <math.h>
42 #include <string.h>
43
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"
57
58 #include "gromacs/utility/fatalerror.h"
59
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 /****************************************************************************/
68
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)
74 {
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;
90
91     if ((natoms = read_first_x(oenv, &status, fn, &t, &x0, box)) == 0)
92     {
93         gmx_fatal(FARGS, "Could not read coordinates from statusfile\n");
94     }
95
96     if (!*nslices)
97     {
98         *nslices = (int)(box[axis][axis] * 10); /* default value */
99
100
101     }
102     switch (axis)
103     {
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;
117     }
118
119     clear_rvec(dipole);
120     snew(count, *nslices);
121     snew(sum, *nslices);
122     snew(dip, *nslices);
123     snew(frame, *nslices);
124
125     *slWidth = box[axis][axis]/(*nslices);
126     fprintf(stderr, "Box divided in %d slices. Initial width of slice: %f\n",
127             *nslices, *slWidth);
128
129     teller = 0;
130
131     gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms);
132     /*********** Start processing trajectory ***********/
133     do
134     {
135         *slWidth = box[axis][axis]/(*nslices);
136         teller++;
137
138         gmx_rmpbc(gpbc, natoms, box, x0);
139
140         if (bMicel)
141         {
142             calc_xcm(x0, nmic, micel, top->atoms.atom, com, FALSE);
143         }
144
145         for (i = 0; i < ngx/3; i++)
146         {
147             /* put all waters in box */
148             for (j = 0; j < DIM; j++)
149             {
150                 if (x0[index[3*i]][j] < 0)
151                 {
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];
155                 }
156                 if (x0[index[3*i]][j] > box[j][j])
157                 {
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];
161                 }
162             }
163
164             for (j = 0; j < DIM; j++)
165             {
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;
170             }
171
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.
175              */
176
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           */
181
182                 sum[slice]   += iprod(dipole, normal) / (norm(dipole) * norm(normal));
183                 frame[slice] += iprod(dipole, normal) / (norm(dipole) * norm(normal));
184                 count[slice]++;
185
186             }
187             else
188             {
189                 /* this is for flat interfaces      */
190
191                 /* determine which slice atom is in */
192                 slice = (x0[index[3*i]][axis] / (*slWidth));
193                 if (slice < 0 || slice >= *nslices)
194                 {
195                     fprintf(stderr, "Coordinate: %f ", x0[index[3*i]][axis]);
196                     fprintf(stderr, "HELP PANIC! slice = %d, OUT OF RANGE!\n", slice);
197                 }
198                 else
199                 {
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]++;
206                 }
207             }
208         }
209
210     }
211     while (read_next_x(oenv, status, &t, x0, box));
212     /*********** done with status file **********/
213
214     fprintf(stderr, "\nRead trajectory. Printing parameters to file\n");
215     gmx_rmpbc_done(gpbc);
216
217     for (i = 0; i < *nslices; i++) /* average over frames */
218     {
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 */
221         {
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];
226         }
227         else
228         {
229             fprintf(stderr, "No water in slice %d\n", i);
230         }
231     }
232
233     *slOrder  = sum; /* copy a pointer, I hope */
234     *slDipole = dip;
235     sfree(x0);       /* free memory used by coordinate arrays */
236 }
237
238 void h2order_plot(rvec dipole[], real order[], const char *afile,
239                   int nslices, real slWidth, const output_env_t oenv)
240 {
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 */
245
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);
252
253     for (slice = 0; slice < nslices; slice++)
254     {
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]);
258     }
259
260     gmx_ffclose(ord);
261 }
262
263 int gmx_h2order(int argc, char *argv[])
264 {
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."
274     };
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."}
284     };
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."
290     };
291
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       */
311     };
312
313 #define NFILE asize(fnm)
314
315     if (!parse_common_args(&argc, argv,
316                            PCA_CAN_VIEW | PCA_CAN_TIME, NFILE,
317                            fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
318     {
319         return 0;
320     }
321     bMicel = opt2bSet("-nm", NFILE, fnm);
322
323     top = read_top(ftp2fn(efTPX, NFILE, fnm), &ePBC); /* read topology file */
324
325     rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &ngx, &index, &grpname);
326
327     if (bMicel)
328     {
329         rd_index(opt2fn("-nm", NFILE, fnm), 1, &nmic, &micelle, &micname);
330     }
331
332     calc_h2order(ftp2fn(efTRX, NFILE, fnm), index, ngx, &slDipole, &slOrder,
333                  &slWidth, &nslices, top, ePBC, axis, bMicel, micelle, nmic,
334                  oenv);
335
336     h2order_plot(slDipole, slOrder, opt2fn("-o", NFILE, fnm), nslices,
337                  slWidth, oenv);
338
339     do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); /* view xvgr file */
340
341     return 0;
342 }