int gmx_current(int argc, char *argv[]) { static int nshift = 1000; static real temp = 300.0; static real eps_rf = 0.0; static gmx_bool bNoJump = TRUE; static real bfit = 100.0; static real bvit = 0.5; static real efit = 400.0; static real evit = 5.0; t_pargs pa[] = { { "-sh", FALSE, etINT, {&nshift}, "Shift of the frames for averaging the correlation functions and the mean-square displacement."}, { "-nojump", FALSE, etBOOL, {&bNoJump}, "Removes jumps of atoms across the box."}, { "-eps", FALSE, etREAL, {&eps_rf}, "Dielectric constant of the surrounding medium. The value zero corresponds to infinity (tin-foil boundary conditions)."}, { "-bfit", FALSE, etREAL, {&bfit}, "Begin of the fit of the straight line to the MSD of the translational fraction of the dipole moment."}, { "-efit", FALSE, etREAL, {&efit}, "End of the fit of the straight line to the MSD of the translational fraction of the dipole moment."}, { "-bvit", FALSE, etREAL, {&bvit}, "Begin of the fit of the current autocorrelation function to a*t^b."}, { "-evit", FALSE, etREAL, {&evit}, "End of the fit of the current autocorrelation function to a*t^b."}, { "-temp", FALSE, etREAL, {&temp}, "Temperature for calculating epsilon."} }; gmx_output_env_t *oenv; t_topology top; char **grpname = NULL; const char *indexfn; t_trxframe fr; real *mass2 = NULL; matrix box; int *index0; int *indexm = NULL; int isize; t_trxstatus *status; int flags = 0; gmx_bool bACF; gmx_bool bINT; int ePBC = -1; int nmols; int i; real *qmol; FILE *outf = NULL; FILE *mcor = NULL; FILE *fmj = NULL; FILE *fmd = NULL; FILE *fmjdsp = NULL; FILE *fcur = NULL; t_filenm fnm[] = { { efTPS, NULL, NULL, ffREAD }, /* this is for the topology */ { efNDX, NULL, NULL, ffOPTRD }, { efTRX, "-f", NULL, ffREAD }, /* and this for the trajectory */ { efXVG, "-o", "current", ffWRITE }, { efXVG, "-caf", "caf", ffOPTWR }, { efXVG, "-dsp", "dsp", ffWRITE }, { efXVG, "-md", "md", ffWRITE }, { efXVG, "-mj", "mj", ffWRITE }, { efXVG, "-mc", "mc", ffOPTWR } }; #define NFILE asize(fnm) const char *desc[] = { "[THISMODULE] is a tool for calculating the current autocorrelation function, the correlation", "of the rotational and translational dipole moment of the system, and the resulting static", "dielectric constant. To obtain a reasonable result, the index group has to be neutral.", "Furthermore, the routine is capable of extracting the static conductivity from the current ", "autocorrelation function, if velocities are given. Additionally, an Einstein-Helfand fit ", "can be used to obtain the static conductivity." "[PAR]", "The flag [TT]-caf[tt] is for the output of the current autocorrelation function and [TT]-mc[tt] writes the", "correlation of the rotational and translational part of the dipole moment in the corresponding", "file. However, this option is only available for trajectories containing velocities.", "Options [TT]-sh[tt] and [TT]-tr[tt] are responsible for the averaging and integration of the", "autocorrelation functions. Since averaging proceeds by shifting the starting point", "through the trajectory, the shift can be modified with [TT]-sh[tt] to enable the choice of uncorrelated", "starting points. Towards the end, statistical inaccuracy grows and integrating the", "correlation function only yields reliable values until a certain point, depending on", "the number of frames. The option [TT]-tr[tt] controls the region of the integral taken into account", "for calculating the static dielectric constant.", "[PAR]", "Option [TT]-temp[tt] sets the temperature required for the computation of the static dielectric constant.", "[PAR]", "Option [TT]-eps[tt] controls the dielectric constant of the surrounding medium for simulations using", "a Reaction Field or dipole corrections of the Ewald summation ([TT]-eps[tt]\\=0 corresponds to", "tin-foil boundary conditions).", "[PAR]", "[TT]-[no]nojump[tt] unfolds the coordinates to allow free diffusion. This is required to get a continuous", "translational dipole moment, required for the Einstein-Helfand fit. The results from the fit allow", "the determination of the dielectric constant for system of charged molecules. However, it is also possible to extract", "the dielectric constant from the fluctuations of the total dipole moment in folded coordinates. But this", "option has to be used with care, since only very short time spans fulfill the approximation that the density", "of the molecules is approximately constant and the averages are already converged. To be on the safe side,", "the dielectric constant should be calculated with the help of the Einstein-Helfand method for", "the translational part of the dielectric constant." }; /* At first the arguments will be parsed and the system information processed */ if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } bACF = opt2bSet("-caf", NFILE, fnm); bINT = opt2bSet("-mc", NFILE, fnm); read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, NULL, NULL, box, TRUE); indexfn = ftp2fn_null(efNDX, NFILE, fnm); snew(grpname, 1); get_index(&(top.atoms), indexfn, 1, &isize, &index0, grpname); flags = flags | TRX_READ_X | TRX_READ_V; read_first_frame(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &fr, flags); snew(mass2, top.atoms.nr); snew(qmol, top.atoms.nr); precalc(top, mass2, qmol); snew(indexm, isize); for (i = 0; i < isize; i++) { indexm[i] = index0[i]; } nmols = isize; index_atom2mol(&nmols, indexm, &top.mols); if (fr.bV) { if (bACF) { outf = xvgropen(opt2fn("-caf", NFILE, fnm), "Current autocorrelation function", output_env_get_xvgr_tlabel(oenv), "ACF (e nm/ps)\\S2", oenv); fprintf(outf, "# time\t acf\t average \t std.dev\n"); } fcur = xvgropen(opt2fn("-o", NFILE, fnm), "Current", output_env_get_xvgr_tlabel(oenv), "J(t) (e nm/ps)", oenv); fprintf(fcur, "# time\t Jx\t Jy \t J_z \n"); if (bINT) { mcor = xvgropen(opt2fn("-mc", NFILE, fnm), "M\\sD\\N - current autocorrelation function", output_env_get_xvgr_tlabel(oenv), "< M\\sD\\N (0)\\c7\\CJ(t) > (e nm/ps)\\S2", oenv); fprintf(mcor, "# time\t M_D(0) J(t) acf \t Integral acf\n"); } } fmj = xvgropen(opt2fn("-mj", NFILE, fnm), "Averaged translational part of M", output_env_get_xvgr_tlabel(oenv), "< M\\sJ\\N > (enm)", oenv); fprintf(fmj, "# time\t x\t y \t z \t average of M_J^2 \t std.dev\n"); fmd = xvgropen(opt2fn("-md", NFILE, fnm), "Averaged rotational part of M", output_env_get_xvgr_tlabel(oenv), "< M\\sD\\N > (enm)", oenv); fprintf(fmd, "# time\t x\t y \t z \t average of M_D^2 \t std.dev\n"); fmjdsp = xvgropen(opt2fn("-dsp", NFILE, fnm), "MSD of the squared translational dipole moment M", output_env_get_xvgr_tlabel(oenv), "<|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); /* System information is read and prepared, dielectric() processes the frames * and calculates the requested quantities */ dielectric(fmj, fmd, outf, fcur, mcor, fmjdsp, bNoJump, bACF, bINT, ePBC, top, fr, temp, bfit, efit, bvit, evit, status, isize, nmols, nshift, index0, indexm, mass2, qmol, eps_rf, oenv); xvgrclose(fmj); xvgrclose(fmd); xvgrclose(fmjdsp); if (fr.bV) { if (bACF) { xvgrclose(outf); } xvgrclose(fcur); if (bINT) { xvgrclose(mcor); } } return 0; }
int gmx_velacc(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] computes the velocity autocorrelation function.", "When the [TT]-m[tt] option is used, the momentum autocorrelation", "function is calculated.[PAR]", "With option [TT]-mol[tt] the velocity autocorrelation function of", "molecules is calculated. In this case the index group should consist", "of molecule numbers instead of atom numbers.[PAR]", "Be sure that your trajectory contains frames with velocity information", "(i.e. [TT]nstvout[tt] was set in your original [REF].mdp[ref] file),", "and that the time interval between data collection points is", "much shorter than the time scale of the autocorrelation." }; static gmx_bool bMass = FALSE, bMol = FALSE, bRecip = TRUE; t_pargs pa[] = { { "-m", FALSE, etBOOL, {&bMass}, "Calculate the momentum autocorrelation function" }, { "-recip", FALSE, etBOOL, {&bRecip}, "Use cm^-1 on X-axis instead of 1/ps for spectra." }, { "-mol", FALSE, etBOOL, {&bMol}, "Calculate the velocity acf of molecules" } }; t_topology top; int ePBC = -1; t_trxframe fr; matrix box; gmx_bool bTPS = FALSE, bTop = FALSE; int gnx; int *index; char *grpname; /* t0, t1 are the beginning and end time respectively. * dt is the time step, mass is temp variable for atomic mass. */ real t0, t1, dt, mass; t_trxstatus *status; int counter, n_alloc, i, j, counter_dim, k, l; rvec mv_mol; /* Array for the correlation function */ real **c1; real *normm = NULL; gmx_output_env_t *oenv; #define NHISTO 360 t_filenm fnm[] = { { efTRN, "-f", NULL, ffREAD }, { efTPS, NULL, NULL, ffOPTRD }, { efNDX, NULL, NULL, ffOPTRD }, { efXVG, "-o", "vac", ffWRITE }, { efXVG, "-os", "spectrum", ffOPTWR } }; #define NFILE asize(fnm) int npargs; t_pargs *ppa; npargs = asize(pa); ppa = add_acf_pargs(&npargs, pa); if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv)) { sfree(ppa); return 0; } if (bMol || bMass) { bTPS = ftp2bSet(efTPS, NFILE, fnm) || !ftp2bSet(efNDX, NFILE, fnm); } if (bTPS) { bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, NULL, NULL, box, TRUE); get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); } else { rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); } if (bMol) { if (!bTop) { gmx_fatal(FARGS, "Need a topology to determine the molecules"); } snew(normm, top.atoms.nr); precalc(top, normm); index_atom2mol(&gnx, index, &top.mols); } /* Correlation stuff */ snew(c1, gnx); for (i = 0; (i < gnx); i++) { c1[i] = NULL; } read_first_frame(oenv, &status, ftp2fn(efTRN, NFILE, fnm), &fr, TRX_NEED_V); t0 = fr.time; n_alloc = 0; counter = 0; do { if (counter >= n_alloc) { n_alloc += 100; for (i = 0; i < gnx; i++) { srenew(c1[i], DIM*n_alloc); } } counter_dim = DIM*counter; if (bMol) { for (i = 0; i < gnx; i++) { clear_rvec(mv_mol); k = top.mols.index[index[i]]; l = top.mols.index[index[i]+1]; for (j = k; j < l; j++) { if (bMass) { mass = top.atoms.atom[j].m; } else { mass = normm[j]; } mv_mol[XX] += mass*fr.v[j][XX]; mv_mol[YY] += mass*fr.v[j][YY]; mv_mol[ZZ] += mass*fr.v[j][ZZ]; } c1[i][counter_dim+XX] = mv_mol[XX]; c1[i][counter_dim+YY] = mv_mol[YY]; c1[i][counter_dim+ZZ] = mv_mol[ZZ]; } } else { for (i = 0; i < gnx; i++) { if (bMass) { mass = top.atoms.atom[index[i]].m; } else { mass = 1; } c1[i][counter_dim+XX] = mass*fr.v[index[i]][XX]; c1[i][counter_dim+YY] = mass*fr.v[index[i]][YY]; c1[i][counter_dim+ZZ] = mass*fr.v[index[i]][ZZ]; } } t1 = fr.time; counter++; } while (read_next_frame(oenv, status, &fr)); close_trj(status); if (counter >= 4) { /* Compute time step between frames */ dt = (t1-t0)/(counter-1); do_autocorr(opt2fn("-o", NFILE, fnm), oenv, bMass ? "Momentum Autocorrelation Function" : "Velocity Autocorrelation Function", counter, gnx, c1, dt, eacVector, TRUE); do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); if (opt2bSet("-os", NFILE, fnm)) { calc_spectrum(counter/2, (real *) (c1[0]), (t1-t0)/2, opt2fn("-os", NFILE, fnm), oenv, bRecip); do_view(oenv, opt2fn("-os", NFILE, fnm), "-nxy"); } } else { fprintf(stderr, "Not enough frames in trajectory - no output generated.\n"); } return 0; }
void do_corr(const char *trx_file, const char *ndx_file, const char *msd_file, const char *mol_file, const char *pdb_file, real t_pdb, int nrgrp, t_topology *top, int ePBC, gmx_bool bTen, gmx_bool bMW, gmx_bool bRmCOMM, int type, real dim_factor, int axis, real dt, real beginfit, real endfit, const output_env_t oenv) { t_corr *msd; int *gnx; /* the selected groups' sizes */ atom_id **index; /* selected groups' indices */ char **grpname; int i, i0, i1, j, N, nat_trx; real *DD, *SigmaD, a, a2, b, r, chi2; rvec *x; matrix box; int *gnx_com = NULL; /* the COM removal group size */ atom_id **index_com = NULL; /* the COM removal group atom indices */ char **grpname_com = NULL; /* the COM removal group name */ snew(gnx, nrgrp); snew(index, nrgrp); snew(grpname, nrgrp); fprintf(stderr, "\nSelect a group to calculate mean squared displacement for:\n"); get_index(&top->atoms, ndx_file, nrgrp, gnx, index, grpname); if (bRmCOMM) { snew(gnx_com, 1); snew(index_com, 1); snew(grpname_com, 1); fprintf(stderr, "\nNow select a group for center of mass removal:\n"); get_index(&top->atoms, ndx_file, 1, gnx_com, index_com, grpname_com); } if (mol_file) { index_atom2mol(&gnx[0], index[0], &top->mols); } msd = init_corr(nrgrp, type, axis, dim_factor, mol_file == NULL ? 0 : gnx[0], bTen, bMW, dt, top, beginfit, endfit); nat_trx = corr_loop(msd, trx_file, top, ePBC, mol_file ? gnx[0] : 0, gnx, index, (mol_file != NULL) ? calc1_mol : (bMW ? calc1_mw : calc1_norm), bTen, gnx_com, index_com, dt, t_pdb, pdb_file ? &x : NULL, box, oenv); /* Correct for the number of points */ for (j = 0; (j < msd->ngrp); j++) { for (i = 0; (i < msd->nframes); i++) { msd->data[j][i] /= msd->ndata[j][i]; if (bTen) { msmul(msd->datam[j][i], 1.0/msd->ndata[j][i], msd->datam[j][i]); } } } if (mol_file) { if (pdb_file && x == NULL) { fprintf(stderr, "\nNo frame found need time tpdb = %g ps\n" "Can not write %s\n\n", t_pdb, pdb_file); } i = top->atoms.nr; top->atoms.nr = nat_trx; printmol(msd, mol_file, pdb_file, index[0], top, x, ePBC, box, oenv); top->atoms.nr = i; } DD = NULL; SigmaD = NULL; if (beginfit == -1) { i0 = static_cast<int>(0.1*(msd->nframes - 1) + 0.5); beginfit = msd->time[i0]; } else { for (i0 = 0; i0 < msd->nframes && msd->time[i0] < beginfit; i0++) { ; } } if (endfit == -1) { i1 = static_cast<int>(0.9*(msd->nframes - 1) + 0.5) + 1; endfit = msd->time[i1-1]; } else { for (i1 = i0; i1 < msd->nframes && msd->time[i1] <= endfit; i1++) { ; } } fprintf(stdout, "Fitting from %g to %g %s\n\n", beginfit, endfit, output_env_get_time_unit(oenv)); N = i1-i0; if (N <= 2) { fprintf(stdout, "Not enough points for fitting (%d).\n" "Can not determine the diffusion constant.\n", N); } else { snew(DD, msd->ngrp); snew(SigmaD, msd->ngrp); for (j = 0; j < msd->ngrp; j++) { if (N >= 4) { lsq_y_ax_b(N/2, &(msd->time[i0]), &(msd->data[j][i0]), &a, &b, &r, &chi2); lsq_y_ax_b(N/2, &(msd->time[i0+N/2]), &(msd->data[j][i0+N/2]), &a2, &b, &r, &chi2); SigmaD[j] = std::abs(a-a2); } else { SigmaD[j] = 0; } lsq_y_ax_b(N, &(msd->time[i0]), &(msd->data[j][i0]), &(DD[j]), &b, &r, &chi2); DD[j] *= FACTOR/msd->dim_factor; SigmaD[j] *= FACTOR/msd->dim_factor; if (DD[j] > 0.01 && DD[j] < 1e4) { fprintf(stdout, "D[%10s] %.4f (+/- %.4f) 1e-5 cm^2/s\n", grpname[j], DD[j], SigmaD[j]); } else { fprintf(stdout, "D[%10s] %.4g (+/- %.4g) 1e-5 cm^2/s\n", grpname[j], DD[j], SigmaD[j]); } } } /* Print mean square displacement */ corr_print(msd, bTen, msd_file, "Mean Square Displacement", "MSD (nm\\S2\\N)", msd->time[msd->nframes-1], beginfit, endfit, DD, SigmaD, grpname, oenv); }