Update instructions in containers.rst
[gromacs.git] / src / gromacs / gmxana / gmx_current.cpp
blob067f46c797df0162caf343c1733dd9b0304cfa5c
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2008,2009,2010,2011,2012 by the GROMACS development team.
5 * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
6 * Copyright (c) 2019,2020, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 #include "gmxpre.h"
39 #include <cmath>
40 #include <cstdlib>
42 #include "gromacs/commandline/pargs.h"
43 #include "gromacs/fileio/confio.h"
44 #include "gromacs/fileio/trxio.h"
45 #include "gromacs/fileio/xvgr.h"
46 #include "gromacs/gmxana/gmx_ana.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/topology/topology.h"
54 #include "gromacs/trajectory/trajectoryframe.h"
55 #include "gromacs/utility/arraysize.h"
56 #include "gromacs/utility/cstringutil.h"
57 #include "gromacs/utility/fatalerror.h"
58 #include "gromacs/utility/gmxassert.h"
59 #include "gromacs/utility/smalloc.h"
61 #define EPSI0 (EPSILON0 * E_CHARGE * E_CHARGE * AVOGADRO / (KILO * NANO)) /* EPSILON0 in SI units */
63 static void index_atom2mol(int* n, int* index, t_block* mols)
65 int nat, i, nmol, mol, j;
67 nat = *n;
68 i = 0;
69 nmol = 0;
70 mol = 0;
71 while (i < nat)
73 while (index[i] > mols->index[mol])
75 mol++;
76 if (mol >= mols->nr)
78 gmx_fatal(FARGS, "Atom index out of range: %d", index[i] + 1);
81 for (j = mols->index[mol]; j < mols->index[mol + 1]; j++)
83 if (i >= nat || index[i] != j)
85 gmx_fatal(FARGS, "The index group does not consist of whole molecules");
87 i++;
89 index[nmol++] = mol;
92 fprintf(stderr, "\nSplit group of %d atoms into %d molecules\n", nat, nmol);
94 *n = nmol;
97 static gmx_bool precalc(t_topology top, real mass2[], real qmol[])
100 real mtot;
101 real qtot;
102 real qall;
103 int i, j, k, l;
104 int ai, ci;
105 gmx_bool bNEU;
106 ai = 0;
107 ci = 0;
108 qall = 0.0;
111 for (i = 0; i < top.mols.nr; i++)
113 k = top.mols.index[i];
114 l = top.mols.index[i + 1];
115 mtot = 0.0;
116 qtot = 0.0;
118 for (j = k; j < l; j++)
120 mtot += top.atoms.atom[j].m;
121 qtot += top.atoms.atom[j].q;
124 for (j = k; j < l; j++)
126 top.atoms.atom[j].q -= top.atoms.atom[j].m * qtot / mtot;
127 mass2[j] = top.atoms.atom[j].m / mtot;
128 qmol[j] = qtot;
132 qall += qtot;
134 if (qtot < 0.0)
136 ai++;
138 if (qtot > 0.0)
140 ci++;
144 if (std::abs(qall) > 0.01)
146 printf("\n\nSystem not neutral (q=%f) will not calculate translational part of the dipole "
147 "moment.\n",
148 qall);
149 bNEU = FALSE;
151 else
153 bNEU = TRUE;
156 return bNEU;
159 static void remove_jump(matrix box, int natoms, rvec xp[], rvec x[])
162 rvec hbox;
163 int d, i, m;
165 for (d = 0; d < DIM; d++)
167 hbox[d] = 0.5 * box[d][d];
169 for (i = 0; i < natoms; i++)
171 for (m = DIM - 1; m >= 0; m--)
173 while (x[i][m] - xp[i][m] <= -hbox[m])
175 for (d = 0; d <= m; d++)
177 x[i][d] += box[m][d];
180 while (x[i][m] - xp[i][m] > hbox[m])
182 for (d = 0; d <= m; d++)
184 x[i][d] -= box[m][d];
191 static void calc_mj(t_topology top,
192 PbcType pbcType,
193 matrix box,
194 gmx_bool bNoJump,
195 int isize,
196 const int index0[],
197 rvec fr[],
198 rvec mj,
199 real mass2[],
200 real qmol[])
203 int i, j, k, l;
204 rvec tmp;
205 rvec center;
206 rvec mt1, mt2;
207 t_pbc pbc;
210 calc_box_center(ecenterRECT, box, center);
212 if (!bNoJump)
214 set_pbc(&pbc, pbcType, box);
217 clear_rvec(tmp);
220 for (i = 0; i < isize; i++)
222 clear_rvec(mt1);
223 clear_rvec(mt2);
224 k = top.mols.index[index0[i]];
225 l = top.mols.index[index0[i + 1]];
226 for (j = k; j < l; j++)
228 svmul(mass2[j], fr[j], tmp);
229 rvec_inc(mt1, tmp);
232 if (bNoJump)
234 svmul(qmol[k], mt1, mt1);
236 else
238 pbc_dx(&pbc, mt1, center, mt2);
239 svmul(qmol[k], mt2, mt1);
242 rvec_inc(mj, mt1);
247 static real calceps(real prefactor, real md2, real mj2, real cor, real eps_rf, gmx_bool bCOR)
250 /* bCOR determines if the correlation is computed via
251 * static properties (FALSE) or the correlation integral (TRUE)
254 real epsilon = 0.0;
257 if (bCOR)
259 epsilon = md2 - 2.0 * cor + mj2;
261 else
263 epsilon = md2 + mj2 + 2.0 * cor;
266 if (eps_rf == 0.0)
268 epsilon = 1.0 + prefactor * epsilon;
270 else
272 epsilon = 2.0 * eps_rf + 1.0 + 2.0 * eps_rf * prefactor * epsilon;
273 epsilon /= 2.0 * eps_rf + 1.0 - prefactor * epsilon;
277 return epsilon;
281 static real calc_cacf(FILE* fcacf, real prefactor, real cacf[], real time[], int nfr, const int vfr[], int ei, int nshift)
284 int i;
285 real deltat = 0.0;
286 real rfr;
287 real sigma = 0.0;
288 real sigma_ret = 0.0;
290 if (nfr > 1)
292 i = 0;
294 while (i < nfr)
296 real corint;
298 rfr = static_cast<real>(nfr + i) / nshift;
299 cacf[i] /= rfr;
301 if (time[vfr[i]] <= time[vfr[ei]])
303 sigma_ret = sigma;
306 fprintf(fcacf, "%.3f\t%10.6g\t%10.6g\n", time[vfr[i]], cacf[i], sigma);
308 if ((i + 1) < nfr)
310 deltat = (time[vfr[i + 1]] - time[vfr[i]]);
312 corint = 2.0 * deltat * cacf[i] * prefactor;
313 if (i == 0 || (i + 1) == nfr)
315 corint *= 0.5;
317 sigma += corint;
319 i++;
322 else
324 printf("Too less points.\n");
327 return sigma_ret;
330 static void calc_mjdsp(FILE* fmjdsp, real prefactor, real dsp2[], real time[], int nfr, const real refr[])
333 int i;
335 fprintf(fmjdsp, "#Prefactor fit E-H: 1 / 6.0*V*k_B*T: %g\n", prefactor);
337 for (i = 0; i < nfr; i++)
340 if (refr[i] != 0.0)
342 dsp2[i] *= prefactor / refr[i];
343 fprintf(fmjdsp, "%.3f\t%10.6g\n", time[i], dsp2[i]);
349 static void dielectric(FILE* fmj,
350 FILE* fmd,
351 FILE* outf,
352 FILE* fcur,
353 FILE* mcor,
354 FILE* fmjdsp,
355 gmx_bool bNoJump,
356 gmx_bool bACF,
357 gmx_bool bINT,
358 PbcType pbcType,
359 t_topology top,
360 t_trxframe fr,
361 real temp,
362 real bfit,
363 real efit,
364 real bvit,
365 real evit,
366 t_trxstatus* status,
367 int isize,
368 int nmols,
369 int nshift,
370 const int* index0,
371 int indexm[],
372 real mass2[],
373 real qmol[],
374 real eps_rf,
375 const gmx_output_env_t* oenv)
377 int i, j;
378 int valloc, nalloc, nfr, nvfr;
379 int vshfr;
380 real* xshfr = nullptr;
381 int* vfr = nullptr;
382 real refr = 0.0;
383 real* cacf = nullptr;
384 real* time = nullptr;
385 real* djc = nullptr;
386 real corint = 0.0;
387 real prefactorav = 0.0;
388 real prefactor = 0.0;
389 real volume;
390 real volume_av = 0.0;
391 real dk_s, dk_d, dk_f;
392 real mj = 0.0;
393 real mj2 = 0.0;
394 real mjd = 0.0;
395 real mjdav = 0.0;
396 real md2 = 0.0;
397 real mdav2 = 0.0;
398 real sgk;
399 rvec mja_tmp;
400 rvec mjd_tmp;
401 rvec mdvec;
402 rvec* mu = nullptr;
403 rvec* xp = nullptr;
404 rvec* v0 = nullptr;
405 rvec* mjdsp = nullptr;
406 real* dsp2 = nullptr;
407 real t0;
408 real rtmp;
410 rvec tmp;
411 rvec* mtrans = nullptr;
414 * Variables for the least-squares fit for Einstein-Helfand and Green-Kubo
417 int bi, ei, ie, ii;
418 real rest = 0.0;
419 real sigma = 0.0;
420 real malt = 0.0;
421 real err = 0.0;
422 real* xfit;
423 real* yfit;
424 gmx_rmpbc_t gpbc = nullptr;
427 * indices for EH
430 ei = 0;
431 bi = 0;
434 * indices for GK
437 ii = 0;
438 ie = 0;
439 t0 = 0;
440 sgk = 0.0;
443 /* This is the main loop over frames */
446 nfr = 0;
449 nvfr = 0;
450 vshfr = 0;
451 nalloc = 0;
452 valloc = 0;
454 clear_rvec(mja_tmp);
455 clear_rvec(mjd_tmp);
456 clear_rvec(mdvec);
457 clear_rvec(tmp);
458 gpbc = gmx_rmpbc_init(&top.idef, pbcType, fr.natoms);
463 refr = (nfr + 1);
465 if (nfr >= nalloc)
467 nalloc += 100;
468 srenew(time, nalloc);
469 srenew(mu, nalloc);
470 srenew(mjdsp, nalloc);
471 srenew(dsp2, nalloc);
472 srenew(mtrans, nalloc);
473 srenew(xshfr, nalloc);
475 for (i = nfr; i < nalloc; i++)
477 clear_rvec(mjdsp[i]);
478 clear_rvec(mu[i]);
479 clear_rvec(mtrans[i]);
480 dsp2[i] = 0.0;
481 xshfr[i] = 0.0;
484 GMX_RELEASE_ASSERT(time != nullptr, "Memory not allocated correctly - time array is NULL");
486 if (nfr == 0)
488 t0 = fr.time;
491 time[nfr] = fr.time - t0;
493 if (time[nfr] <= bfit)
495 bi = nfr;
497 if (time[nfr] <= efit)
499 ei = nfr;
502 if (bNoJump)
505 if (xp)
507 remove_jump(fr.box, fr.natoms, xp, fr.x);
509 else
511 snew(xp, fr.natoms);
514 for (i = 0; i < fr.natoms; i++)
516 copy_rvec(fr.x[i], xp[i]);
520 gmx_rmpbc_trxfr(gpbc, &fr);
522 calc_mj(top, pbcType, fr.box, bNoJump, nmols, indexm, fr.x, mtrans[nfr], mass2, qmol);
524 for (i = 0; i < isize; i++)
526 j = index0[i];
527 svmul(top.atoms.atom[j].q, fr.x[j], fr.x[j]);
528 rvec_inc(mu[nfr], fr.x[j]);
531 /*if(mod(nfr,nshift)==0){*/
532 if (nfr % nshift == 0)
534 for (j = nfr; j >= 0; j--)
536 rvec_sub(mtrans[nfr], mtrans[j], tmp);
537 dsp2[nfr - j] += norm2(tmp);
538 xshfr[nfr - j] += 1.0;
542 if (fr.bV)
544 if (nvfr >= valloc)
546 valloc += 100;
547 srenew(vfr, valloc);
548 if (bINT)
550 srenew(djc, valloc);
552 srenew(v0, valloc);
553 if (bACF)
555 srenew(cacf, valloc);
558 if (time[nfr] <= bvit)
560 ii = nvfr;
562 if (time[nfr] <= evit)
564 ie = nvfr;
566 vfr[nvfr] = nfr;
567 clear_rvec(v0[nvfr]);
568 if (bACF)
570 cacf[nvfr] = 0.0;
572 if (bINT)
574 djc[nvfr] = 0.0;
576 for (i = 0; i < isize; i++)
578 j = index0[i];
579 svmul(mass2[j], fr.v[j], fr.v[j]);
580 svmul(qmol[j], fr.v[j], fr.v[j]);
581 rvec_inc(v0[nvfr], fr.v[j]);
584 fprintf(fcur, "%.3f\t%.6f\t%.6f\t%.6f\n", time[nfr], v0[nfr][XX], v0[nfr][YY], v0[nfr][ZZ]);
585 if (bACF || bINT)
587 /*if(mod(nvfr,nshift)==0){*/
588 if (nvfr % nshift == 0)
590 for (j = nvfr; j >= 0; j--)
592 if (bACF)
594 cacf[nvfr - j] += iprod(v0[nvfr], v0[j]);
596 if (bINT)
598 djc[nvfr - j] += iprod(mu[vfr[j]], v0[nvfr]);
601 vshfr++;
604 nvfr++;
607 volume = det(fr.box);
608 volume_av += volume;
610 rvec_inc(mja_tmp, mtrans[nfr]);
611 mjd += iprod(mu[nfr], mtrans[nfr]);
612 rvec_inc(mdvec, mu[nfr]);
614 mj2 += iprod(mtrans[nfr], mtrans[nfr]);
615 md2 += iprod(mu[nfr], mu[nfr]);
617 fprintf(fmj, "%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n", time[nfr], mtrans[nfr][XX],
618 mtrans[nfr][YY], mtrans[nfr][ZZ], mj2 / refr, norm(mja_tmp) / refr);
619 fprintf(fmd, "%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n", time[nfr], mu[nfr][XX],
620 mu[nfr][YY], mu[nfr][ZZ], md2 / refr, norm(mdvec) / refr);
622 nfr++;
624 } while (read_next_frame(oenv, status, &fr));
626 gmx_rmpbc_done(gpbc);
628 volume_av /= refr;
630 prefactor = 1.0;
631 prefactor /= 3.0 * EPSILON0 * volume_av * BOLTZ * temp;
634 prefactorav = E_CHARGE * E_CHARGE;
635 prefactorav /= volume_av * BOLTZMANN * temp * NANO * 6.0;
637 fprintf(stderr, "Prefactor fit E-H: 1 / 6.0*V*k_B*T: %g\n", prefactorav);
639 calc_mjdsp(fmjdsp, prefactorav, dsp2, time, nfr, xshfr);
642 * Now we can average and calculate the correlation functions
646 mj2 /= refr;
647 mjd /= refr;
648 md2 /= refr;
650 svmul(1.0 / refr, mdvec, mdvec);
651 svmul(1.0 / refr, mja_tmp, mja_tmp);
653 mdav2 = norm2(mdvec);
654 mj = norm2(mja_tmp);
655 mjdav = iprod(mdvec, mja_tmp);
658 printf("\n\nAverage translational dipole moment M_J [enm] after %d frames (|M|^2): %f %f %f "
659 "(%f)\n",
660 nfr, mja_tmp[XX], mja_tmp[YY], mja_tmp[ZZ], mj2);
661 printf("\n\nAverage molecular dipole moment M_D [enm] after %d frames (|M|^2): %f %f %f (%f)\n",
662 nfr, mdvec[XX], mdvec[YY], mdvec[ZZ], md2);
664 if (v0 != nullptr)
666 if (bINT)
669 printf("\nCalculating M_D - current correlation integral ... \n");
670 corint = calc_cacf(mcor, prefactorav / EPSI0, djc, time, nvfr, vfr, ie, nshift);
673 if (bACF)
676 printf("\nCalculating current autocorrelation ... \n");
677 sgk = calc_cacf(outf, prefactorav / PICO, cacf, time, nvfr, vfr, ie, nshift);
679 if (ie > ii)
682 snew(xfit, ie - ii + 1);
683 snew(yfit, ie - ii + 1);
685 for (i = ii; i <= ie; i++)
688 xfit[i - ii] = std::log(time[vfr[i]]);
689 rtmp = std::abs(cacf[i]);
690 yfit[i - ii] = std::log(rtmp);
693 lsq_y_ax_b(ie - ii, xfit, yfit, &sigma, &malt, &err, &rest);
695 malt = std::exp(malt);
697 sigma += 1.0;
699 malt *= prefactorav * 2.0e12 / sigma;
701 sfree(xfit);
702 sfree(yfit);
708 /* Calculation of the dielectric constant */
710 fprintf(stderr, "\n********************************************\n");
711 dk_s = calceps(prefactor, md2, mj2, mjd, eps_rf, FALSE);
712 fprintf(stderr, "\nAbsolute values:\n epsilon=%f\n", dk_s);
713 fprintf(stderr, " <M_D^2> , <M_J^2>, <(M_J*M_D)^2>: (%f, %f, %f)\n\n", md2, mj2, mjd);
714 fprintf(stderr, "********************************************\n");
717 dk_f = calceps(prefactor, md2 - mdav2, mj2 - mj, mjd - mjdav, eps_rf, FALSE);
718 fprintf(stderr, "\n\nFluctuations:\n epsilon=%f\n\n", dk_f);
719 fprintf(stderr, "\n deltaM_D , deltaM_J, deltaM_JD: (%f, %f, %f)\n", md2 - mdav2, mj2 - mj,
720 mjd - mjdav);
721 fprintf(stderr, "\n********************************************\n");
722 if (bINT)
724 dk_d = calceps(prefactor, md2 - mdav2, mj2 - mj, corint, eps_rf, TRUE);
725 fprintf(stderr, "\nStatic dielectric constant using integral and fluctuations: %f\n", dk_d);
726 fprintf(stderr, "\n < M_JM_D > via integral: %.3f\n", -1.0 * corint);
729 fprintf(stderr, "\n***************************************************");
730 fprintf(stderr, "\n\nAverage volume V=%f nm^3 at T=%f K\n", volume_av, temp);
731 fprintf(stderr, "and corresponding refactor 1.0 / 3.0*V*k_B*T*EPSILON_0: %f \n", prefactor);
734 if (bACF && (ii < nvfr))
736 fprintf(stderr, "Integral and integrated fit to the current acf yields at t=%f:\n", time[vfr[ii]]);
737 fprintf(stderr, "sigma=%8.3f (pure integral: %.3f)\n",
738 sgk - malt * std::pow(time[vfr[ii]], sigma), sgk);
741 if (ei > bi)
743 fprintf(stderr, "\nStart fit at %f ps (%f).\n", time[bi], bfit);
744 fprintf(stderr, "End fit at %f ps (%f).\n\n", time[ei], efit);
746 snew(xfit, ei - bi + 1);
747 snew(yfit, ei - bi + 1);
749 for (i = bi; i <= ei; i++)
751 xfit[i - bi] = time[i];
752 yfit[i - bi] = dsp2[i];
755 lsq_y_ax_b(ei - bi, xfit, yfit, &sigma, &malt, &err, &rest);
757 sigma *= 1e12;
758 dk_d = calceps(prefactor, md2, 0.5 * malt / prefactorav, corint, eps_rf, TRUE);
760 fprintf(stderr,
761 "Einstein-Helfand fit to the MSD of the translational dipole moment yields:\n\n");
762 fprintf(stderr, "sigma=%.4f\n", sigma);
763 fprintf(stderr, "translational fraction of M^2: %.4f\n", 0.5 * malt / prefactorav);
764 fprintf(stderr, "Dielectric constant using EH: %.4f\n", dk_d);
766 sfree(xfit);
767 sfree(yfit);
769 else
771 fprintf(stderr, "Too few points for a fit.\n");
775 if (v0 != nullptr)
777 sfree(v0);
779 if (bACF)
781 sfree(cacf);
783 if (bINT)
785 sfree(djc);
788 sfree(time);
791 sfree(mjdsp);
792 sfree(mu);
796 int gmx_current(int argc, char* argv[])
799 static int nshift = 1000;
800 static real temp = 300.0;
801 static real eps_rf = 0.0;
802 static gmx_bool bNoJump = TRUE;
803 static real bfit = 100.0;
804 static real bvit = 0.5;
805 static real efit = 400.0;
806 static real evit = 5.0;
807 t_pargs pa[] = {
808 { "-sh",
809 FALSE,
810 etINT,
811 { &nshift },
812 "Shift of the frames for averaging the correlation functions and the mean-square "
813 "displacement." },
814 { "-nojump", FALSE, etBOOL, { &bNoJump }, "Removes jumps of atoms across the box." },
815 { "-eps",
816 FALSE,
817 etREAL,
818 { &eps_rf },
819 "Dielectric constant of the surrounding medium. The value zero corresponds to "
820 "infinity (tin-foil boundary conditions)." },
821 { "-bfit",
822 FALSE,
823 etREAL,
824 { &bfit },
825 "Begin of the fit of the straight line to the MSD of the translational fraction "
826 "of the dipole moment." },
827 { "-efit",
828 FALSE,
829 etREAL,
830 { &efit },
831 "End of the fit of the straight line to the MSD of the translational fraction of "
832 "the dipole moment." },
833 { "-bvit",
834 FALSE,
835 etREAL,
836 { &bvit },
837 "Begin of the fit of the current autocorrelation function to a*t^b." },
838 { "-evit",
839 FALSE,
840 etREAL,
841 { &evit },
842 "End of the fit of the current autocorrelation function to a*t^b." },
843 { "-temp", FALSE, etREAL, { &temp }, "Temperature for calculating epsilon." }
846 gmx_output_env_t* oenv;
847 t_topology top;
848 char** grpname = nullptr;
849 const char* indexfn;
850 t_trxframe fr;
851 real* mass2 = nullptr;
852 matrix box;
853 int* index0;
854 int* indexm = nullptr;
855 int isize;
856 t_trxstatus* status;
857 int flags = 0;
858 gmx_bool bACF;
859 gmx_bool bINT;
860 PbcType pbcType = PbcType::Unset;
861 int nmols;
862 int i;
863 real* qmol;
864 FILE* outf = nullptr;
865 FILE* mcor = nullptr;
866 FILE* fmj = nullptr;
867 FILE* fmd = nullptr;
868 FILE* fmjdsp = nullptr;
869 FILE* fcur = nullptr;
870 t_filenm fnm[] = { { efTPS, nullptr, nullptr, ffREAD }, /* this is for the topology */
871 { efNDX, nullptr, nullptr, ffOPTRD },
872 { efTRX, "-f", nullptr, ffREAD }, /* and this for the trajectory */
873 { efXVG, "-o", "current", ffWRITE },
874 { efXVG, "-caf", "caf", ffOPTWR },
875 { efXVG, "-dsp", "dsp", ffWRITE },
876 { efXVG, "-md", "md", ffWRITE },
877 { efXVG, "-mj", "mj", ffWRITE },
878 { efXVG, "-mc", "mc", ffOPTWR } };
880 #define NFILE asize(fnm)
883 const char* desc[] = {
884 "[THISMODULE] is a tool for calculating the current autocorrelation function, the "
885 "correlation",
886 "of the rotational and translational dipole moment of the system, and the resulting static",
887 "dielectric constant. To obtain a reasonable result, the index group has to be neutral.",
888 "Furthermore, the routine is capable of extracting the static conductivity from the "
889 "current ",
890 "autocorrelation function, if velocities are given. Additionally, an Einstein-Helfand fit ",
891 "can be used to obtain the static conductivity.",
892 "[PAR]",
893 "The flag [TT]-caf[tt] is for the output of the current autocorrelation function and "
894 "[TT]-mc[tt] writes the",
895 "correlation of the rotational and translational part of the dipole moment in the "
896 "corresponding",
897 "file. However, this option is only available for trajectories containing velocities.",
898 "Options [TT]-sh[tt] and [TT]-tr[tt] are responsible for the averaging and integration of "
899 "the",
900 "autocorrelation functions. Since averaging proceeds by shifting the starting point",
901 "through the trajectory, the shift can be modified with [TT]-sh[tt] to enable the choice "
902 "of uncorrelated",
903 "starting points. Towards the end, statistical inaccuracy grows and integrating the",
904 "correlation function only yields reliable values until a certain point, depending on",
905 "the number of frames. The option [TT]-tr[tt] controls the region of the integral taken "
906 "into account",
907 "for calculating the static dielectric constant.",
908 "[PAR]",
909 "Option [TT]-temp[tt] sets the temperature required for the computation of the static "
910 "dielectric constant.",
911 "[PAR]",
912 "Option [TT]-eps[tt] controls the dielectric constant of the surrounding medium for "
913 "simulations using",
914 "a Reaction Field or dipole corrections of the Ewald summation ([TT]-eps[tt]\\=0 "
915 "corresponds to",
916 "tin-foil boundary conditions).",
917 "[PAR]",
918 "[TT]-[no]nojump[tt] unfolds the coordinates to allow free diffusion. This is required to "
919 "get a continuous",
920 "translational dipole moment, required for the Einstein-Helfand fit. The results from the "
921 "fit allow",
922 "the determination of the dielectric constant for system of charged molecules. However, it "
923 "is also possible to extract",
924 "the dielectric constant from the fluctuations of the total dipole moment in folded "
925 "coordinates. But this",
926 "option has to be used with care, since only very short time spans fulfill the "
927 "approximation that the density",
928 "of the molecules is approximately constant and the averages are already converged. To be "
929 "on the safe side,",
930 "the dielectric constant should be calculated with the help of the Einstein-Helfand method "
931 "for",
932 "the translational part of the dielectric constant."
936 /* At first the arguments will be parsed and the system information processed */
937 if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
938 asize(desc), desc, 0, nullptr, &oenv))
940 return 0;
943 bACF = opt2bSet("-caf", NFILE, fnm);
944 bINT = opt2bSet("-mc", NFILE, fnm);
946 read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &pbcType, nullptr, nullptr, box, TRUE);
948 indexfn = ftp2fn_null(efNDX, NFILE, fnm);
949 snew(grpname, 1);
951 get_index(&(top.atoms), indexfn, 1, &isize, &index0, grpname);
953 flags = flags | TRX_READ_X | TRX_READ_V;
955 read_first_frame(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &fr, flags);
957 snew(mass2, top.atoms.nr);
958 snew(qmol, top.atoms.nr);
960 precalc(top, mass2, qmol);
963 snew(indexm, isize);
965 for (i = 0; i < isize; i++)
967 indexm[i] = index0[i];
970 nmols = isize;
973 index_atom2mol(&nmols, indexm, &top.mols);
975 if (fr.bV)
977 if (bACF)
979 outf = xvgropen(opt2fn("-caf", NFILE, fnm), "Current autocorrelation function",
980 output_env_get_xvgr_tlabel(oenv), "ACF (e nm/ps)\\S2", oenv);
981 fprintf(outf, "# time\t acf\t average \t std.dev\n");
983 fcur = xvgropen(opt2fn("-o", NFILE, fnm), "Current", output_env_get_xvgr_tlabel(oenv),
984 "J(t) (e nm/ps)", oenv);
985 fprintf(fcur, "# time\t Jx\t Jy \t J_z \n");
986 if (bINT)
988 mcor = xvgropen(opt2fn("-mc", NFILE, fnm),
989 "M\\sD\\N - current autocorrelation function",
990 output_env_get_xvgr_tlabel(oenv),
991 "< M\\sD\\N (0)\\c7\\CJ(t) > (e nm/ps)\\S2", oenv);
992 fprintf(mcor, "# time\t M_D(0) J(t) acf \t Integral acf\n");
996 fmj = xvgropen(opt2fn("-mj", NFILE, fnm), "Averaged translational part of M",
997 output_env_get_xvgr_tlabel(oenv), "< M\\sJ\\N > (enm)", oenv);
998 fprintf(fmj, "# time\t x\t y \t z \t average of M_J^2 \t std.dev\n");
999 fmd = xvgropen(opt2fn("-md", NFILE, fnm), "Averaged rotational part of M",
1000 output_env_get_xvgr_tlabel(oenv), "< M\\sD\\N > (enm)", oenv);
1001 fprintf(fmd, "# time\t x\t y \t z \t average of M_D^2 \t std.dev\n");
1003 fmjdsp = xvgropen(
1004 opt2fn("-dsp", NFILE, fnm), "MSD of the squared translational dipole moment M",
1005 output_env_get_xvgr_tlabel(oenv),
1006 "<|M\\sJ\\N(t)-M\\sJ\\N(0)|\\S2\\N > / 6.0*V*k\\sB\\N*T / Sm\\S-1\\Nps\\S-1\\N", oenv);
1009 /* System information is read and prepared, dielectric() processes the frames
1010 * and calculates the requested quantities */
1012 dielectric(fmj, fmd, outf, fcur, mcor, fmjdsp, bNoJump, bACF, bINT, pbcType, top, fr, temp, bfit, efit,
1013 bvit, evit, status, isize, nmols, nshift, index0, indexm, mass2, qmol, eps_rf, oenv);
1015 xvgrclose(fmj);
1016 xvgrclose(fmd);
1017 xvgrclose(fmjdsp);
1018 if (fr.bV)
1020 if (bACF)
1022 xvgrclose(outf);
1024 xvgrclose(fcur);
1025 if (bINT)
1027 xvgrclose(mcor);
1031 return 0;