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
55 #include "gmx_statistics.h"
58 #define SQR(x) (pow(x,2.0))
59 #define EPSI0 (EPSILON0*E_CHARGE*E_CHARGE*AVOGADRO/(KILO*NANO)) /* EPSILON0 in SI units */
62 static void index_atom2mol(int *n
,int *index
,t_block
*mols
)
71 while (index
[i
] > mols
->index
[mol
]) {
74 gmx_fatal(FARGS
,"Atom index out of range: %d",index
[i
]+1);
76 for(j
=mols
->index
[mol
]; j
<mols
->index
[mol
+1]; j
++) {
77 if (i
>= nat
|| index
[i
] != j
)
78 gmx_fatal(FARGS
,"The index group does not consist of whole molecules");
84 fprintf(stderr
,"\nSplit group of %d atoms into %d molecules\n",nat
,nmol
);
89 static gmx_bool
precalc(t_topology top
,real mass2
[],real qmol
[]){
103 for(i
=0;i
<top
.mols
.nr
;i
++){
105 l
=top
.mols
.index
[i
+1];
110 mtot
+=top
.atoms
.atom
[j
].m
;
111 qtot
+=top
.atoms
.atom
[j
].q
;
115 top
.atoms
.atom
[j
].q
-=top
.atoms
.atom
[j
].m
*qtot
/mtot
;
116 mass2
[j
]=top
.atoms
.atom
[j
].m
/mtot
;
130 printf("\n\nSystem not neutral (q=%f) will not calculate translational part of the dipole moment.\n",qall
);
139 static void remove_jump(matrix box
,int natoms
,rvec xp
[],rvec x
[]){
145 hbox
[d
] = 0.5*box
[d
][d
];
146 for(i
=0; i
<natoms
; i
++)
147 for(m
=DIM
-1; m
>=0; m
--) {
148 while (x
[i
][m
]-xp
[i
][m
] <= -hbox
[m
])
150 x
[i
][d
] += box
[m
][d
];
151 while (x
[i
][m
]-xp
[i
][m
] > hbox
[m
])
153 x
[i
][d
] -= box
[m
][d
];
157 static void calc_mj(t_topology top
,int ePBC
,matrix box
,gmx_bool bNoJump
,int isize
,int index0
[],\
158 rvec fr
[],rvec mj
,real mass2
[],real qmol
[]){
167 calc_box_center(ecenterRECT
,box
,center
);
170 set_pbc(&pbc
,ePBC
,box
);
175 for(i
=0;i
<isize
;i
++){
178 k
=top
.mols
.index
[index0
[i
]];
179 l
=top
.mols
.index
[index0
[i
+1]];
181 svmul(mass2
[j
],fr
[j
],tmp
);
186 svmul(qmol
[k
],mt1
,mt1
);
188 pbc_dx(&pbc
,mt1
,center
,mt2
);
189 svmul(qmol
[k
],mt2
,mt1
);
199 static real
calceps(real prefactor
,real md2
,real mj2
,real cor
,real eps_rf
,gmx_bool bCOR
){
201 /* bCOR determines if the correlation is computed via
202 * static properties (FALSE) or the correlation integral (TRUE)
208 if (bCOR
) epsilon
=md2
-2.0*cor
+mj2
;
209 else epsilon
=md2
+mj2
+2.0*cor
;
212 epsilon
=1.0+prefactor
*epsilon
;
216 epsilon
=2.0*eps_rf
+1.0+2.0*eps_rf
*prefactor
*epsilon
;
217 epsilon
/=2.0*eps_rf
+1.0-prefactor
*epsilon
;
226 static real
calc_cacf(FILE *fcacf
,real prefactor
,real cacf
[],real time
[],int nfr
,int vfr
[],int ei
,int nshift
){
241 rfr
=(real
) (nfr
/nshift
-i
/nshift
);
244 if(time
[vfr
[i
]]<=time
[vfr
[ei
]])
247 fprintf(fcacf
,"%.3f\t%10.6g\t%10.6g\n",time
[vfr
[i
]],cacf
[i
],sigma
);
250 deltat
=(time
[vfr
[i
+1]]-time
[vfr
[i
]]);
252 corint
=2.0*deltat
*cacf
[i
]*prefactor
;
253 if(i
==0 || (i
+1)==nfr
)
261 printf("Too less points.\n");
267 static void calc_mjdsp(FILE *fmjdsp
,real vol
,real temp
,real prefactor
,rvec mjdsp
[],real dsp2
[],real time
[],int nfr
,real refr
[]){
274 fprintf(fmjdsp
,"#Prefactor fit E-H: 1 / 6.0*V*k_B*T: %g\n",prefactor
);
281 dsp2
[i
]*=prefactor
/refr
[i
];
282 fprintf(fmjdsp
,"%.3f\t%10.6g\n",time
[i
],dsp2
[i
]);
291 static void dielectric(FILE *fmj
,FILE *fmd
,FILE *outf
,FILE *fcur
,FILE *mcor
,
292 FILE *fmjdsp
, gmx_bool bNoJump
,gmx_bool bACF
,gmx_bool bINT
,
293 int ePBC
,t_topology top
, t_trxframe fr
,real temp
,
294 real trust
,real bfit
,real efit
,real bvit
,real evit
,
295 t_trxstatus
*status
,int isize
,int nmols
, int nshift
,
296 atom_id
*index0
,int indexm
[],real mass2
[],
297 real qmol
[], real eps_rf
, const output_env_t oenv
)
300 int valloc
,nalloc
,nfr
,nvfr
,m
,itrust
=0;
310 real prefactorav
=0.0;
341 * Variables for the least-squares fit for Einstein-Helfand and Green-Kubo
351 gmx_rmpbc_t gpbc
=NULL
;
370 /* This is the main loop over frames */
385 gpbc
= gmx_rmpbc_init(&top
.idef
,ePBC
,fr
.natoms
,fr
.box
);
395 srenew(mjdsp
,nalloc
);
397 srenew(mtrans
,nalloc
);
398 srenew(xshfr
,nalloc
);
400 for(i
=nfr
;i
<nalloc
;i
++){
401 clear_rvec(mjdsp
[i
]);
403 clear_rvec(mtrans
[i
]);
416 time
[nfr
]=fr
.time
-t0
;
426 remove_jump(fr
.box
,fr
.natoms
,xp
,fr
.x
);
430 for(i
=0; i
<fr
.natoms
;i
++)
431 copy_rvec(fr
.x
[i
],xp
[i
]);
435 gmx_rmpbc_trxfr(gpbc
,&fr
);
437 calc_mj(top
,ePBC
,fr
.box
,bNoJump
,nmols
,indexm
,fr
.x
,mtrans
[nfr
],mass2
,qmol
);
439 for(i
=0;i
<isize
;i
++){
441 svmul(top
.atoms
.atom
[j
].q
,fr
.x
[j
],fr
.x
[j
]);
442 rvec_inc(mu
[nfr
],fr
.x
[j
]);
445 /*if(mod(nfr,nshift)==0){*/
448 rvec_sub(mtrans
[nfr
],mtrans
[j
],tmp
);
449 dsp2
[nfr
-j
]+=norm2(tmp
);
469 clear_rvec(v0
[nvfr
]);
474 for(i
=0;i
<isize
;i
++){
476 svmul(mass2
[j
],fr
.v
[j
],fr
.v
[j
]);
477 svmul(qmol
[j
],fr
.v
[j
],fr
.v
[j
]);
478 rvec_inc(v0
[nvfr
],fr
.v
[j
]);
481 fprintf(fcur
,"%.3f\t%.6f\t%.6f\t%.6f\n",time
[nfr
],v0
[nfr
][XX
],v0
[nfr
][YY
],v0
[nfr
][ZZ
]);
483 /*if(mod(nvfr,nshift)==0){*/
485 for(j
=nvfr
;j
>=0;j
--){
487 cacf
[nvfr
-j
]+=iprod(v0
[nvfr
],v0
[j
]);
489 djc
[nvfr
-j
]+=iprod(mu
[vfr
[j
]],v0
[nvfr
]);
496 volume
= det(fr
.box
);
499 rvec_inc(mja_tmp
,mtrans
[nfr
]);
500 mjd
+=iprod(mu
[nfr
],mtrans
[nfr
]);
501 rvec_inc(mdvec
,mu
[nfr
]);
503 mj2
+=iprod(mtrans
[nfr
],mtrans
[nfr
]);
504 md2
+=iprod(mu
[nfr
],mu
[nfr
]);
506 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
);
507 fprintf(fmd
,"%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n", \
508 time
[nfr
],mu
[nfr
][XX
],mu
[nfr
][YY
],mu
[nfr
][ZZ
],md2
/refr
,norm(mdvec
)/refr
);
512 }while(read_next_frame(oenv
,status
,&fr
));
514 gmx_rmpbc_done(gpbc
);
519 prefactor
/=3.0*EPSILON0
*volume_av
*BOLTZ
*temp
;
522 prefactorav
=E_CHARGE
*E_CHARGE
;
523 prefactorav
/=volume_av
*BOLTZMANN
*temp
*NANO
*6.0;
525 fprintf(stderr
,"Prefactor fit E-H: 1 / 6.0*V*k_B*T: %g\n",prefactorav
);
527 calc_mjdsp(fmjdsp
,volume_av
,temp
,prefactorav
,mjdsp
,dsp2
,time
,nfr
,xshfr
);
530 * Now we can average and calculate the correlation functions
538 svmul(1.0/refr
,mdvec
,mdvec
);
539 svmul(1.0/refr
,mja_tmp
,mja_tmp
);
543 mjdav
=iprod(mdvec
,mja_tmp
);
546 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
);
547 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
);
555 printf("\nCalculating M_D - current correlation integral ... \n");
556 corint
=calc_cacf(mcor
,prefactorav
/EPSI0
,djc
,time
,nvfr
,vfr
,ie
,nshift
);
562 printf("\nCalculating current autocorrelation ... \n");
563 sgk
=calc_cacf(outf
,prefactorav
/PICO
,cacf
,time
,nvfr
,vfr
,ie
,nshift
);
572 xfit
[i
-ii
]=log(time
[vfr
[i
]]);
574 yfit
[i
-ii
]=log(rtmp
);
578 lsq_y_ax_b(ie
-ii
,xfit
,yfit
,&sigma
,&malt
,&err
,&rest
);
584 malt
*=prefactorav
*2.0e12
/sigma
;
594 /* Calculation of the dielectric constant */
596 fprintf(stderr
,"\n********************************************\n");
597 dk_s
=calceps(prefactor
,md2
,mj2
,mjd
,eps_rf
,FALSE
);
598 fprintf(stderr
,"\nAbsolute values:\n epsilon=%f\n",dk_s
);
599 fprintf(stderr
," <M_D^2> , <M_J^2>, <(M_J*M_D)^2>: (%f, %f, %f)\n\n",md2
,mj2
,mjd
);
600 fprintf(stderr
,"********************************************\n");
603 dk_f
=calceps(prefactor
,md2
-mdav2
,mj2
-mj
,mjd
-mjdav
,eps_rf
,FALSE
);
604 fprintf(stderr
,"\n\nFluctuations:\n epsilon=%f\n\n",dk_f
);
605 fprintf(stderr
,"\n deltaM_D , deltaM_J, deltaM_JD: (%f, %f, %f)\n",md2
-mdav2
,mj2
-mj
,mjd
-mjdav
);
606 fprintf(stderr
,"\n********************************************\n");
608 dk_d
=calceps(prefactor
,md2
-mdav2
,mj2
-mj
,corint
,eps_rf
,TRUE
);
609 fprintf(stderr
,"\nStatic dielectric constant using integral and fluctuations: %f\n",dk_d
);
610 fprintf(stderr
,"\n < M_JM_D > via integral: %.3f\n",-1.0*corint
);
613 fprintf(stderr
,"\n***************************************************");
614 fprintf(stderr
,"\n\nAverage volume V=%f nm^3 at T=%f K\n",volume_av
,temp
);
615 fprintf(stderr
,"and corresponding refactor 1.0 / 3.0*V*k_B*T*EPSILON_0: %f \n",prefactor
);
620 fprintf(stderr
,"Integral and integrated fit to the current acf yields at t=%f:\n",time
[vfr
[ii
]]);
621 fprintf(stderr
,"sigma=%8.3f (pure integral: %.3f)\n",sgk
-malt
*pow(time
[vfr
[ii
]],sigma
),sgk
);
625 fprintf(stderr
,"\nStart fit at %f ps (%f).\n",time
[bi
],bfit
);
626 fprintf(stderr
,"End fit at %f ps (%f).\n\n",time
[ei
],efit
);
636 lsq_y_ax_b(ei
-bi
,xfit
,yfit
,&sigma
,&malt
,&err
,&rest
);
639 dk_d
=calceps(prefactor
,md2
,0.5*malt
/prefactorav
,corint
,eps_rf
,TRUE
);
641 fprintf(stderr
,"Einstein-Helfand fit to the MSD of the translational dipole moment yields:\n\n");
642 fprintf(stderr
,"sigma=%.4f\n",sigma
);
643 fprintf(stderr
,"translational fraction of M^2: %.4f\n",0.5*malt
/prefactorav
);
644 fprintf(stderr
,"Dielectric constant using EH: %.4f\n",dk_d
);
650 fprintf(stderr
,"Too less points for a fit.\n");
670 int gmx_current(int argc
,char *argv
[])
673 static int nshift
=1000;
674 static real temp
=300.0;
675 static real trust
=0.25;
676 static real eps_rf
=0.0;
677 static gmx_bool bNoJump
=TRUE
;
678 static real bfit
=100.0;
679 static real bvit
=0.5;
680 static real efit
=400.0;
681 static real evit
=5.0;
683 { "-sh", FALSE
, etINT
, {&nshift
},
684 "Shift of the frames for averaging the correlation functions and the mean-square displacement."},
685 { "-nojump", FALSE
, etBOOL
, {&bNoJump
},
686 "Removes jumps of atoms across the box."},
687 { "-eps", FALSE
, etREAL
, {&eps_rf
},
688 "Dielectric constant of the surrounding medium. eps=0.0 corresponds to eps=infinity (thinfoil boundary conditions)."},
689 { "-bfit", FALSE
, etREAL
, {&bfit
},
690 "Begin of the fit of the straight line to the MSD of the translational fraction of the dipole moment."},
691 { "-efit", FALSE
, etREAL
, {&efit
},
692 "End of the fit of the straight line to the MSD of the translational fraction of the dipole moment."},
693 { "-bvit", FALSE
, etREAL
, {&bvit
},
694 "Begin of the fit of the current autocorrelation function to a*t^b."},
695 { "-evit", FALSE
, etREAL
, {&evit
},
696 "End of the fit of the current autocorrelation function to a*t^b."},
697 { "-tr", FALSE
, etREAL
, {&trust
},
698 "Fraction of the trajectory taken into account for the integral."},
699 { "-temp", FALSE
, etREAL
, {&temp
},
700 "Temperature for calculating epsilon."
713 atom_id
*index0
=NULL
;
739 { efTPS
, NULL
, NULL
, ffREAD
}, /* this is for the topology */
740 { efNDX
, NULL
, NULL
, ffOPTRD
},
741 { efTRX
, "-f", NULL
, ffREAD
}, /* and this for the trajectory */
742 { efXVG
, "-o", "current.xvg", ffWRITE
},
743 { efXVG
, "-caf", "caf.xvg", ffOPTWR
},
744 { efXVG
, "-dsp", "dsp.xvg", ffWRITE
},
745 { efXVG
, "-md", "md.xvg", ffWRITE
},
746 { efXVG
, "-mj", "mj.xvg", ffWRITE
},
747 { efXVG
, "-mc", "mc.xvg", ffOPTWR
}
750 #define NFILE asize(fnm)
753 const char *desc
[] = {
754 "This is a tool for calculating the current autocorrelation function, the correlation",
755 "of the rotational and translational dipole moment of the system, and the resulting static",
756 "dielectric constant. To obtain a reasonable result the index group has to be neutral.",
757 "Furthermore the routine is capable of extracting the static conductivity from the current ",
758 "autocorrelation function, if velocities are given. Additionally an Einstein-Helfand fit also",
759 "allows to get the static conductivity."
761 "The flag [TT]-caf[tt] is for the output of the current autocorrelation function and [TT]-mc[tt] writes the",
762 "correlation of the rotational and translational part of the dipole moment in the corresponding",
763 "file. However this option is only available for trajectories containing velocities.",
764 "Options [TT]-sh[tt] and [TT]-tr[tt] are responsible for the averaging and integration of the",
765 "autocorrelation functions. Since averaging proceeds by shifting the starting point",
766 "through the trajectory, the shift can be modified with [TT]-sh[tt] to enable the choice of uncorrelated",
767 "starting points. Towards the end, statistical inaccuracy grows and integrating the",
768 "correlation function only yields reliable values until a certain point, depending on",
769 "the number of frames. The option [TT]-tr[tt] controls the region of the integral taken into account",
770 "for calculating the static dielectric constant.",
772 "Option [TT]-temp[tt] sets the temperature required for the computation of the static dielectric constant.",
774 "Option [TT]-eps[tt] controls the dielectric constant of the surrounding medium for simulations using",
775 "a Reaction Field or dipole corrections of the Ewald summation (eps=0 corresponds to",
776 "tin-foil boundary conditions).",
778 "[TT]-[no]nojump[tt] unfolds the coordinates to allow free diffusion. This is required to get a continuous",
779 "translational dipole moment, required for the Einstein-Helfand fit. The resuls from the fit allow to",
780 "determine the dielectric constant for system of charged molecules. However it is also possible to extract",
781 "the dielectric constant from the fluctuations of the total dipole moment in folded coordinates. But this",
782 "options has to be used with care, since only very short time spans fulfill the approximation, that the density",
783 "of the molecules is approximately constant and the averages are already converged. To be on the safe side,",
784 "the dielectric constant should be calculated with the help of the Einstein-Helfand method for",
785 "the translational part of the dielectric constant."
789 /* At first the arguments will be parsed and the system information processed */
791 CopyRight(stderr
,argv
[0]);
793 parse_common_args(&argc
,argv
,PCA_CAN_TIME
| PCA_CAN_VIEW
,
794 NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,0,NULL
,&oenv
);
796 bACF
= opt2bSet("-caf",NFILE
,fnm
);
797 bINT
= opt2bSet("-mc",NFILE
,fnm
);
799 bTop
=read_tps_conf(ftp2fn(efTPS
,NFILE
,fnm
),title
,&top
,&ePBC
,&xtop
,&vtop
,box
,TRUE
);
805 indexfn
= ftp2fn_null(efNDX
,NFILE
,fnm
);
808 get_index(&(top
.atoms
),indexfn
,1,&isize
,&index0
,grpname
);
810 flags
= flags
| TRX_READ_X
| TRX_READ_V
;
812 read_first_frame(oenv
,&status
,ftp2fn(efTRX
,NFILE
,fnm
),&fr
,flags
);
814 snew(mass2
,top
.atoms
.nr
);
815 snew(qmol
,top
.atoms
.nr
);
817 bNEU
=precalc(top
,mass2
,qmol
);
828 index_atom2mol(&nmols
,indexm
,&top
.mols
);
832 outf
=xvgropen(opt2fn("-caf",NFILE
,fnm
),
833 "Current autocorrelation function",output_env_get_xvgr_tlabel(oenv
),
834 "ACF (e nm/ps)\\S2",oenv
);
835 fprintf(outf
,"# time\t acf\t average \t std.dev\n");
837 fcur
=xvgropen(opt2fn("-o",NFILE
,fnm
),
838 "Current",output_env_get_xvgr_tlabel(oenv
),"J(t) (e nm/ps)",oenv
);
839 fprintf(fcur
,"# time\t Jx\t Jy \t J_z \n");
841 mcor
= xvgropen(opt2fn("-mc",NFILE
,fnm
),
842 "M\\sD\\N - current autocorrelation function",
843 output_env_get_xvgr_tlabel(oenv
),
844 "< M\\sD\\N (0)\\c7\\CJ(t) > (e nm/ps)\\S2",oenv
);
845 fprintf(mcor
,"# time\t M_D(0) J(t) acf \t Integral acf\n");
849 fmj
= xvgropen(opt2fn("-mj",NFILE
,fnm
),
850 "Averaged translational part of M",output_env_get_xvgr_tlabel(oenv
),
851 "< M\\sJ\\N > (enm)",oenv
);
852 fprintf(fmj
,"# time\t x\t y \t z \t average of M_J^2 \t std.dev\n");
853 fmd
= xvgropen(opt2fn("-md",NFILE
,fnm
),
854 "Averaged rotational part of M",output_env_get_xvgr_tlabel(oenv
),
855 "< M\\sD\\N > (enm)",oenv
);
856 fprintf(fmd
,"# time\t x\t y \t z \t average of M_D^2 \t std.dev\n");
858 fmjdsp
= xvgropen(opt2fn("-dsp",NFILE
,fnm
),
859 "MSD of the squared translational dipole moment M",
860 output_env_get_xvgr_tlabel(oenv
),
861 "<|M\\sJ\\N(t)-M\\sJ\\N(0)|\\S2\\N > / 6.0*V*k\\sB\\N*T / Sm\\S-1\\Nps\\S-1\\N",
865 /* System information is read and prepared, dielectric() processes the frames
866 * and calculates the requested quantities */
868 dielectric(fmj
,fmd
,outf
,fcur
,mcor
,fmjdsp
,bNoJump
,bACF
,bINT
,ePBC
,top
,fr
,
869 temp
,trust
, bfit
,efit
,bvit
,evit
,status
,isize
,nmols
,nshift
,
870 index0
,indexm
,mass2
,qmol
,eps_rf
,oenv
);