2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2008,2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
40 #include "gromacs/commandline/pargs.h"
41 #include "gromacs/fileio/confio.h"
42 #include "gromacs/fileio/trxio.h"
43 #include "gromacs/fileio/xvgr.h"
44 #include "gromacs/gmxana/gmx_ana.h"
45 #include "gromacs/legacyheaders/macros.h"
46 #include "gromacs/legacyheaders/typedefs.h"
47 #include "gromacs/math/units.h"
48 #include "gromacs/math/vec.h"
49 #include "gromacs/pbcutil/pbc.h"
50 #include "gromacs/pbcutil/rmpbc.h"
51 #include "gromacs/statistics/statistics.h"
52 #include "gromacs/topology/index.h"
53 #include "gromacs/utility/cstringutil.h"
54 #include "gromacs/utility/fatalerror.h"
55 #include "gromacs/utility/gmxassert.h"
56 #include "gromacs/utility/smalloc.h"
58 #define EPSI0 (EPSILON0*E_CHARGE*E_CHARGE*AVOGADRO/(KILO*NANO)) /* EPSILON0 in SI units */
60 static void index_atom2mol(int *n, int *index, t_block *mols)
62 int nat, i, nmol, mol, j;
70 while (index[i] > mols->index[mol])
75 gmx_fatal(FARGS, "Atom index out of range: %d", index[i]+1);
78 for (j = mols->index[mol]; j < mols->index[mol+1]; j++)
80 if (i >= nat || index[i] != j)
82 gmx_fatal(FARGS, "The index group does not consist of whole molecules");
89 fprintf(stderr, "\nSplit group of %d atoms into %d molecules\n", nat, nmol);
94 static gmx_bool precalc(t_topology top, real mass2[], real qmol[])
109 for (i = 0; i < top.mols.nr; i++)
111 k = top.mols.index[i];
112 l = top.mols.index[i+1];
116 for (j = k; j < l; j++)
118 mtot += top.atoms.atom[j].m;
119 qtot += top.atoms.atom[j].q;
122 for (j = k; j < l; j++)
124 top.atoms.atom[j].q -= top.atoms.atom[j].m*qtot/mtot;
125 mass2[j] = top.atoms.atom[j].m/mtot;
142 if (std::abs(qall) > 0.01)
144 printf("\n\nSystem not neutral (q=%f) will not calculate translational part of the dipole moment.\n", qall);
156 static void remove_jump(matrix box, int natoms, rvec xp[], rvec x[])
162 for (d = 0; d < DIM; d++)
164 hbox[d] = 0.5*box[d][d];
166 for (i = 0; i < natoms; i++)
168 for (m = DIM-1; m >= 0; m--)
170 while (x[i][m]-xp[i][m] <= -hbox[m])
172 for (d = 0; d <= m; d++)
174 x[i][d] += box[m][d];
177 while (x[i][m]-xp[i][m] > hbox[m])
179 for (d = 0; d <= m; d++)
181 x[i][d] -= box[m][d];
188 static void calc_mj(t_topology top, int ePBC, matrix box, gmx_bool bNoJump, int isize, int index0[], \
189 rvec fr[], rvec mj, real mass2[], real qmol[])
199 calc_box_center(ecenterRECT, box, center);
203 set_pbc(&pbc, ePBC, box);
209 for (i = 0; i < isize; i++)
213 k = top.mols.index[index0[i]];
214 l = top.mols.index[index0[i+1]];
215 for (j = k; j < l; j++)
217 svmul(mass2[j], fr[j], tmp);
223 svmul(qmol[k], mt1, mt1);
227 pbc_dx(&pbc, mt1, center, mt2);
228 svmul(qmol[k], mt2, mt1);
238 static real calceps(real prefactor, real md2, real mj2, real cor, real eps_rf, gmx_bool bCOR)
241 /* bCOR determines if the correlation is computed via
242 * static properties (FALSE) or the correlation integral (TRUE)
250 epsilon = md2-2.0*cor+mj2;
254 epsilon = md2+mj2+2.0*cor;
259 epsilon = 1.0+prefactor*epsilon;
264 epsilon = 2.0*eps_rf+1.0+2.0*eps_rf*prefactor*epsilon;
265 epsilon /= 2.0*eps_rf+1.0-prefactor*epsilon;
274 static real calc_cacf(FILE *fcacf, real prefactor, real cacf[], real time[], int nfr, int vfr[], int ei, int nshift)
281 real sigma_ret = 0.0;
291 rfr = static_cast<real>(nfr+i)/nshift;
294 if (time[vfr[i]] <= time[vfr[ei]])
299 fprintf(fcacf, "%.3f\t%10.6g\t%10.6g\n", time[vfr[i]], cacf[i], sigma);
303 deltat = (time[vfr[i+1]]-time[vfr[i]]);
305 corint = 2.0*deltat*cacf[i]*prefactor;
306 if (i == 0 || (i+1) == nfr)
318 printf("Too less points.\n");
325 static void calc_mjdsp(FILE *fmjdsp, real prefactor, real dsp2[], real time[], int nfr, real refr[])
330 fprintf(fmjdsp, "#Prefactor fit E-H: 1 / 6.0*V*k_B*T: %g\n", prefactor);
332 for (i = 0; i < nfr; i++)
337 dsp2[i] *= prefactor/refr[i];
338 fprintf(fmjdsp, "%.3f\t%10.6g\n", time[i], dsp2[i]);
347 static void dielectric(FILE *fmj, FILE *fmd, FILE *outf, FILE *fcur, FILE *mcor,
348 FILE *fmjdsp, gmx_bool bNoJump, gmx_bool bACF, gmx_bool bINT,
349 int ePBC, t_topology top, t_trxframe fr, real temp,
350 real bfit, real efit, real bvit, real evit,
351 t_trxstatus *status, int isize, int nmols, int nshift,
352 atom_id *index0, int indexm[], real mass2[],
353 real qmol[], real eps_rf, const output_env_t oenv)
356 int valloc, nalloc, nfr, nvfr;
365 real prefactorav = 0.0;
366 real prefactor = 0.0;
368 real volume_av = 0.0;
369 real dk_s, dk_d, dk_f;
392 * Variables for the least-squares fit for Einstein-Helfand and Green-Kubo
402 gmx_rmpbc_t gpbc = NULL;
421 /* This is the main loop over frames */
436 gpbc = gmx_rmpbc_init(&top.idef, ePBC, fr.natoms);
446 srenew(time, nalloc);
448 srenew(mjdsp, nalloc);
449 srenew(dsp2, nalloc);
450 srenew(mtrans, nalloc);
451 srenew(xshfr, nalloc);
453 for (i = nfr; i < nalloc; i++)
455 clear_rvec(mjdsp[i]);
457 clear_rvec(mtrans[i]);
462 GMX_RELEASE_ASSERT(time != NULL, "Memory not allocated correctly - time array is NULL");
470 time[nfr] = fr.time-t0;
472 if (time[nfr] <= bfit)
476 if (time[nfr] <= efit)
486 remove_jump(fr.box, fr.natoms, xp, fr.x);
493 for (i = 0; i < fr.natoms; i++)
495 copy_rvec(fr.x[i], xp[i]);
500 gmx_rmpbc_trxfr(gpbc, &fr);
502 calc_mj(top, ePBC, fr.box, bNoJump, nmols, indexm, fr.x, mtrans[nfr], mass2, qmol);
504 for (i = 0; i < isize; i++)
507 svmul(top.atoms.atom[j].q, fr.x[j], fr.x[j]);
508 rvec_inc(mu[nfr], fr.x[j]);
511 /*if(mod(nfr,nshift)==0){*/
514 for (j = nfr; j >= 0; j--)
516 rvec_sub(mtrans[nfr], mtrans[j], tmp);
517 dsp2[nfr-j] += norm2(tmp);
535 srenew(cacf, valloc);
538 if (time[nfr] <= bvit)
542 if (time[nfr] <= evit)
547 clear_rvec(v0[nvfr]);
556 for (i = 0; i < isize; i++)
559 svmul(mass2[j], fr.v[j], fr.v[j]);
560 svmul(qmol[j], fr.v[j], fr.v[j]);
561 rvec_inc(v0[nvfr], fr.v[j]);
564 fprintf(fcur, "%.3f\t%.6f\t%.6f\t%.6f\n", time[nfr], v0[nfr][XX], v0[nfr][YY], v0[nfr][ZZ]);
567 /*if(mod(nvfr,nshift)==0){*/
568 if (nvfr%nshift == 0)
570 for (j = nvfr; j >= 0; j--)
574 cacf[nvfr-j] += iprod(v0[nvfr], v0[j]);
578 djc[nvfr-j] += iprod(mu[vfr[j]], v0[nvfr]);
587 volume = det(fr.box);
590 rvec_inc(mja_tmp, mtrans[nfr]);
591 mjd += iprod(mu[nfr], mtrans[nfr]);
592 rvec_inc(mdvec, mu[nfr]);
594 mj2 += iprod(mtrans[nfr], mtrans[nfr]);
595 md2 += iprod(mu[nfr], mu[nfr]);
597 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);
598 fprintf(fmd, "%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n", \
599 time[nfr], mu[nfr][XX], mu[nfr][YY], mu[nfr][ZZ], md2/refr, norm(mdvec)/refr);
604 while (read_next_frame(oenv, status, &fr));
606 gmx_rmpbc_done(gpbc);
611 prefactor /= 3.0*EPSILON0*volume_av*BOLTZ*temp;
614 prefactorav = E_CHARGE*E_CHARGE;
615 prefactorav /= volume_av*BOLTZMANN*temp*NANO*6.0;
617 fprintf(stderr, "Prefactor fit E-H: 1 / 6.0*V*k_B*T: %g\n", prefactorav);
619 calc_mjdsp(fmjdsp, prefactorav, dsp2, time, nfr, xshfr);
622 * Now we can average and calculate the correlation functions
630 svmul(1.0/refr, mdvec, mdvec);
631 svmul(1.0/refr, mja_tmp, mja_tmp);
633 mdav2 = norm2(mdvec);
635 mjdav = iprod(mdvec, mja_tmp);
638 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);
639 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);
646 printf("\nCalculating M_D - current correlation integral ... \n");
647 corint = calc_cacf(mcor, prefactorav/EPSI0, djc, time, nvfr, vfr, ie, nshift);
654 printf("\nCalculating current autocorrelation ... \n");
655 sgk = calc_cacf(outf, prefactorav/PICO, cacf, time, nvfr, vfr, ie, nshift);
663 for (i = ii; i <= ie; i++)
666 xfit[i-ii] = std::log(time[vfr[i]]);
667 rtmp = std::abs(cacf[i]);
668 yfit[i-ii] = std::log(rtmp);
672 lsq_y_ax_b(ie-ii, xfit, yfit, &sigma, &malt, &err, &rest);
674 malt = std::exp(malt);
678 malt *= prefactorav*2.0e12/sigma;
688 /* Calculation of the dielectric constant */
690 fprintf(stderr, "\n********************************************\n");
691 dk_s = calceps(prefactor, md2, mj2, mjd, eps_rf, FALSE);
692 fprintf(stderr, "\nAbsolute values:\n epsilon=%f\n", dk_s);
693 fprintf(stderr, " <M_D^2> , <M_J^2>, <(M_J*M_D)^2>: (%f, %f, %f)\n\n", md2, mj2, mjd);
694 fprintf(stderr, "********************************************\n");
697 dk_f = calceps(prefactor, md2-mdav2, mj2-mj, mjd-mjdav, eps_rf, FALSE);
698 fprintf(stderr, "\n\nFluctuations:\n epsilon=%f\n\n", dk_f);
699 fprintf(stderr, "\n deltaM_D , deltaM_J, deltaM_JD: (%f, %f, %f)\n", md2-mdav2, mj2-mj, mjd-mjdav);
700 fprintf(stderr, "\n********************************************\n");
703 dk_d = calceps(prefactor, md2-mdav2, mj2-mj, corint, eps_rf, TRUE);
704 fprintf(stderr, "\nStatic dielectric constant using integral and fluctuations: %f\n", dk_d);
705 fprintf(stderr, "\n < M_JM_D > via integral: %.3f\n", -1.0*corint);
708 fprintf(stderr, "\n***************************************************");
709 fprintf(stderr, "\n\nAverage volume V=%f nm^3 at T=%f K\n", volume_av, temp);
710 fprintf(stderr, "and corresponding refactor 1.0 / 3.0*V*k_B*T*EPSILON_0: %f \n", prefactor);
714 if (bACF && (ii < nvfr))
716 fprintf(stderr, "Integral and integrated fit to the current acf yields at t=%f:\n", time[vfr[ii]]);
717 fprintf(stderr, "sigma=%8.3f (pure integral: %.3f)\n", sgk-malt*std::pow(time[vfr[ii]], sigma), sgk);
722 fprintf(stderr, "\nStart fit at %f ps (%f).\n", time[bi], bfit);
723 fprintf(stderr, "End fit at %f ps (%f).\n\n", time[ei], efit);
728 for (i = bi; i <= ei; i++)
730 xfit[i-bi] = time[i];
731 yfit[i-bi] = dsp2[i];
734 lsq_y_ax_b(ei-bi, xfit, yfit, &sigma, &malt, &err, &rest);
737 dk_d = calceps(prefactor, md2, 0.5*malt/prefactorav, corint, eps_rf, TRUE);
739 fprintf(stderr, "Einstein-Helfand fit to the MSD of the translational dipole moment yields:\n\n");
740 fprintf(stderr, "sigma=%.4f\n", sigma);
741 fprintf(stderr, "translational fraction of M^2: %.4f\n", 0.5*malt/prefactorav);
742 fprintf(stderr, "Dielectric constant using EH: %.4f\n", dk_d);
749 fprintf(stderr, "Too few points for a fit.\n");
775 int gmx_current(int argc, char *argv[])
778 static int nshift = 1000;
779 static real temp = 300.0;
780 static real eps_rf = 0.0;
781 static gmx_bool bNoJump = TRUE;
782 static real bfit = 100.0;
783 static real bvit = 0.5;
784 static real efit = 400.0;
785 static real evit = 5.0;
787 { "-sh", FALSE, etINT, {&nshift},
788 "Shift of the frames for averaging the correlation functions and the mean-square displacement."},
789 { "-nojump", FALSE, etBOOL, {&bNoJump},
790 "Removes jumps of atoms across the box."},
791 { "-eps", FALSE, etREAL, {&eps_rf},
792 "Dielectric constant of the surrounding medium. The value zero corresponds to infinity (tin-foil boundary conditions)."},
793 { "-bfit", FALSE, etREAL, {&bfit},
794 "Begin of the fit of the straight line to the MSD of the translational fraction of the dipole moment."},
795 { "-efit", FALSE, etREAL, {&efit},
796 "End of the fit of the straight line to the MSD of the translational fraction of the dipole moment."},
797 { "-bvit", FALSE, etREAL, {&bvit},
798 "Begin of the fit of the current autocorrelation function to a*t^b."},
799 { "-evit", FALSE, etREAL, {&evit},
800 "End of the fit of the current autocorrelation function to a*t^b."},
801 { "-temp", FALSE, etREAL, {&temp},
802 "Temperature for calculating epsilon."}
808 char **grpname = NULL;
832 { efTPS, NULL, NULL, ffREAD }, /* this is for the topology */
833 { efNDX, NULL, NULL, ffOPTRD },
834 { efTRX, "-f", NULL, ffREAD }, /* and this for the trajectory */
835 { efXVG, "-o", "current", ffWRITE },
836 { efXVG, "-caf", "caf", ffOPTWR },
837 { efXVG, "-dsp", "dsp", ffWRITE },
838 { efXVG, "-md", "md", ffWRITE },
839 { efXVG, "-mj", "mj", ffWRITE },
840 { efXVG, "-mc", "mc", ffOPTWR }
843 #define NFILE asize(fnm)
846 const char *desc[] = {
847 "[THISMODULE] is a tool for calculating the current autocorrelation function, the correlation",
848 "of the rotational and translational dipole moment of the system, and the resulting static",
849 "dielectric constant. To obtain a reasonable result, the index group has to be neutral.",
850 "Furthermore, the routine is capable of extracting the static conductivity from the current ",
851 "autocorrelation function, if velocities are given. Additionally, an Einstein-Helfand fit ",
852 "can be used to obtain the static conductivity."
854 "The flag [TT]-caf[tt] is for the output of the current autocorrelation function and [TT]-mc[tt] writes the",
855 "correlation of the rotational and translational part of the dipole moment in the corresponding",
856 "file. However, this option is only available for trajectories containing velocities.",
857 "Options [TT]-sh[tt] and [TT]-tr[tt] are responsible for the averaging and integration of the",
858 "autocorrelation functions. Since averaging proceeds by shifting the starting point",
859 "through the trajectory, the shift can be modified with [TT]-sh[tt] to enable the choice of uncorrelated",
860 "starting points. Towards the end, statistical inaccuracy grows and integrating the",
861 "correlation function only yields reliable values until a certain point, depending on",
862 "the number of frames. The option [TT]-tr[tt] controls the region of the integral taken into account",
863 "for calculating the static dielectric constant.",
865 "Option [TT]-temp[tt] sets the temperature required for the computation of the static dielectric constant.",
867 "Option [TT]-eps[tt] controls the dielectric constant of the surrounding medium for simulations using",
868 "a Reaction Field or dipole corrections of the Ewald summation ([TT]-eps[tt]\\=0 corresponds to",
869 "tin-foil boundary conditions).",
871 "[TT]-[no]nojump[tt] unfolds the coordinates to allow free diffusion. This is required to get a continuous",
872 "translational dipole moment, required for the Einstein-Helfand fit. The results from the fit allow",
873 "the determination of the dielectric constant for system of charged molecules. However, it is also possible to extract",
874 "the dielectric constant from the fluctuations of the total dipole moment in folded coordinates. But this",
875 "option has to be used with care, since only very short time spans fulfill the approximation that the density",
876 "of the molecules is approximately constant and the averages are already converged. To be on the safe side,",
877 "the dielectric constant should be calculated with the help of the Einstein-Helfand method for",
878 "the translational part of the dielectric constant."
882 /* At first the arguments will be parsed and the system information processed */
883 if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW,
884 NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
889 bACF = opt2bSet("-caf", NFILE, fnm);
890 bINT = opt2bSet("-mc", NFILE, fnm);
892 read_tps_conf(ftp2fn(efTPS, NFILE, fnm), title, &top, &ePBC, &xtop, &vtop, box, TRUE);
898 indexfn = ftp2fn_null(efNDX, NFILE, fnm);
901 get_index(&(top.atoms), indexfn, 1, &isize, &index0, grpname);
903 flags = flags | TRX_READ_X | TRX_READ_V;
905 read_first_frame(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &fr, flags);
907 snew(mass2, top.atoms.nr);
908 snew(qmol, top.atoms.nr);
910 precalc(top, mass2, qmol);
915 for (i = 0; i < isize; i++)
917 indexm[i] = index0[i];
923 index_atom2mol(&nmols, indexm, &top.mols);
929 outf = xvgropen(opt2fn("-caf", NFILE, fnm),
930 "Current autocorrelation function", output_env_get_xvgr_tlabel(oenv),
931 "ACF (e nm/ps)\\S2", oenv);
932 fprintf(outf, "# time\t acf\t average \t std.dev\n");
934 fcur = xvgropen(opt2fn("-o", NFILE, fnm),
935 "Current", output_env_get_xvgr_tlabel(oenv), "J(t) (e nm/ps)", oenv);
936 fprintf(fcur, "# time\t Jx\t Jy \t J_z \n");
939 mcor = xvgropen(opt2fn("-mc", NFILE, fnm),
940 "M\\sD\\N - current autocorrelation function",
941 output_env_get_xvgr_tlabel(oenv),
942 "< M\\sD\\N (0)\\c7\\CJ(t) > (e nm/ps)\\S2", oenv);
943 fprintf(mcor, "# time\t M_D(0) J(t) acf \t Integral acf\n");
947 fmj = xvgropen(opt2fn("-mj", NFILE, fnm),
948 "Averaged translational part of M", output_env_get_xvgr_tlabel(oenv),
949 "< M\\sJ\\N > (enm)", oenv);
950 fprintf(fmj, "# time\t x\t y \t z \t average of M_J^2 \t std.dev\n");
951 fmd = xvgropen(opt2fn("-md", NFILE, fnm),
952 "Averaged rotational part of M", output_env_get_xvgr_tlabel(oenv),
953 "< M\\sD\\N > (enm)", oenv);
954 fprintf(fmd, "# time\t x\t y \t z \t average of M_D^2 \t std.dev\n");
956 fmjdsp = xvgropen(opt2fn("-dsp", NFILE, fnm),
957 "MSD of the squared translational dipole moment M",
958 output_env_get_xvgr_tlabel(oenv),
959 "<|M\\sJ\\N(t)-M\\sJ\\N(0)|\\S2\\N > / 6.0*V*k\\sB\\N*T / Sm\\S-1\\Nps\\S-1\\N",
963 /* System information is read and prepared, dielectric() processes the frames
964 * and calculates the requested quantities */
966 dielectric(fmj, fmd, outf, fcur, mcor, fmjdsp, bNoJump, bACF, bINT, ePBC, top, fr,
967 temp, bfit, efit, bvit, evit, status, isize, nmols, nshift,
968 index0, indexm, mass2, qmol, eps_rf, oenv);