Merge branch release-4-6
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_dipoles.cpp
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * Green Red Orange Magenta Azure Cyan Skyblue
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38 #include <string.h>
39 #include <math.h>
40
41 #include <algorithm>
42
43 #include "macros.h"
44 #include "statutil.h"
45 #include "sysstuff.h"
46 #include "smalloc.h"
47 #include "vec.h"
48 #include "pbc.h"
49 #include "bondf.h"
50 #include "gromacs/fileio/futil.h"
51 #include "xvgr.h"
52 #include "txtdump.h"
53 #include "gmx_statistics.h"
54 #include "gstat.h"
55 #include "index.h"
56 #include "random.h"
57 #include "names.h"
58 #include "physics.h"
59 #include "calcmu.h"
60 #include "gromacs/fileio/enxio.h"
61 #include "nrjac.h"
62 #include "gromacs/fileio/matio.h"
63 #include "gmx_ana.h"
64 #include "copyrite.h"
65 #include "gromacs/fileio/trxio.h"
66
67 #include "gromacs/utility/exceptions.h"
68 #include "gromacs/utility/programinfo.h"
69
70 #define e2d(x) ENM2DEBYE*(x)
71 #define EANG2CM  E_CHARGE*1.0e-10       /* e Angstrom to Coulomb meter */
72 #define CM2D  SPEED_OF_LIGHT*1.0e+24    /* Coulomb meter to Debye */
73
74 typedef struct {
75     int      nelem;
76     real     spacing, radius;
77     real    *elem;
78     int     *count;
79     gmx_bool bPhi;
80     int      nx, ny;
81     real   **cmap;
82 } t_gkrbin;
83
84 static t_gkrbin *mk_gkrbin(real radius, real rcmax, gmx_bool bPhi, int ndegrees)
85 {
86     t_gkrbin *gb;
87     char     *ptr;
88     int       i;
89
90     snew(gb, 1);
91
92     if ((ptr = getenv("GKRWIDTH")) != NULL)
93     {
94         double bw = strtod(ptr, NULL);
95         gb->spacing = bw;
96     }
97     else
98     {
99         gb->spacing = 0.01; /* nm */
100     }
101     gb->nelem   = 1 + static_cast<int>(radius/gb->spacing);
102     if (rcmax == 0)
103     {
104         gb->nx = gb->nelem;
105     }
106     else
107     {
108         gb->nx = 1 + static_cast<int>(rcmax/gb->spacing);
109     }
110     gb->radius  = radius;
111     snew(gb->elem, gb->nelem);
112     snew(gb->count, gb->nelem);
113
114     snew(gb->cmap, gb->nx);
115     gb->ny = std::max(2, ndegrees);
116     for (i = 0; (i < gb->nx); i++)
117     {
118         snew(gb->cmap[i], gb->ny);
119     }
120     gb->bPhi = bPhi;
121
122     return gb;
123 }
124
125 static void done_gkrbin(t_gkrbin **gb)
126 {
127     sfree((*gb)->elem);
128     sfree((*gb)->count);
129     sfree((*gb));
130     *gb = NULL;
131 }
132
133 static void add2gkr(t_gkrbin *gb, real r, real cosa, real phi)
134 {
135     int  cy, index = gmx_nint(r/gb->spacing);
136     real alpha;
137
138     if (index < gb->nelem)
139     {
140         gb->elem[index]  += cosa;
141         gb->count[index]++;
142     }
143     if (index < gb->nx)
144     {
145         alpha = acos(cosa);
146         if (gb->bPhi)
147         {
148             cy = static_cast<int>((M_PI+phi)*gb->ny/(2*M_PI));
149         }
150         else
151         {
152             cy = static_cast<int>((alpha*gb->ny)/M_PI); /*((1+cosa)*0.5*(gb->ny));*/
153         }
154         cy = std::min(gb->ny-1, std::max(0, cy));
155         if (debug)
156         {
157             fprintf(debug, "CY: %10f  %5d\n", alpha, cy);
158         }
159         gb->cmap[index][cy] += 1;
160     }
161 }
162
163 static void rvec2sprvec(rvec dipcart, rvec dipsp)
164 {
165     clear_rvec(dipsp);
166     dipsp[0] = sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]+dipcart[ZZ]*dipcart[ZZ]); /* R */
167     dipsp[1] = atan2(dipcart[YY], dipcart[XX]);                                               /* Theta */
168     dipsp[2] = atan2(sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]), dipcart[ZZ]);     /* Phi */
169 }
170
171
172
173 void do_gkr(t_gkrbin *gb, int ncos, int *ngrp, int *molindex[],
174             int mindex[], rvec x[], rvec mu[],
175             int ePBC, matrix box, t_atom *atom, int *nAtom)
176 {
177     static rvec *xcm[2] = { NULL, NULL};
178     int          gi, gj, j0, j1, i, j, k, n, grp0, grp1;
179     real         qtot, q, cosa, rr, phi;
180     rvec         dx;
181     t_pbc        pbc;
182
183     for (n = 0; (n < ncos); n++)
184     {
185         if (!xcm[n])
186         {
187             snew(xcm[n], ngrp[n]);
188         }
189         for (i = 0; (i < ngrp[n]); i++)
190         {
191             /* Calculate center of mass of molecule */
192             gi = molindex[n][i];
193             j0 = mindex[gi];
194
195             if (nAtom[n] > 0)
196             {
197                 copy_rvec(x[j0+nAtom[n]-1], xcm[n][i]);
198             }
199             else
200             {
201                 j1 = mindex[gi+1];
202                 clear_rvec(xcm[n][i]);
203                 qtot = 0;
204                 for (j = j0; j < j1; j++)
205                 {
206                     q     = fabs(atom[j].q);
207                     qtot += q;
208                     for (k = 0; k < DIM; k++)
209                     {
210                         xcm[n][i][k] += q*x[j][k];
211                     }
212                 }
213                 svmul(1/qtot, xcm[n][i], xcm[n][i]);
214             }
215         }
216     }
217     set_pbc(&pbc, ePBC, box);
218     grp0 = 0;
219     grp1 = ncos-1;
220     for (i = 0; i < ngrp[grp0]; i++)
221     {
222         gi = molindex[grp0][i];
223         j0 = (ncos == 2) ? 0 : i+1;
224         for (j = j0; j < ngrp[grp1]; j++)
225         {
226             gj   = molindex[grp1][j];
227             if ((iprod(mu[gi], mu[gi]) > 0) && (iprod(mu[gj], mu[gj]) > 0))
228             {
229                 /* Compute distance between molecules including PBC */
230                 pbc_dx(&pbc, xcm[grp0][i], xcm[grp1][j], dx);
231                 rr = norm(dx);
232
233                 if (gb->bPhi)
234                 {
235                     rvec xi, xj, xk, xl;
236                     rvec r_ij, r_kj, r_kl, mm, nn;
237                     real sign;
238                     int  t1, t2, t3;
239
240                     copy_rvec(xcm[grp0][i], xj);
241                     copy_rvec(xcm[grp1][j], xk);
242                     rvec_add(xj, mu[gi], xi);
243                     rvec_add(xk, mu[gj], xl);
244                     phi = dih_angle(xi, xj, xk, xl, &pbc,
245                                     r_ij, r_kj, r_kl, mm, nn, /* out */
246                                     &sign, &t1, &t2, &t3);
247                     cosa = cos(phi);
248                 }
249                 else
250                 {
251                     cosa = cos_angle(mu[gi], mu[gj]);
252                     phi  = 0;
253                 }
254                 if (debug || gmx_isnan(cosa))
255                 {
256                     fprintf(debug ? debug : stderr,
257                             "mu[%d] = %5.2f %5.2f %5.2f |mi| = %5.2f, mu[%d] = %5.2f %5.2f %5.2f |mj| = %5.2f rr = %5.2f cosa = %5.2f\n",
258                             gi, mu[gi][XX], mu[gi][YY], mu[gi][ZZ], norm(mu[gi]),
259                             gj, mu[gj][XX], mu[gj][YY], mu[gj][ZZ], norm(mu[gj]),
260                             rr, cosa);
261                 }
262
263                 add2gkr(gb, rr, cosa, phi);
264             }
265         }
266     }
267 }
268
269 static real normalize_cmap(t_gkrbin *gb)
270 {
271     int    i, j;
272     real   hi;
273     double vol;
274
275     hi = 0;
276     for (i = 0; (i < gb->nx); i++)
277     {
278         vol = 4*M_PI*sqr(gb->spacing*i)*gb->spacing;
279         for (j = 0; (j < gb->ny); j++)
280         {
281             gb->cmap[i][j] /= vol;
282             hi              = std::max(hi, gb->cmap[i][j]);
283         }
284     }
285     if (hi <= 0)
286     {
287         gmx_fatal(FARGS, "No data in the cmap");
288     }
289     return hi;
290 }
291
292 static void print_cmap(const char *cmap, t_gkrbin *gb, int *nlevels)
293 {
294     FILE   *out;
295     int     i, j;
296     real    hi;
297
298     real   *xaxis, *yaxis;
299     t_rgb   rlo = { 1, 1, 1 };
300     t_rgb   rhi = { 0, 0, 0 };
301
302     hi = normalize_cmap(gb);
303     snew(xaxis, gb->nx+1);
304     for (i = 0; (i < gb->nx+1); i++)
305     {
306         xaxis[i] = i*gb->spacing;
307     }
308     snew(yaxis, gb->ny);
309     for (j = 0; (j < gb->ny); j++)
310     {
311         if (gb->bPhi)
312         {
313             yaxis[j] = (360.0*j)/(gb->ny-1.0)-180;
314         }
315         else
316         {
317             yaxis[j] = (180.0*j)/(gb->ny-1.0);
318         }
319         /*2.0*j/(gb->ny-1.0)-1.0;*/
320     }
321     out = ffopen(cmap, "w");
322     write_xpm(out, 0,
323               "Dipole Orientation Distribution", "Fraction", "r (nm)",
324               gb->bPhi ? "Phi" : "Alpha",
325               gb->nx, gb->ny, xaxis, yaxis,
326               gb->cmap, 0, hi, rlo, rhi, nlevels);
327     ffclose(out);
328     sfree(xaxis);
329     sfree(yaxis);
330 }
331
332 static void print_gkrbin(const char *fn, t_gkrbin *gb,
333                          int ngrp, int nframes, real volume,
334                          const output_env_t oenv)
335 {
336     /* We compute Gk(r), gOO and hOO according to
337      * Nymand & Linse, JCP 112 (2000) pp 6386-6395.
338      * In this implementation the angle between dipoles is stored
339      * rather than their inner product. This allows to take polarizible
340      * models into account. The RDF is calculated as well, almost for free!
341      */
342     FILE       *fp;
343     const char *leg[] = { "G\\sk\\N(r)", "< cos >", "h\\sOO\\N", "g\\sOO\\N", "Energy" };
344     int         i, last;
345     real        x0, x1, ggg, Gkr, vol_s, rho, gOO, hOO, cosav, ener;
346     double      fac;
347
348     fp = xvgropen(fn, "Distance dependent Gk", "r (nm)", "G\\sk\\N(r)", oenv);
349     xvgr_legend(fp, asize(leg), leg, oenv);
350
351     Gkr = 1;  /* Self-dipole inproduct = 1 */
352     rho = ngrp/volume;
353
354     if (debug)
355     {
356         fprintf(debug, "Number density is %g molecules / nm^3\n", rho);
357         fprintf(debug, "ngrp = %d, nframes = %d\n", ngrp, nframes);
358     }
359
360     last = gb->nelem-1;
361     while (last > 1 && gb->elem[last-1] == 0)
362     {
363         last--;
364     }
365
366     /* Divide by dipole squared, by number of frames, by number of origins.
367      * Multiply by 2 because we only take half the matrix of interactions
368      * into account.
369      */
370     fac  = 2.0/((double) ngrp * (double) nframes);
371
372     x0 = 0;
373     for (i = 0; i < last; i++)
374     {
375         /* Centre of the coordinate in the spherical layer */
376         x1    = x0+gb->spacing;
377
378         /* Volume of the layer */
379         vol_s = (4.0/3.0)*M_PI*(x1*x1*x1-x0*x0*x0);
380
381         /* gOO */
382         gOO   = gb->count[i]*fac/(rho*vol_s);
383
384         /* Dipole correlation hOO, normalized by the relative number density, like
385          * in a Radial distribution function.
386          */
387         ggg  = gb->elem[i]*fac;
388         hOO  = 3.0*ggg/(rho*vol_s);
389         Gkr += ggg;
390         if (gb->count[i])
391         {
392             cosav = gb->elem[i]/gb->count[i];
393         }
394         else
395         {
396             cosav = 0;
397         }
398         ener = -0.5*cosav*ONE_4PI_EPS0/(x1*x1*x1);
399
400         fprintf(fp, "%10.5e %12.5e %12.5e %12.5e %12.5e  %12.5e\n",
401                 x1, Gkr, cosav, hOO, gOO, ener);
402
403         /* Swap x0 and x1 */
404         x0 = x1;
405     }
406     ffclose(fp);
407 }
408
409 gmx_bool read_mu_from_enx(ener_file_t fmu, int Vol, ivec iMu, rvec mu, real *vol,
410                           real *t, int nre, t_enxframe *fr)
411 {
412     int          i;
413     gmx_bool     bCont;
414     char         buf[22];
415
416     bCont = do_enx(fmu, fr);
417     if (fr->nre != nre)
418     {
419         fprintf(stderr, "Something strange: expected %d entries in energy file at step %s\n(time %g) but found %d entries\n",
420                 nre, gmx_step_str(fr->step, buf), fr->t, fr->nre);
421     }
422
423     if (bCont)
424     {
425         if (Vol != -1)          /* we've got Volume in the energy file */
426         {
427             *vol = fr->ener[Vol].e;
428         }
429         for (i = 0; i < DIM; i++)
430         {
431             mu[i] = fr->ener[iMu[i]].e;
432         }
433         *t = fr->t;
434     }
435
436     return bCont;
437 }
438
439 static void neutralize_mols(int n, int *index, t_block *mols, t_atom *atom)
440 {
441     double mtot, qtot;
442     int    ncharged, m, a0, a1, a;
443
444     ncharged = 0;
445     for (m = 0; m < n; m++)
446     {
447         a0   = mols->index[index[m]];
448         a1   = mols->index[index[m]+1];
449         mtot = 0;
450         qtot = 0;
451         for (a = a0; a < a1; a++)
452         {
453             mtot += atom[a].m;
454             qtot += atom[a].q;
455         }
456         /* This check is only for the count print */
457         if (fabs(qtot) > 0.01)
458         {
459             ncharged++;
460         }
461         if (mtot > 0)
462         {
463             /* Remove the net charge at the center of mass */
464             for (a = a0; a < a1; a++)
465             {
466                 atom[a].q -= qtot*atom[a].m/mtot;
467             }
468         }
469     }
470
471     if (ncharged)
472     {
473         printf("There are %d charged molecules in the selection,\n"
474                "will subtract their charge at their center of mass\n", ncharged);
475     }
476 }
477
478 static void mol_dip(int k0, int k1, rvec x[], t_atom atom[], rvec mu)
479 {
480     int  k, m;
481     real q;
482
483     clear_rvec(mu);
484     for (k = k0; (k < k1); k++)
485     {
486         q  = e2d(atom[k].q);
487         for (m = 0; (m < DIM); m++)
488         {
489             mu[m] += q*x[k][m];
490         }
491     }
492 }
493
494 static void mol_quad(int k0, int k1, rvec x[], t_atom atom[], rvec quad)
495 {
496     int      i, k, m, n, niter;
497     real     q, r2, mass, masstot;
498     rvec     com;        /* center of mass */
499     rvec     r;          /* distance of atoms to center of mass */
500     double **inten;
501     double   dd[DIM], **ev, tmp;
502
503     snew(inten, DIM);
504     snew(ev, DIM);
505     for (i = 0; (i < DIM); i++)
506     {
507         snew(inten[i], DIM);
508         snew(ev[i], DIM);
509         dd[i] = 0.0;
510     }
511
512     /* Compute center of mass */
513     clear_rvec(com);
514     masstot = 0.0;
515     for (k = k0; (k < k1); k++)
516     {
517         mass     = atom[k].m;
518         masstot += mass;
519         for (i = 0; (i < DIM); i++)
520         {
521             com[i] += mass*x[k][i];
522         }
523     }
524     svmul((1.0/masstot), com, com);
525
526     /* We want traceless quadrupole moments, so let us calculate the complete
527      * quadrupole moment tensor and diagonalize this tensor to get
528      * the individual components on the diagonal.
529      */
530
531 #define delta(a, b) (( a == b ) ? 1.0 : 0.0)
532
533     for (m = 0; (m < DIM); m++)
534     {
535         for (n = 0; (n < DIM); n++)
536         {
537             inten[m][n] = 0;
538         }
539     }
540     for (k = k0; (k < k1); k++)         /* loop over atoms in a molecule */
541     {
542         q  = (atom[k].q)*100.0;
543         rvec_sub(x[k], com, r);
544         r2 = iprod(r, r);
545         for (m = 0; (m < DIM); m++)
546         {
547             for (n = 0; (n < DIM); n++)
548             {
549                 inten[m][n] += 0.5*q*(3.0*r[m]*r[n] - r2*delta(m, n))*EANG2CM*CM2D;
550             }
551         }
552     }
553     if (debug)
554     {
555         for (i = 0; (i < DIM); i++)
556         {
557             fprintf(debug, "Q[%d] = %8.3f  %8.3f  %8.3f\n",
558                     i, inten[i][XX], inten[i][YY], inten[i][ZZ]);
559         }
560     }
561
562     /* We've got the quadrupole tensor, now diagonalize the sucker */
563     jacobi(inten, 3, dd, ev, &niter);
564
565     if (debug)
566     {
567         for (i = 0; (i < DIM); i++)
568         {
569             fprintf(debug, "ev[%d] = %8.3f  %8.3f  %8.3f\n",
570                     i, ev[i][XX], ev[i][YY], ev[i][ZZ]);
571         }
572         for (i = 0; (i < DIM); i++)
573         {
574             fprintf(debug, "Q'[%d] = %8.3f  %8.3f  %8.3f\n",
575                     i, inten[i][XX], inten[i][YY], inten[i][ZZ]);
576         }
577     }
578     /* Sort the eigenvalues, for water we know that the order is as follows:
579      *
580      * Q_yy, Q_zz, Q_xx
581      *
582      * At the moment I have no idea how this will work out for other molecules...
583      */
584
585 #define SWAP(i)                                 \
586     if (dd[i+1] > dd[i]) {                      \
587         tmp     = dd[i];                              \
588         dd[i]   = dd[i+1];                          \
589         dd[i+1] = tmp;                            \
590     }
591     SWAP(0);
592     SWAP(1);
593     SWAP(0);
594
595     for (m = 0; (m < DIM); m++)
596     {
597         quad[0] = dd[2];  /* yy */
598         quad[1] = dd[0];  /* zz */
599         quad[2] = dd[1];  /* xx */
600     }
601
602     if (debug)
603     {
604         pr_rvec(debug, 0, "Quadrupole", quad, DIM, TRUE);
605     }
606
607     /* clean-up */
608     for (i = 0; (i < DIM); i++)
609     {
610         sfree(inten[i]);
611         sfree(ev[i]);
612     }
613     sfree(inten);
614     sfree(ev);
615 }
616
617 /*
618  * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
619  */
620 real calc_eps(double M_diff, double volume, double epsRF, double temp)
621 {
622     double eps, A, teller, noemer;
623     double eps_0 = 8.854187817e-12;   /* epsilon_0 in C^2 J^-1 m^-1 */
624     double fac   = 1.112650021e-59;   /* converts Debye^2 to C^2 m^2 */
625
626     A = M_diff*fac/(3*eps_0*volume*NANO*NANO*NANO*BOLTZMANN*temp);
627
628     if (epsRF == 0.0)
629     {
630         teller = 1 + A;
631         noemer = 1;
632     }
633     else
634     {
635         teller = 1 + (A*2*epsRF/(2*epsRF+1));
636         noemer = 1 - (A/(2*epsRF+1));
637     }
638     eps = teller / noemer;
639
640     return eps;
641 }
642
643 static void update_slab_dipoles(int k0, int k1, rvec x[], rvec mu,
644                                 int idim, int nslice, rvec slab_dipole[],
645                                 matrix box)
646 {
647     int  k;
648     real xdim = 0;
649
650     for (k = k0; (k < k1); k++)
651     {
652         xdim += x[k][idim];
653     }
654     xdim /= (k1-k0);
655     k     = ((int)(xdim*nslice/box[idim][idim] + nslice)) % nslice;
656     rvec_inc(slab_dipole[k], mu);
657 }
658
659 static void dump_slab_dipoles(const char *fn, int idim, int nslice,
660                               rvec slab_dipole[], matrix box, int nframes,
661                               const output_env_t oenv)
662 {
663     FILE       *fp;
664     char        buf[STRLEN];
665     int         i;
666     real        mutot;
667     const char *leg_dim[4] = {
668         "\\f{12}m\\f{4}\\sX\\N",
669         "\\f{12}m\\f{4}\\sY\\N",
670         "\\f{12}m\\f{4}\\sZ\\N",
671         "\\f{12}m\\f{4}\\stot\\N"
672     };
673
674     sprintf(buf, "Box-%c (nm)", 'X'+idim);
675     fp = xvgropen(fn, "Average dipole moment per slab", buf, "\\f{12}m\\f{4} (D)",
676                   oenv);
677     xvgr_legend(fp, DIM, leg_dim, oenv);
678     for (i = 0; (i < nslice); i++)
679     {
680         mutot = norm(slab_dipole[i])/nframes;
681         fprintf(fp, "%10.3f  %10.3f  %10.3f  %10.3f  %10.3f\n",
682                 ((i+0.5)*box[idim][idim])/nslice,
683                 slab_dipole[i][XX]/nframes,
684                 slab_dipole[i][YY]/nframes,
685                 slab_dipole[i][ZZ]/nframes,
686                 mutot);
687     }
688     ffclose(fp);
689     do_view(oenv, fn, "-autoscale xy -nxy");
690 }
691
692 static void compute_avercos(int n, rvec dip[], real *dd, rvec axis, gmx_bool bPairs)
693 {
694     int    i, j, k;
695     double dc, d, ddc1, ddc2, ddc3;
696     rvec   xxx = { 1, 0, 0 };
697     rvec   yyy = { 0, 1, 0 };
698     rvec   zzz = { 0, 0, 1 };
699
700     d    = 0;
701     ddc1 = ddc2 = ddc3 = 0;
702     for (i = k = 0; (i < n); i++)
703     {
704         ddc1 += fabs(cos_angle(dip[i], xxx));
705         ddc2 += fabs(cos_angle(dip[i], yyy));
706         ddc3 += fabs(cos_angle(dip[i], zzz));
707         if (bPairs)
708         {
709             for (j = i+1; (j < n); j++, k++)
710             {
711                 dc  = cos_angle(dip[i], dip[j]);
712                 d  += fabs(dc);
713             }
714         }
715     }
716     *dd      = d/k;
717     axis[XX] = ddc1/n;
718     axis[YY] = ddc2/n;
719     axis[ZZ] = ddc3/n;
720 }
721
722 static void do_dip(t_topology *top, int ePBC, real volume,
723                    const char *fn,
724                    const char *out_mtot, const char *out_eps,
725                    const char *out_aver, const char *dipdist,
726                    const char *cosaver, const char *fndip3d,
727                    const char *fnadip,  gmx_bool bPairs,
728                    const char *corrtype, const char *corf,
729                    gmx_bool bGkr,     const char *gkrfn,
730                    gmx_bool bPhi,     int  *nlevels,  int ndegrees,
731                    int  ncos,
732                    const char *cmap,    real rcmax,
733                    gmx_bool bQuad,
734                    gmx_bool bMU,      const char *mufn,
735                    int  *gnx,     int  *molindex[],
736                    real mu_max,   real mu_aver,
737                    real epsilonRF, real temp,
738                    int  *gkatom,  int skip,
739                    gmx_bool bSlab,    int nslices,
740                    const char *axtitle, const char *slabfn,
741                    const output_env_t oenv)
742 {
743     const char *leg_mtot[] = {
744         "M\\sx \\N",
745         "M\\sy \\N",
746         "M\\sz \\N",
747         "|M\\stot \\N|"
748     };
749 #define NLEGMTOT asize(leg_mtot)
750     const char *leg_eps[] = {
751         "epsilon",
752         "G\\sk",
753         "g\\sk"
754     };
755 #define NLEGEPS asize(leg_eps)
756     const char *leg_aver[] = {
757         "< |M|\\S2\\N >",
758         "< |M| >\\S2\\N",
759         "< |M|\\S2\\N > - < |M| >\\S2\\N",
760         "< |M| >\\S2\\N / < |M|\\S2\\N >"
761     };
762 #define NLEGAVER asize(leg_aver)
763     const char *leg_cosaver[] = {
764         "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
765         "RMSD cos",
766         "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
767         "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
768         "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
769     };
770 #define NLEGCOSAVER asize(leg_cosaver)
771     const char *leg_adip[] = {
772         "<mu>",
773         "Std. Dev.",
774         "Error"
775     };
776 #define NLEGADIP asize(leg_adip)
777
778     FILE         *outdd, *outmtot, *outaver, *outeps, *caver = NULL;
779     FILE         *dip3d = NULL, *adip = NULL;
780     rvec         *x, *dipole = NULL, mu_t, quad, *dipsp = NULL;
781     t_gkrbin     *gkrbin = NULL;
782     gmx_enxnm_t  *enm    = NULL;
783     t_enxframe   *fr;
784     int           nframes = 1000, nre, timecheck = 0, ncolour = 0;
785     ener_file_t   fmu     = NULL;
786     int           i, n, m, natom = 0, gnx_tot, teller, tel3;
787     t_trxstatus  *status;
788     int          *dipole_bin, ndipbin, ibin, iVol, idim = -1;
789     unsigned long mode;
790     real          rcut = 0, t, t0, t1, dt, dd, rms_cos;
791     rvec          dipaxis;
792     matrix        box;
793     gmx_bool      bCorr, bTotal, bCont;
794     double        M_diff = 0, epsilon, invtel, vol_aver;
795     double        mu_ave, mu_mol, M2_ave = 0, M_ave2 = 0, M_av[DIM], M_av2[DIM];
796     double        M[3], M2[3], M4[3], Gk = 0, g_k = 0;
797     gmx_stats_t  *Qlsq, mulsq, muframelsq = NULL;
798     ivec          iMu;
799     real        **muall        = NULL;
800     rvec         *slab_dipoles = NULL;
801     t_atom       *atom         = NULL;
802     t_block      *mols         = NULL;
803     gmx_rmpbc_t   gpbc         = NULL;
804
805     gnx_tot = gnx[0];
806     if (ncos > 1)
807     {
808         gnx_tot += gnx[1];
809     }
810
811     vol_aver = 0.0;
812
813     iVol = -1;
814
815     /* initialize to a negative value so we can see that it wasn't picked up */
816     iMu[XX] = iMu[YY] = iMu[ZZ] = -1;
817     if (bMU)
818     {
819         fmu = open_enx(mufn, "r");
820         do_enxnms(fmu, &nre, &enm);
821
822         /* Determine the indexes of the energy grps we need */
823         for (i = 0; (i < nre); i++)
824         {
825             if (strstr(enm[i].name, "Volume"))
826             {
827                 iVol = i;
828             }
829             else if (strstr(enm[i].name, "Mu-X"))
830             {
831                 iMu[XX] = i;
832             }
833             else if (strstr(enm[i].name, "Mu-Y"))
834             {
835                 iMu[YY] = i;
836             }
837             else if (strstr(enm[i].name, "Mu-Z"))
838             {
839                 iMu[ZZ] = i;
840             }
841         }
842         if (iMu[XX] < 0 || iMu[YY] < 0 || iMu[ZZ] < 0)
843         {
844             gmx_fatal(FARGS, "No index for Mu-X, Mu-Y or Mu-Z energy group.");
845         }
846     }
847     else
848     {
849         atom = top->atoms.atom;
850         mols = &(top->mols);
851     }
852     if ((iVol == -1) && bMU)
853     {
854         printf("Using Volume from topology: %g nm^3\n", volume);
855     }
856
857     /* Correlation stuff */
858     bCorr  = (corrtype[0] != 'n');
859     bTotal = (corrtype[0] == 't');
860     if (bCorr)
861     {
862         if (bTotal)
863         {
864             snew(muall, 1);
865             snew(muall[0], nframes*DIM);
866         }
867         else
868         {
869             snew(muall, gnx[0]);
870             for (i = 0; (i < gnx[0]); i++)
871             {
872                 snew(muall[i], nframes*DIM);
873             }
874         }
875     }
876
877     /* Allocate array which contains for every molecule in a frame the
878      * dipole moment.
879      */
880     if (!bMU)
881     {
882         snew(dipole, gnx_tot);
883     }
884
885     /* Statistics */
886     snew(Qlsq, DIM);
887     for (i = 0; (i < DIM); i++)
888     {
889         Qlsq[i] = gmx_stats_init();
890     }
891     mulsq = gmx_stats_init();
892
893     /* Open all the files */
894     outmtot = xvgropen(out_mtot,
895                        "Total dipole moment of the simulation box vs. time",
896                        "Time (ps)", "Total Dipole Moment (Debye)", oenv);
897     outeps  = xvgropen(out_eps, "Epsilon and Kirkwood factors",
898                        "Time (ps)", "", oenv);
899     outaver = xvgropen(out_aver, "Total dipole moment",
900                        "Time (ps)", "D", oenv);
901     if (bSlab)
902     {
903         idim = axtitle[0] - 'X';
904         if ((idim < 0) || (idim >= DIM))
905         {
906             idim = axtitle[0] - 'x';
907         }
908         if ((idim < 0) || (idim >= DIM))
909         {
910             bSlab = FALSE;
911         }
912         if (nslices < 2)
913         {
914             bSlab = FALSE;
915         }
916         fprintf(stderr, "axtitle = %s, nslices = %d, idim = %d\n",
917                 axtitle, nslices, idim);
918         if (bSlab)
919         {
920             snew(slab_dipoles, nslices);
921             fprintf(stderr, "Doing slab analysis\n");
922         }
923     }
924
925     if (fnadip)
926     {
927         adip = xvgropen(fnadip, "Average molecular dipole", "Dipole (D)", "", oenv);
928         xvgr_legend(adip, NLEGADIP, leg_adip, oenv);
929
930     }
931     if (cosaver)
932     {
933         caver = xvgropen(cosaver, bPairs ? "Average pair orientation" :
934                          "Average absolute dipole orientation", "Time (ps)", "", oenv);
935         xvgr_legend(caver, NLEGCOSAVER, bPairs ? leg_cosaver : &(leg_cosaver[1]),
936                     oenv);
937     }
938
939     if (fndip3d)
940     {
941         snew(dipsp, gnx_tot);
942
943         /* we need a dummy file for gnuplot */
944         dip3d = (FILE *)ffopen("dummy.dat", "w");
945         fprintf(dip3d, "%f %f %f", 0.0, 0.0, 0.0);
946         ffclose(dip3d);
947
948         dip3d = (FILE *)ffopen(fndip3d, "w");
949         try
950         {
951             gmx::BinaryInformationSettings settings;
952             settings.generatedByHeader(true);
953             settings.linePrefix("# ");
954             gmx::printBinaryInformation(dip3d, gmx::ProgramInfo::getInstance(),
955                                         settings);
956         }
957         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
958     }
959
960     /* Write legends to all the files */
961     xvgr_legend(outmtot, NLEGMTOT, leg_mtot, oenv);
962     xvgr_legend(outaver, NLEGAVER, leg_aver, oenv);
963
964     if (bMU && (mu_aver == -1))
965     {
966         xvgr_legend(outeps, NLEGEPS-2, leg_eps, oenv);
967     }
968     else
969     {
970         xvgr_legend(outeps, NLEGEPS, leg_eps, oenv);
971     }
972
973     snew(fr, 1);
974     clear_rvec(mu_t);
975     teller = 0;
976     /* Read the first frame from energy or traj file */
977     if (bMU)
978     {
979         do
980         {
981             bCont = read_mu_from_enx(fmu, iVol, iMu, mu_t, &volume, &t, nre, fr);
982             if (bCont)
983             {
984                 timecheck = check_times(t);
985                 if (timecheck < 0)
986                 {
987                     teller++;
988                 }
989                 if ((teller % 10) == 0)
990                 {
991                     fprintf(stderr, "\r Skipping Frame %6d, time: %8.3f", teller, t);
992                 }
993             }
994             else
995             {
996                 printf("End of %s reached\n", mufn);
997                 break;
998             }
999         }
1000         while (bCont && (timecheck < 0));
1001     }
1002     else
1003     {
1004         natom  = read_first_x(oenv, &status, fn, &t, &x, box);
1005     }
1006
1007     /* Calculate spacing for dipole bin (simple histogram) */
1008     ndipbin = 1 + static_cast<int>(mu_max/0.01);
1009     snew(dipole_bin, ndipbin);
1010     mu_ave     = 0.0;
1011     for (m = 0; (m < DIM); m++)
1012     {
1013         M[m] = M2[m] = M4[m] = 0.0;
1014     }
1015
1016     if (bGkr)
1017     {
1018         /* Use 0.7 iso 0.5 to account for pressure scaling */
1019         /*  rcut   = 0.7*sqrt(max_cutoff2(box)); */
1020         rcut   = 0.7*sqrt(sqr(box[XX][XX])+sqr(box[YY][YY])+sqr(box[ZZ][ZZ]));
1021
1022         gkrbin = mk_gkrbin(rcut, rcmax, bPhi, ndegrees);
1023     }
1024     gpbc = gmx_rmpbc_init(&top->idef, ePBC, natom);
1025
1026     /* Start while loop over frames */
1027     t0     = t;
1028     teller = 0;
1029     do
1030     {
1031         if (bCorr && (teller >= nframes))
1032         {
1033             nframes += 1000;
1034             if (bTotal)
1035             {
1036                 srenew(muall[0], nframes*DIM);
1037             }
1038             else
1039             {
1040                 for (i = 0; (i < gnx_tot); i++)
1041                 {
1042                     srenew(muall[i], nframes*DIM);
1043                 }
1044             }
1045         }
1046         t1 = t;
1047
1048         muframelsq = gmx_stats_init();
1049
1050         /* Initialise */
1051         for (m = 0; (m < DIM); m++)
1052         {
1053             M_av2[m] = 0;
1054         }
1055
1056         if (bMU)
1057         {
1058             /* Copy rvec into double precision local variable */
1059             for (m = 0; (m < DIM); m++)
1060             {
1061                 M_av[m]  = mu_t[m];
1062             }
1063         }
1064         else
1065         {
1066             /* Initialise */
1067             for (m = 0; (m < DIM); m++)
1068             {
1069                 M_av[m] = 0;
1070             }
1071
1072             gmx_rmpbc(gpbc, natom, box, x);
1073
1074             /* Begin loop of all molecules in frame */
1075             for (n = 0; (n < ncos); n++)
1076             {
1077                 for (i = 0; (i < gnx[n]); i++)
1078                 {
1079                     int ind0, ind1;
1080
1081                     ind0  = mols->index[molindex[n][i]];
1082                     ind1  = mols->index[molindex[n][i]+1];
1083
1084                     mol_dip(ind0, ind1, x, atom, dipole[i]);
1085                     gmx_stats_add_point(mulsq, 0, norm(dipole[i]), 0, 0);
1086                     gmx_stats_add_point(muframelsq, 0, norm(dipole[i]), 0, 0);
1087                     if (bSlab)
1088                     {
1089                         update_slab_dipoles(ind0, ind1, x,
1090                                             dipole[i], idim, nslices, slab_dipoles, box);
1091                     }
1092                     if (bQuad)
1093                     {
1094                         mol_quad(ind0, ind1, x, atom, quad);
1095                         for (m = 0; (m < DIM); m++)
1096                         {
1097                             gmx_stats_add_point(Qlsq[m], 0, quad[m], 0, 0);
1098                         }
1099                     }
1100                     if (bCorr && !bTotal)
1101                     {
1102                         tel3              = DIM*teller;
1103                         muall[i][tel3+XX] = dipole[i][XX];
1104                         muall[i][tel3+YY] = dipole[i][YY];
1105                         muall[i][tel3+ZZ] = dipole[i][ZZ];
1106                     }
1107                     mu_mol = 0.0;
1108                     for (m = 0; (m < DIM); m++)
1109                     {
1110                         M_av[m]  += dipole[i][m];               /* M per frame */
1111                         mu_mol   += dipole[i][m]*dipole[i][m];  /* calc. mu for distribution */
1112                     }
1113                     mu_mol = sqrt(mu_mol);
1114
1115                     mu_ave += mu_mol;                         /* calc. the average mu */
1116
1117                     /* Update the dipole distribution */
1118                     ibin = (int)(ndipbin*mu_mol/mu_max + 0.5);
1119                     if (ibin < ndipbin)
1120                     {
1121                         dipole_bin[ibin]++;
1122                     }
1123
1124                     if (fndip3d)
1125                     {
1126                         rvec2sprvec(dipole[i], dipsp[i]);
1127
1128                         if (dipsp[i][YY] > -M_PI && dipsp[i][YY] < -0.5*M_PI)
1129                         {
1130                             if (dipsp[i][ZZ] < 0.5 * M_PI)
1131                             {
1132                                 ncolour = 1;
1133                             }
1134                             else
1135                             {
1136                                 ncolour = 2;
1137                             }
1138                         }
1139                         else if (dipsp[i][YY] > -0.5*M_PI && dipsp[i][YY] < 0.0*M_PI)
1140                         {
1141                             if (dipsp[i][ZZ] < 0.5 * M_PI)
1142                             {
1143                                 ncolour = 3;
1144                             }
1145                             else
1146                             {
1147                                 ncolour = 4;
1148                             }
1149                         }
1150                         else if (dipsp[i][YY] > 0.0 && dipsp[i][YY] < 0.5*M_PI)
1151                         {
1152                             if (dipsp[i][ZZ] < 0.5 * M_PI)
1153                             {
1154                                 ncolour = 5;
1155                             }
1156                             else
1157                             {
1158                                 ncolour = 6;
1159                             }
1160                         }
1161                         else if (dipsp[i][YY] > 0.5*M_PI && dipsp[i][YY] < M_PI)
1162                         {
1163                             if (dipsp[i][ZZ] < 0.5 * M_PI)
1164                             {
1165                                 ncolour = 7;
1166                             }
1167                             else
1168                             {
1169                                 ncolour = 8;
1170                             }
1171                         }
1172                         if (dip3d)
1173                         {
1174                             fprintf(dip3d, "set arrow %d from %f, %f, %f to %f, %f, %f lt %d  # %d %d\n",
1175                                     i+1,
1176                                     x[ind0][XX],
1177                                     x[ind0][YY],
1178                                     x[ind0][ZZ],
1179                                     x[ind0][XX]+dipole[i][XX]/25,
1180                                     x[ind0][YY]+dipole[i][YY]/25,
1181                                     x[ind0][ZZ]+dipole[i][ZZ]/25,
1182                                     ncolour, ind0, i);
1183                         }
1184                     }
1185                 } /* End loop of all molecules in frame */
1186
1187                 if (dip3d)
1188                 {
1189                     fprintf(dip3d, "set title \"t = %4.3f\"\n", t);
1190                     fprintf(dip3d, "set xrange [0.0:%4.2f]\n", box[XX][XX]);
1191                     fprintf(dip3d, "set yrange [0.0:%4.2f]\n", box[YY][YY]);
1192                     fprintf(dip3d, "set zrange [0.0:%4.2f]\n\n", box[ZZ][ZZ]);
1193                     fprintf(dip3d, "splot 'dummy.dat' using 1:2:3 w vec\n");
1194                     fprintf(dip3d, "pause -1 'Hit return to continue'\n");
1195                 }
1196             }
1197         }
1198         /* Compute square of total dipole */
1199         for (m = 0; (m < DIM); m++)
1200         {
1201             M_av2[m] = M_av[m]*M_av[m];
1202         }
1203
1204         if (cosaver)
1205         {
1206             compute_avercos(gnx_tot, dipole, &dd, dipaxis, bPairs);
1207             rms_cos = sqrt(sqr(dipaxis[XX]-0.5)+
1208                            sqr(dipaxis[YY]-0.5)+
1209                            sqr(dipaxis[ZZ]-0.5));
1210             if (bPairs)
1211             {
1212                 fprintf(caver, "%10.3e  %10.3e  %10.3e  %10.3e  %10.3e  %10.3e\n",
1213                         t, dd, rms_cos, dipaxis[XX], dipaxis[YY], dipaxis[ZZ]);
1214             }
1215             else
1216             {
1217                 fprintf(caver, "%10.3e  %10.3e  %10.3e  %10.3e  %10.3e\n",
1218                         t, rms_cos, dipaxis[XX], dipaxis[YY], dipaxis[ZZ]);
1219             }
1220         }
1221
1222         if (bGkr)
1223         {
1224             do_gkr(gkrbin, ncos, gnx, molindex, mols->index, x, dipole, ePBC, box,
1225                    atom, gkatom);
1226         }
1227
1228         if (bTotal)
1229         {
1230             tel3              = DIM*teller;
1231             muall[0][tel3+XX] = M_av[XX];
1232             muall[0][tel3+YY] = M_av[YY];
1233             muall[0][tel3+ZZ] = M_av[ZZ];
1234         }
1235
1236         /* Write to file the total dipole moment of the box, and its components
1237          * for this frame.
1238          */
1239         if ((skip == 0) || ((teller % skip) == 0))
1240         {
1241             fprintf(outmtot, "%10g  %12.8e %12.8e %12.8e %12.8e\n",
1242                     t, M_av[XX], M_av[YY], M_av[ZZ],
1243                     sqrt(M_av2[XX]+M_av2[YY]+M_av2[ZZ]));
1244         }
1245
1246         for (m = 0; (m < DIM); m++)
1247         {
1248             M[m]  += M_av[m];
1249             M2[m] += M_av2[m];
1250             M4[m] += sqr(M_av2[m]);
1251         }
1252         /* Increment loop counter */
1253         teller++;
1254
1255         /* Calculate for output the running averages */
1256         invtel  = 1.0/teller;
1257         M2_ave  = (M2[XX]+M2[YY]+M2[ZZ])*invtel;
1258         M_ave2  = invtel*(invtel*(M[XX]*M[XX] + M[YY]*M[YY] + M[ZZ]*M[ZZ]));
1259         M_diff  = M2_ave - M_ave2;
1260
1261         /* Compute volume from box in traj, else we use the one from above */
1262         if (!bMU)
1263         {
1264             volume  = det(box);
1265         }
1266         vol_aver += volume;
1267
1268         epsilon = calc_eps(M_diff, (vol_aver/teller), epsilonRF, temp);
1269
1270         /* Calculate running average for dipole */
1271         if (mu_ave != 0)
1272         {
1273             mu_aver = (mu_ave/gnx_tot)*invtel;
1274         }
1275
1276         if ((skip == 0) || ((teller % skip) == 0))
1277         {
1278             /* Write to file < |M|^2 >, |< M >|^2. And the difference between
1279              * the two. Here M is sum mu_i. Further write the finite system
1280              * Kirkwood G factor and epsilon.
1281              */
1282             fprintf(outaver, "%10g  %10.3e %10.3e %10.3e %10.3e\n",
1283                     t, M2_ave, M_ave2, M_diff, M_ave2/M2_ave);
1284
1285             if (fnadip)
1286             {
1287                 real aver;
1288                 gmx_stats_get_average(muframelsq, &aver);
1289                 fprintf(adip, "%10g %f \n", t, aver);
1290             }
1291             /*if (dipole)
1292                printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1293              */
1294             if (!bMU || (mu_aver != -1))
1295             {
1296                 /* Finite system Kirkwood G-factor */
1297                 Gk = M_diff/(gnx_tot*mu_aver*mu_aver);
1298                 /* Infinite system Kirkwood G-factor */
1299                 if (epsilonRF == 0.0)
1300                 {
1301                     g_k = ((2*epsilon+1)*Gk/(3*epsilon));
1302                 }
1303                 else
1304                 {
1305                     g_k = ((2*epsilonRF+epsilon)*(2*epsilon+1)*
1306                            Gk/(3*epsilon*(2*epsilonRF+1)));
1307                 }
1308
1309                 fprintf(outeps, "%10g  %10.3e %10.3e %10.3e\n", t, epsilon, Gk, g_k);
1310
1311             }
1312             else
1313             {
1314                 fprintf(outeps, "%10g  %12.8e\n", t, epsilon);
1315             }
1316         }
1317         gmx_stats_done(muframelsq);
1318
1319         if (bMU)
1320         {
1321             bCont = read_mu_from_enx(fmu, iVol, iMu, mu_t, &volume, &t, nre, fr);
1322         }
1323         else
1324         {
1325             bCont = read_next_x(oenv, status, &t, x, box);
1326         }
1327         timecheck = check_times(t);
1328     }
1329     while (bCont && (timecheck == 0) );
1330
1331     gmx_rmpbc_done(gpbc);
1332
1333     if (!bMU)
1334     {
1335         close_trj(status);
1336     }
1337
1338     ffclose(outmtot);
1339     ffclose(outaver);
1340     ffclose(outeps);
1341
1342     if (fnadip)
1343     {
1344         ffclose(adip);
1345     }
1346
1347     if (cosaver)
1348     {
1349         ffclose(caver);
1350     }
1351
1352     if (dip3d)
1353     {
1354         fprintf(dip3d, "set xrange [0.0:%4.2f]\n", box[XX][XX]);
1355         fprintf(dip3d, "set yrange [0.0:%4.2f]\n", box[YY][YY]);
1356         fprintf(dip3d, "set zrange [0.0:%4.2f]\n\n", box[ZZ][ZZ]);
1357         fprintf(dip3d, "splot 'dummy.dat' using 1:2:3 w vec\n");
1358         fprintf(dip3d, "pause -1 'Hit return to continue'\n");
1359         ffclose(dip3d);
1360     }
1361
1362     if (bSlab)
1363     {
1364         dump_slab_dipoles(slabfn, idim, nslices, slab_dipoles, box, teller, oenv);
1365         sfree(slab_dipoles);
1366     }
1367
1368     vol_aver /= teller;
1369     printf("Average volume over run is %g\n", vol_aver);
1370     if (bGkr)
1371     {
1372         print_gkrbin(gkrfn, gkrbin, gnx[0], teller, vol_aver, oenv);
1373         print_cmap(cmap, gkrbin, nlevels);
1374     }
1375     /* Autocorrelation function */
1376     if (bCorr)
1377     {
1378         if (teller < 2)
1379         {
1380             printf("Not enough frames for autocorrelation\n");
1381         }
1382         else
1383         {
1384             dt = (t1 - t0)/(teller-1);
1385             printf("t0 %g, t %g, teller %d\n", t0, t, teller);
1386
1387             mode = eacVector;
1388
1389             if (bTotal)
1390             {
1391                 do_autocorr(corf, oenv, "Autocorrelation Function of Total Dipole",
1392                             teller, 1, muall, dt, mode, TRUE);
1393             }
1394             else
1395             {
1396                 do_autocorr(corf, oenv, "Dipole Autocorrelation Function",
1397                             teller, gnx_tot, muall, dt,
1398                             mode, strcmp(corrtype, "molsep"));
1399             }
1400         }
1401     }
1402     if (!bMU)
1403     {
1404         real aver, sigma, error;
1405
1406         gmx_stats_get_ase(mulsq, &aver, &sigma, &error);
1407         printf("\nDipole moment (Debye)\n");
1408         printf("---------------------\n");
1409         printf("Average  = %8.4f  Std. Dev. = %8.4f  Error = %8.4f\n",
1410                aver, sigma, error);
1411         if (bQuad)
1412         {
1413             rvec a, s, e;
1414             for (m = 0; (m < DIM); m++)
1415             {
1416                 gmx_stats_get_ase(mulsq, &(a[m]), &(s[m]), &(e[m]));
1417             }
1418
1419             printf("\nQuadrupole moment (Debye-Ang)\n");
1420             printf("-----------------------------\n");
1421             printf("Averages  = %8.4f  %8.4f  %8.4f\n", a[XX], a[YY], a[ZZ]);
1422             printf("Std. Dev. = %8.4f  %8.4f  %8.4f\n", s[XX], s[YY], s[ZZ]);
1423             printf("Error     = %8.4f  %8.4f  %8.4f\n", e[XX], e[YY], e[ZZ]);
1424         }
1425         printf("\n");
1426     }
1427     printf("The following averages for the complete trajectory have been calculated:\n\n");
1428     printf(" Total < M_x > = %g Debye\n", M[XX]/teller);
1429     printf(" Total < M_y > = %g Debye\n", M[YY]/teller);
1430     printf(" Total < M_z > = %g Debye\n\n", M[ZZ]/teller);
1431
1432     printf(" Total < M_x^2 > = %g Debye^2\n", M2[XX]/teller);
1433     printf(" Total < M_y^2 > = %g Debye^2\n", M2[YY]/teller);
1434     printf(" Total < M_z^2 > = %g Debye^2\n\n", M2[ZZ]/teller);
1435
1436     printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave);
1437     printf(" Total |< M >|^2 = %g Debye^2\n\n", M_ave2);
1438
1439     printf(" < |M|^2 > - |< M >|^2 = %g Debye^2\n\n", M_diff);
1440
1441     if (!bMU || (mu_aver != -1))
1442     {
1443         printf("Finite system Kirkwood g factor G_k = %g\n", Gk);
1444         printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k);
1445     }
1446     printf("Epsilon = %g\n", epsilon);
1447
1448     if (!bMU)
1449     {
1450         /* Write to file the dipole moment distibution during the simulation.
1451          */
1452         outdd = xvgropen(dipdist, "Dipole Moment Distribution", "mu (Debye)", "", oenv);
1453         for (i = 0; (i < ndipbin); i++)
1454         {
1455             fprintf(outdd, "%10g  %10f\n",
1456                     (i*mu_max)/ndipbin, dipole_bin[i]/(double)teller);
1457         }
1458         ffclose(outdd);
1459         sfree(dipole_bin);
1460     }
1461     if (bGkr)
1462     {
1463         done_gkrbin(&gkrbin);
1464     }
1465 }
1466
1467 void dipole_atom2molindex(int *n, int *index, t_block *mols)
1468 {
1469     int nmol, i, j, m;
1470
1471     nmol = 0;
1472     i    = 0;
1473     while (i < *n)
1474     {
1475         m = 0;
1476         while (m < mols->nr && index[i] != mols->index[m])
1477         {
1478             m++;
1479         }
1480         if (m == mols->nr)
1481         {
1482             gmx_fatal(FARGS, "index[%d]=%d does not correspond to the first atom of a molecule", i+1, index[i]+1);
1483         }
1484         for (j = mols->index[m]; j < mols->index[m+1]; j++)
1485         {
1486             if (i >= *n || index[i] != j)
1487             {
1488                 gmx_fatal(FARGS, "The index group is not a set of whole molecules");
1489             }
1490             i++;
1491         }
1492         /* Modify the index in place */
1493         index[nmol++] = m;
1494     }
1495     printf("There are %d molecules in the selection\n", nmol);
1496
1497     *n = nmol;
1498 }
1499 int gmx_dipoles(int argc, char *argv[])
1500 {
1501     const char    *desc[] = {
1502         "[TT]g_dipoles[tt] computes the total dipole plus fluctuations of a simulation",
1503         "system. From this you can compute e.g. the dielectric constant for",
1504         "low-dielectric media.",
1505         "For molecules with a net charge, the net charge is subtracted at",
1506         "center of mass of the molecule.[PAR]",
1507         "The file [TT]Mtot.xvg[tt] contains the total dipole moment of a frame, the",
1508         "components as well as the norm of the vector.",
1509         "The file [TT]aver.xvg[tt] contains [CHEVRON][MAG][GRK]mu[grk][mag]^2[chevron] and [MAG][CHEVRON][GRK]mu[grk][chevron][mag]^2 during the",
1510         "simulation.",
1511         "The file [TT]dipdist.xvg[tt] contains the distribution of dipole moments during",
1512         "the simulation",
1513         "The value of [TT]-mumax[tt] is used as the highest value in the distribution graph.[PAR]",
1514         "Furthermore, the dipole autocorrelation function will be computed when",
1515         "option [TT]-corr[tt] is used. The output file name is given with the [TT]-c[tt]",
1516         "option.",
1517         "The correlation functions can be averaged over all molecules",
1518         "([TT]mol[tt]), plotted per molecule separately ([TT]molsep[tt])",
1519         "or it can be computed over the total dipole moment of the simulation box",
1520         "([TT]total[tt]).[PAR]",
1521         "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1522         "G-factor, as well as the average cosine of the angle between the dipoles",
1523         "as a function of the distance. The plot also includes gOO and hOO",
1524         "according to Nymand & Linse, J. Chem. Phys. 112 (2000) pp 6386-6395. In the same plot, ",
1525         "we also include the energy per scale computed by taking the inner product of",
1526         "the dipoles divided by the distance to the third power.[PAR]",
1527         "[PAR]",
1528         "EXAMPLES[PAR]",
1529         "[TT]g_dipoles -corr mol -P 1 -o dip_sqr -mu 2.273 -mumax 5.0[tt][PAR]",
1530         "This will calculate the autocorrelation function of the molecular",
1531         "dipoles using a first order Legendre polynomial of the angle of the",
1532         "dipole vector and itself a time t later. For this calculation 1001",
1533         "frames will be used. Further, the dielectric constant will be calculated",
1534         "using an [TT]-epsilonRF[tt] of infinity (default), temperature of 300 K (default) and",
1535         "an average dipole moment of the molecule of 2.273 (SPC). For the",
1536         "distribution function a maximum of 5.0 will be used."
1537     };
1538     real           mu_max     = 5, mu_aver = -1, rcmax = 0;
1539     real           epsilonRF  = 0.0, temp = 300;
1540     gmx_bool       bPairs     = TRUE, bPhi = FALSE, bQuad = FALSE;
1541     const char    *corrtype[] = {NULL, "none", "mol", "molsep", "total", NULL};
1542     const char    *axtitle    = "Z";
1543     int            nslices    = 10; /* nr of slices defined       */
1544     int            skip       = 0, nFA = 0, nFB = 0, ncos = 1;
1545     int            nlevels    = 20, ndegrees = 90;
1546     output_env_t   oenv;
1547     t_pargs        pa[] = {
1548         { "-mu",       FALSE, etREAL, {&mu_aver},
1549           "dipole of a single molecule (in Debye)" },
1550         { "-mumax",    FALSE, etREAL, {&mu_max},
1551           "max dipole in Debye (for histogram)" },
1552         { "-epsilonRF", FALSE, etREAL, {&epsilonRF},
1553           "[GRK]epsilon[grk] of the reaction field used during the simulation, needed for dielectric constant calculation. WARNING: 0.0 means infinity (default)" },
1554         { "-skip",     FALSE, etINT, {&skip},
1555           "Skip steps in the output (but not in the computations)" },
1556         { "-temp",     FALSE, etREAL, {&temp},
1557           "Average temperature of the simulation (needed for dielectric constant calculation)" },
1558         { "-corr",     FALSE, etENUM, {corrtype},
1559           "Correlation function to calculate" },
1560         { "-pairs",    FALSE, etBOOL, {&bPairs},
1561           "Calculate [MAG][COS][GRK]theta[grk][cos][mag] between all pairs of molecules. May be slow" },
1562         { "-quad",     FALSE, etBOOL, {&bQuad},
1563           "Take quadrupole into account"},
1564         { "-ncos",     FALSE, etINT, {&ncos},
1565           "Must be 1 or 2. Determines whether the [CHEVRON][COS][GRK]theta[grk][cos][chevron] is computed between all molecules in one group, or between molecules in two different groups. This turns on the [TT]-g[tt] flag." },
1566         { "-axis",     FALSE, etSTR, {&axtitle},
1567           "Take the normal on the computational box in direction X, Y or Z." },
1568         { "-sl",       FALSE, etINT, {&nslices},
1569           "Divide the box into this number of slices." },
1570         { "-gkratom",  FALSE, etINT, {&nFA},
1571           "Use the n-th atom of a molecule (starting from 1) to calculate the distance between molecules rather than the center of charge (when 0) in the calculation of distance dependent Kirkwood factors" },
1572         { "-gkratom2", FALSE, etINT, {&nFB},
1573           "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of molecules" },
1574         { "-rcmax",    FALSE, etREAL, {&rcmax},
1575           "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If zero, a criterion based on the box length will be used." },
1576         { "-phi",      FALSE, etBOOL, {&bPhi},
1577           "Plot the 'torsion angle' defined as the rotation of the two dipole vectors around the distance vector between the two molecules in the [TT].xpm[tt] file from the [TT]-cmap[tt] option. By default the cosine of the angle between the dipoles is plotted." },
1578         { "-nlevels",  FALSE, etINT, {&nlevels},
1579           "Number of colors in the cmap output" },
1580         { "-ndegrees", FALSE, etINT, {&ndegrees},
1581           "Number of divisions on the [IT]y[it]-axis in the cmap output (for 180 degrees)" }
1582     };
1583     int           *gnx;
1584     int            nFF[2];
1585     atom_id      **grpindex;
1586     char         **grpname = NULL;
1587     gmx_bool       bGkr, bMU, bSlab;
1588     t_filenm       fnm[] = {
1589         { efEDR, "-en", NULL,         ffOPTRD },
1590         { efTRX, "-f", NULL,           ffREAD },
1591         { efTPX, NULL, NULL,           ffREAD },
1592         { efNDX, NULL, NULL,           ffOPTRD },
1593         { efXVG, "-o",   "Mtot",       ffWRITE },
1594         { efXVG, "-eps", "epsilon",    ffWRITE },
1595         { efXVG, "-a",   "aver",       ffWRITE },
1596         { efXVG, "-d",   "dipdist",    ffWRITE },
1597         { efXVG, "-c",   "dipcorr",    ffOPTWR },
1598         { efXVG, "-g",   "gkr",        ffOPTWR },
1599         { efXVG, "-adip", "adip",       ffOPTWR },
1600         { efXVG, "-dip3d", "dip3d",    ffOPTWR },
1601         { efXVG, "-cos", "cosaver",    ffOPTWR },
1602         { efXPM, "-cmap", "cmap",       ffOPTWR },
1603         { efXVG, "-slab", "slab",       ffOPTWR }
1604     };
1605 #define NFILE asize(fnm)
1606     int            npargs;
1607     t_pargs       *ppa;
1608     t_topology    *top;
1609     int            ePBC;
1610     int            k, natoms;
1611     matrix         box;
1612
1613     npargs = asize(pa);
1614     ppa    = add_acf_pargs(&npargs, pa);
1615     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
1616                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
1617     {
1618         return 0;
1619     }
1620
1621     printf("Using %g as mu_max and %g as the dipole moment.\n",
1622            mu_max, mu_aver);
1623     if (epsilonRF == 0.0)
1624     {
1625         printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1626     }
1627
1628     bMU   = opt2bSet("-en", NFILE, fnm);
1629     if (bMU)
1630     {
1631         gmx_fatal(FARGS, "Due to new ways of treating molecules in GROMACS the total dipole in the energy file may be incorrect, because molecules can be split over periodic boundary conditions before computing the dipole. Please use your trajectory file.");
1632     }
1633     bGkr  = opt2bSet("-g", NFILE, fnm);
1634     if (opt2parg_bSet("-ncos", asize(pa), pa))
1635     {
1636         if ((ncos != 1) && (ncos != 2))
1637         {
1638             gmx_fatal(FARGS, "ncos has to be either 1 or 2");
1639         }
1640         bGkr = TRUE;
1641     }
1642     bSlab = (opt2bSet("-slab", NFILE, fnm) || opt2parg_bSet("-sl", asize(pa), pa) ||
1643              opt2parg_bSet("-axis", asize(pa), pa));
1644     if (bMU)
1645     {
1646         if (bQuad)
1647         {
1648             printf("WARNING: Can not determine quadrupoles from energy file\n");
1649             bQuad = FALSE;
1650         }
1651         if (bGkr)
1652         {
1653             printf("WARNING: Can not determine Gk(r) from energy file\n");
1654             bGkr  = FALSE;
1655             ncos  = 1;
1656         }
1657         if (mu_aver == -1)
1658         {
1659             printf("WARNING: Can not calculate Gk and gk, since you did\n"
1660                    "         not enter a valid dipole for the molecules\n");
1661         }
1662     }
1663
1664     snew(top, 1);
1665     ePBC = read_tpx_top(ftp2fn(efTPX, NFILE, fnm), NULL, box,
1666                         &natoms, NULL, NULL, NULL, top);
1667
1668     snew(gnx, ncos);
1669     snew(grpname, ncos);
1670     snew(grpindex, ncos);
1671     get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm),
1672               ncos, gnx, grpindex, grpname);
1673     for (k = 0; (k < ncos); k++)
1674     {
1675         dipole_atom2molindex(&gnx[k], grpindex[k], &(top->mols));
1676         neutralize_mols(gnx[k], grpindex[k], &(top->mols), top->atoms.atom);
1677     }
1678     nFF[0] = nFA;
1679     nFF[1] = nFB;
1680     do_dip(top, ePBC, det(box), ftp2fn(efTRX, NFILE, fnm),
1681            opt2fn("-o", NFILE, fnm), opt2fn("-eps", NFILE, fnm),
1682            opt2fn("-a", NFILE, fnm), opt2fn("-d", NFILE, fnm),
1683            opt2fn_null("-cos", NFILE, fnm),
1684            opt2fn_null("-dip3d", NFILE, fnm), opt2fn_null("-adip", NFILE, fnm),
1685            bPairs, corrtype[0],
1686            opt2fn("-c", NFILE, fnm),
1687            bGkr,    opt2fn("-g", NFILE, fnm),
1688            bPhi,    &nlevels,  ndegrees,
1689            ncos,
1690            opt2fn("-cmap", NFILE, fnm), rcmax,
1691            bQuad, bMU,     opt2fn("-en", NFILE, fnm),
1692            gnx, grpindex, mu_max, mu_aver, epsilonRF, temp, nFF, skip,
1693            bSlab, nslices, axtitle, opt2fn("-slab", NFILE, fnm), oenv);
1694
1695     do_view(oenv, opt2fn("-o", NFILE, fnm), "-autoscale xy -nxy");
1696     do_view(oenv, opt2fn("-eps", NFILE, fnm), "-autoscale xy -nxy");
1697     do_view(oenv, opt2fn("-a", NFILE, fnm), "-autoscale xy -nxy");
1698     do_view(oenv, opt2fn("-d", NFILE, fnm), "-autoscale xy");
1699     do_view(oenv, opt2fn("-c", NFILE, fnm), "-autoscale xy");
1700
1701     return 0;
1702 }