1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
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.
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.
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.
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.
30 * For more info, check our website at http://www.gromacs.org
33 * Green Red Orange Magenta Azure Cyan Skyblue
52 #include "gmx_statistics.h"
65 #define e2d(x) ENM2DEBYE*(x)
66 #define EANG2CM E_CHARGE*1.0e-10 /* e Angstrom to Coulomb meter */
67 #define CM2D SPEED_OF_LIGHT*1.0e+24 /* Coulomb meter to Debye */
79 static t_gkrbin *mk_gkrbin(real radius, real rcmax, gmx_bool bPhi, int ndegrees)
87 if ((ptr = getenv("GKRWIDTH")) != NULL)
91 sscanf(ptr, "%lf", &bw);
96 gb->spacing = 0.01; /* nm */
98 gb->nelem = 1 + radius/gb->spacing;
105 gb->nx = 1 + rcmax/gb->spacing;
108 snew(gb->elem, gb->nelem);
109 snew(gb->count, gb->nelem);
111 snew(gb->cmap, gb->nx);
112 gb->ny = max(2, ndegrees);
113 for (i = 0; (i < gb->nx); i++)
115 snew(gb->cmap[i], gb->ny);
122 static void done_gkrbin(t_gkrbin **gb)
130 static void add2gkr(t_gkrbin *gb, real r, real cosa, real phi)
132 int cy, index = gmx_nint(r/gb->spacing);
135 if (index < gb->nelem)
137 gb->elem[index] += cosa;
145 cy = (M_PI+phi)*gb->ny/(2*M_PI);
149 cy = (alpha*gb->ny)/M_PI; /*((1+cosa)*0.5*(gb->ny));*/
151 cy = min(gb->ny-1, max(0, cy));
154 fprintf(debug, "CY: %10f %5d\n", alpha, cy);
156 gb->cmap[index][cy] += 1;
160 static void rvec2sprvec(rvec dipcart, rvec dipsp)
163 dipsp[0] = sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]+dipcart[ZZ]*dipcart[ZZ]); /* R */
164 dipsp[1] = atan2(dipcart[YY], dipcart[XX]); /* Theta */
165 dipsp[2] = atan2(sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]), dipcart[ZZ]); /* Phi */
170 void do_gkr(t_gkrbin *gb, int ncos, int *ngrp, int *molindex[],
171 int mindex[], rvec x[], rvec mu[],
172 int ePBC, matrix box, t_atom *atom, int *nAtom)
174 static rvec *xcm[2] = { NULL, NULL};
175 int gi, gj, j0, j1, i, j, k, n, index, grp0, grp1;
176 real qtot, q, r2, cosa, rr, phi;
180 for (n = 0; (n < ncos); n++)
184 snew(xcm[n], ngrp[n]);
186 for (i = 0; (i < ngrp[n]); i++)
188 /* Calculate center of mass of molecule */
194 copy_rvec(x[j0+nAtom[n]-1], xcm[n][i]);
199 clear_rvec(xcm[n][i]);
201 for (j = j0; j < j1; j++)
205 for (k = 0; k < DIM; k++)
207 xcm[n][i][k] += q*x[j][k];
210 svmul(1/qtot, xcm[n][i], xcm[n][i]);
214 set_pbc(&pbc, ePBC, box);
217 for (i = 0; i < ngrp[grp0]; i++)
219 gi = molindex[grp0][i];
220 j0 = (ncos == 2) ? 0 : i+1;
221 for (j = j0; j < ngrp[grp1]; j++)
223 gj = molindex[grp1][j];
224 if ((iprod(mu[gi], mu[gi]) > 0) && (iprod(mu[gj], mu[gj]) > 0))
226 /* Compute distance between molecules including PBC */
227 pbc_dx(&pbc, xcm[grp0][i], xcm[grp1][j], dx);
233 rvec r_ij, r_kj, r_kl, mm, nn;
237 copy_rvec(xcm[grp0][i], xj);
238 copy_rvec(xcm[grp1][j], xk);
239 rvec_add(xj, mu[gi], xi);
240 rvec_add(xk, mu[gj], xl);
241 phi = dih_angle(xi, xj, xk, xl, &pbc,
242 r_ij, r_kj, r_kl, mm, nn, /* out */
243 &sign, &t1, &t2, &t3);
248 cosa = cos_angle(mu[gi], mu[gj]);
251 if (debug || (cosa != cosa))
253 fprintf(debug ? debug : stderr,
254 "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",
255 gi, mu[gi][XX], mu[gi][YY], mu[gi][ZZ], norm(mu[gi]),
256 gj, mu[gj][XX], mu[gj][YY], mu[gj][ZZ], norm(mu[gj]),
260 add2gkr(gb, rr, cosa, phi);
266 static real normalize_cmap(t_gkrbin *gb)
272 for (i = 0; (i < gb->nx); i++)
274 vol = 4*M_PI*sqr(gb->spacing*i)*gb->spacing;
275 for (j = 0; (j < gb->ny); j++)
277 gb->cmap[i][j] /= vol;
278 hi = max(hi, gb->cmap[i][j]);
283 gmx_fatal(FARGS, "No data in the cmap");
288 static void print_cmap(const char *cmap, t_gkrbin *gb, int *nlevels)
295 t_rgb rlo = { 1, 1, 1 };
296 t_rgb rhi = { 0, 0, 0 };
298 hi = normalize_cmap(gb);
299 snew(xaxis, gb->nx+1);
300 for (i = 0; (i < gb->nx+1); i++)
302 xaxis[i] = i*gb->spacing;
305 for (j = 0; (j < gb->ny); j++)
309 yaxis[j] = (360.0*j)/(gb->ny-1.0)-180;
313 yaxis[j] = (180.0*j)/(gb->ny-1.0);
315 /*2.0*j/(gb->ny-1.0)-1.0;*/
317 out = ffopen(cmap, "w");
319 "Dipole Orientation Distribution", "Fraction", "r (nm)",
320 gb->bPhi ? "Phi" : "Alpha",
321 gb->nx, gb->ny, xaxis, yaxis,
322 gb->cmap, 0, hi, rlo, rhi, nlevels);
328 static void print_gkrbin(const char *fn, t_gkrbin *gb,
329 int ngrp, int nframes, real volume,
330 const output_env_t oenv)
332 /* We compute Gk(r), gOO and hOO according to
333 * Nymand & Linse, JCP 112 (2000) pp 6386-6395.
334 * In this implementation the angle between dipoles is stored
335 * rather than their inner product. This allows to take polarizible
336 * models into account. The RDF is calculated as well, almost for free!
339 const char *leg[] = { "G\\sk\\N(r)", "< cos >", "h\\sOO\\N", "g\\sOO\\N", "Energy" };
341 real x0, x1, ggg, Gkr, vol_s, rho, gOO, hOO, cosav, ener;
344 fp = xvgropen(fn, "Distance dependent Gk", "r (nm)", "G\\sk\\N(r)", oenv);
345 xvgr_legend(fp, asize(leg), leg, oenv);
347 Gkr = 1; /* Self-dipole inproduct = 1 */
352 fprintf(debug, "Number density is %g molecules / nm^3\n", rho);
353 fprintf(debug, "ngrp = %d, nframes = %d\n", ngrp, nframes);
357 while (last > 1 && gb->elem[last-1] == 0)
362 /* Divide by dipole squared, by number of frames, by number of origins.
363 * Multiply by 2 because we only take half the matrix of interactions
366 fac = 2.0/((double) ngrp * (double) nframes);
369 for (i = 0; i < last; i++)
371 /* Centre of the coordinate in the spherical layer */
374 /* Volume of the layer */
375 vol_s = (4.0/3.0)*M_PI*(x1*x1*x1-x0*x0*x0);
378 gOO = gb->count[i]*fac/(rho*vol_s);
380 /* Dipole correlation hOO, normalized by the relative number density, like
381 * in a Radial distribution function.
383 ggg = gb->elem[i]*fac;
384 hOO = 3.0*ggg/(rho*vol_s);
388 cosav = gb->elem[i]/gb->count[i];
394 ener = -0.5*cosav*ONE_4PI_EPS0/(x1*x1*x1);
396 fprintf(fp, "%10.5e %12.5e %12.5e %12.5e %12.5e %12.5e\n",
397 x1, Gkr, cosav, hOO, gOO, ener);
405 gmx_bool read_mu_from_enx(ener_file_t fmu, int Vol, ivec iMu, rvec mu, real *vol,
406 real *t, int nre, t_enxframe *fr)
412 bCont = do_enx(fmu, fr);
415 fprintf(stderr, "Something strange: expected %d entries in energy file at step %s\n(time %g) but found %d entries\n",
416 nre, gmx_step_str(fr->step, buf), fr->t, fr->nre);
421 if (Vol != -1) /* we've got Volume in the energy file */
423 *vol = fr->ener[Vol].e;
425 for (i = 0; i < DIM; i++)
427 mu[i] = fr->ener[iMu[i]].e;
435 static void neutralize_mols(int n, int *index, t_block *mols, t_atom *atom)
438 int ncharged, m, a0, a1, a;
441 for (m = 0; m < n; m++)
443 a0 = mols->index[index[m]];
444 a1 = mols->index[index[m]+1];
447 for (a = a0; a < a1; a++)
452 /* This check is only for the count print */
453 if (fabs(qtot) > 0.01)
459 /* Remove the net charge at the center of mass */
460 for (a = a0; a < a1; a++)
462 atom[a].q -= qtot*atom[a].m/mtot;
469 printf("There are %d charged molecules in the selection,\n"
470 "will subtract their charge at their center of mass\n", ncharged);
474 static void mol_dip(int k0, int k1, rvec x[], t_atom atom[], rvec mu)
480 for (k = k0; (k < k1); k++)
483 for (m = 0; (m < DIM); m++)
490 static void mol_quad(int k0, int k1, rvec x[], t_atom atom[], rvec quad)
492 int i, k, m, n, niter;
493 real q, r2, mass, masstot;
494 rvec com; /* center of mass */
495 rvec r; /* distance of atoms to center of mass */
498 double dd[DIM], **ev, tmp;
502 for (i = 0; (i < DIM); i++)
509 /* Compute center of mass */
512 for (k = k0; (k < k1); k++)
516 for (i = 0; (i < DIM); i++)
518 com[i] += mass*x[k][i];
521 svmul((1.0/masstot), com, com);
523 /* We want traceless quadrupole moments, so let us calculate the complete
524 * quadrupole moment tensor and diagonalize this tensor to get
525 * the individual components on the diagonal.
528 #define delta(a, b) (( a == b ) ? 1.0 : 0.0)
530 for (m = 0; (m < DIM); m++)
532 for (n = 0; (n < DIM); n++)
537 for (k = k0; (k < k1); k++) /* loop over atoms in a molecule */
539 q = (atom[k].q)*100.0;
540 rvec_sub(x[k], com, r);
542 for (m = 0; (m < DIM); m++)
544 for (n = 0; (n < DIM); n++)
546 inten[m][n] += 0.5*q*(3.0*r[m]*r[n] - r2*delta(m, n))*EANG2CM*CM2D;
552 for (i = 0; (i < DIM); i++)
554 fprintf(debug, "Q[%d] = %8.3f %8.3f %8.3f\n",
555 i, inten[i][XX], inten[i][YY], inten[i][ZZ]);
559 /* We've got the quadrupole tensor, now diagonalize the sucker */
560 jacobi(inten, 3, dd, ev, &niter);
564 for (i = 0; (i < DIM); i++)
566 fprintf(debug, "ev[%d] = %8.3f %8.3f %8.3f\n",
567 i, ev[i][XX], ev[i][YY], ev[i][ZZ]);
569 for (i = 0; (i < DIM); i++)
571 fprintf(debug, "Q'[%d] = %8.3f %8.3f %8.3f\n",
572 i, inten[i][XX], inten[i][YY], inten[i][ZZ]);
575 /* Sort the eigenvalues, for water we know that the order is as follows:
579 * At the moment I have no idea how this will work out for other molecules...
583 if (dd[i+1] > dd[i]) { \
592 for (m = 0; (m < DIM); m++)
594 quad[0] = dd[2]; /* yy */
595 quad[1] = dd[0]; /* zz */
596 quad[2] = dd[1]; /* xx */
601 pr_rvec(debug, 0, "Quadrupole", quad, DIM, TRUE);
605 for (i = 0; (i < DIM); i++)
615 * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
617 real calc_eps(double M_diff, double volume, double epsRF, double temp)
619 double eps, A, teller, noemer;
620 double eps_0 = 8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
621 double fac = 1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
623 A = M_diff*fac/(3*eps_0*volume*NANO*NANO*NANO*BOLTZMANN*temp);
632 teller = 1 + (A*2*epsRF/(2*epsRF+1));
633 noemer = 1 - (A/(2*epsRF+1));
635 eps = teller / noemer;
640 static void update_slab_dipoles(int k0, int k1, rvec x[], rvec mu,
641 int idim, int nslice, rvec slab_dipole[],
647 for (k = k0; (k < k1); k++)
652 k = ((int)(xdim*nslice/box[idim][idim] + nslice)) % nslice;
653 rvec_inc(slab_dipole[k], mu);
656 static void dump_slab_dipoles(const char *fn, int idim, int nslice,
657 rvec slab_dipole[], matrix box, int nframes,
658 const output_env_t oenv)
664 const char *leg_dim[4] = {
665 "\\f{12}m\\f{4}\\sX\\N",
666 "\\f{12}m\\f{4}\\sY\\N",
667 "\\f{12}m\\f{4}\\sZ\\N",
668 "\\f{12}m\\f{4}\\stot\\N"
671 sprintf(buf, "Box-%c (nm)", 'X'+idim);
672 fp = xvgropen(fn, "Average dipole moment per slab", buf, "\\f{12}m\\f{4} (D)",
674 xvgr_legend(fp, DIM, leg_dim, oenv);
675 for (i = 0; (i < nslice); i++)
677 mutot = norm(slab_dipole[i])/nframes;
678 fprintf(fp, "%10.3f %10.3f %10.3f %10.3f %10.3f\n",
679 ((i+0.5)*box[idim][idim])/nslice,
680 slab_dipole[i][XX]/nframes,
681 slab_dipole[i][YY]/nframes,
682 slab_dipole[i][ZZ]/nframes,
686 do_view(oenv, fn, "-autoscale xy -nxy");
689 static void compute_avercos(int n, rvec dip[], real *dd, rvec axis, gmx_bool bPairs)
692 double dc, dc1, d, n5, ddc1, ddc2, ddc3;
693 rvec xxx = { 1, 0, 0 };
694 rvec yyy = { 0, 1, 0 };
695 rvec zzz = { 0, 0, 1 };
698 ddc1 = ddc2 = ddc3 = 0;
699 for (i = k = 0; (i < n); i++)
701 ddc1 += fabs(cos_angle(dip[i], xxx));
702 ddc2 += fabs(cos_angle(dip[i], yyy));
703 ddc3 += fabs(cos_angle(dip[i], zzz));
706 for (j = i+1; (j < n); j++, k++)
708 dc = cos_angle(dip[i], dip[j]);
719 static void do_dip(t_topology *top, int ePBC, real volume,
721 const char *out_mtot, const char *out_eps,
722 const char *out_aver, const char *dipdist,
723 const char *cosaver, const char *fndip3d,
724 const char *fnadip, gmx_bool bPairs,
725 const char *corrtype, const char *corf,
726 gmx_bool bGkr, const char *gkrfn,
727 gmx_bool bPhi, int *nlevels, int ndegrees,
729 const char *cmap, real rcmax,
730 gmx_bool bQuad, const char *quadfn,
731 gmx_bool bMU, const char *mufn,
732 int *gnx, int *molindex[],
733 real mu_max, real mu_aver,
734 real epsilonRF, real temp,
735 int *gkatom, int skip,
736 gmx_bool bSlab, int nslices,
737 const char *axtitle, const char *slabfn,
738 const output_env_t oenv)
740 const char *leg_mtot[] = {
746 #define NLEGMTOT asize(leg_mtot)
747 const char *leg_eps[] = {
752 #define NLEGEPS asize(leg_eps)
753 const char *leg_aver[] = {
756 "< |M|\\S2\\N > - < |M| >\\S2\\N",
757 "< |M| >\\S2\\N / < |M|\\S2\\N >"
759 #define NLEGAVER asize(leg_aver)
760 const char *leg_cosaver[] = {
761 "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
763 "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
764 "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
765 "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
767 #define NLEGCOSAVER asize(leg_cosaver)
768 const char *leg_adip[] = {
773 #define NLEGADIP asize(leg_adip)
775 FILE *outdd, *outmtot, *outaver, *outeps, *caver = NULL;
776 FILE *dip3d = NULL, *adip = NULL;
777 rvec *x, *dipole = NULL, mu_t, quad, *dipsp = NULL;
778 t_gkrbin *gkrbin = NULL;
779 gmx_enxnm_t *enm = NULL;
781 int nframes = 1000, nre, timecheck = 0, ncolour = 0;
782 ener_file_t fmu = NULL;
783 int i, j, k, n, m, natom = 0, nmol, gnx_tot, teller, tel3;
785 int *dipole_bin, ndipbin, ibin, iVol, step, idim = -1;
788 real rcut = 0, t, t0, t1, dt, lambda, dd, rms_cos;
791 gmx_bool bCorr, bTotal, bCont;
792 double M_diff = 0, epsilon, invtel, vol_aver;
793 double mu_ave, mu_mol, M2_ave = 0, M_ave2 = 0, M_av[DIM], M_av2[DIM];
794 double M[3], M2[3], M4[3], Gk = 0, g_k = 0;
795 gmx_stats_t Mx, My, Mz, Msq, Vol, *Qlsq, mulsq, muframelsq = NULL;
798 rvec *slab_dipoles = NULL;
800 t_block *mols = NULL;
801 gmx_rmpbc_t gpbc = NULL;
813 /* initialize to a negative value so we can see that it wasn't picked up */
814 iMu[XX] = iMu[YY] = iMu[ZZ] = -1;
817 fmu = open_enx(mufn, "r");
818 do_enxnms(fmu, &nre, &enm);
820 /* Determine the indexes of the energy grps we need */
821 for (i = 0; (i < nre); i++)
823 if (strstr(enm[i].name, "Volume"))
827 else if (strstr(enm[i].name, "Mu-X"))
831 else if (strstr(enm[i].name, "Mu-Y"))
835 else if (strstr(enm[i].name, "Mu-Z"))
840 if (iMu[XX] < 0 || iMu[YY] < 0 || iMu[ZZ] < 0)
842 gmx_fatal(FARGS,"No index for Mu-X, Mu-Y or Mu-Z energy group.");
847 atom = top->atoms.atom;
850 if ((iVol == -1) && bMU)
852 printf("Using Volume from topology: %g nm^3\n", volume);
855 /* Correlation stuff */
856 bCorr = (corrtype[0] != 'n');
857 bTotal = (corrtype[0] == 't');
863 snew(muall[0], nframes*DIM);
868 for (i = 0; (i < gnx[0]); i++)
870 snew(muall[i], nframes*DIM);
875 /* Allocate array which contains for every molecule in a frame the
880 snew(dipole, gnx_tot);
885 for (i = 0; (i < DIM); i++)
887 Qlsq[i] = gmx_stats_init();
889 mulsq = gmx_stats_init();
891 /* Open all the files */
892 outmtot = xvgropen(out_mtot,
893 "Total dipole moment of the simulation box vs. time",
894 "Time (ps)", "Total Dipole Moment (Debye)", oenv);
895 outeps = xvgropen(out_eps, "Epsilon and Kirkwood factors",
896 "Time (ps)", "", oenv);
897 outaver = xvgropen(out_aver, "Total dipole moment",
898 "Time (ps)", "D", oenv);
901 idim = axtitle[0] - 'X';
902 if ((idim < 0) || (idim >= DIM))
904 idim = axtitle[0] - 'x';
906 if ((idim < 0) || (idim >= DIM))
914 fprintf(stderr, "axtitle = %s, nslices = %d, idim = %d\n",
915 axtitle, nslices, idim);
918 snew(slab_dipoles, nslices);
919 fprintf(stderr, "Doing slab analysis\n");
925 adip = xvgropen(fnadip, "Average molecular dipole", "Dipole (D)", "", oenv);
926 xvgr_legend(adip, NLEGADIP, leg_adip, oenv);
931 caver = xvgropen(cosaver, bPairs ? "Average pair orientation" :
932 "Average absolute dipole orientation", "Time (ps)", "", oenv);
933 xvgr_legend(caver, NLEGCOSAVER, bPairs ? leg_cosaver : &(leg_cosaver[1]),
939 snew(dipsp, gnx_tot);
941 /* we need a dummy file for gnuplot */
942 dip3d = (FILE *)ffopen("dummy.dat", "w");
943 fprintf(dip3d, "%f %f %f", 0.0, 0.0, 0.0);
946 dip3d = (FILE *)ffopen(fndip3d, "w");
947 fprintf(dip3d, "# This file was created by %s\n", Program());
948 fprintf(dip3d, "# which is part of G R O M A C S:\n");
949 fprintf(dip3d, "#\n");
952 /* Write legends to all the files */
953 xvgr_legend(outmtot, NLEGMTOT, leg_mtot, oenv);
954 xvgr_legend(outaver, NLEGAVER, leg_aver, oenv);
956 if (bMU && (mu_aver == -1))
958 xvgr_legend(outeps, NLEGEPS-2, leg_eps, oenv);
962 xvgr_legend(outeps, NLEGEPS, leg_eps, oenv);
968 /* Read the first frame from energy or traj file */
973 bCont = read_mu_from_enx(fmu, iVol, iMu, mu_t, &volume, &t, nre, fr);
976 timecheck = check_times(t);
981 if ((teller % 10) == 0)
983 fprintf(stderr, "\r Skipping Frame %6d, time: %8.3f", teller, t);
988 printf("End of %s reached\n", mufn);
992 while (bCont && (timecheck < 0));
996 natom = read_first_x(oenv, &status, fn, &t, &x, box);
999 /* Calculate spacing for dipole bin (simple histogram) */
1000 ndipbin = 1+(mu_max/0.01);
1001 snew(dipole_bin, ndipbin);
1004 for (m = 0; (m < DIM); m++)
1006 M[m] = M2[m] = M4[m] = 0.0;
1011 /* Use 0.7 iso 0.5 to account for pressure scaling */
1012 /* rcut = 0.7*sqrt(max_cutoff2(box)); */
1013 rcut = 0.7*sqrt(sqr(box[XX][XX])+sqr(box[YY][YY])+sqr(box[ZZ][ZZ]));
1015 gkrbin = mk_gkrbin(rcut, rcmax, bPhi, ndegrees);
1017 gpbc = gmx_rmpbc_init(&top->idef, ePBC, natom, box);
1019 /* Start while loop over frames */
1024 if (bCorr && (teller >= nframes))
1029 srenew(muall[0], nframes*DIM);
1033 for (i = 0; (i < gnx_tot); i++)
1035 srenew(muall[i], nframes*DIM);
1041 muframelsq = gmx_stats_init();
1044 for (m = 0; (m < DIM); m++)
1051 /* Copy rvec into double precision local variable */
1052 for (m = 0; (m < DIM); m++)
1060 for (m = 0; (m < DIM); m++)
1065 gmx_rmpbc(gpbc, natom, box, x);
1067 /* Begin loop of all molecules in frame */
1068 for (n = 0; (n < ncos); n++)
1070 for (i = 0; (i < gnx[n]); i++)
1074 ind0 = mols->index[molindex[n][i]];
1075 ind1 = mols->index[molindex[n][i]+1];
1077 mol_dip(ind0, ind1, x, atom, dipole[i]);
1078 gmx_stats_add_point(mulsq, 0, norm(dipole[i]), 0, 0);
1079 gmx_stats_add_point(muframelsq, 0, norm(dipole[i]), 0, 0);
1082 update_slab_dipoles(ind0, ind1, x,
1083 dipole[i], idim, nslices, slab_dipoles, box);
1087 mol_quad(ind0, ind1, x, atom, quad);
1088 for (m = 0; (m < DIM); m++)
1090 gmx_stats_add_point(Qlsq[m], 0, quad[m], 0, 0);
1093 if (bCorr && !bTotal)
1096 muall[i][tel3+XX] = dipole[i][XX];
1097 muall[i][tel3+YY] = dipole[i][YY];
1098 muall[i][tel3+ZZ] = dipole[i][ZZ];
1101 for (m = 0; (m < DIM); m++)
1103 M_av[m] += dipole[i][m]; /* M per frame */
1104 mu_mol += dipole[i][m]*dipole[i][m]; /* calc. mu for distribution */
1106 mu_mol = sqrt(mu_mol);
1108 mu_ave += mu_mol; /* calc. the average mu */
1110 /* Update the dipole distribution */
1111 ibin = (int)(ndipbin*mu_mol/mu_max + 0.5);
1119 rvec2sprvec(dipole[i], dipsp[i]);
1121 if (dipsp[i][YY] > -M_PI && dipsp[i][YY] < -0.5*M_PI)
1123 if (dipsp[i][ZZ] < 0.5 * M_PI)
1132 else if (dipsp[i][YY] > -0.5*M_PI && dipsp[i][YY] < 0.0*M_PI)
1134 if (dipsp[i][ZZ] < 0.5 * M_PI)
1143 else if (dipsp[i][YY] > 0.0 && dipsp[i][YY] < 0.5*M_PI)
1145 if (dipsp[i][ZZ] < 0.5 * M_PI)
1154 else if (dipsp[i][YY] > 0.5*M_PI && dipsp[i][YY] < M_PI)
1156 if (dipsp[i][ZZ] < 0.5 * M_PI)
1167 fprintf(dip3d, "set arrow %d from %f, %f, %f to %f, %f, %f lt %d # %d %d\n",
1172 x[ind0][XX]+dipole[i][XX]/25,
1173 x[ind0][YY]+dipole[i][YY]/25,
1174 x[ind0][ZZ]+dipole[i][ZZ]/25,
1178 } /* End loop of all molecules in frame */
1182 fprintf(dip3d, "set title \"t = %4.3f\"\n", t);
1183 fprintf(dip3d, "set xrange [0.0:%4.2f]\n", box[XX][XX]);
1184 fprintf(dip3d, "set yrange [0.0:%4.2f]\n", box[YY][YY]);
1185 fprintf(dip3d, "set zrange [0.0:%4.2f]\n\n", box[ZZ][ZZ]);
1186 fprintf(dip3d, "splot 'dummy.dat' using 1:2:3 w vec\n");
1187 fprintf(dip3d, "pause -1 'Hit return to continue'\n");
1191 /* Compute square of total dipole */
1192 for (m = 0; (m < DIM); m++)
1194 M_av2[m] = M_av[m]*M_av[m];
1199 compute_avercos(gnx_tot, dipole, &dd, dipaxis, bPairs);
1200 rms_cos = sqrt(sqr(dipaxis[XX]-0.5)+
1201 sqr(dipaxis[YY]-0.5)+
1202 sqr(dipaxis[ZZ]-0.5));
1205 fprintf(caver, "%10.3e %10.3e %10.3e %10.3e %10.3e %10.3e\n",
1206 t, dd, rms_cos, dipaxis[XX], dipaxis[YY], dipaxis[ZZ]);
1210 fprintf(caver, "%10.3e %10.3e %10.3e %10.3e %10.3e\n",
1211 t, rms_cos, dipaxis[XX], dipaxis[YY], dipaxis[ZZ]);
1217 do_gkr(gkrbin, ncos, gnx, molindex, mols->index, x, dipole, ePBC, box,
1224 muall[0][tel3+XX] = M_av[XX];
1225 muall[0][tel3+YY] = M_av[YY];
1226 muall[0][tel3+ZZ] = M_av[ZZ];
1229 /* Write to file the total dipole moment of the box, and its components
1232 if ((skip == 0) || ((teller % skip) == 0))
1234 fprintf(outmtot, "%10g %12.8e %12.8e %12.8e %12.8e\n",
1235 t, M_av[XX], M_av[YY], M_av[ZZ],
1236 sqrt(M_av2[XX]+M_av2[YY]+M_av2[ZZ]));
1239 for (m = 0; (m < DIM); m++)
1243 M4[m] += sqr(M_av2[m]);
1245 /* Increment loop counter */
1248 /* Calculate for output the running averages */
1249 invtel = 1.0/teller;
1250 M2_ave = (M2[XX]+M2[YY]+M2[ZZ])*invtel;
1251 M_ave2 = invtel*(invtel*(M[XX]*M[XX] + M[YY]*M[YY] + M[ZZ]*M[ZZ]));
1252 M_diff = M2_ave - M_ave2;
1254 /* Compute volume from box in traj, else we use the one from above */
1261 epsilon = calc_eps(M_diff, (vol_aver/teller), epsilonRF, temp);
1263 /* Calculate running average for dipole */
1266 mu_aver = (mu_ave/gnx_tot)*invtel;
1269 if ((skip == 0) || ((teller % skip) == 0))
1271 /* Write to file < |M|^2 >, |< M >|^2. And the difference between
1272 * the two. Here M is sum mu_i. Further write the finite system
1273 * Kirkwood G factor and epsilon.
1275 fprintf(outaver, "%10g %10.3e %10.3e %10.3e %10.3e\n",
1276 t, M2_ave, M_ave2, M_diff, M_ave2/M2_ave);
1281 gmx_stats_get_average(muframelsq, &aver);
1282 fprintf(adip, "%10g %f \n", t, aver);
1285 printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1287 if (!bMU || (mu_aver != -1))
1289 /* Finite system Kirkwood G-factor */
1290 Gk = M_diff/(gnx_tot*mu_aver*mu_aver);
1291 /* Infinite system Kirkwood G-factor */
1292 if (epsilonRF == 0.0)
1294 g_k = ((2*epsilon+1)*Gk/(3*epsilon));
1298 g_k = ((2*epsilonRF+epsilon)*(2*epsilon+1)*
1299 Gk/(3*epsilon*(2*epsilonRF+1)));
1302 fprintf(outeps, "%10g %10.3e %10.3e %10.3e\n", t, epsilon, Gk, g_k);
1307 fprintf(outeps, "%10g %12.8e\n", t, epsilon);
1310 gmx_stats_done(muframelsq);
1314 bCont = read_mu_from_enx(fmu, iVol, iMu, mu_t, &volume, &t, nre, fr);
1318 bCont = read_next_x(oenv, status, &t, natom, x, box);
1320 timecheck = check_times(t);
1322 while (bCont && (timecheck == 0) );
1324 gmx_rmpbc_done(gpbc);
1347 fprintf(dip3d, "set xrange [0.0:%4.2f]\n", box[XX][XX]);
1348 fprintf(dip3d, "set yrange [0.0:%4.2f]\n", box[YY][YY]);
1349 fprintf(dip3d, "set zrange [0.0:%4.2f]\n\n", box[ZZ][ZZ]);
1350 fprintf(dip3d, "splot 'dummy.dat' using 1:2:3 w vec\n");
1351 fprintf(dip3d, "pause -1 'Hit return to continue'\n");
1357 dump_slab_dipoles(slabfn, idim, nslices, slab_dipoles, box, teller, oenv);
1358 sfree(slab_dipoles);
1362 printf("Average volume over run is %g\n", vol_aver);
1365 print_gkrbin(gkrfn, gkrbin, gnx[0], teller, vol_aver, oenv);
1366 print_cmap(cmap, gkrbin, nlevels);
1368 /* Autocorrelation function */
1373 printf("Not enough frames for autocorrelation\n");
1377 dt = (t1 - t0)/(teller-1);
1378 printf("t0 %g, t %g, teller %d\n", t0, t, teller);
1384 do_autocorr(corf, oenv, "Autocorrelation Function of Total Dipole",
1385 teller, 1, muall, dt, mode, TRUE);
1389 do_autocorr(corf, oenv, "Dipole Autocorrelation Function",
1390 teller, gnx_tot, muall, dt,
1391 mode, strcmp(corrtype, "molsep"));
1397 real aver, sigma, error, lsq;
1399 gmx_stats_get_ase(mulsq, &aver, &sigma, &error);
1400 printf("\nDipole moment (Debye)\n");
1401 printf("---------------------\n");
1402 printf("Average = %8.4f Std. Dev. = %8.4f Error = %8.4f\n",
1403 aver, sigma, error);
1408 for (m = 0; (m < DIM); m++)
1410 gmx_stats_get_ase(mulsq, &(a[m]), &(s[m]), &(e[m]));
1413 printf("\nQuadrupole moment (Debye-Ang)\n");
1414 printf("-----------------------------\n");
1415 printf("Averages = %8.4f %8.4f %8.4f\n", a[XX], a[YY], a[ZZ]);
1416 printf("Std. Dev. = %8.4f %8.4f %8.4f\n", s[XX], s[YY], s[ZZ]);
1417 printf("Error = %8.4f %8.4f %8.4f\n", e[XX], e[YY], e[ZZ]);
1421 printf("The following averages for the complete trajectory have been calculated:\n\n");
1422 printf(" Total < M_x > = %g Debye\n", M[XX]/teller);
1423 printf(" Total < M_y > = %g Debye\n", M[YY]/teller);
1424 printf(" Total < M_z > = %g Debye\n\n", M[ZZ]/teller);
1426 printf(" Total < M_x^2 > = %g Debye^2\n", M2[XX]/teller);
1427 printf(" Total < M_y^2 > = %g Debye^2\n", M2[YY]/teller);
1428 printf(" Total < M_z^2 > = %g Debye^2\n\n", M2[ZZ]/teller);
1430 printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave);
1431 printf(" Total |< M >|^2 = %g Debye^2\n\n", M_ave2);
1433 printf(" < |M|^2 > - |< M >|^2 = %g Debye^2\n\n", M_diff);
1435 if (!bMU || (mu_aver != -1))
1437 printf("Finite system Kirkwood g factor G_k = %g\n", Gk);
1438 printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k);
1440 printf("Epsilon = %g\n", epsilon);
1444 /* Write to file the dipole moment distibution during the simulation.
1446 outdd = xvgropen(dipdist, "Dipole Moment Distribution", "mu (Debye)", "", oenv);
1447 for (i = 0; (i < ndipbin); i++)
1449 fprintf(outdd, "%10g %10f\n",
1450 (i*mu_max)/ndipbin, dipole_bin[i]/(double)teller);
1457 done_gkrbin(&gkrbin);
1461 void dipole_atom2molindex(int *n, int *index, t_block *mols)
1470 while (m < mols->nr && index[i] != mols->index[m])
1476 gmx_fatal(FARGS, "index[%d]=%d does not correspond to the first atom of a molecule", i+1, index[i]+1);
1478 for (j = mols->index[m]; j < mols->index[m+1]; j++)
1480 if (i >= *n || index[i] != j)
1482 gmx_fatal(FARGS, "The index group is not a set of whole molecules");
1486 /* Modify the index in place */
1489 printf("There are %d molecules in the selection\n", nmol);
1493 int gmx_dipoles(int argc, char *argv[])
1495 const char *desc[] = {
1496 "[TT]g_dipoles[tt] computes the total dipole plus fluctuations of a simulation",
1497 "system. From this you can compute e.g. the dielectric constant for",
1498 "low-dielectric media.",
1499 "For molecules with a net charge, the net charge is subtracted at",
1500 "center of mass of the molecule.[PAR]",
1501 "The file [TT]Mtot.xvg[tt] contains the total dipole moment of a frame, the",
1502 "components as well as the norm of the vector.",
1503 "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",
1505 "The file [TT]dipdist.xvg[tt] contains the distribution of dipole moments during",
1507 "The value of [TT]-mumax[tt] is used as the highest value in the distribution graph.[PAR]",
1508 "Furthermore, the dipole autocorrelation function will be computed when",
1509 "option [TT]-corr[tt] is used. The output file name is given with the [TT]-c[tt]",
1511 "The correlation functions can be averaged over all molecules",
1512 "([TT]mol[tt]), plotted per molecule separately ([TT]molsep[tt])",
1513 "or it can be computed over the total dipole moment of the simulation box",
1514 "([TT]total[tt]).[PAR]",
1515 "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1516 "G-factor, as well as the average cosine of the angle between the dipoles",
1517 "as a function of the distance. The plot also includes gOO and hOO",
1518 "according to Nymand & Linse, J. Chem. Phys. 112 (2000) pp 6386-6395. In the same plot, ",
1519 "we also include the energy per scale computed by taking the inner product of",
1520 "the dipoles divided by the distance to the third power.[PAR]",
1523 "[TT]g_dipoles -corr mol -P 1 -o dip_sqr -mu 2.273 -mumax 5.0[tt][PAR]",
1524 "This will calculate the autocorrelation function of the molecular",
1525 "dipoles using a first order Legendre polynomial of the angle of the",
1526 "dipole vector and itself a time t later. For this calculation 1001",
1527 "frames will be used. Further, the dielectric constant will be calculated",
1528 "using an [TT]-epsilonRF[tt] of infinity (default), temperature of 300 K (default) and",
1529 "an average dipole moment of the molecule of 2.273 (SPC). For the",
1530 "distribution function a maximum of 5.0 will be used."
1532 real mu_max = 5, mu_aver = -1, rcmax = 0;
1533 real epsilonRF = 0.0, temp = 300;
1534 gmx_bool bAverCorr = FALSE, bMolCorr = FALSE, bPairs = TRUE, bPhi = FALSE;
1535 const char *corrtype[] = {NULL, "none", "mol", "molsep", "total", NULL};
1536 const char *axtitle = "Z";
1537 int nslices = 10; /* nr of slices defined */
1538 int skip = 0, nFA = 0, nFB = 0, ncos = 1;
1539 int nlevels = 20, ndegrees = 90;
1542 { "-mu", FALSE, etREAL, {&mu_aver},
1543 "dipole of a single molecule (in Debye)" },
1544 { "-mumax", FALSE, etREAL, {&mu_max},
1545 "max dipole in Debye (for histogram)" },
1546 { "-epsilonRF", FALSE, etREAL, {&epsilonRF},
1547 "[GRK]epsilon[grk] of the reaction field used during the simulation, needed for dielectric constant calculation. WARNING: 0.0 means infinity (default)" },
1548 { "-skip", FALSE, etINT, {&skip},
1549 "Skip steps in the output (but not in the computations)" },
1550 { "-temp", FALSE, etREAL, {&temp},
1551 "Average temperature of the simulation (needed for dielectric constant calculation)" },
1552 { "-corr", FALSE, etENUM, {corrtype},
1553 "Correlation function to calculate" },
1554 { "-pairs", FALSE, etBOOL, {&bPairs},
1555 "Calculate [MAG][COS][GRK]theta[grk][cos][mag] between all pairs of molecules. May be slow" },
1556 { "-ncos", FALSE, etINT, {&ncos},
1557 "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." },
1558 { "-axis", FALSE, etSTR, {&axtitle},
1559 "Take the normal on the computational box in direction X, Y or Z." },
1560 { "-sl", FALSE, etINT, {&nslices},
1561 "Divide the box into this number of slices." },
1562 { "-gkratom", FALSE, etINT, {&nFA},
1563 "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" },
1564 { "-gkratom2", FALSE, etINT, {&nFB},
1565 "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of molecules" },
1566 { "-rcmax", FALSE, etREAL, {&rcmax},
1567 "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If zero, a criterion based on the box length will be used." },
1568 { "-phi", FALSE, etBOOL, {&bPhi},
1569 "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." },
1570 { "-nlevels", FALSE, etINT, {&nlevels},
1571 "Number of colors in the cmap output" },
1572 { "-ndegrees", FALSE, etINT, {&ndegrees},
1573 "Number of divisions on the [IT]y[it]-axis in the cmap output (for 180 degrees)" }
1578 char **grpname = NULL;
1579 gmx_bool bCorr, bQuad, bGkr, bMU, bSlab;
1581 { efEDR, "-en", NULL, ffOPTRD },
1582 { efTRX, "-f", NULL, ffREAD },
1583 { efTPX, NULL, NULL, ffREAD },
1584 { efNDX, NULL, NULL, ffOPTRD },
1585 { efXVG, "-o", "Mtot", ffWRITE },
1586 { efXVG, "-eps", "epsilon", ffWRITE },
1587 { efXVG, "-a", "aver", ffWRITE },
1588 { efXVG, "-d", "dipdist", ffWRITE },
1589 { efXVG, "-c", "dipcorr", ffOPTWR },
1590 { efXVG, "-g", "gkr", ffOPTWR },
1591 { efXVG, "-adip", "adip", ffOPTWR },
1592 { efXVG, "-dip3d", "dip3d", ffOPTWR },
1593 { efXVG, "-cos", "cosaver", ffOPTWR },
1594 { efXPM, "-cmap", "cmap", ffOPTWR },
1595 { efXVG, "-q", "quadrupole", ffOPTWR },
1596 { efXVG, "-slab", "slab", ffOPTWR }
1598 #define NFILE asize(fnm)
1607 ppa = add_acf_pargs(&npargs, pa);
1608 parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
1609 NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv);
1611 printf("Using %g as mu_max and %g as the dipole moment.\n",
1613 if (epsilonRF == 0.0)
1615 printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1618 bMU = opt2bSet("-en", NFILE, fnm);
1621 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.");
1623 bQuad = opt2bSet("-q", NFILE, fnm);
1624 bGkr = opt2bSet("-g", NFILE, fnm);
1625 if (opt2parg_bSet("-ncos", asize(pa), pa))
1627 if ((ncos != 1) && (ncos != 2))
1629 gmx_fatal(FARGS, "ncos has to be either 1 or 2");
1633 bSlab = (opt2bSet("-slab", NFILE, fnm) || opt2parg_bSet("-sl", asize(pa), pa) ||
1634 opt2parg_bSet("-axis", asize(pa), pa));
1640 printf("WARNING: Can not determine quadrupoles from energy file\n");
1645 printf("WARNING: Can not determine Gk(r) from energy file\n");
1651 printf("WARNING: Can not calculate Gk and gk, since you did\n"
1652 " not enter a valid dipole for the molecules\n");
1657 ePBC = read_tpx_top(ftp2fn(efTPX, NFILE, fnm), NULL, box,
1658 &natoms, NULL, NULL, NULL, top);
1661 snew(grpname, ncos);
1662 snew(grpindex, ncos);
1663 get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm),
1664 ncos, gnx, grpindex, grpname);
1665 for (k = 0; (k < ncos); k++)
1667 dipole_atom2molindex(&gnx[k], grpindex[k], &(top->mols));
1668 neutralize_mols(gnx[k], grpindex[k], &(top->mols), top->atoms.atom);
1672 do_dip(top, ePBC, det(box), ftp2fn(efTRX, NFILE, fnm),
1673 opt2fn("-o", NFILE, fnm), opt2fn("-eps", NFILE, fnm),
1674 opt2fn("-a", NFILE, fnm), opt2fn("-d", NFILE, fnm),
1675 opt2fn_null("-cos", NFILE, fnm),
1676 opt2fn_null("-dip3d", NFILE, fnm), opt2fn_null("-adip", NFILE, fnm),
1677 bPairs, corrtype[0],
1678 opt2fn("-c", NFILE, fnm),
1679 bGkr, opt2fn("-g", NFILE, fnm),
1680 bPhi, &nlevels, ndegrees,
1682 opt2fn("-cmap", NFILE, fnm), rcmax,
1683 bQuad, opt2fn("-q", NFILE, fnm),
1684 bMU, opt2fn("-en", NFILE, fnm),
1685 gnx, grpindex, mu_max, mu_aver, epsilonRF, temp, nFF, skip,
1686 bSlab, nslices, axtitle, opt2fn("-slab", NFILE, fnm), oenv);
1688 do_view(oenv, opt2fn("-o", NFILE, fnm), "-autoscale xy -nxy");
1689 do_view(oenv, opt2fn("-eps", NFILE, fnm), "-autoscale xy -nxy");
1690 do_view(oenv, opt2fn("-a", NFILE, fnm), "-autoscale xy -nxy");
1691 do_view(oenv, opt2fn("-d", NFILE, fnm), "-autoscale xy");
1692 do_view(oenv, opt2fn("-c", NFILE, fnm), "-autoscale xy");