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"
63 #define e2d(x) ENM2DEBYE*(x)
64 #define EANG2CM E_CHARGE*1.0e-10 /* e Angstrom to Coulomb meter */
65 #define CM2D SPEED_OF_LIGHT*1.0e+24 /* Coulomb meter to Debye */
77 static t_gkrbin *mk_gkrbin(real radius,real rcmax,bool bPhi,int ndegrees)
85 if ((ptr = getenv("GKRWIDTH")) != NULL) {
88 sscanf(ptr,"%lf",&bw);
92 gb->spacing = 0.01; /* nm */
93 gb->nelem = 1 + radius/gb->spacing;
97 gb->nx = 1 + rcmax/gb->spacing;
99 snew(gb->elem,gb->nelem);
100 snew(gb->count,gb->nelem);
102 snew(gb->cmap,gb->nx);
103 gb->ny = max(2,ndegrees);
104 for(i=0; (i<gb->nx); i++)
105 snew(gb->cmap[i],gb->ny);
111 static void done_gkrbin(t_gkrbin **gb)
119 static void add2gkr(t_gkrbin *gb,real r,real cosa,real phi)
121 int cy,index = gmx_nint(r/gb->spacing);
124 if (index < gb->nelem) {
125 gb->elem[index] += cosa;
128 if (index < gb->nx) {
131 cy = (M_PI+phi)*gb->ny/(2*M_PI);
133 cy = (alpha*gb->ny)/M_PI;/*((1+cosa)*0.5*(gb->ny));*/
134 cy = min(gb->ny-1,max(0,cy));
136 fprintf(debug,"CY: %10f %5d\n",alpha,cy);
137 gb->cmap[index][cy] += 1;
141 static void rvec2sprvec(rvec dipcart,rvec dipsp)
144 dipsp[0] = sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]+dipcart[ZZ]*dipcart[ZZ]); /* R */
145 dipsp[1] = atan2(dipcart[YY],dipcart[XX]); /* Theta */
146 dipsp[2] = atan2(sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]),dipcart[ZZ]); /* Phi */
150 void do_gkr(t_gkrbin *gb,int ncos,int *ngrp,int *molindex[],
151 int mindex[],rvec x[],rvec mu[],
152 int ePBC,matrix box,t_atom *atom,int *nAtom)
154 static rvec *xcm[2] = { NULL, NULL};
155 int gi,gj,j0,j1,i,j,k,n,index,grp0,grp1;
156 real qtot,q,r2,cosa,rr,phi;
160 for(n=0; (n<ncos); n++) {
162 snew(xcm[n],ngrp[n]);
163 for(i=0; (i<ngrp[n]); i++) {
164 /* Calculate center of mass of molecule */
169 copy_rvec(x[j0+nAtom[n]-1],xcm[n][i]);
172 clear_rvec(xcm[n][i]);
174 for(j=j0; j<j1; j++) {
178 xcm[n][i][k] += q*x[j][k];
180 svmul(1/qtot,xcm[n][i],xcm[n][i]);
184 set_pbc(&pbc,ePBC,box);
187 for(i=0; i<ngrp[grp0]; i++) {
188 gi = molindex[grp0][i];
189 j0 = (ncos == 2) ? 0 : i+1;
190 for(j=j0; j<ngrp[grp1]; j++) {
191 gj = molindex[grp1][j];
192 if ((iprod(mu[gi],mu[gi]) > 0) && (iprod(mu[gj],mu[gj]) > 0)) {
193 /* Compute distance between molecules including PBC */
194 pbc_dx(&pbc,xcm[grp0][i],xcm[grp1][j],dx);
199 rvec r_ij,r_kj,r_kl,mm,nn;
203 copy_rvec(xcm[grp0][i],xj);
204 copy_rvec(xcm[grp1][j],xk);
205 rvec_add(xj,mu[gi],xi);
206 rvec_add(xk,mu[gj],xl);
207 phi = dih_angle(xi,xj,xk,xl,&pbc,
208 r_ij,r_kj,r_kl,mm,nn, /* out */
209 &cosa,&sign,&t1,&t2,&t3);
212 cosa = cos_angle(mu[gi],mu[gj]);
215 if (debug || (cosa != cosa)) {
216 fprintf(debug ? debug : stderr,
217 "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",
218 gi,mu[gi][XX],mu[gi][YY],mu[gi][ZZ],norm(mu[gi]),
219 gj,mu[gj][XX],mu[gj][YY],mu[gj][ZZ],norm(mu[gj]),
223 add2gkr(gb,rr,cosa,phi);
229 static real normalize_cmap(t_gkrbin *gb)
235 for(i=0; (i<gb->nx); i++) {
236 vol = 4*M_PI*sqr(gb->spacing*i)*gb->spacing;
237 for(j=0; (j<gb->ny); j++) {
238 gb->cmap[i][j] /= vol;
239 hi = max(hi,gb->cmap[i][j]);
243 gmx_fatal(FARGS,"No data in the cmap");
247 static void print_cmap(const char *cmap,t_gkrbin *gb,int *nlevels)
254 t_rgb rlo = { 1, 1, 1 };
255 t_rgb rhi = { 0, 0, 0 };
257 hi = normalize_cmap(gb);
258 snew(xaxis,gb->nx+1);
259 for(i=0; (i<gb->nx+1); i++)
260 xaxis[i] = i*gb->spacing;
262 for(j=0; (j<gb->ny); j++) {
264 yaxis[j] = (360.0*j)/(gb->ny-1.0)-180;
266 yaxis[j] = (180.0*j)/(gb->ny-1.0);
267 /*2.0*j/(gb->ny-1.0)-1.0;*/
269 out = fopen(cmap,"w");
271 "Dipole Orientation Distribution","Fraction","r (nm)",
272 gb->bPhi ? "Phi" : "Alpha",
273 gb->nx,gb->ny,xaxis,yaxis,
274 gb->cmap,0,hi,rlo,rhi,nlevels);
280 static void print_gkrbin(const char *fn,t_gkrbin *gb,
281 int ngrp,int nframes,real volume,
282 const output_env_t oenv)
284 /* We compute Gk(r), gOO and hOO according to
285 * Nymand & Linse, JCP 112 (2000) pp 6386-6395.
286 * In this implementation the angle between dipoles is stored
287 * rather than their inner product. This allows to take polarizible
288 * models into account. The RDF is calculated as well, almost for free!
291 char *leg[] = { "G\\sk\\N(r)", "< cos >", "h\\sOO\\N", "g\\sOO\\N", "Energy" };
293 real x0,x1,ggg,Gkr,vol_s,rho,gOO,hOO,cosav,ener;
296 fp=xvgropen(fn,"Distance dependent Gk","r (nm)","G\\sk\\N(r)",oenv);
297 xvgr_legend(fp,asize(leg),leg,oenv);
299 Gkr = 1; /* Self-dipole inproduct = 1 */
303 fprintf(debug,"Number density is %g molecules / nm^3\n",rho);
304 fprintf(debug,"ngrp = %d, nframes = %d\n",ngrp,nframes);
308 while(last>1 && gb->elem[last-1]==0)
311 /* Divide by dipole squared, by number of frames, by number of origins.
312 * Multiply by 2 because we only take half the matrix of interactions
315 fac = 2.0/((double) ngrp * (double) nframes);
318 for(i=0; i<last; i++) {
319 /* Centre of the coordinate in the spherical layer */
322 /* Volume of the layer */
323 vol_s = (4.0/3.0)*M_PI*(x1*x1*x1-x0*x0*x0);
326 gOO = gb->count[i]*fac/(rho*vol_s);
328 /* Dipole correlation hOO, normalized by the relative number density, like
329 * in a Radial distribution function.
331 ggg = gb->elem[i]*fac;
332 hOO = 3.0*ggg/(rho*vol_s);
335 cosav = gb->elem[i]/gb->count[i];
338 ener = -0.5*cosav*ONE_4PI_EPS0/(x1*x1*x1);
340 fprintf(fp,"%10.5e %12.5e %12.5e %12.5e %12.5e %12.5e\n",
341 x1,Gkr,cosav,hOO,gOO,ener);
349 bool read_mu_from_enx(ener_file_t fmu,int Vol,ivec iMu,rvec mu,real *vol,
350 real *t, int nre,t_enxframe *fr)
356 bCont = do_enx(fmu,fr);
358 fprintf(stderr,"Something strange: expected %d entries in energy file at step %s\n(time %g) but found %d entries\n",
359 nre,gmx_step_str(fr->step,buf),fr->t,fr->nre);
362 if (Vol != -1) /* we've got Volume in the energy file */
363 *vol = fr->ener[Vol].e;
364 for (i=0; i<DIM; i++)
365 mu[i] = fr->ener[iMu[i]].e;
372 static void neutralize_mols(int n,int *index,t_block *mols,t_atom *atom)
375 int ncharged,m,a0,a1,a;
379 a0 = mols->index[index[m]];
380 a1 = mols->index[index[m]+1];
383 for(a=a0; a<a1; a++) {
387 /* This check is only for the count print */
388 if (fabs(qtot) > 0.01)
391 /* Remove the net charge at the center of mass */
393 atom[a].q -= qtot*atom[a].m/mtot;
398 printf("There are %d charged molecules in the selection,\n"
399 "will subtract their charge at their center of mass\n",ncharged);
402 static void mol_dip(int k0,int k1,rvec x[],t_atom atom[],rvec mu)
408 for(k=k0; (k<k1); k++) {
410 for(m=0; (m<DIM); m++)
415 static void mol_quad(int k0,int k1,rvec x[],t_atom atom[],rvec quad)
418 real q,r2,mass,masstot;
419 rvec com; /* center of mass */
420 rvec r; /* distance of atoms to center of mass */
423 double dd[DIM],**ev,tmp;
427 for(i=0; (i<DIM); i++) {
433 /* Compute center of mass */
436 for(k=k0; (k<k1); k++) {
439 for(i=0; (i<DIM); i++)
440 com[i] += mass*x[k][i];
442 svmul((1.0/masstot),com,com);
444 /* We want traceless quadrupole moments, so let us calculate the complete
445 * quadrupole moment tensor and diagonalize this tensor to get
446 * the individual components on the diagonal.
449 #define delta(a,b) (( a == b ) ? 1.0 : 0.0)
451 for(m=0; (m<DIM); m++)
452 for(n=0; (n<DIM); n++)
454 for(k=k0; (k<k1); k++) { /* loop over atoms in a molecule */
455 q = (atom[k].q)*100.0;
456 rvec_sub(x[k],com,r);
458 for(m=0; (m<DIM); m++)
459 for(n=0; (n<DIM); n++)
460 inten[m][n] += 0.5*q*(3.0*r[m]*r[n] - r2*delta(m,n))*EANG2CM*CM2D;
463 for(i=0; (i<DIM); i++)
464 fprintf(debug,"Q[%d] = %8.3f %8.3f %8.3f\n",
465 i,inten[i][XX],inten[i][YY],inten[i][ZZ]);
467 /* We've got the quadrupole tensor, now diagonalize the sucker */
468 jacobi(inten,3,dd,ev,&niter);
471 for(i=0; (i<DIM); i++)
472 fprintf(debug,"ev[%d] = %8.3f %8.3f %8.3f\n",
473 i,ev[i][XX],ev[i][YY],ev[i][ZZ]);
474 for(i=0; (i<DIM); i++)
475 fprintf(debug,"Q'[%d] = %8.3f %8.3f %8.3f\n",
476 i,inten[i][XX],inten[i][YY],inten[i][ZZ]);
478 /* Sort the eigenvalues, for water we know that the order is as follows:
482 * At the moment I have no idea how this will work out for other molecules...
486 if (dd[i+1] > dd[i]) { \
495 for(m=0; (m<DIM); m++) {
496 quad[0]=dd[2]; /* yy */
497 quad[1]=dd[0]; /* zz */
498 quad[2]=dd[1]; /* xx */
502 pr_rvec(debug,0,"Quadrupole",quad,DIM,TRUE);
505 for(i=0; (i<DIM); i++) {
514 * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
516 real calc_eps(double M_diff,double volume,double epsRF,double temp)
518 double eps,A,teller,noemer;
519 double eps_0=8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
520 double fac=1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
522 A = M_diff*fac/(3*eps_0*volume*NANO*NANO*NANO*BOLTZMANN*temp);
528 teller = 1 + (A*2*epsRF/(2*epsRF+1));
529 noemer = 1 - (A/(2*epsRF+1));
531 eps = teller / noemer;
536 static void update_slab_dipoles(int k0,int k1,rvec x[],rvec mu,
537 int idim,int nslice,rvec slab_dipole[],
543 for(k=k0; (k<k1); k++)
546 k = ((int)(xdim*nslice/box[idim][idim] + nslice)) % nslice;
547 rvec_inc(slab_dipole[k],mu);
550 static void dump_slab_dipoles(const char *fn,int idim,int nslice,
551 rvec slab_dipole[], matrix box,int nframes,
552 const output_env_t oenv)
559 "\\f{12}m\\f{4}\\sX\\N",
560 "\\f{12}m\\f{4}\\sY\\N",
561 "\\f{12}m\\f{4}\\sZ\\N",
562 "\\f{12}m\\f{4}\\stot\\N"
565 sprintf(buf,"Box-%c (nm)",'X'+idim);
566 fp = xvgropen(fn,"Average dipole moment per slab",buf,"\\f{12}m\\f{4} (D)",
568 xvgr_legend(fp,DIM,leg_dim,oenv);
569 for(i=0; (i<nslice); i++) {
570 mutot = norm(slab_dipole[i])/nframes;
571 fprintf(fp,"%10.3f %10.3f %10.3f %10.3f %10.3f\n",
572 ((i+0.5)*box[idim][idim])/nslice,
573 slab_dipole[i][XX]/nframes,
574 slab_dipole[i][YY]/nframes,
575 slab_dipole[i][ZZ]/nframes,
579 do_view(oenv,fn,"-autoscale xy -nxy");
582 static void compute_avercos(int n,rvec dip[],real *dd,rvec axis,bool bPairs)
585 double dc,dc1,d,n5,ddc1,ddc2,ddc3;
586 rvec xxx = { 1, 0, 0 };
587 rvec yyy = { 0, 1, 0 };
588 rvec zzz = { 0, 0, 1 };
591 ddc1 = ddc2 = ddc3 = 0;
592 for(i=k=0; (i<n); i++) {
593 ddc1 += fabs(cos_angle(dip[i],xxx));
594 ddc2 += fabs(cos_angle(dip[i],yyy));
595 ddc3 += fabs(cos_angle(dip[i],zzz));
597 for(j=i+1; (j<n); j++,k++) {
598 dc = cos_angle(dip[i],dip[j]);
608 static void do_dip(t_topology *top,int ePBC,real volume,
610 const char *out_mtot,const char *out_eps,
611 const char *out_aver, const char *dipdist,
612 const char *cosaver, const char *fndip3d,
613 const char *fnadip, bool bPairs,
614 const char *corrtype,const char *corf,
615 bool bGkr, const char *gkrfn,
616 bool bPhi, int *nlevels, int ndegrees,
618 const char *cmap, real rcmax,
619 bool bQuad, const char *quadfn,
620 bool bMU, const char *mufn,
621 int *gnx, int *molindex[],
622 real mu_max, real mu_aver,
623 real epsilonRF,real temp,
624 int *gkatom, int skip,
625 bool bSlab, int nslices,
626 const char *axtitle, const char *slabfn,
627 const output_env_t oenv)
635 #define NLEGMTOT asize(leg_mtot)
641 #define NLEGEPS asize(leg_eps)
645 "< |M|\\S2\\N > - < |M| >\\S2\\N",
646 "< |M| >\\S2\\N / < |M|\\S2\\N >"
648 #define NLEGAVER asize(leg_aver)
649 char *leg_cosaver[] = {
650 "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
652 "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
653 "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
654 "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
656 #define NLEGCOSAVER asize(leg_cosaver)
662 #define NLEGADIP asize(leg_adip)
664 FILE *outdd,*outmtot,*outaver,*outeps,*caver=NULL;
665 FILE *dip3d=NULL,*adip=NULL;
666 rvec *x,*dipole=NULL,mu_t,quad,*dipsp=NULL;
667 t_gkrbin *gkrbin = NULL;
668 gmx_enxnm_t *enm=NULL;
670 int nframes=1000,nre,timecheck=0,ncolour=0;
671 ener_file_t fmu=NULL;
672 int i,j,k,n,m,natom=0,nmol,status,gnx_tot,teller,tel3;
673 int *dipole_bin,ndipbin,ibin,iVol,step,idim=-1;
676 real rcut=0,t,t0,t1,dt,lambda,dd,rms_cos;
679 bool bCorr,bTotal,bCont;
680 double M_diff=0,epsilon,invtel,vol_aver;
681 double mu_ave,mu_mol,M2_ave=0,M_ave2=0,M_av[DIM],M_av2[DIM];
682 double M[3],M2[3],M4[3],Gk=0,g_k=0;
683 gmx_stats_t Mx,My,Mz,Msq,Vol,*Qlsq,mulsq,muframelsq=NULL;
686 rvec *slab_dipoles=NULL;
699 fmu = open_enx(mufn,"r");
700 do_enxnms(fmu,&nre,&enm);
702 /* Determine the indexes of the energy grps we need */
703 for (i=0; (i<nre); i++) {
704 if (strstr(enm[i].name,"Volume"))
706 else if (strstr(enm[i].name,"Mu-X"))
708 else if (strstr(enm[i].name,"Mu-Y"))
710 else if (strstr(enm[i].name,"Mu-Z"))
715 atom = top->atoms.atom;
720 printf("Using Volume from topology: %g nm^3\n",volume);
722 /* Correlation stuff */
723 bCorr = (corrtype[0] != 'n');
724 bTotal = (corrtype[0] == 't');
728 snew(muall[0],nframes*DIM);
732 for(i=0; (i<gnx[0]); i++)
733 snew(muall[i],nframes*DIM);
737 /* Allocate array which contains for every molecule in a frame the
741 snew(dipole,gnx_tot);
745 for(i=0; (i<DIM); i++)
746 Qlsq[i] = gmx_stats_init();
747 mulsq = gmx_stats_init();
749 /* Open all the files */
750 outmtot = xvgropen(out_mtot,
751 "Total dipole moment of the simulation box vs. time",
752 "Time (ps)","Total Dipole Moment (Debye)",oenv);
753 outeps = xvgropen(out_eps,"Epsilon and Kirkwood factors",
754 "Time (ps)","",oenv);
755 outaver = xvgropen(out_aver,"Total dipole moment",
756 "Time (ps)","D",oenv);
758 idim = axtitle[0] - 'X';
759 if ((idim < 0) || (idim >= DIM))
760 idim = axtitle[0] - 'x';
761 if ((idim < 0) || (idim >= DIM))
765 fprintf(stderr,"axtitle = %s, nslices = %d, idim = %d\n",
766 axtitle,nslices,idim);
768 snew(slab_dipoles,nslices);
769 fprintf(stderr,"Doing slab analysis\n");
774 adip = xvgropen(fnadip, "Average molecular dipole","Dipole (D)","",oenv);
775 xvgr_legend(adip,NLEGADIP,leg_adip, oenv);
779 caver = xvgropen(cosaver,bPairs ? "Average pair orientation" :
780 "Average absolute dipole orientation","Time (ps)","",oenv);
781 xvgr_legend(caver,NLEGCOSAVER,bPairs ? leg_cosaver : &(leg_cosaver[1]),
788 /* we need a dummy file for gnuplot */
789 dip3d = (FILE *)ffopen("dummy.dat","w");
790 fprintf(dip3d,"%f %f %f", 0.0,0.0,0.0);
793 dip3d = (FILE *)ffopen(fndip3d,"w");
794 fprintf(dip3d,"# This file was created by %s\n",Program());
795 fprintf(dip3d,"# which is part of G R O M A C S:\n");
796 fprintf(dip3d,"#\n");
799 /* Write legends to all the files */
800 xvgr_legend(outmtot,NLEGMTOT,leg_mtot,oenv);
801 xvgr_legend(outaver,NLEGAVER,leg_aver,oenv);
803 if (bMU && (mu_aver == -1))
804 xvgr_legend(outeps,NLEGEPS-2,leg_eps,oenv);
806 xvgr_legend(outeps,NLEGEPS,leg_eps,oenv);
811 /* Read the first frame from energy or traj file */
814 bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr);
816 timecheck=check_times(t);
819 if ((teller % 10) == 0)
820 fprintf(stderr,"\r Skipping Frame %6d, time: %8.3f", teller, t);
823 printf("End of %s reached\n",mufn);
826 } while (bCont && (timecheck < 0));
828 natom = read_first_x(oenv,&status,fn,&t,&x,box);
830 /* Calculate spacing for dipole bin (simple histogram) */
831 ndipbin = 1+(mu_max/0.01);
832 snew(dipole_bin, ndipbin);
835 for(m=0; (m<DIM); m++) {
836 M[m] = M2[m] = M4[m] = 0.0;
840 /* Use 0.7 iso 0.5 to account for pressure scaling */
841 /* rcut = 0.7*sqrt(max_cutoff2(box)); */
842 rcut = 0.7*sqrt(sqr(box[XX][XX])+sqr(box[YY][YY])+sqr(box[ZZ][ZZ]));
844 gkrbin = mk_gkrbin(rcut,rcmax,bPhi,ndegrees);
847 /* Start while loop over frames */
851 if (bCorr && (teller >= nframes)) {
854 srenew(muall[0],nframes*DIM);
857 for(i=0; (i<gnx_tot); i++)
858 srenew(muall[i],nframes*DIM);
864 /* Copy rvec into double precision local variable */
865 for(m=0; (m<DIM); m++)
870 for(m=0; (m<DIM); m++) {
874 rm_pbc(&(top->idef),ePBC,natom,box,x,x);
876 muframelsq = gmx_stats_init();
877 /* Begin loop of all molecules in frame */
878 for(n=0; (n<ncos); n++) {
879 for(i=0; (i<gnx[n]); i++) {
882 ind0 = mols->index[molindex[n][i]];
883 ind1 = mols->index[molindex[n][i]+1];
885 mol_dip(ind0,ind1,x,atom,dipole[i]);
886 gmx_stats_add_point(mulsq,0,norm(dipole[i]),0,0);
887 gmx_stats_add_point(muframelsq,0,norm(dipole[i]),0,0);
889 update_slab_dipoles(ind0,ind1,x,
890 dipole[i],idim,nslices,slab_dipoles,box);
892 mol_quad(ind0,ind1,x,atom,quad);
893 for(m=0; (m<DIM); m++)
894 gmx_stats_add_point(Qlsq[m],0,quad[m],0,0);
896 if (bCorr && !bTotal) {
898 muall[i][tel3+XX] = dipole[i][XX];
899 muall[i][tel3+YY] = dipole[i][YY];
900 muall[i][tel3+ZZ] = dipole[i][ZZ];
903 for(m=0; (m<DIM); m++) {
904 M_av[m] += dipole[i][m]; /* M per frame */
905 mu_mol += dipole[i][m]*dipole[i][m]; /* calc. mu for distribution */
907 mu_mol = sqrt(mu_mol);
909 mu_ave += mu_mol; /* calc. the average mu */
911 /* Update the dipole distribution */
912 ibin = (int)(ndipbin*mu_mol/mu_max + 0.5);
917 rvec2sprvec(dipole[i],dipsp[i]);
919 if (dipsp[i][YY] > -M_PI && dipsp[i][YY] < -0.5*M_PI) {
920 if (dipsp[i][ZZ] < 0.5 * M_PI) {
925 }else if (dipsp[i][YY] > -0.5*M_PI && dipsp[i][YY] < 0.0*M_PI) {
926 if (dipsp[i][ZZ] < 0.5 * M_PI) {
931 }else if (dipsp[i][YY] > 0.0 && dipsp[i][YY] < 0.5*M_PI) {
932 if (dipsp[i][ZZ] < 0.5 * M_PI) {
937 }else if (dipsp[i][YY] > 0.5*M_PI && dipsp[i][YY] < M_PI) {
938 if (dipsp[i][ZZ] < 0.5 * M_PI) {
945 fprintf(dip3d,"set arrow %d from %f, %f, %f to %f, %f, %f lt %d # %d %d\n",
950 x[ind0][XX]+dipole[i][XX]/25,
951 x[ind0][YY]+dipole[i][YY]/25,
952 x[ind0][ZZ]+dipole[i][ZZ]/25,
955 } /* End loop of all molecules in frame */
958 fprintf(dip3d,"set title \"t = %4.3f\"\n",t);
959 fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
960 fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
961 fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
962 fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
963 fprintf(dip3d,"pause -1 'Hit return to continue'\n");
967 /* Compute square of total dipole */
968 for(m=0; (m<DIM); m++)
969 M_av2[m] = M_av[m]*M_av[m];
972 compute_avercos(gnx_tot,dipole,&dd,dipaxis,bPairs);
973 rms_cos = sqrt(sqr(dipaxis[XX]-0.5)+
974 sqr(dipaxis[YY]-0.5)+
975 sqr(dipaxis[ZZ]-0.5));
977 fprintf(caver,"%10.3e %10.3e %10.3e %10.3e %10.3e %10.3e\n",
978 t,dd,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
980 fprintf(caver,"%10.3e %10.3e %10.3e %10.3e %10.3e\n",
981 t,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
985 do_gkr(gkrbin,ncos,gnx,molindex,mols->index,x,dipole,ePBC,box,
991 muall[0][tel3+XX] = M_av[XX];
992 muall[0][tel3+YY] = M_av[YY];
993 muall[0][tel3+ZZ] = M_av[ZZ];
996 /* Write to file the total dipole moment of the box, and its components
999 if ((skip == 0) || ((teller % skip) == 0))
1000 fprintf(outmtot,"%10g %12.8e %12.8e %12.8e %12.8e\n",
1001 t,M_av[XX],M_av[YY],M_av[ZZ],
1002 sqrt(M_av2[XX]+M_av2[YY]+M_av2[ZZ]));
1004 for(m=0; (m<DIM); m++) {
1007 M4[m] += sqr(M_av2[m]);
1009 /* Increment loop counter */
1012 /* Calculate for output the running averages */
1013 invtel = 1.0/teller;
1014 M2_ave = (M2[XX]+M2[YY]+M2[ZZ])*invtel;
1015 M_ave2 = invtel*(invtel*(M[XX]*M[XX] + M[YY]*M[YY] + M[ZZ]*M[ZZ]));
1016 M_diff = M2_ave - M_ave2;
1018 /* Compute volume from box in traj, else we use the one from above */
1023 epsilon = calc_eps(M_diff,(vol_aver/teller),epsilonRF,temp);
1025 /* Calculate running average for dipole */
1027 mu_aver = (mu_ave/gnx_tot)*invtel;
1029 if ((skip == 0) || ((teller % skip) == 0)) {
1030 /* Write to file < |M|^2 >, < |M| >^2. And the difference between
1031 * the two. Here M is sum mu_i. Further write the finite system
1032 * Kirkwood G factor and epsilon.
1034 fprintf(outaver,"%10g %10.3e %10.3e %10.3e %10.3e\n",
1035 t,M2_ave,M_ave2,M_diff,M_ave2/M2_ave);
1039 gmx_stats_get_average(muframelsq,&aver);
1040 fprintf(adip, "%10g %f \n", t,aver);
1043 printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1045 if (!bMU || (mu_aver != -1)) {
1046 /* Finite system Kirkwood G-factor */
1047 Gk = M_diff/(gnx_tot*mu_aver*mu_aver);
1048 /* Infinite system Kirkwood G-factor */
1049 if (epsilonRF == 0.0)
1050 g_k = ((2*epsilon+1)*Gk/(3*epsilon));
1052 g_k = ((2*epsilonRF+epsilon)*(2*epsilon+1)*
1053 Gk/(3*epsilon*(2*epsilonRF+1)));
1055 fprintf(outeps,"%10g %10.3e %10.3e %10.3e\n",t,epsilon,Gk,g_k);
1059 fprintf(outeps,"%10g %12.8e\n",t,epsilon);
1063 bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr);
1065 bCont = read_next_x(oenv,status,&t,natom,x,box);
1082 fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
1083 fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
1084 fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
1085 fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
1086 fprintf(dip3d,"pause -1 'Hit return to continue'\n");
1091 dump_slab_dipoles(slabfn,idim,nslices,slab_dipoles,box,teller,oenv);
1092 sfree(slab_dipoles);
1096 printf("Average volume over run is %g\n",vol_aver);
1098 print_gkrbin(gkrfn,gkrbin,gnx[0],teller,vol_aver,oenv);
1099 print_cmap(cmap,gkrbin,nlevels);
1101 /* Autocorrelation function */
1104 printf("Not enough frames for autocorrelation\n");
1107 dt=(t1 - t0)/(teller-1);
1108 printf("t0 %g, t %g, teller %d\n", t0,t,teller);
1113 do_autocorr(corf,oenv,"Autocorrelation Function of Total Dipole",
1114 teller,1,muall,dt,mode,TRUE);
1116 do_autocorr(corf,oenv,"Dipole Autocorrelation Function",
1117 teller,gnx_tot,muall,dt,
1118 mode,strcmp(corrtype,"molsep"));
1122 real aver,sigma,error,lsq;
1124 gmx_stats_get_ase(mulsq,&aver,&sigma,&error);
1125 printf("\nDipole moment (Debye)\n");
1126 printf("---------------------\n");
1127 printf("Average = %8.4f Std. Dev. = %8.4f Error = %8.4f\n",
1132 for(m=0; (m<DIM); m++)
1133 gmx_stats_get_ase(mulsq,&(a[m]),&(s[m]),&(e[m]));
1135 printf("\nQuadrupole moment (Debye-Ang)\n");
1136 printf("-----------------------------\n");
1137 printf("Averages = %8.4f %8.4f %8.4f\n",a[XX],a[YY],a[ZZ]);
1138 printf("Std. Dev. = %8.4f %8.4f %8.4f\n",s[XX],s[YY],s[ZZ]);
1139 printf("Error = %8.4f %8.4f %8.4f\n",e[XX],e[YY],e[ZZ]);
1143 printf("The following averages for the complete trajectory have been calculated:\n\n");
1144 printf(" Total < M_x > = %g Debye\n", M[XX]/teller);
1145 printf(" Total < M_y > = %g Debye\n", M[YY]/teller);
1146 printf(" Total < M_z > = %g Debye\n\n", M[ZZ]/teller);
1148 printf(" Total < M_x^2 > = %g Debye^2\n", M2[XX]/teller);
1149 printf(" Total < M_y^2 > = %g Debye^2\n", M2[YY]/teller);
1150 printf(" Total < M_z^2 > = %g Debye^2\n\n", M2[ZZ]/teller);
1152 printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave);
1153 printf(" Total < |M| >^2 = %g Debye^2\n\n", M_ave2);
1155 printf(" < |M|^2 > - < |M| >^2 = %g Debye^2\n\n", M_diff);
1157 if (!bMU || (mu_aver != -1)) {
1158 printf("Finite system Kirkwood g factor G_k = %g\n", Gk);
1159 printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k);
1161 printf("Epsilon = %g\n", epsilon);
1164 /* Write to file the dipole moment distibution during the simulation.
1166 outdd=xvgropen(dipdist,"Dipole Moment Distribution","mu (Debye)","",oenv);
1167 for(i=0; (i<ndipbin); i++)
1168 fprintf(outdd,"%10g %10f\n",
1169 (i*mu_max)/ndipbin,dipole_bin[i]/(double)teller);
1174 done_gkrbin(&gkrbin);
1177 void dipole_atom2molindex(int *n,int *index,t_block *mols)
1185 while(m < mols->nr && index[i] != mols->index[m])
1188 gmx_fatal(FARGS,"index[%d]=%d does not correspond to the first atom of a molecule",i+1,index[i]+1);
1189 for(j=mols->index[m]; j<mols->index[m+1]; j++) {
1190 if (i >= *n || index[i] != j)
1191 gmx_fatal(FARGS,"The index group is not a set of whole molecules");
1194 /* Modify the index in place */
1197 printf("There are %d molecules in the selection\n",nmol);
1201 int gmx_dipoles(int argc,char *argv[])
1203 const char *desc[] = {
1204 "g_dipoles computes the total dipole plus fluctuations of a simulation",
1205 "system. From this you can compute e.g. the dielectric constant for",
1206 "low dielectric media.",
1207 "For molecules with a net charge, the net charge is subtracted at",
1208 "center of mass of the molecule.[PAR]",
1209 "The file Mtot.xvg contains the total dipole moment of a frame, the",
1210 "components as well as the norm of the vector.",
1211 "The file aver.xvg contains < |Mu|^2 > and < |Mu| >^2 during the",
1213 "The file dipdist.xvg contains the distribution of dipole moments during",
1215 "The mu_max is used as the highest value in the distribution graph.[PAR]",
1216 "Furthermore the dipole autocorrelation function will be computed when",
1217 "option -corr is used. The output file name is given with the [TT]-c[tt]",
1219 "The correlation functions can be averaged over all molecules",
1220 "([TT]mol[tt]), plotted per molecule seperately ([TT]molsep[tt])",
1221 "or it can be computed over the total dipole moment of the simulation box",
1222 "([TT]total[tt]).[PAR]",
1223 "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1224 "G-factor, as well as the average cosine of the angle between the dipoles",
1225 "as a function of the distance. The plot also includes gOO and hOO",
1226 "according to Nymand & Linse, JCP 112 (2000) pp 6386-6395. In the same plot",
1227 "we also include the energy per scale computed by taking the inner product of",
1228 "the dipoles divided by the distance to the third power.[PAR]",
1231 "g_dipoles -corr mol -P1 -o dip_sqr -mu 2.273 -mumax 5.0 -nofft[PAR]",
1232 "This will calculate the autocorrelation function of the molecular",
1233 "dipoles using a first order Legendre polynomial of the angle of the",
1234 "dipole vector and itself a time t later. For this calculation 1001",
1235 "frames will be used. Further the dielectric constant will be calculated",
1236 "using an epsilonRF of infinity (default), temperature of 300 K (default) and",
1237 "an average dipole moment of the molecule of 2.273 (SPC). For the",
1238 "distribution function a maximum of 5.0 will be used."
1240 real mu_max=5, mu_aver=-1,rcmax=0;
1241 real epsilonRF=0.0, temp=300;
1242 bool bAverCorr=FALSE,bMolCorr=FALSE,bPairs=TRUE,bPhi=FALSE;
1243 const char *corrtype[]={NULL, "none", "mol", "molsep", "total", NULL};
1244 const char *axtitle="Z";
1245 int nslices = 10; /* nr of slices defined */
1246 int skip=0,nFA=0,nFB=0,ncos=1;
1247 int nlevels=20,ndegrees=90;
1250 { "-mu", FALSE, etREAL, {&mu_aver},
1251 "dipole of a single molecule (in Debye)" },
1252 { "-mumax", FALSE, etREAL, {&mu_max},
1253 "max dipole in Debye (for histrogram)" },
1254 { "-epsilonRF",FALSE, etREAL, {&epsilonRF},
1255 "epsilon of the reaction field used during the simulation, needed for dieclectric constant calculation. WARNING: 0.0 means infinity (default)" },
1256 { "-skip", FALSE, etINT, {&skip},
1257 "Skip steps in the output (but not in the computations)" },
1258 { "-temp", FALSE, etREAL, {&temp},
1259 "Average temperature of the simulation (needed for dielectric constant calculation)" },
1260 { "-corr", FALSE, etENUM, {corrtype},
1261 "Correlation function to calculate" },
1262 { "-pairs", FALSE, etBOOL, {&bPairs},
1263 "Calculate |cos theta| between all pairs of molecules. May be slow" },
1264 { "-ncos", FALSE, etINT, {&ncos},
1265 "Must be 1 or 2. Determines whether the <cos> is computed between all mole cules in one group, or between molecules in two different groups. This turns on the -gkr flag." },
1266 { "-axis", FALSE, etSTR, {&axtitle},
1267 "Take the normal on the computational box in direction X, Y or Z." },
1268 { "-sl", FALSE, etINT, {&nslices},
1269 "Divide the box in #nr slices." },
1270 { "-gkratom", FALSE, etINT, {&nFA},
1271 "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" },
1272 { "-gkratom2", FALSE, etINT, {&nFB},
1273 "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of molecules" },
1274 { "-rcmax", FALSE, etREAL, {&rcmax},
1275 "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If zero, a criterium based on the box length will be used." },
1276 { "-phi", FALSE, etBOOL, {&bPhi},
1277 "Plot the 'torsion angle' defined as the rotation of the two dipole vectors around the distance vector between the two molecules in the xpm file from the -cmap option. By default the cosine of the angle between the dipoles is plotted." },
1278 { "-nlevels", FALSE, etINT, {&nlevels},
1279 "Number of colors in the cmap output" },
1280 { "-ndegrees", FALSE, etINT, {&ndegrees},
1281 "Number of divisions on the y-axis in the camp output (for 180 degrees)" }
1286 char **grpname=NULL;
1287 bool bCorr,bQuad,bGkr,bMU,bSlab;
1289 { efEDR, "-en", NULL, ffOPTRD },
1290 { efTRX, "-f", NULL, ffREAD },
1291 { efTPX, NULL, NULL, ffREAD },
1292 { efNDX, NULL, NULL, ffOPTRD },
1293 { efXVG, "-o", "Mtot", ffWRITE },
1294 { efXVG, "-eps", "epsilon", ffWRITE },
1295 { efXVG, "-a", "aver", ffWRITE },
1296 { efXVG, "-d", "dipdist", ffWRITE },
1297 { efXVG, "-c", "dipcorr", ffOPTWR },
1298 { efXVG, "-g", "gkr", ffOPTWR },
1299 { efXVG, "-adip","adip", ffOPTWR },
1300 { efXVG, "-dip3d", "dip3d", ffOPTWR },
1301 { efXVG, "-cos", "cosaver", ffOPTWR },
1302 { efXPM, "-cmap","cmap", ffOPTWR },
1303 { efXVG, "-q", "quadrupole", ffOPTWR },
1304 { efXVG, "-slab","slab", ffOPTWR }
1306 #define NFILE asize(fnm)
1314 CopyRight(stderr,argv[0]);
1316 ppa = add_acf_pargs(&npargs,pa);
1317 parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
1318 NFILE,fnm,npargs,ppa,asize(desc),desc,0,NULL,&oenv);
1320 printf("Using %g as mu_max and %g as the dipole moment.\n",
1322 if (epsilonRF == 0.0)
1323 printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1325 bMU = opt2bSet("-en",NFILE,fnm);
1326 bQuad = opt2bSet("-q",NFILE,fnm);
1327 bGkr = opt2bSet("-g",NFILE,fnm);
1328 if (opt2parg_bSet("-ncos",asize(pa),pa)) {
1329 if ((ncos != 1) && (ncos != 2))
1330 gmx_fatal(FARGS,"ncos has to be either 1 or 2");
1333 bSlab = (opt2bSet("-slab",NFILE,fnm) || opt2parg_bSet("-sl",asize(pa),pa) ||
1334 opt2parg_bSet("-axis",asize(pa),pa));
1338 printf("WARNING: Can not determine quadrupoles from energy file\n");
1342 printf("WARNING: Can not determine Gk(r) from energy file\n");
1347 printf("WARNING: Can not calculate Gk and gk, since you did\n"
1348 " not enter a valid dipole for the molecules\n");
1352 ePBC = read_tpx_top(ftp2fn(efTPX,NFILE,fnm),NULL,box,
1353 &natoms,NULL,NULL,NULL,top);
1357 snew(grpindex,ncos);
1358 get_index(&top->atoms,ftp2fn_null(efNDX,NFILE,fnm),
1359 ncos,gnx,grpindex,grpname);
1360 for(k=0; (k<ncos); k++) {
1361 dipole_atom2molindex(&gnx[k],grpindex[k],&(top->mols));
1362 neutralize_mols(gnx[k],grpindex[k],&(top->mols),top->atoms.atom);
1366 do_dip(top,ePBC,det(box),ftp2fn(efTRX,NFILE,fnm),
1367 opt2fn("-o",NFILE,fnm),opt2fn("-eps",NFILE,fnm),
1368 opt2fn("-a",NFILE,fnm),opt2fn("-d",NFILE,fnm),
1369 opt2fn_null("-cos",NFILE,fnm),
1370 opt2fn_null("-dip3d",NFILE,fnm),opt2fn_null("-adip",NFILE,fnm),
1372 opt2fn("-c",NFILE,fnm),
1373 bGkr, opt2fn("-g",NFILE,fnm),
1374 bPhi, &nlevels, ndegrees,
1376 opt2fn("-cmap",NFILE,fnm),rcmax,
1377 bQuad, opt2fn("-q",NFILE,fnm),
1378 bMU, opt2fn("-en",NFILE,fnm),
1379 gnx,grpindex,mu_max,mu_aver,epsilonRF,temp,nFF,skip,
1380 bSlab,nslices,axtitle,opt2fn("-slab",NFILE,fnm),oenv);
1382 do_view(oenv,opt2fn("-o",NFILE,fnm),"-autoscale xy -nxy");
1383 do_view(oenv,opt2fn("-eps",NFILE,fnm),"-autoscale xy -nxy");
1384 do_view(oenv,opt2fn("-a",NFILE,fnm),"-autoscale xy -nxy");
1385 do_view(oenv,opt2fn("-d",NFILE,fnm),"-autoscale xy");
1386 do_view(oenv,opt2fn("-c",NFILE,fnm),"-autoscale xy");