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) {
90 sscanf(ptr,"%lf",&bw);
94 gb->spacing = 0.01; /* nm */
95 gb->nelem = 1 + radius/gb->spacing;
99 gb->nx = 1 + rcmax/gb->spacing;
101 snew(gb->elem,gb->nelem);
102 snew(gb->count,gb->nelem);
104 snew(gb->cmap,gb->nx);
105 gb->ny = max(2,ndegrees);
106 for(i=0; (i<gb->nx); i++)
107 snew(gb->cmap[i],gb->ny);
113 static void done_gkrbin(t_gkrbin **gb)
121 static void add2gkr(t_gkrbin *gb,real r,real cosa,real phi)
123 int cy,index = gmx_nint(r/gb->spacing);
126 if (index < gb->nelem) {
127 gb->elem[index] += cosa;
130 if (index < gb->nx) {
133 cy = (M_PI+phi)*gb->ny/(2*M_PI);
135 cy = (alpha*gb->ny)/M_PI;/*((1+cosa)*0.5*(gb->ny));*/
136 cy = min(gb->ny-1,max(0,cy));
138 fprintf(debug,"CY: %10f %5d\n",alpha,cy);
139 gb->cmap[index][cy] += 1;
143 static void rvec2sprvec(rvec dipcart,rvec dipsp)
146 dipsp[0] = sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]+dipcart[ZZ]*dipcart[ZZ]); /* R */
147 dipsp[1] = atan2(dipcart[YY],dipcart[XX]); /* Theta */
148 dipsp[2] = atan2(sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]),dipcart[ZZ]); /* Phi */
153 void do_gkr(t_gkrbin *gb,int ncos,int *ngrp,int *molindex[],
154 int mindex[],rvec x[],rvec mu[],
155 int ePBC,matrix box,t_atom *atom,int *nAtom)
157 static rvec *xcm[2] = { NULL, NULL};
158 int gi,gj,j0,j1,i,j,k,n,index,grp0,grp1;
159 real qtot,q,r2,cosa,rr,phi;
163 for(n=0; (n<ncos); n++) {
165 snew(xcm[n],ngrp[n]);
166 for(i=0; (i<ngrp[n]); i++) {
167 /* Calculate center of mass of molecule */
172 copy_rvec(x[j0+nAtom[n]-1],xcm[n][i]);
175 clear_rvec(xcm[n][i]);
177 for(j=j0; j<j1; j++) {
181 xcm[n][i][k] += q*x[j][k];
183 svmul(1/qtot,xcm[n][i],xcm[n][i]);
187 set_pbc(&pbc,ePBC,box);
190 for(i=0; i<ngrp[grp0]; i++) {
191 gi = molindex[grp0][i];
192 j0 = (ncos == 2) ? 0 : i+1;
193 for(j=j0; j<ngrp[grp1]; j++) {
194 gj = molindex[grp1][j];
195 if ((iprod(mu[gi],mu[gi]) > 0) && (iprod(mu[gj],mu[gj]) > 0)) {
196 /* Compute distance between molecules including PBC */
197 pbc_dx(&pbc,xcm[grp0][i],xcm[grp1][j],dx);
202 rvec r_ij,r_kj,r_kl,mm,nn;
206 copy_rvec(xcm[grp0][i],xj);
207 copy_rvec(xcm[grp1][j],xk);
208 rvec_add(xj,mu[gi],xi);
209 rvec_add(xk,mu[gj],xl);
210 phi = dih_angle(xi,xj,xk,xl,&pbc,
211 r_ij,r_kj,r_kl,mm,nn, /* out */
216 cosa = cos_angle(mu[gi],mu[gj]);
219 if (debug || (cosa != cosa)) {
220 fprintf(debug ? debug : stderr,
221 "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",
222 gi,mu[gi][XX],mu[gi][YY],mu[gi][ZZ],norm(mu[gi]),
223 gj,mu[gj][XX],mu[gj][YY],mu[gj][ZZ],norm(mu[gj]),
227 add2gkr(gb,rr,cosa,phi);
233 static real normalize_cmap(t_gkrbin *gb)
239 for(i=0; (i<gb->nx); i++) {
240 vol = 4*M_PI*sqr(gb->spacing*i)*gb->spacing;
241 for(j=0; (j<gb->ny); j++) {
242 gb->cmap[i][j] /= vol;
243 hi = max(hi,gb->cmap[i][j]);
247 gmx_fatal(FARGS,"No data in the cmap");
251 static void print_cmap(const char *cmap,t_gkrbin *gb,int *nlevels)
258 t_rgb rlo = { 1, 1, 1 };
259 t_rgb rhi = { 0, 0, 0 };
261 hi = normalize_cmap(gb);
262 snew(xaxis,gb->nx+1);
263 for(i=0; (i<gb->nx+1); i++)
264 xaxis[i] = i*gb->spacing;
266 for(j=0; (j<gb->ny); j++) {
268 yaxis[j] = (360.0*j)/(gb->ny-1.0)-180;
270 yaxis[j] = (180.0*j)/(gb->ny-1.0);
271 /*2.0*j/(gb->ny-1.0)-1.0;*/
273 out = ffopen(cmap,"w");
275 "Dipole Orientation Distribution","Fraction","r (nm)",
276 gb->bPhi ? "Phi" : "Alpha",
277 gb->nx,gb->ny,xaxis,yaxis,
278 gb->cmap,0,hi,rlo,rhi,nlevels);
284 static void print_gkrbin(const char *fn,t_gkrbin *gb,
285 int ngrp,int nframes,real volume,
286 const output_env_t oenv)
288 /* We compute Gk(r), gOO and hOO according to
289 * Nymand & Linse, JCP 112 (2000) pp 6386-6395.
290 * In this implementation the angle between dipoles is stored
291 * rather than their inner product. This allows to take polarizible
292 * models into account. The RDF is calculated as well, almost for free!
295 const char *leg[] = { "G\\sk\\N(r)", "< cos >", "h\\sOO\\N", "g\\sOO\\N", "Energy" };
297 real x0,x1,ggg,Gkr,vol_s,rho,gOO,hOO,cosav,ener;
300 fp=xvgropen(fn,"Distance dependent Gk","r (nm)","G\\sk\\N(r)",oenv);
301 xvgr_legend(fp,asize(leg),leg,oenv);
303 Gkr = 1; /* Self-dipole inproduct = 1 */
307 fprintf(debug,"Number density is %g molecules / nm^3\n",rho);
308 fprintf(debug,"ngrp = %d, nframes = %d\n",ngrp,nframes);
312 while(last>1 && gb->elem[last-1]==0)
315 /* Divide by dipole squared, by number of frames, by number of origins.
316 * Multiply by 2 because we only take half the matrix of interactions
319 fac = 2.0/((double) ngrp * (double) nframes);
322 for(i=0; i<last; i++) {
323 /* Centre of the coordinate in the spherical layer */
326 /* Volume of the layer */
327 vol_s = (4.0/3.0)*M_PI*(x1*x1*x1-x0*x0*x0);
330 gOO = gb->count[i]*fac/(rho*vol_s);
332 /* Dipole correlation hOO, normalized by the relative number density, like
333 * in a Radial distribution function.
335 ggg = gb->elem[i]*fac;
336 hOO = 3.0*ggg/(rho*vol_s);
339 cosav = gb->elem[i]/gb->count[i];
342 ener = -0.5*cosav*ONE_4PI_EPS0/(x1*x1*x1);
344 fprintf(fp,"%10.5e %12.5e %12.5e %12.5e %12.5e %12.5e\n",
345 x1,Gkr,cosav,hOO,gOO,ener);
353 gmx_bool read_mu_from_enx(ener_file_t fmu,int Vol,ivec iMu,rvec mu,real *vol,
354 real *t, int nre,t_enxframe *fr)
360 bCont = do_enx(fmu,fr);
362 fprintf(stderr,"Something strange: expected %d entries in energy file at step %s\n(time %g) but found %d entries\n",
363 nre,gmx_step_str(fr->step,buf),fr->t,fr->nre);
366 if (Vol != -1) /* we've got Volume in the energy file */
367 *vol = fr->ener[Vol].e;
368 for (i=0; i<DIM; i++)
369 mu[i] = fr->ener[iMu[i]].e;
376 static void neutralize_mols(int n,int *index,t_block *mols,t_atom *atom)
379 int ncharged,m,a0,a1,a;
383 a0 = mols->index[index[m]];
384 a1 = mols->index[index[m]+1];
387 for(a=a0; a<a1; a++) {
391 /* This check is only for the count print */
392 if (fabs(qtot) > 0.01)
395 /* Remove the net charge at the center of mass */
397 atom[a].q -= qtot*atom[a].m/mtot;
402 printf("There are %d charged molecules in the selection,\n"
403 "will subtract their charge at their center of mass\n",ncharged);
406 static void mol_dip(int k0,int k1,rvec x[],t_atom atom[],rvec mu)
412 for(k=k0; (k<k1); k++) {
414 for(m=0; (m<DIM); m++)
419 static void mol_quad(int k0,int k1,rvec x[],t_atom atom[],rvec quad)
422 real q,r2,mass,masstot;
423 rvec com; /* center of mass */
424 rvec r; /* distance of atoms to center of mass */
427 double dd[DIM],**ev,tmp;
431 for(i=0; (i<DIM); i++) {
437 /* Compute center of mass */
440 for(k=k0; (k<k1); k++) {
443 for(i=0; (i<DIM); i++)
444 com[i] += mass*x[k][i];
446 svmul((1.0/masstot),com,com);
448 /* We want traceless quadrupole moments, so let us calculate the complete
449 * quadrupole moment tensor and diagonalize this tensor to get
450 * the individual components on the diagonal.
453 #define delta(a,b) (( a == b ) ? 1.0 : 0.0)
455 for(m=0; (m<DIM); m++)
456 for(n=0; (n<DIM); n++)
458 for(k=k0; (k<k1); k++) { /* loop over atoms in a molecule */
459 q = (atom[k].q)*100.0;
460 rvec_sub(x[k],com,r);
462 for(m=0; (m<DIM); m++)
463 for(n=0; (n<DIM); n++)
464 inten[m][n] += 0.5*q*(3.0*r[m]*r[n] - r2*delta(m,n))*EANG2CM*CM2D;
467 for(i=0; (i<DIM); i++)
468 fprintf(debug,"Q[%d] = %8.3f %8.3f %8.3f\n",
469 i,inten[i][XX],inten[i][YY],inten[i][ZZ]);
471 /* We've got the quadrupole tensor, now diagonalize the sucker */
472 jacobi(inten,3,dd,ev,&niter);
475 for(i=0; (i<DIM); i++)
476 fprintf(debug,"ev[%d] = %8.3f %8.3f %8.3f\n",
477 i,ev[i][XX],ev[i][YY],ev[i][ZZ]);
478 for(i=0; (i<DIM); i++)
479 fprintf(debug,"Q'[%d] = %8.3f %8.3f %8.3f\n",
480 i,inten[i][XX],inten[i][YY],inten[i][ZZ]);
482 /* Sort the eigenvalues, for water we know that the order is as follows:
486 * At the moment I have no idea how this will work out for other molecules...
490 if (dd[i+1] > dd[i]) { \
499 for(m=0; (m<DIM); m++) {
500 quad[0]=dd[2]; /* yy */
501 quad[1]=dd[0]; /* zz */
502 quad[2]=dd[1]; /* xx */
506 pr_rvec(debug,0,"Quadrupole",quad,DIM,TRUE);
509 for(i=0; (i<DIM); i++) {
518 * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
520 real calc_eps(double M_diff,double volume,double epsRF,double temp)
522 double eps,A,teller,noemer;
523 double eps_0=8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
524 double fac=1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
526 A = M_diff*fac/(3*eps_0*volume*NANO*NANO*NANO*BOLTZMANN*temp);
532 teller = 1 + (A*2*epsRF/(2*epsRF+1));
533 noemer = 1 - (A/(2*epsRF+1));
535 eps = teller / noemer;
540 static void update_slab_dipoles(int k0,int k1,rvec x[],rvec mu,
541 int idim,int nslice,rvec slab_dipole[],
547 for(k=k0; (k<k1); k++)
550 k = ((int)(xdim*nslice/box[idim][idim] + nslice)) % nslice;
551 rvec_inc(slab_dipole[k],mu);
554 static void dump_slab_dipoles(const char *fn,int idim,int nslice,
555 rvec slab_dipole[], matrix box,int nframes,
556 const output_env_t oenv)
562 const char *leg_dim[4] = {
563 "\\f{12}m\\f{4}\\sX\\N",
564 "\\f{12}m\\f{4}\\sY\\N",
565 "\\f{12}m\\f{4}\\sZ\\N",
566 "\\f{12}m\\f{4}\\stot\\N"
569 sprintf(buf,"Box-%c (nm)",'X'+idim);
570 fp = xvgropen(fn,"Average dipole moment per slab",buf,"\\f{12}m\\f{4} (D)",
572 xvgr_legend(fp,DIM,leg_dim,oenv);
573 for(i=0; (i<nslice); i++) {
574 mutot = norm(slab_dipole[i])/nframes;
575 fprintf(fp,"%10.3f %10.3f %10.3f %10.3f %10.3f\n",
576 ((i+0.5)*box[idim][idim])/nslice,
577 slab_dipole[i][XX]/nframes,
578 slab_dipole[i][YY]/nframes,
579 slab_dipole[i][ZZ]/nframes,
583 do_view(oenv,fn,"-autoscale xy -nxy");
586 static void compute_avercos(int n,rvec dip[],real *dd,rvec axis,gmx_bool bPairs)
589 double dc,dc1,d,n5,ddc1,ddc2,ddc3;
590 rvec xxx = { 1, 0, 0 };
591 rvec yyy = { 0, 1, 0 };
592 rvec zzz = { 0, 0, 1 };
595 ddc1 = ddc2 = ddc3 = 0;
596 for(i=k=0; (i<n); i++)
598 ddc1 += fabs(cos_angle(dip[i],xxx));
599 ddc2 += fabs(cos_angle(dip[i],yyy));
600 ddc3 += fabs(cos_angle(dip[i],zzz));
602 for(j=i+1; (j<n); j++,k++)
604 dc = cos_angle(dip[i],dip[j]);
614 static void do_dip(t_topology *top,int ePBC,real volume,
616 const char *out_mtot,const char *out_eps,
617 const char *out_aver, const char *dipdist,
618 const char *cosaver, const char *fndip3d,
619 const char *fnadip, gmx_bool bPairs,
620 const char *corrtype,const char *corf,
621 gmx_bool bGkr, const char *gkrfn,
622 gmx_bool bPhi, int *nlevels, int ndegrees,
624 const char *cmap, real rcmax,
625 gmx_bool bQuad, const char *quadfn,
626 gmx_bool bMU, const char *mufn,
627 int *gnx, int *molindex[],
628 real mu_max, real mu_aver,
629 real epsilonRF,real temp,
630 int *gkatom, int skip,
631 gmx_bool bSlab, int nslices,
632 const char *axtitle, const char *slabfn,
633 const output_env_t oenv)
635 const char *leg_mtot[] = {
641 #define NLEGMTOT asize(leg_mtot)
642 const char *leg_eps[] = {
647 #define NLEGEPS asize(leg_eps)
648 const char *leg_aver[] = {
651 "< |M|\\S2\\N > - < |M| >\\S2\\N",
652 "< |M| >\\S2\\N / < |M|\\S2\\N >"
654 #define NLEGAVER asize(leg_aver)
655 const char *leg_cosaver[] = {
656 "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
658 "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
659 "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
660 "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
662 #define NLEGCOSAVER asize(leg_cosaver)
663 const char *leg_adip[] = {
668 #define NLEGADIP asize(leg_adip)
670 FILE *outdd,*outmtot,*outaver,*outeps,*caver=NULL;
671 FILE *dip3d=NULL,*adip=NULL;
672 rvec *x,*dipole=NULL,mu_t,quad,*dipsp=NULL;
673 t_gkrbin *gkrbin = NULL;
674 gmx_enxnm_t *enm=NULL;
676 int nframes=1000,nre,timecheck=0,ncolour=0;
677 ener_file_t fmu=NULL;
678 int i,j,k,n,m,natom=0,nmol,gnx_tot,teller,tel3;
680 int *dipole_bin,ndipbin,ibin,iVol,step,idim=-1;
683 real rcut=0,t,t0,t1,dt,lambda,dd,rms_cos;
686 gmx_bool bCorr,bTotal,bCont;
687 double M_diff=0,epsilon,invtel,vol_aver;
688 double mu_ave,mu_mol,M2_ave=0,M_ave2=0,M_av[DIM],M_av2[DIM];
689 double M[3],M2[3],M4[3],Gk=0,g_k=0;
690 gmx_stats_t Mx,My,Mz,Msq,Vol,*Qlsq,mulsq,muframelsq=NULL;
693 rvec *slab_dipoles=NULL;
696 gmx_rmpbc_t gpbc=NULL;
708 fmu = open_enx(mufn,"r");
709 do_enxnms(fmu,&nre,&enm);
711 /* Determine the indexes of the energy grps we need */
712 for (i=0; (i<nre); i++) {
713 if (strstr(enm[i].name,"Volume"))
715 else if (strstr(enm[i].name,"Mu-X"))
717 else if (strstr(enm[i].name,"Mu-Y"))
719 else if (strstr(enm[i].name,"Mu-Z"))
725 atom = top->atoms.atom;
729 if ((iVol == -1) && bMU)
730 printf("Using Volume from topology: %g nm^3\n",volume);
732 /* Correlation stuff */
733 bCorr = (corrtype[0] != 'n');
734 bTotal = (corrtype[0] == 't');
740 snew(muall[0],nframes*DIM);
745 for(i=0; (i<gnx[0]); i++)
746 snew(muall[i],nframes*DIM);
750 /* Allocate array which contains for every molecule in a frame the
754 snew(dipole,gnx_tot);
758 for(i=0; (i<DIM); i++)
759 Qlsq[i] = gmx_stats_init();
760 mulsq = gmx_stats_init();
762 /* Open all the files */
763 outmtot = xvgropen(out_mtot,
764 "Total dipole moment of the simulation box vs. time",
765 "Time (ps)","Total Dipole Moment (Debye)",oenv);
766 outeps = xvgropen(out_eps,"Epsilon and Kirkwood factors",
767 "Time (ps)","",oenv);
768 outaver = xvgropen(out_aver,"Total dipole moment",
769 "Time (ps)","D",oenv);
772 idim = axtitle[0] - 'X';
773 if ((idim < 0) || (idim >= DIM))
774 idim = axtitle[0] - 'x';
775 if ((idim < 0) || (idim >= DIM))
779 fprintf(stderr,"axtitle = %s, nslices = %d, idim = %d\n",
780 axtitle,nslices,idim);
783 snew(slab_dipoles,nslices);
784 fprintf(stderr,"Doing slab analysis\n");
790 adip = xvgropen(fnadip, "Average molecular dipole","Dipole (D)","",oenv);
791 xvgr_legend(adip,NLEGADIP,leg_adip, oenv);
796 caver = xvgropen(cosaver,bPairs ? "Average pair orientation" :
797 "Average absolute dipole orientation","Time (ps)","",oenv);
798 xvgr_legend(caver,NLEGCOSAVER,bPairs ? leg_cosaver : &(leg_cosaver[1]),
806 /* we need a dummy file for gnuplot */
807 dip3d = (FILE *)ffopen("dummy.dat","w");
808 fprintf(dip3d,"%f %f %f", 0.0,0.0,0.0);
811 dip3d = (FILE *)ffopen(fndip3d,"w");
812 fprintf(dip3d,"# This file was created by %s\n",Program());
813 fprintf(dip3d,"# which is part of G R O M A C S:\n");
814 fprintf(dip3d,"#\n");
817 /* Write legends to all the files */
818 xvgr_legend(outmtot,NLEGMTOT,leg_mtot,oenv);
819 xvgr_legend(outaver,NLEGAVER,leg_aver,oenv);
821 if (bMU && (mu_aver == -1))
822 xvgr_legend(outeps,NLEGEPS-2,leg_eps,oenv);
824 xvgr_legend(outeps,NLEGEPS,leg_eps,oenv);
829 /* Read the first frame from energy or traj file */
833 bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr);
836 timecheck=check_times(t);
839 if ((teller % 10) == 0)
840 fprintf(stderr,"\r Skipping Frame %6d, time: %8.3f", teller, t);
844 printf("End of %s reached\n",mufn);
847 } while (bCont && (timecheck < 0));
849 natom = read_first_x(oenv,&status,fn,&t,&x,box);
851 /* Calculate spacing for dipole bin (simple histogram) */
852 ndipbin = 1+(mu_max/0.01);
853 snew(dipole_bin, ndipbin);
856 for(m=0; (m<DIM); m++)
858 M[m] = M2[m] = M4[m] = 0.0;
863 /* Use 0.7 iso 0.5 to account for pressure scaling */
864 /* rcut = 0.7*sqrt(max_cutoff2(box)); */
865 rcut = 0.7*sqrt(sqr(box[XX][XX])+sqr(box[YY][YY])+sqr(box[ZZ][ZZ]));
867 gkrbin = mk_gkrbin(rcut,rcmax,bPhi,ndegrees);
869 gpbc = gmx_rmpbc_init(&top->idef,ePBC,natom,box);
871 /* Start while loop over frames */
876 if (bCorr && (teller >= nframes))
881 srenew(muall[0],nframes*DIM);
885 for(i=0; (i<gnx_tot); i++)
886 srenew(muall[i],nframes*DIM);
891 muframelsq = gmx_stats_init();
894 for(m=0; (m<DIM); m++)
899 /* Copy rvec into double precision local variable */
900 for(m=0; (m<DIM); m++)
906 for(m=0; (m<DIM); m++)
909 gmx_rmpbc(gpbc,natom,box,x);
911 /* Begin loop of all molecules in frame */
912 for(n=0; (n<ncos); n++)
914 for(i=0; (i<gnx[n]); i++)
918 ind0 = mols->index[molindex[n][i]];
919 ind1 = mols->index[molindex[n][i]+1];
921 mol_dip(ind0,ind1,x,atom,dipole[i]);
922 gmx_stats_add_point(mulsq,0,norm(dipole[i]),0,0);
923 gmx_stats_add_point(muframelsq,0,norm(dipole[i]),0,0);
925 update_slab_dipoles(ind0,ind1,x,
926 dipole[i],idim,nslices,slab_dipoles,box);
929 mol_quad(ind0,ind1,x,atom,quad);
930 for(m=0; (m<DIM); m++)
931 gmx_stats_add_point(Qlsq[m],0,quad[m],0,0);
933 if (bCorr && !bTotal)
936 muall[i][tel3+XX] = dipole[i][XX];
937 muall[i][tel3+YY] = dipole[i][YY];
938 muall[i][tel3+ZZ] = dipole[i][ZZ];
941 for(m=0; (m<DIM); m++)
943 M_av[m] += dipole[i][m]; /* M per frame */
944 mu_mol += dipole[i][m]*dipole[i][m]; /* calc. mu for distribution */
946 mu_mol = sqrt(mu_mol);
948 mu_ave += mu_mol; /* calc. the average mu */
950 /* Update the dipole distribution */
951 ibin = (int)(ndipbin*mu_mol/mu_max + 0.5);
957 rvec2sprvec(dipole[i],dipsp[i]);
959 if (dipsp[i][YY] > -M_PI && dipsp[i][YY] < -0.5*M_PI) {
960 if (dipsp[i][ZZ] < 0.5 * M_PI)
969 else if (dipsp[i][YY] > -0.5*M_PI && dipsp[i][YY] < 0.0*M_PI)
971 if (dipsp[i][ZZ] < 0.5 * M_PI)
979 }else if (dipsp[i][YY] > 0.0 && dipsp[i][YY] < 0.5*M_PI) {
980 if (dipsp[i][ZZ] < 0.5 * M_PI) {
986 else if (dipsp[i][YY] > 0.5*M_PI && dipsp[i][YY] < M_PI)
988 if (dipsp[i][ZZ] < 0.5 * M_PI)
998 fprintf(dip3d,"set arrow %d from %f, %f, %f to %f, %f, %f lt %d # %d %d\n",
1003 x[ind0][XX]+dipole[i][XX]/25,
1004 x[ind0][YY]+dipole[i][YY]/25,
1005 x[ind0][ZZ]+dipole[i][ZZ]/25,
1008 } /* End loop of all molecules in frame */
1012 fprintf(dip3d,"set title \"t = %4.3f\"\n",t);
1013 fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
1014 fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
1015 fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
1016 fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
1017 fprintf(dip3d,"pause -1 'Hit return to continue'\n");
1021 /* Compute square of total dipole */
1022 for(m=0; (m<DIM); m++)
1023 M_av2[m] = M_av[m]*M_av[m];
1027 compute_avercos(gnx_tot,dipole,&dd,dipaxis,bPairs);
1028 rms_cos = sqrt(sqr(dipaxis[XX]-0.5)+
1029 sqr(dipaxis[YY]-0.5)+
1030 sqr(dipaxis[ZZ]-0.5));
1032 fprintf(caver,"%10.3e %10.3e %10.3e %10.3e %10.3e %10.3e\n",
1033 t,dd,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
1035 fprintf(caver,"%10.3e %10.3e %10.3e %10.3e %10.3e\n",
1036 t,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
1041 do_gkr(gkrbin,ncos,gnx,molindex,mols->index,x,dipole,ePBC,box,
1048 muall[0][tel3+XX] = M_av[XX];
1049 muall[0][tel3+YY] = M_av[YY];
1050 muall[0][tel3+ZZ] = M_av[ZZ];
1053 /* Write to file the total dipole moment of the box, and its components
1056 if ((skip == 0) || ((teller % skip) == 0))
1057 fprintf(outmtot,"%10g %12.8e %12.8e %12.8e %12.8e\n",
1058 t,M_av[XX],M_av[YY],M_av[ZZ],
1059 sqrt(M_av2[XX]+M_av2[YY]+M_av2[ZZ]));
1061 for(m=0; (m<DIM); m++)
1065 M4[m] += sqr(M_av2[m]);
1067 /* Increment loop counter */
1070 /* Calculate for output the running averages */
1071 invtel = 1.0/teller;
1072 M2_ave = (M2[XX]+M2[YY]+M2[ZZ])*invtel;
1073 M_ave2 = invtel*(invtel*(M[XX]*M[XX] + M[YY]*M[YY] + M[ZZ]*M[ZZ]));
1074 M_diff = M2_ave - M_ave2;
1076 /* Compute volume from box in traj, else we use the one from above */
1081 epsilon = calc_eps(M_diff,(vol_aver/teller),epsilonRF,temp);
1083 /* Calculate running average for dipole */
1085 mu_aver = (mu_ave/gnx_tot)*invtel;
1087 if ((skip == 0) || ((teller % skip) == 0))
1089 /* Write to file < |M|^2 >, |< M >|^2. And the difference between
1090 * the two. Here M is sum mu_i. Further write the finite system
1091 * Kirkwood G factor and epsilon.
1093 fprintf(outaver,"%10g %10.3e %10.3e %10.3e %10.3e\n",
1094 t,M2_ave,M_ave2,M_diff,M_ave2/M2_ave);
1099 gmx_stats_get_average(muframelsq,&aver);
1100 fprintf(adip, "%10g %f \n", t,aver);
1103 printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1105 if (!bMU || (mu_aver != -1))
1107 /* Finite system Kirkwood G-factor */
1108 Gk = M_diff/(gnx_tot*mu_aver*mu_aver);
1109 /* Infinite system Kirkwood G-factor */
1110 if (epsilonRF == 0.0)
1111 g_k = ((2*epsilon+1)*Gk/(3*epsilon));
1113 g_k = ((2*epsilonRF+epsilon)*(2*epsilon+1)*
1114 Gk/(3*epsilon*(2*epsilonRF+1)));
1116 fprintf(outeps,"%10g %10.3e %10.3e %10.3e\n",t,epsilon,Gk,g_k);
1120 fprintf(outeps,"%10g %12.8e\n",t,epsilon);
1122 gmx_stats_done(muframelsq);
1125 bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr);
1127 bCont = read_next_x(oenv,status,&t,natom,x,box);
1128 timecheck=check_times(t);
1129 } while (bCont && (timecheck == 0) );
1131 gmx_rmpbc_done(gpbc);
1147 fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
1148 fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
1149 fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
1150 fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
1151 fprintf(dip3d,"pause -1 'Hit return to continue'\n");
1156 dump_slab_dipoles(slabfn,idim,nslices,slab_dipoles,box,teller,oenv);
1157 sfree(slab_dipoles);
1161 printf("Average volume over run is %g\n",vol_aver);
1163 print_gkrbin(gkrfn,gkrbin,gnx[0],teller,vol_aver,oenv);
1164 print_cmap(cmap,gkrbin,nlevels);
1166 /* Autocorrelation function */
1169 printf("Not enough frames for autocorrelation\n");
1172 dt=(t1 - t0)/(teller-1);
1173 printf("t0 %g, t %g, teller %d\n", t0,t,teller);
1178 do_autocorr(corf,oenv,"Autocorrelation Function of Total Dipole",
1179 teller,1,muall,dt,mode,TRUE);
1181 do_autocorr(corf,oenv,"Dipole Autocorrelation Function",
1182 teller,gnx_tot,muall,dt,
1183 mode,strcmp(corrtype,"molsep"));
1187 real aver,sigma,error,lsq;
1189 gmx_stats_get_ase(mulsq,&aver,&sigma,&error);
1190 printf("\nDipole moment (Debye)\n");
1191 printf("---------------------\n");
1192 printf("Average = %8.4f Std. Dev. = %8.4f Error = %8.4f\n",
1197 for(m=0; (m<DIM); m++)
1198 gmx_stats_get_ase(mulsq,&(a[m]),&(s[m]),&(e[m]));
1200 printf("\nQuadrupole moment (Debye-Ang)\n");
1201 printf("-----------------------------\n");
1202 printf("Averages = %8.4f %8.4f %8.4f\n",a[XX],a[YY],a[ZZ]);
1203 printf("Std. Dev. = %8.4f %8.4f %8.4f\n",s[XX],s[YY],s[ZZ]);
1204 printf("Error = %8.4f %8.4f %8.4f\n",e[XX],e[YY],e[ZZ]);
1208 printf("The following averages for the complete trajectory have been calculated:\n\n");
1209 printf(" Total < M_x > = %g Debye\n", M[XX]/teller);
1210 printf(" Total < M_y > = %g Debye\n", M[YY]/teller);
1211 printf(" Total < M_z > = %g Debye\n\n", M[ZZ]/teller);
1213 printf(" Total < M_x^2 > = %g Debye^2\n", M2[XX]/teller);
1214 printf(" Total < M_y^2 > = %g Debye^2\n", M2[YY]/teller);
1215 printf(" Total < M_z^2 > = %g Debye^2\n\n", M2[ZZ]/teller);
1217 printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave);
1218 printf(" Total |< M >|^2 = %g Debye^2\n\n", M_ave2);
1220 printf(" < |M|^2 > - |< M >|^2 = %g Debye^2\n\n", M_diff);
1222 if (!bMU || (mu_aver != -1)) {
1223 printf("Finite system Kirkwood g factor G_k = %g\n", Gk);
1224 printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k);
1226 printf("Epsilon = %g\n", epsilon);
1229 /* Write to file the dipole moment distibution during the simulation.
1231 outdd=xvgropen(dipdist,"Dipole Moment Distribution","mu (Debye)","",oenv);
1232 for(i=0; (i<ndipbin); i++)
1233 fprintf(outdd,"%10g %10f\n",
1234 (i*mu_max)/ndipbin,dipole_bin[i]/(double)teller);
1239 done_gkrbin(&gkrbin);
1242 void dipole_atom2molindex(int *n,int *index,t_block *mols)
1250 while(m < mols->nr && index[i] != mols->index[m])
1253 gmx_fatal(FARGS,"index[%d]=%d does not correspond to the first atom of a molecule",i+1,index[i]+1);
1254 for(j=mols->index[m]; j<mols->index[m+1]; j++) {
1255 if (i >= *n || index[i] != j)
1256 gmx_fatal(FARGS,"The index group is not a set of whole molecules");
1259 /* Modify the index in place */
1262 printf("There are %d molecules in the selection\n",nmol);
1266 int gmx_dipoles(int argc,char *argv[])
1268 const char *desc[] = {
1269 "[TT]g_dipoles[tt] computes the total dipole plus fluctuations of a simulation",
1270 "system. From this you can compute e.g. the dielectric constant for",
1271 "low dielectric media.",
1272 "For molecules with a net charge, the net charge is subtracted at",
1273 "center of mass of the molecule.[PAR]",
1274 "The file [TT]Mtot.xvg[tt] contains the total dipole moment of a frame, the",
1275 "components as well as the norm of the vector.",
1276 "The file [TT]aver.xvg[tt] contains < |Mu|^2 > and |< Mu >|^2 during the",
1278 "The file [TT]dipdist.xvg[tt] contains the distribution of dipole moments during",
1280 "The mu_max is used as the highest value in the distribution graph.[PAR]",
1281 "Furthermore the dipole autocorrelation function will be computed when",
1282 "option [TT]-corr[tt] is used. The output file name is given with the [TT]-c[tt]",
1284 "The correlation functions can be averaged over all molecules",
1285 "([TT]mol[tt]), plotted per molecule separately ([TT]molsep[tt])",
1286 "or it can be computed over the total dipole moment of the simulation box",
1287 "([TT]total[tt]).[PAR]",
1288 "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1289 "G-factor, as well as the average cosine of the angle between the dipoles",
1290 "as a function of the distance. The plot also includes gOO and hOO",
1291 "according to Nymand & Linse, JCP 112 (2000) pp 6386-6395. In the same plot",
1292 "we also include the energy per scale computed by taking the inner product of",
1293 "the dipoles divided by the distance to the third power.[PAR]",
1296 "[TT]g_dipoles -corr mol -P1 -o dip_sqr -mu 2.273 -mumax 5.0 -nofft[tt][PAR]",
1297 "This will calculate the autocorrelation function of the molecular",
1298 "dipoles using a first order Legendre polynomial of the angle of the",
1299 "dipole vector and itself a time t later. For this calculation 1001",
1300 "frames will be used. Further the dielectric constant will be calculated",
1301 "using an epsilonRF of infinity (default), temperature of 300 K (default) and",
1302 "an average dipole moment of the molecule of 2.273 (SPC). For the",
1303 "distribution function a maximum of 5.0 will be used."
1305 real mu_max=5, mu_aver=-1,rcmax=0;
1306 real epsilonRF=0.0, temp=300;
1307 gmx_bool bAverCorr=FALSE,bMolCorr=FALSE,bPairs=TRUE,bPhi=FALSE;
1308 const char *corrtype[]={NULL, "none", "mol", "molsep", "total", NULL};
1309 const char *axtitle="Z";
1310 int nslices = 10; /* nr of slices defined */
1311 int skip=0,nFA=0,nFB=0,ncos=1;
1312 int nlevels=20,ndegrees=90;
1315 { "-mu", FALSE, etREAL, {&mu_aver},
1316 "dipole of a single molecule (in Debye)" },
1317 { "-mumax", FALSE, etREAL, {&mu_max},
1318 "max dipole in Debye (for histrogram)" },
1319 { "-epsilonRF",FALSE, etREAL, {&epsilonRF},
1320 "epsilon of the reaction field used during the simulation, needed for dielectric constant calculation. WARNING: 0.0 means infinity (default)" },
1321 { "-skip", FALSE, etINT, {&skip},
1322 "Skip steps in the output (but not in the computations)" },
1323 { "-temp", FALSE, etREAL, {&temp},
1324 "Average temperature of the simulation (needed for dielectric constant calculation)" },
1325 { "-corr", FALSE, etENUM, {corrtype},
1326 "Correlation function to calculate" },
1327 { "-pairs", FALSE, etBOOL, {&bPairs},
1328 "Calculate |cos theta| between all pairs of molecules. May be slow" },
1329 { "-ncos", FALSE, etINT, {&ncos},
1330 "Must be 1 or 2. Determines whether the <cos> is computed between all molecules in one group, or between molecules in two different groups. This turns on the [TT]-gkr[tt] flag." },
1331 { "-axis", FALSE, etSTR, {&axtitle},
1332 "Take the normal on the computational box in direction X, Y or Z." },
1333 { "-sl", FALSE, etINT, {&nslices},
1334 "Divide the box in #nr slices." },
1335 { "-gkratom", FALSE, etINT, {&nFA},
1336 "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" },
1337 { "-gkratom2", FALSE, etINT, {&nFB},
1338 "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of molecules" },
1339 { "-rcmax", FALSE, etREAL, {&rcmax},
1340 "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If zero, a criterium based on the box length will be used." },
1341 { "-phi", FALSE, etBOOL, {&bPhi},
1342 "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." },
1343 { "-nlevels", FALSE, etINT, {&nlevels},
1344 "Number of colors in the cmap output" },
1345 { "-ndegrees", FALSE, etINT, {&ndegrees},
1346 "Number of divisions on the y-axis in the camp output (for 180 degrees)" }
1351 char **grpname=NULL;
1352 gmx_bool bCorr,bQuad,bGkr,bMU,bSlab;
1354 { efEDR, "-en", NULL, ffOPTRD },
1355 { efTRX, "-f", NULL, ffREAD },
1356 { efTPX, NULL, NULL, ffREAD },
1357 { efNDX, NULL, NULL, ffOPTRD },
1358 { efXVG, "-o", "Mtot", ffWRITE },
1359 { efXVG, "-eps", "epsilon", ffWRITE },
1360 { efXVG, "-a", "aver", ffWRITE },
1361 { efXVG, "-d", "dipdist", ffWRITE },
1362 { efXVG, "-c", "dipcorr", ffOPTWR },
1363 { efXVG, "-g", "gkr", ffOPTWR },
1364 { efXVG, "-adip","adip", ffOPTWR },
1365 { efXVG, "-dip3d", "dip3d", ffOPTWR },
1366 { efXVG, "-cos", "cosaver", ffOPTWR },
1367 { efXPM, "-cmap","cmap", ffOPTWR },
1368 { efXVG, "-q", "quadrupole", ffOPTWR },
1369 { efXVG, "-slab","slab", ffOPTWR }
1371 #define NFILE asize(fnm)
1379 CopyRight(stderr,argv[0]);
1381 ppa = add_acf_pargs(&npargs,pa);
1382 parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
1383 NFILE,fnm,npargs,ppa,asize(desc),desc,0,NULL,&oenv);
1385 printf("Using %g as mu_max and %g as the dipole moment.\n",
1387 if (epsilonRF == 0.0)
1388 printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1390 bMU = opt2bSet("-en",NFILE,fnm);
1392 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.");
1393 bQuad = opt2bSet("-q",NFILE,fnm);
1394 bGkr = opt2bSet("-g",NFILE,fnm);
1395 if (opt2parg_bSet("-ncos",asize(pa),pa)) {
1396 if ((ncos != 1) && (ncos != 2))
1397 gmx_fatal(FARGS,"ncos has to be either 1 or 2");
1400 bSlab = (opt2bSet("-slab",NFILE,fnm) || opt2parg_bSet("-sl",asize(pa),pa) ||
1401 opt2parg_bSet("-axis",asize(pa),pa));
1405 printf("WARNING: Can not determine quadrupoles from energy file\n");
1409 printf("WARNING: Can not determine Gk(r) from energy file\n");
1414 printf("WARNING: Can not calculate Gk and gk, since you did\n"
1415 " not enter a valid dipole for the molecules\n");
1419 ePBC = read_tpx_top(ftp2fn(efTPX,NFILE,fnm),NULL,box,
1420 &natoms,NULL,NULL,NULL,top);
1424 snew(grpindex,ncos);
1425 get_index(&top->atoms,ftp2fn_null(efNDX,NFILE,fnm),
1426 ncos,gnx,grpindex,grpname);
1427 for(k=0; (k<ncos); k++)
1429 dipole_atom2molindex(&gnx[k],grpindex[k],&(top->mols));
1430 neutralize_mols(gnx[k],grpindex[k],&(top->mols),top->atoms.atom);
1434 do_dip(top,ePBC,det(box),ftp2fn(efTRX,NFILE,fnm),
1435 opt2fn("-o",NFILE,fnm),opt2fn("-eps",NFILE,fnm),
1436 opt2fn("-a",NFILE,fnm),opt2fn("-d",NFILE,fnm),
1437 opt2fn_null("-cos",NFILE,fnm),
1438 opt2fn_null("-dip3d",NFILE,fnm),opt2fn_null("-adip",NFILE,fnm),
1440 opt2fn("-c",NFILE,fnm),
1441 bGkr, opt2fn("-g",NFILE,fnm),
1442 bPhi, &nlevels, ndegrees,
1444 opt2fn("-cmap",NFILE,fnm),rcmax,
1445 bQuad, opt2fn("-q",NFILE,fnm),
1446 bMU, opt2fn("-en",NFILE,fnm),
1447 gnx,grpindex,mu_max,mu_aver,epsilonRF,temp,nFF,skip,
1448 bSlab,nslices,axtitle,opt2fn("-slab",NFILE,fnm),oenv);
1450 do_view(oenv,opt2fn("-o",NFILE,fnm),"-autoscale xy -nxy");
1451 do_view(oenv,opt2fn("-eps",NFILE,fnm),"-autoscale xy -nxy");
1452 do_view(oenv,opt2fn("-a",NFILE,fnm),"-autoscale xy -nxy");
1453 do_view(oenv,opt2fn("-d",NFILE,fnm),"-autoscale xy");
1454 do_view(oenv,opt2fn("-c",NFILE,fnm),"-autoscale xy");