3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Copyright (c) 1991-2001
11 * BIOSON Research Institute, Dept. of Biophysical Chemistry
12 * University of Groningen, The Netherlands
14 * 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 * Do check out http://www.gromacs.org , or mail us at gromacs@gromacs.org .
33 * Gyas ROwers Mature At Cryogenic Speed
35 * finished FD 09/07/08
51 #include "gmx_statistics.h"
54 #define SQR(x) (pow(x,2.0))
55 #define EPSI0 (EPSILON0*E_CHARGE*E_CHARGE*AVOGADRO/(KILO*NANO)) /* EPSILON0 in SI units */
58 static void index_atom2mol(int *n
,int *index
,t_block
*mols
)
67 while (index
[i
] > mols
->index
[mol
]) {
70 gmx_fatal(FARGS
,"Atom index out of range: %d",index
[i
]+1);
72 for(j
=mols
->index
[mol
]; j
<mols
->index
[mol
+1]; j
++) {
73 if (i
>= nat
|| index
[i
] != j
)
74 gmx_fatal(FARGS
,"The index group does not consist of whole molecules");
80 fprintf(stderr
,"\nSplit group of %d atoms into %d molecules\n",nat
,nmol
);
85 static bool precalc(t_topology top
,real mass2
[],real qmol
[]){
99 for(i
=0;i
<top
.mols
.nr
;i
++){
101 l
=top
.mols
.index
[i
+1];
106 mtot
+=top
.atoms
.atom
[j
].m
;
107 qtot
+=top
.atoms
.atom
[j
].q
;
111 top
.atoms
.atom
[j
].q
-=top
.atoms
.atom
[j
].m
*qtot
/mtot
;
112 mass2
[j
]=top
.atoms
.atom
[j
].m
/mtot
;
126 printf("\n\nSystem not neutral (q=%f) will not calculate translational part of the dipole moment.\n",qall
);
135 static void remove_jump(matrix box
,int natoms
,rvec xp
[],rvec x
[]){
141 hbox
[d
] = 0.5*box
[d
][d
];
142 for(i
=0; i
<natoms
; i
++)
143 for(m
=DIM
-1; m
>=0; m
--) {
144 while (x
[i
][m
]-xp
[i
][m
] <= -hbox
[m
])
146 x
[i
][d
] += box
[m
][d
];
147 while (x
[i
][m
]-xp
[i
][m
] > hbox
[m
])
149 x
[i
][d
] -= box
[m
][d
];
153 static void calc_mj(t_topology top
,int ePBC
,matrix box
,bool bNoJump
,int isize
,int index0
[],\
154 rvec fr
[],rvec mj
,real mass2
[],real qmol
[]){
163 calc_box_center(ecenterRECT
,box
,center
);
166 set_pbc(&pbc
,ePBC
,box
);
171 for(i
=0;i
<isize
;i
++){
174 k
=top
.mols
.index
[index0
[i
]];
175 l
=top
.mols
.index
[index0
[i
+1]];
177 svmul(mass2
[j
],fr
[j
],tmp
);
182 svmul(qmol
[k
],mt1
,mt1
);
184 pbc_dx(&pbc
,mt1
,center
,mt2
);
185 svmul(qmol
[k
],mt2
,mt1
);
195 static real
calceps(real prefactor
,real md2
,real mj2
,real cor
,real eps_rf
,bool bCOR
){
197 /* bCOR determines if the correlation is computed via
198 * static properties (FALSE) or the correlation integral (TRUE)
204 if (bCOR
) epsilon
=md2
-2.0*cor
+mj2
;
205 else epsilon
=md2
+mj2
+2.0*cor
;
208 epsilon
=1.0+prefactor
*epsilon
;
212 epsilon
=2.0*eps_rf
+1.0+2.0*eps_rf
*prefactor
*epsilon
;
213 epsilon
/=2.0*eps_rf
+1.0-prefactor
*epsilon
;
222 static real
calc_cacf(FILE *fcacf
,real prefactor
,real cacf
[],real time
[],int nfr
,int vfr
[],int ei
,int nshift
){
237 rfr
=(real
) (nfr
/nshift
-i
/nshift
);
240 if(time
[vfr
[i
]]<=time
[vfr
[ei
]])
243 fprintf(fcacf
,"%.3f\t%10.6g\t%10.6g\n",time
[vfr
[i
]],cacf
[i
],sigma
);
246 deltat
=(time
[vfr
[i
+1]]-time
[vfr
[i
]]);
248 corint
=2.0*deltat
*cacf
[i
]*prefactor
;
249 if(i
==0 || (i
+1)==nfr
)
257 printf("Too less points.\n");
263 static void calc_mjdsp(FILE *fmjdsp
,real vol
,real temp
,real prefactor
,rvec mjdsp
[],real dsp2
[],real time
[],int nfr
,real refr
[]){
270 fprintf(fmjdsp
,"#Prefactor fit E-H: 1 / 6.0*V*k_B*T: %g\n",prefactor
);
277 dsp2
[i
]*=prefactor
/refr
[i
];
278 fprintf(fmjdsp
,"%.3f\t%10.6g\n",time
[i
],dsp2
[i
]);
287 static void dielectric(FILE *fmj
,FILE *fmd
,FILE *outf
,FILE *fcur
,FILE *mcor
,
288 FILE *fmjdsp
, bool bNoJump
,bool bACF
,bool bINT
,
289 int ePBC
,t_topology top
, t_trxframe fr
,real temp
,
290 real trust
,real bfit
,real efit
,real bvit
,real evit
,
291 int status
,int isize
,int nmols
, int nshift
,
292 atom_id
*index0
,int indexm
[],real mass2
[],
293 real qmol
[], real eps_rf
, const output_env_t oenv
)
296 int valloc
,nalloc
,nfr
,nvfr
,m
,itrust
=0;
306 real prefactorav
=0.0;
337 * Variables for the least-squares fit for Einstein-Helfand and Green-Kubo
365 /* This is the main loop over frames */
389 srenew(mjdsp
,nalloc
);
391 srenew(mtrans
,nalloc
);
392 srenew(xshfr
,nalloc
);
394 for(i
=nfr
;i
<nalloc
;i
++){
395 clear_rvec(mjdsp
[i
]);
397 clear_rvec(mtrans
[i
]);
410 time
[nfr
]=fr
.time
-t0
;
420 remove_jump(fr
.box
,fr
.natoms
,xp
,fr
.x
);
424 for(i
=0; i
<fr
.natoms
;i
++)
425 copy_rvec(fr
.x
[i
],xp
[i
]);
429 rm_pbc(&top
.idef
,ePBC
,fr
.natoms
,fr
.box
,fr
.x
,fr
.x
);
431 calc_mj(top
,ePBC
,fr
.box
,bNoJump
,nmols
,indexm
,fr
.x
,mtrans
[nfr
],mass2
,qmol
);
433 for(i
=0;i
<isize
;i
++){
435 svmul(top
.atoms
.atom
[j
].q
,fr
.x
[j
],fr
.x
[j
]);
436 rvec_inc(mu
[nfr
],fr
.x
[j
]);
439 /*if(mod(nfr,nshift)==0){*/
442 rvec_sub(mtrans
[nfr
],mtrans
[j
],tmp
);
443 dsp2
[nfr
-j
]+=norm2(tmp
);
463 clear_rvec(v0
[nvfr
]);
468 for(i
=0;i
<isize
;i
++){
470 svmul(mass2
[j
],fr
.v
[j
],fr
.v
[j
]);
471 svmul(qmol
[j
],fr
.v
[j
],fr
.v
[j
]);
472 rvec_inc(v0
[nvfr
],fr
.v
[j
]);
475 fprintf(fcur
,"%.3f\t%.6f\t%.6f\t%.6f\n",time
[nfr
],v0
[nfr
][XX
],v0
[nfr
][YY
],v0
[nfr
][ZZ
]);
477 /*if(mod(nvfr,nshift)==0){*/
479 for(j
=nvfr
;j
>=0;j
--){
481 cacf
[nvfr
-j
]+=iprod(v0
[nvfr
],v0
[j
]);
483 djc
[nvfr
-j
]+=iprod(mu
[vfr
[j
]],v0
[nvfr
]);
490 volume
= det(fr
.box
);
493 rvec_inc(mja_tmp
,mtrans
[nfr
]);
494 mjd
+=iprod(mu
[nfr
],mtrans
[nfr
]);
495 rvec_inc(mdvec
,mu
[nfr
]);
497 mj2
+=iprod(mtrans
[nfr
],mtrans
[nfr
]);
498 md2
+=iprod(mu
[nfr
],mu
[nfr
]);
500 fprintf(fmj
,"%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n",time
[nfr
],mtrans
[nfr
][XX
],mtrans
[nfr
][YY
],mtrans
[nfr
][ZZ
],mj2
/refr
,norm(mja_tmp
)/refr
);
501 fprintf(fmd
,"%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n", \
502 time
[nfr
],mu
[nfr
][XX
],mu
[nfr
][YY
],mu
[nfr
][ZZ
],md2
/refr
,norm(mdvec
)/refr
);
506 }while(read_next_frame(oenv
,status
,&fr
));
511 prefactor
/=3.0*EPSILON0
*volume_av
*BOLTZ
*temp
;
514 prefactorav
=E_CHARGE
*E_CHARGE
;
515 prefactorav
/=volume_av
*BOLTZMANN
*temp
*NANO
*6.0;
517 fprintf(stderr
,"Prefactor fit E-H: 1 / 6.0*V*k_B*T: %g\n",prefactorav
);
519 calc_mjdsp(fmjdsp
,volume_av
,temp
,prefactorav
,mjdsp
,dsp2
,time
,nfr
,xshfr
);
522 * Now we can average and calculate the correlation functions
530 svmul(1.0/refr
,mdvec
,mdvec
);
531 svmul(1.0/refr
,mja_tmp
,mja_tmp
);
535 mjdav
=iprod(mdvec
,mja_tmp
);
538 printf("\n\nAverage translational dipole moment M_J [enm] after %d frames (|M|^2): %f %f %f (%f)\n",nfr
,mja_tmp
[XX
],mja_tmp
[YY
],mja_tmp
[ZZ
],mj2
);
539 printf("\n\nAverage molecular dipole moment M_D [enm] after %d frames (|M|^2): %f %f %f (%f)\n",nfr
,mdvec
[XX
],mdvec
[YY
],mdvec
[ZZ
],md2
);
547 printf("\nCalculating M_D - current correlation integral ... \n");
548 corint
=calc_cacf(mcor
,prefactorav
/EPSI0
,djc
,time
,nvfr
,vfr
,ie
,nshift
);
554 printf("\nCalculating current autocorrelation ... \n");
555 sgk
=calc_cacf(outf
,prefactorav
/PICO
,cacf
,time
,nvfr
,vfr
,ie
,nshift
);
564 xfit
[i
-ii
]=log(time
[vfr
[i
]]);
566 yfit
[i
-ii
]=log(rtmp
);
570 lsq_y_ax_b(ie
-ii
,xfit
,yfit
,&sigma
,&malt
,&err
,&rest
);
576 malt
*=prefactorav
*2.0e12
/sigma
;
586 /* Calculation of the dielectric constant */
588 fprintf(stderr
,"\n********************************************\n");
589 dk_s
=calceps(prefactor
,md2
,mj2
,mjd
,eps_rf
,FALSE
);
590 fprintf(stderr
,"\nAbsolute values:\n epsilon=%f\n",dk_s
);
591 fprintf(stderr
," <M_D^2> , <M_J^2>, <(M_J*M_D)^2>: (%f, %f, %f)\n\n",md2
,mj2
,mjd
);
592 fprintf(stderr
,"********************************************\n");
595 dk_f
=calceps(prefactor
,md2
-mdav2
,mj2
-mj
,mjd
-mjdav
,eps_rf
,FALSE
);
596 fprintf(stderr
,"\n\nFluctuations:\n epsilon=%f\n\n",dk_f
);
597 fprintf(stderr
,"\n deltaM_D , deltaM_J, deltaM_JD: (%f, %f, %f)\n",md2
-mdav2
,mj2
-mj
,mjd
-mjdav
);
598 fprintf(stderr
,"\n********************************************\n");
600 dk_d
=calceps(prefactor
,md2
-mdav2
,mj2
-mj
,corint
,eps_rf
,TRUE
);
601 fprintf(stderr
,"\nStatic dielectric constant using integral and fluctuations: %f\n",dk_d
);
602 fprintf(stderr
,"\n < M_JM_D > via integral: %.3f\n",-1.0*corint
);
605 fprintf(stderr
,"\n***************************************************");
606 fprintf(stderr
,"\n\nAverage volume V=%f nm^3 at T=%f K\n",volume_av
,temp
);
607 fprintf(stderr
,"and corresponding refactor 1.0 / 3.0*V*k_B*T*EPSILON_0: %f \n",prefactor
);
612 fprintf(stderr
,"Integral and integrated fit to the current acf yields at t=%f:\n",time
[vfr
[ii
]]);
613 fprintf(stderr
,"sigma=%8.3f (pure integral: %.3f)\n",sgk
-malt
*pow(time
[vfr
[ii
]],sigma
),sgk
);
617 fprintf(stderr
,"\nStart fit at %f ps (%f).\n",time
[bi
],bfit
);
618 fprintf(stderr
,"End fit at %f ps (%f).\n\n",time
[ei
],efit
);
628 lsq_y_ax_b(ei
-bi
,xfit
,yfit
,&sigma
,&malt
,&err
,&rest
);
631 dk_d
=calceps(prefactor
,md2
,0.5*malt
/prefactorav
,corint
,eps_rf
,TRUE
);
633 fprintf(stderr
,"Einstein-Helfand fit to the MSD of the translational dipole moment yields:\n\n");
634 fprintf(stderr
,"sigma=%.4f\n",sigma
);
635 fprintf(stderr
,"translational fraction of M^2: %.4f\n",0.5*malt
/prefactorav
);
636 fprintf(stderr
,"Dielectric constant using EH: %.4f\n",dk_d
);
642 fprintf(stderr
,"Too less points for a fit.\n");
662 int gmx_current(int argc
,char *argv
[])
665 static int nshift
=1000;
666 static real temp
=300.0;
667 static real trust
=0.25;
668 static real eps_rf
=0.0;
669 static bool bNoJump
=TRUE
;
670 static real bfit
=100.0;
671 static real bvit
=0.5;
672 static real efit
=400.0;
673 static real evit
=5.0;
675 { "-sh", FALSE
, etINT
, {&nshift
},
676 "Shift of the frames for averaging the correlation functions and the mean-square displacement."},
677 { "-nojump", FALSE
, etBOOL
, {&bNoJump
},
678 "Removes jumps of atoms across the box."},
679 { "-eps", FALSE
, etREAL
, {&eps_rf
},
680 "Dielectric constant of the surrounding medium. eps=0.0 corresponds to eps=infinity (thinfoil boundary conditions)."},
681 { "-bfit", FALSE
, etREAL
, {&bfit
},
682 "Begin of the fit of the straight line to the MSD of the translational fraction of the dipole moment."},
683 { "-efit", FALSE
, etREAL
, {&efit
},
684 "End of the fit of the straight line to the MSD of the translational fraction of the dipole moment."},
685 { "-bvit", FALSE
, etREAL
, {&bvit
},
686 "Begin of the fit of the current autocorrelation function to a*t^b."},
687 { "-evit", FALSE
, etREAL
, {&evit
},
688 "End of the fit of the current autocorrelation function to a*t^b."},
689 { "-tr", FALSE
, etREAL
, {&trust
},
690 "Fraction of the trajectory taken into account for the integral."},
691 { "-temp", FALSE
, etREAL
, {&temp
},
692 "Temperature for calculating epsilon."
705 atom_id
*index0
=NULL
;
731 { efTPS
, NULL
, NULL
, ffREAD
}, /* this is for the topology */
732 { efNDX
, NULL
, NULL
, ffOPTRD
},
733 { efTRX
, "-f", NULL
, ffREAD
}, /* and this for the trajectory */
734 { efXVG
, "-o", "current.xvg", ffWRITE
},
735 { efXVG
, "-caf", "caf.xvg", ffOPTWR
},
736 { efXVG
, "-dsp", "dsp.xvg", ffWRITE
},
737 { efXVG
, "-md", "md.xvg", ffWRITE
},
738 { efXVG
, "-mj", "mj.xvg", ffWRITE
},
739 { efXVG
, "-mc", "mc.xvg", ffOPTWR
}
742 #define NFILE asize(fnm)
745 const char *desc
[] = {
746 "This is a tool for calculating the current autocorrelation function, the correlation",
747 "of the rotational and translational dipole moment of the system, and the resulting static",
748 "dielectric constant. To obtain a reasonable result the index group has to be neutral.",
749 "Furthermore the routine is capable of extracting the static conductivity from the current ",
750 "autocorrelation function, if velocities are given. Additionally an Einstein-Helfand fit also",
751 "allows to get the static conductivity."
753 "The flag [TT]-caf[tt] is for the output of the current autocorrelation function and [TT]-mc[tt] writes the",
754 "correlation of the rotational and translational part of the dipole moment in the corresponding",
755 "file. However this option is only available for trajectories containing velocities.",
756 "Options [TT]-sh[tt] and [TT]-tr[tt] are responsible for the averaging and integration of the",
757 "autocorrelation functions. Since averaging proceeds by shifting the starting point",
758 "through the trajectory, the shift can be modified with [TT]-sh[tt] to enable the choice of uncorrelated",
759 "starting points. Towards the end, statistical inaccuracy grows and integrating the",
760 "correlation function only yields reliable values until a certain point, depending on",
761 "the number of frames. The option [TT]-tr[tt] controls the region of the integral taken into account",
762 "for calculating the static dielectric constant.",
764 "Option [TT]-temp[tt] sets the temperature required for the computation of the static dielectric constant.",
766 "Option [TT]-eps[tt] controls the dielectric constant of the surrounding medium for simulations using",
767 "a Reaction Field or dipole corrections of the Ewald summation (eps=0 corresponds to",
768 "tin-foil boundary conditions).",
770 "[TT]-[no]nojump[tt] unfolds the coordinates to allow free diffusion. This is required to get a continuous",
771 "translational dipole moment, required for the Einstein-Helfand fit. The resuls from the fit allow to",
772 "determine the dielectric constant for system of charged molecules. However it is also possible to extract",
773 "the dielectric constant from the fluctuations of the total dipole moment in folded coordinates. But this",
774 "options has to be used with care, since only very short time spans fulfill the approximation, that the density",
775 "of the molecules is approximately constant and the averages are already converged. To be on the safe side,",
776 "the dielectric constant should be calculated with the help of the Einstein-Helfand method for",
777 "the translational part of the dielectric constant."
781 /* At first the arguments will be parsed and the system information processed */
783 CopyRight(stderr
,argv
[0]);
785 parse_common_args(&argc
,argv
,PCA_CAN_TIME
| PCA_CAN_VIEW
,
786 NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,0,NULL
,&oenv
);
788 bACF
= opt2bSet("-caf",NFILE
,fnm
);
789 bINT
= opt2bSet("-mc",NFILE
,fnm
);
791 bTop
=read_tps_conf(ftp2fn(efTPS
,NFILE
,fnm
),title
,&top
,&ePBC
,&xtop
,&vtop
,box
,TRUE
);
797 indexfn
= ftp2fn_null(efNDX
,NFILE
,fnm
);
800 get_index(&(top
.atoms
),indexfn
,1,&isize
,&index0
,grpname
);
802 flags
= flags
| TRX_READ_X
| TRX_READ_V
;
804 read_first_frame(oenv
,&status
,ftp2fn(efTRX
,NFILE
,fnm
),&fr
,flags
);
806 snew(mass2
,top
.atoms
.nr
);
807 snew(qmol
,top
.atoms
.nr
);
809 bNEU
=precalc(top
,mass2
,qmol
);
820 index_atom2mol(&nmols
,indexm
,&top
.mols
);
824 outf
=xvgropen(opt2fn("-caf",NFILE
,fnm
),
825 "Current autocorrelation function",output_env_get_xvgr_tlabel(oenv
),
826 "ACF (e nm/ps)\\S2",oenv
);
827 fprintf(outf
,"# time\t acf\t average \t std.dev\n");
829 fcur
=xvgropen(opt2fn("-o",NFILE
,fnm
),
830 "Current",output_env_get_xvgr_tlabel(oenv
),"J(t) (e nm/ps)",oenv
);
831 fprintf(fcur
,"# time\t Jx\t Jy \t J_z \n");
833 mcor
= xvgropen(opt2fn("-mc",NFILE
,fnm
),
834 "M\\sD\\N - current autocorrelation function",
835 output_env_get_xvgr_tlabel(oenv
),
836 "< M\\sD\\N (0)\\c7\\CJ(t) > (e nm/ps)\\S2",oenv
);
837 fprintf(mcor
,"# time\t M_D(0) J(t) acf \t Integral acf\n");
841 fmj
= xvgropen(opt2fn("-mj",NFILE
,fnm
),
842 "Averaged translational part of M",output_env_get_xvgr_tlabel(oenv
),
843 "< M\\sJ\\N > (enm)",oenv
);
844 fprintf(fmj
,"# time\t x\t y \t z \t average of M_J^2 \t std.dev\n");
845 fmd
= xvgropen(opt2fn("-md",NFILE
,fnm
),
846 "Averaged rotational part of M",output_env_get_xvgr_tlabel(oenv
),
847 "< M\\sD\\N > (enm)",oenv
);
848 fprintf(fmd
,"# time\t x\t y \t z \t average of M_D^2 \t std.dev\n");
850 fmjdsp
= xvgropen(opt2fn("-dsp",NFILE
,fnm
),
851 "MSD of the squared translational dipole moment M",
852 output_env_get_xvgr_tlabel(oenv
),
853 "<|M\\sJ\\N(t)-M\\sJ\\N(0)|\\S2\\N > / 6.0*V*k\\sB\\N*T / Sm\\S-1\\Nps\\S-1\\N",
857 /* System information is read and prepared, dielectric() processes the frames
858 * and calculates the requested quantities */
860 dielectric(fmj
,fmd
,outf
,fcur
,mcor
,fmjdsp
,bNoJump
,bACF
,bINT
,ePBC
,top
,fr
,
861 temp
,trust
, bfit
,efit
,bvit
,evit
,status
,isize
,nmols
,nshift
,
862 index0
,indexm
,mass2
,qmol
,eps_rf
,oenv
);