79db631c1ee2e8b3c376711eba7752c094fe97f0
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_densorder.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 #include "gmxpre.h"
36
37 #include "config.h"
38
39 #include <ctype.h>
40 #include <math.h>
41 #include <string.h>
42
43 #include "gromacs/utility/cstringutil.h"
44 #include "gromacs/legacyheaders/typedefs.h"
45 #include "gromacs/legacyheaders/macros.h"
46 #include "gstat.h"
47 #include "gromacs/pbcutil/pbc.h"
48 #include "gromacs/utility/futil.h"
49 #include "gromacs/topology/index.h"
50 #include "gromacs/fileio/tpxio.h"
51 #include "gromacs/fileio/trxio.h"
52 #include "gromacs/math/units.h"
53 #include "dens_filter.h"
54 #include "binsearch.h"
55 #include "powerspect.h"
56 #include "gmx_ana.h"
57 #include "gromacs/legacyheaders/copyrite.h"
58
59 #include "gromacs/commandline/pargs.h"
60 #include "gromacs/fileio/matio.h"
61 #include "gromacs/fileio/xvgr.h"
62 #include "gromacs/math/vec.h"
63 #include "gromacs/pbcutil/rmpbc.h"
64 #include "gromacs/utility/exceptions.h"
65 #include "gromacs/utility/fatalerror.h"
66 #include "gromacs/utility/smalloc.h"
67
68 #ifdef GMX_DOUBLE
69 #define FLOOR(x) ((int) floor(x))
70 #else
71 #define FLOOR(x) ((int) floorf(x))
72 #endif
73
74 enum {
75     methSEL, methBISECT, methFUNCFIT, methNR
76 };
77
78 static void center_coords(t_atoms *atoms, matrix box, rvec x0[], int axis)
79 {
80     int  i, m;
81     real tmass, mm;
82     rvec com, shift, box_center;
83
84     tmass = 0;
85     clear_rvec(com);
86     for (i = 0; (i < atoms->nr); i++)
87     {
88         mm     = atoms->atom[i].m;
89         tmass += mm;
90         for (m = 0; (m < DIM); m++)
91         {
92             com[m] += mm*x0[i][m];
93         }
94     }
95     for (m = 0; (m < DIM); m++)
96     {
97         com[m] /= tmass;
98     }
99     calc_box_center(ecenterDEF, box, box_center);
100     rvec_sub(box_center, com, shift);
101     shift[axis] -= box_center[axis];
102
103     for (i = 0; (i < atoms->nr); i++)
104     {
105         rvec_dec(x0[i], shift);
106     }
107 }
108
109
110 static void density_in_time (const char *fn, atom_id **index, int gnx[], real bw, real bwz, int nsttblock, real *****Densdevel, int *xslices, int *yslices, int *zslices, int *tblock, t_topology *top, int ePBC, int axis, gmx_bool bCenter, gmx_bool bps1d, const output_env_t oenv)
111
112 {
113 /*
114  * *****Densdevel pointer to array of density values in slices and frame-blocks Densdevel[*nsttblock][*xslices][*yslices][*zslices]
115  * Densslice[x][y][z]
116  * nsttblock - nr of frames in each time-block
117  * bw  widths of normal slices
118  *
119  * axis  - axis direction (normal to slices)
120  * nndx - number ot atoms in **index
121  * grpn  - group number in index
122  */
123     t_trxstatus *status;
124     gmx_rmpbc_t  gpbc = NULL;
125     matrix       box;                    /* Box - 3x3 -each step*/
126     rvec        *x0;                     /* List of Coord without PBC*/
127     int          i, j,                   /* loop indices, checks etc*/
128                  ax1     = 0, ax2 = 0,   /* tangent directions */
129                  framenr = 0,            /* frame number in trajectory*/
130                  slicex, slicey, slicez; /*slice # of x y z position */
131     real ***Densslice = NULL;            /* Density-slice in one frame*/
132     real    dscale;                      /*physical scaling factor*/
133     real    t, x, y, z;                  /* time and coordinates*/
134     rvec    bbww;
135
136     *tblock = 0; /* blocknr in block average - initialise to 0*/
137     /* Axis: X=0, Y=1,Z=2 */
138     switch (axis)
139     {
140         case 0:
141             ax1 = YY; ax2 = ZZ; /*Surface: YZ*/
142             break;
143         case 1:
144             ax1 = ZZ; ax2 = XX; /* Surface : XZ*/
145             break;
146         case 2:
147             ax1 = XX; ax2 = YY; /* Surface XY*/
148             break;
149         default:
150             gmx_fatal(FARGS, "Invalid axes. Terminating\n");
151     }
152
153     if (read_first_x(oenv, &status, fn, &t, &x0, box) == 0)
154     {
155         gmx_fatal(FARGS, "Could not read coordinates from file"); /* Open trajectory for read*/
156
157
158     }
159     *zslices = 1+FLOOR(box[axis][axis]/bwz);
160     *yslices = 1+FLOOR(box[ax2][ax2]/bw);
161     *xslices = 1+FLOOR(box[ax1][ax1]/bw);
162     if (bps1d)
163     {
164         if (*xslices < *yslices)
165         {
166             *xslices = 1;
167         }
168         else
169         {
170             *yslices = 1;
171         }
172     }
173     fprintf(stderr,
174             "\nDividing the box in %5d x %5d x %5d slices with binw %f along axis %d\n", *xslices, *yslices, *zslices, bw, axis );
175
176
177     /****Start trajectory processing***/
178
179     /*Initialize Densdevel and PBC-remove*/
180     gpbc = gmx_rmpbc_init(&top->idef, ePBC, top->atoms.nr);
181
182     *Densdevel = NULL;
183
184     do
185     {
186         bbww[XX] = box[ax1][ax1]/ *xslices;
187         bbww[YY] = box[ax2][ax2]/ *yslices;
188         bbww[ZZ] = box[axis][axis]/ *zslices;
189         gmx_rmpbc(gpbc, top->atoms.nr, box, x0);
190         /*Reset Densslice every nsttblock steps*/
191         /* The first conditional is for clang to understand that this branch is
192          * always taken the first time. */
193         if (Densslice == NULL || framenr % nsttblock == 0)
194         {
195             snew(Densslice, *xslices);
196             for (i = 0; i < *xslices; i++)
197             {
198                 snew(Densslice[i], *yslices);
199                 for (j = 0; j < *yslices; j++)
200                 {
201                     snew(Densslice[i][j], *zslices);
202                 }
203             }
204
205             /* Allocate Memory to  extra frame in Densdevel -  rather stupid approach:
206              * A single frame each time, although only every nsttblock steps.
207              */
208             srenew(*Densdevel, *tblock+1);
209             (*Densdevel)[*tblock] = Densslice;
210         }
211
212         dscale = (*xslices)*(*yslices)*(*zslices)*AMU/ (box[ax1][ax1]*box[ax2][ax2]*box[axis][axis]*nsttblock*(NANO*NANO*NANO));
213
214         if (bCenter)
215         {
216             center_coords(&top->atoms, box, x0, axis);
217         }
218
219
220         for (j = 0; j < gnx[0]; j++)
221         {   /*Loop over all atoms in selected index*/
222             x = x0[index[0][j]][ax1];
223             y = x0[index[0][j]][ax2];
224             z = x0[index[0][j]][axis];
225             while (x < 0)
226             {
227                 x += box[ax1][ax1];
228             }
229             while (x > box[ax1][ax1])
230             {
231                 x -= box[ax1][ax1];
232             }
233
234             while (y < 0)
235             {
236                 y += box[ax2][ax2];
237             }
238             while (y > box[ax2][ax2])
239             {
240                 y -= box[ax2][ax2];
241             }
242
243             while (z < 0)
244             {
245                 z += box[axis][axis];
246             }
247             while (z > box[axis][axis])
248             {
249                 z -= box[axis][axis];
250             }
251
252             slicex = ((int) (x/bbww[XX])) % *xslices;
253             slicey = ((int) (y/bbww[YY])) % *yslices;
254             slicez = ((int) (z/bbww[ZZ])) % *zslices;
255             Densslice[slicex][slicey][slicez] += (top->atoms.atom[index[0][j]].m*dscale);
256         }
257
258         framenr++;
259
260         if (framenr % nsttblock == 0)
261         {
262             /*Implicit incrementation of Densdevel via renewal of Densslice*/
263             /*only every nsttblock steps*/
264             (*tblock)++;
265         }
266
267     }
268     while (read_next_x(oenv, status, &t, x0, box));
269
270
271     /*Free memory we no longer need and exit.*/
272     gmx_rmpbc_done(gpbc);
273     close_trj(status);
274
275     if (0)
276     {
277         FILE *fp;
278         fp = fopen("koko.xvg", "w");
279         for (j = 0; (j < *zslices); j++)
280         {
281             fprintf(fp, "%5d", j);
282             for (i = 0; (i < *tblock); i++)
283             {
284                 fprintf(fp, "  %10g", (*Densdevel)[i][9][1][j]);
285             }
286             fprintf(fp, "\n");
287         }
288         fclose(fp);
289     }
290
291 }
292
293 static void outputfield(const char *fldfn, real ****Densmap,
294                         int xslices, int yslices, int zslices, int tdim)
295 {
296 /*Debug-filename and filehandle*/
297     FILE *fldH;
298     int   n, i, j, k;
299     int   dim[4];
300     real  totdens = 0;
301
302     dim[0] = tdim;
303     dim[1] = xslices;
304     dim[2] = yslices;
305     dim[3] = zslices;
306
307     fldH = gmx_ffopen(fldfn, "w");
308     fwrite(dim, sizeof(int), 4, fldH);
309     for (n = 0; n < tdim; n++)
310     {
311         for (i = 0; i < xslices; i++)
312         {
313             for (j = 0; j < yslices; j++)
314             {
315                 for (k = 0; k < zslices; k++)
316                 {
317                     fwrite(&(Densmap[n][i][j][k]), sizeof(real), 1, fldH);
318                     totdens += (Densmap[n][i][j][k]);
319                 }
320             }
321         }
322     }
323     totdens /= (xslices*yslices*zslices*tdim);
324     fprintf(stderr, "Total density [kg/m^3]  %8f", totdens);
325     gmx_ffclose(fldH);
326 }
327
328 static void filterdensmap(real ****Densmap, int xslices, int yslices, int zslices, int tblocks, int ftsize)
329 {
330     real *kernel;
331     real  std, var;
332     int   i, j, n, order;
333     order = ftsize/2;
334     std   = ((real)order/2.0);
335     var   = std*std;
336     snew(kernel, ftsize);
337     gausskernel(kernel, ftsize, var);
338     for (n = 0; n < tblocks; n++)
339     {
340         for (i = 0; i < xslices; i++)
341         {
342             for (j = 0; j < yslices; j++)
343             {
344                 periodic_convolution(zslices, Densmap[n][i][j], ftsize, kernel);
345             }
346         }
347     }
348 }
349
350
351
352
353 static void interfaces_txy (real ****Densmap, int xslices, int yslices, int zslices,
354                             int tblocks, real binwidth, int method,
355                             real dens1, real dens2, t_interf ****intf1,
356                             t_interf ****intf2, const output_env_t oenv)
357 {
358     /*Returns two pointers to 3D arrays of t_interf structs containing (position,thickness) of the interface(s)*/
359     FILE       *xvg;
360     real       *zDensavg; /* zDensavg[z]*/
361     int         i, j, k, n;
362     int         xysize;
363     int         ndx1, ndx2, *zperm;
364     real        densmid;
365     real        splitpoint, startpoint, endpoint;
366     real       *sigma1, *sigma2;
367     real        beginfit1[4];
368     real        beginfit2[4];
369     real       *fit1 = NULL, *fit2 = NULL;
370     const real *avgfit1;
371     const real *avgfit2;
372     const real  onehalf = 1.00/2.00;
373     t_interf ***int1    = NULL, ***int2 = NULL; /*Interface matrices [t][x,y] - last index in row-major order*/
374     /*Create int1(t,xy) and int2(t,xy) arrays with correct number of interf_t elements*/
375     xysize = xslices*yslices;
376     snew(int1, tblocks);
377     snew(int2, tblocks);
378     for (i = 0; i < tblocks; i++)
379     {
380         snew(int1[i], xysize);
381         snew(int2[i], xysize);
382         for (j = 0; j < xysize; j++)
383         {
384             snew(int1[i][j], 1);
385             snew(int2[i][j], 1);
386             init_interf(int1[i][j]);
387             init_interf(int2[i][j]);
388         }
389     }
390
391     if (method == methBISECT)
392     {
393         densmid = onehalf*(dens1+dens2);
394         snew(zperm, zslices);
395         for (n = 0; n < tblocks; n++)
396         {
397             for (i = 0; i < xslices; i++)
398             {
399                 for (j = 0; j < yslices; j++)
400                 {
401                     rangeArray(zperm, zslices); /*reset permutation array to identity*/
402                     /*Binsearch returns slice-nr where the order param is  <= setpoint sgmid*/
403                     ndx1 = start_binsearch(Densmap[n][i][j], zperm, 0, zslices/2-1, densmid, 1);
404                     ndx2 = start_binsearch(Densmap[n][i][j], zperm, zslices/2, zslices-1, densmid, -1);
405
406                     /* Linear interpolation (for use later if time allows)
407                      * rho_1s= Densmap[n][i][j][zperm[ndx1]]
408                      * rho_1e =Densmap[n][i][j][zperm[ndx1+1]] - in worst case might be far off
409                      * rho_2s =Densmap[n][i][j][zperm[ndx2+1]]
410                      * rho_2e =Densmap[n][i][j][zperm[ndx2]]
411                      * For 1st interface we have:
412                        densl= Densmap[n][i][j][zperm[ndx1]];
413                        densr= Densmap[n][i][j][zperm[ndx1+1]];
414                        alpha=(densmid-densl)/(densr-densl);
415                        deltandx=zperm[ndx1+1]-zperm[ndx1];
416
417                        if(debug){
418                        printf("Alpha, Deltandx  %f %i\n", alpha,deltandx);
419                        }
420                        if(abs(alpha)>1.0 || abs(deltandx)>3){
421                        pos=zperm[ndx1];
422                        spread=-1;
423                        }
424                        else {
425                        pos=zperm[ndx1]+alpha*deltandx;
426                        spread=binwidth*deltandx;
427                        }
428                      * For the 2nd interface  can use the same formulation, since alpha should become negative ie:
429                      * alpha=(densmid-Densmap[n][i][j][zperm[ndx2]])/(Densmap[n][i][j][zperm[nxd2+1]]-Densmap[n][i][j][zperm[ndx2]]);
430                      * deltandx=zperm[ndx2+1]-zperm[ndx2];
431                      * pos=zperm[ndx2]+alpha*deltandx;   */
432
433                     /*After filtering we use the direct approach        */
434                     int1[n][j+(i*yslices)]->Z = (zperm[ndx1]+onehalf)*binwidth;
435                     int1[n][j+(i*yslices)]->t = binwidth;
436                     int2[n][j+(i*yslices)]->Z = (zperm[ndx2]+onehalf)*binwidth;
437                     int2[n][j+(i*yslices)]->t = binwidth;
438                 }
439             }
440         }
441     }
442
443     if (method == methFUNCFIT)
444     {
445         /*Assume a box divided in 2 along midpoint of z for starters*/
446         startpoint = 0.0;
447         endpoint   = binwidth*zslices;
448         splitpoint = (startpoint+endpoint)/2.0;
449         /*Initial fit proposals*/
450         beginfit1[0] = dens1;
451         beginfit1[1] = dens2;
452         beginfit1[2] = (splitpoint/2);
453         beginfit1[3] = 0.5;
454
455         beginfit2[0] = dens2;
456         beginfit2[1] = dens1;
457         beginfit2[2] = (3*splitpoint/2);
458         beginfit2[3] = 0.5;
459
460         snew(zDensavg, zslices);
461         snew(sigma1, zslices);
462         snew(sigma2, zslices);
463
464         for (k = 0; k < zslices; k++)
465         {
466             sigma1[k] = sigma2[k] = 1;
467         }
468         /*Calculate average density along z - avoid smoothing by using coarse-grained-mesh*/
469         for (k = 0; k < zslices; k++)
470         {
471             for (n = 0; n < tblocks; n++)
472             {
473                 for (i = 0; i < xslices; i++)
474                 {
475                     for (j = 0; j < yslices; j++)
476                     {
477                         zDensavg[k] += (Densmap[n][i][j][k]/(xslices*yslices*tblocks));
478                     }
479                 }
480             }
481         }
482
483         if (debug)
484         {
485             xvg = xvgropen("DensprofileonZ.xvg", "Averaged Densityprofile on Z", "z[nm]", "Density[kg/m^3]", oenv);
486             for (k = 0; k < zslices; k++)
487             {
488                 fprintf(xvg, "%4f.3   %8f.4\n", k*binwidth, zDensavg[k]);
489             }
490             xvgrclose(xvg);
491         }
492
493         /*Fit average density in z over whole trajectory to obtain tentative fit-parameters in fit1 and fit2*/
494
495         /*Fit 1st half of box*/
496         do_lmfit(zslices, zDensavg, sigma1, binwidth, NULL, startpoint, splitpoint, oenv, FALSE, effnERF, beginfit1, 3);
497         /*Fit 2nd half of box*/
498         do_lmfit(zslices, zDensavg, sigma2, binwidth, NULL, splitpoint, endpoint, oenv, FALSE, effnERF, beginfit2, 3);
499
500         /*Initialise the const arrays for storing the average fit parameters*/
501         avgfit1 = beginfit1;
502         avgfit2 = beginfit2;
503
504
505
506         /*Now do fit over each x  y and t slice to get Zint(x,y,t) - loop is very large, we potentially should average over time directly*/
507         for (n = 0; n < tblocks; n++)
508         {
509             for (i = 0; i < xslices; i++)
510             {
511                 for (j = 0; j < yslices; j++)
512                 {
513                     /*Reinitialise fit for each mesh-point*/
514                     srenew(fit1, 4);
515                     srenew(fit2, 4);
516                     for (k = 0; k < 4; k++)
517                     {
518                         fit1[k] = avgfit1[k];
519                         fit2[k] = avgfit2[k];
520                     }
521                     /*Now fit and store in structures in row-major order int[n][i][j]*/
522                     do_lmfit(zslices, Densmap[n][i][j], sigma1, binwidth, NULL, startpoint, splitpoint, oenv, FALSE, effnERF, fit1, 1);
523                     int1[n][j+(yslices*i)]->Z = fit1[2];
524                     int1[n][j+(yslices*i)]->t = fit1[3];
525                     do_lmfit(zslices, Densmap[n][i][j], sigma2, binwidth, NULL, splitpoint, endpoint, oenv, FALSE, effnERF, fit2, 2);
526                     int2[n][j+(yslices*i)]->Z = fit2[2];
527                     int2[n][j+(yslices*i)]->t = fit2[3];
528                 }
529             }
530         }
531     }
532
533
534     *intf1 = int1;
535     *intf2 = int2;
536
537 }
538
539 static void writesurftoxpms(t_interf ***surf1, t_interf ***surf2, int tblocks, int xbins, int ybins, int zbins, real bw, real bwz, char **outfiles, int maplevels )
540 {
541     char   numbuf[13];
542     int    n, i, j;
543     real **profile1, **profile2;
544     real   max1, max2, min1, min2, *xticks, *yticks;
545     t_rgb  lo = {0, 0, 0};
546     t_rgb  hi = {1, 1, 1};
547     FILE  *xpmfile1, *xpmfile2;
548
549 /*Prepare xpm structures for output*/
550
551 /*Allocate memory to tick's and matrices*/
552     snew (xticks, xbins+1);
553     snew (yticks, ybins+1);
554
555     profile1 = mk_matrix(xbins, ybins, FALSE);
556     profile2 = mk_matrix(xbins, ybins, FALSE);
557
558     for (i = 0; i < xbins+1; i++)
559     {
560         xticks[i] += bw;
561     }
562     for (j = 0; j < ybins+1; j++)
563     {
564         yticks[j] += bw;
565     }
566
567     xpmfile1 = gmx_ffopen(outfiles[0], "w");
568     xpmfile2 = gmx_ffopen(outfiles[1], "w");
569
570     max1 = max2 = 0.0;
571     min1 = min2 = zbins*bwz;
572
573     for (n = 0; n < tblocks; n++)
574     {
575         sprintf(numbuf, "tblock: %4i", n);
576 /*Filling matrices for inclusion in xpm-files*/
577         for (i = 0; i < xbins; i++)
578         {
579             for (j = 0; j < ybins; j++)
580             {
581                 profile1[i][j] = (surf1[n][j+ybins*i])->Z;
582                 profile2[i][j] = (surf2[n][j+ybins*i])->Z;
583                 /*Finding max and min values*/
584                 if (profile1[i][j] > max1)
585                 {
586                     max1 = profile1[i][j];
587                 }
588                 if (profile1[i][j] < min1)
589                 {
590                     min1 = profile1[i][j];
591                 }
592                 if (profile2[i][j] > max2)
593                 {
594                     max2 = profile2[i][j];
595                 }
596                 if (profile2[i][j] < min2)
597                 {
598                     min2 = profile2[i][j];
599                 }
600             }
601         }
602
603         write_xpm(xpmfile1, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks, profile1, min1, max1, lo, hi, &maplevels);
604         write_xpm(xpmfile2, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks, profile2, min2, max2, lo, hi, &maplevels);
605     }
606
607     gmx_ffclose(xpmfile1);
608     gmx_ffclose(xpmfile2);
609
610
611     sfree(profile1);
612     sfree(profile2);
613     sfree(xticks);
614     sfree(yticks);
615 }
616
617 static void writeraw(t_interf ***int1, t_interf ***int2, int tblocks,
618                      int xbins, int ybins, char **fnms,
619                      const output_env_t oenv)
620 {
621     FILE *raw1, *raw2;
622     int   i, j, n;
623
624     raw1 = gmx_ffopen(fnms[0], "w");
625     raw2 = gmx_ffopen(fnms[1], "w");
626     try
627     {
628         gmx::BinaryInformationSettings settings;
629         settings.generatedByHeader(true);
630         settings.linePrefix("# ");
631         gmx::printBinaryInformation(raw1, output_env_get_program_context(oenv),
632                                     settings);
633         gmx::printBinaryInformation(raw2, output_env_get_program_context(oenv),
634                                     settings);
635     }
636     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
637     fprintf(raw1, "# Legend: nt nx ny\n# Xbin Ybin Z t\n");
638     fprintf(raw2, "# Legend: nt nx ny\n# Xbin Ybin Z t\n");
639     fprintf(raw1, "%i %i %i\n", tblocks, xbins, ybins);
640     fprintf(raw2, "%i %i %i\n", tblocks, xbins, ybins);
641     for (n = 0; n < tblocks; n++)
642     {
643         for (i = 0; i < xbins; i++)
644         {
645             for (j = 0; j < ybins; j++)
646             {
647                 fprintf(raw1, "%i  %i  %8.5f  %6.4f\n", i, j, (int1[n][j+ybins*i])->Z, (int1[n][j+ybins*i])->t);
648                 fprintf(raw2, "%i  %i  %8.5f  %6.4f\n", i, j, (int2[n][j+ybins*i])->Z, (int2[n][j+ybins*i])->t);
649             }
650         }
651     }
652
653     gmx_ffclose(raw1);
654     gmx_ffclose(raw2);
655 }
656
657
658
659 int gmx_densorder(int argc, char *argv[])
660 {
661     static const char *desc[] = {
662         "[THISMODULE] reduces a two-phase density distribution",
663         "along an axis, computed over a MD trajectory,",
664         "to 2D surfaces fluctuating in time, by a fit to",
665         "a functional profile for interfacial densities.",
666         "A time-averaged spatial representation of the",
667         "interfaces can be output with the option [TT]-tavg[tt]."
668     };
669
670     /* Extra arguments - but note how you always get the begin/end
671      * options when running the program, without mentioning them here!
672      */
673
674     output_env_t       oenv;
675     t_topology        *top;
676     char             **grpname;
677     int                ePBC, *ngx;
678     static real        binw      = 0.2;
679     static real        binwz     = 0.05;
680     static real        dens1     = 0.00;
681     static real        dens2     = 1000.00;
682     static int         ftorder   = 0;
683     static int         nsttblock = 100;
684     static int         axis      = 2;
685     static const char *axtitle   = "Z";
686     atom_id          **index; /* Index list for single group*/
687     int                xslices, yslices, zslices, tblock;
688     static gmx_bool    bGraph   = FALSE;
689     static gmx_bool    bCenter  = FALSE;
690     static gmx_bool    bFourier = FALSE;
691     static gmx_bool    bRawOut  = FALSE;
692     static gmx_bool    bOut     = FALSE;
693     static gmx_bool    b1d      = FALSE;
694     static int         nlevels  = 100;
695     /*Densitymap - Densmap[t][x][y][z]*/
696     real           ****Densmap = NULL;
697     /* Surfaces surf[t][surf_x,surf_y]*/
698     t_interf        ***surf1, ***surf2;
699
700     static const char *meth[] = {NULL, "bisect", "functional", NULL};
701     int                eMeth;
702
703     char             **graphfiles, **rawfiles, **spectra; /* Filenames for xpm-surface maps, rawdata and powerspectra */
704     int                nfxpm = -1, nfraw, nfspect;        /* # files for interface maps and spectra = # interfaces */
705
706     t_pargs            pa[] = {
707         { "-1d", FALSE, etBOOL, {&b1d},
708           "Pseudo-1d interface geometry"},
709         { "-bw", FALSE, etREAL, {&binw},
710           "Binwidth of density distribution tangential to interface"},
711         { "-bwn", FALSE, etREAL, {&binwz},
712           "Binwidth of density distribution normal to interface"},
713         { "-order", FALSE, etINT, {&ftorder},
714           "Order of Gaussian filter, order 0 equates to NO filtering"},
715         {"-axis", FALSE, etSTR, {&axtitle},
716          "Axis Direction - X, Y or Z"},
717         {"-method", FALSE, etENUM, {meth},
718          "Interface location method"},
719         {"-d1", FALSE, etREAL, {&dens1},
720          "Bulk density phase 1 (at small z)"},
721         {"-d2", FALSE, etREAL, {&dens2},
722          "Bulk density phase 2 (at large z)"},
723         { "-tblock", FALSE, etINT, {&nsttblock},
724           "Number of frames in one time-block average"},
725         { "-nlevel", FALSE, etINT, {&nlevels},
726           "Number of Height levels in 2D - XPixMaps"}
727     };
728
729
730     t_filenm fnm[] = {
731         { efTPX, "-s",  NULL, ffREAD },               /* this is for the topology */
732         { efTRX, "-f", NULL, ffREAD },                /* and this for the trajectory */
733         { efNDX, "-n", NULL, ffREAD},                 /* this is to select groups */
734         { efDAT, "-o", "Density4D", ffOPTWR},         /* This is for outputting the entire 4D densityfield in binary format */
735         { efOUT, "-or", NULL, ffOPTWRMULT},           /* This is for writing out the entire information in the t_interf arrays */
736         { efXPM, "-og", "interface", ffOPTWRMULT},    /* This is for writing out the interface meshes - one xpm-file per tblock*/
737         { efOUT, "-Spect", "intfspect", ffOPTWRMULT}, /* This is for the trajectory averaged Fourier-spectra*/
738     };
739
740 #define NFILE asize(fnm)
741
742     /* This is the routine responsible for adding default options,
743      * calling the X/motif interface, etc. */
744     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW,
745                            NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
746     {
747         return 0;
748     }
749
750
751     eMeth    = nenum(meth);
752     bFourier = opt2bSet("-Spect", NFILE, fnm);
753     bRawOut  = opt2bSet("-or", NFILE, fnm);
754     bGraph   = opt2bSet("-og", NFILE, fnm);
755     bOut     = opt2bSet("-o", NFILE, fnm);
756     top      = read_top(ftp2fn(efTPX, NFILE, fnm), &ePBC);
757     snew(grpname, 1);
758     snew(index, 1);
759     snew(ngx, 1);
760
761 /* Calculate axis */
762     axis = toupper(axtitle[0]) - 'X';
763
764     get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, ngx, index, grpname);
765
766     density_in_time(ftp2fn(efTRX, NFILE, fnm), index, ngx, binw, binwz, nsttblock, &Densmap, &xslices, &yslices, &zslices, &tblock, top, ePBC, axis, bCenter, b1d, oenv);
767
768     if (ftorder > 0)
769     {
770         filterdensmap(Densmap, xslices, yslices, zslices, tblock, 2*ftorder+1);
771     }
772
773     if (bOut)
774     {
775         outputfield(opt2fn("-o", NFILE, fnm), Densmap, xslices, yslices, zslices, tblock);
776     }
777
778     interfaces_txy(Densmap, xslices, yslices, zslices, tblock, binwz, eMeth, dens1, dens2, &surf1, &surf2, oenv);
779
780     if (bGraph)
781     {
782
783         /*Output surface-xpms*/
784         nfxpm = opt2fns(&graphfiles, "-og", NFILE, fnm);
785         if (nfxpm != 2)
786         {
787             gmx_fatal(FARGS, "No or not correct number (2) of output-files: %d", nfxpm);
788         }
789         writesurftoxpms(surf1, surf2, tblock, xslices, yslices, zslices, binw, binwz, graphfiles, zslices);
790     }
791
792
793
794
795
796 /*Output raw-data*/
797     if (bRawOut)
798     {
799         nfraw = opt2fns(&rawfiles, "-or", NFILE, fnm);
800         if (nfraw != 2)
801         {
802             gmx_fatal(FARGS, "No or not correct number (2) of output-files: %d", nfxpm);
803         }
804         writeraw(surf1, surf2, tblock, xslices, yslices, rawfiles, oenv);
805     }
806
807
808
809     if (bFourier)
810     {
811         nfspect = opt2fns(&spectra, "-Spect", NFILE, fnm);
812         if (nfspect != 2)
813         {
814             gmx_fatal(FARGS, "No or not correct number (2) of output-file-series: %d",
815                       nfspect);
816         }
817         powerspectavg_intf(surf1, surf2, tblock, xslices, yslices, spectra);
818     }
819
820     sfree(Densmap);
821     if (bGraph || bFourier || bRawOut)
822     {
823         sfree(surf1);
824         sfree(surf2);
825     }
826
827     return 0;
828 }