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