2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2012,2013,2014,2015,2017,2018,2019, 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.
37 #include "gromacs/commandline/filenm.h"
38 #include "gromacs/commandline/pargs.h"
39 #include "gromacs/fileio/trxio.h"
40 #include "gromacs/fileio/xvgr.h"
41 #include "gromacs/gmxana/gmx_ana.h"
42 #include "gromacs/math/vec.h"
43 #include "gromacs/pbcutil/pbc.h"
44 #include "gromacs/topology/index.h"
45 #include "gromacs/trajectory/trajectoryframe.h"
46 #include "gromacs/utility/arraysize.h"
47 #include "gromacs/utility/fatalerror.h"
48 #include "gromacs/utility/futil.h"
49 #include "gromacs/utility/pleasecite.h"
50 #include "gromacs/utility/smalloc.h"
52 int gmx_dyecoupl(int argc, char* argv[])
54 const char* desc[] = {
55 "[THISMODULE] extracts dye dynamics from trajectory files.",
56 "Currently, R and kappa^2 between dyes is extracted for (F)RET",
57 "simulations with assumed dipolar coupling as in the Foerster equation.",
58 "It further allows the calculation of R(t) and kappa^2(t), R and",
59 "kappa^2 histograms and averages, as well as the instantaneous FRET",
60 "efficiency E(t) for a specified Foerster radius R_0 (switch [TT]-R0[tt]).",
61 "The input dyes have to be whole (see res and mol pbc options",
62 "in [TT]trjconv[tt]).",
63 "The dye transition dipole moment has to be defined by at least",
64 "a single atom pair, however multiple atom pairs can be provided ",
65 "in the index file. The distance R is calculated on the basis of",
66 "the COMs of the given atom pairs.",
67 "The [TT]-pbcdist[tt] option calculates distances to the nearest periodic",
68 "image instead to the distance in the box. This works however only,",
69 "for periodic boundaries in all 3 dimensions.",
70 "The [TT]-norm[tt] option (area-) normalizes the histograms."
73 static gmx_bool bPBCdist = FALSE, bNormHist = FALSE;
75 gmx_output_env_t* oenv;
79 { "-pbcdist", FALSE, etBOOL, { &bPBCdist }, "Distance R based on PBC" },
80 { "-norm", FALSE, etBOOL, { &bNormHist }, "Normalize histograms" },
81 { "-bins", FALSE, etINT, { &histbins }, "# of histogram bins" },
82 { "-R0", FALSE, etREAL, { &R0 }, "Foerster radius including kappa^2=2/3 in nm" }
86 t_filenm fnm[] = { { efTRX, "-f", nullptr, ffREAD }, { efNDX, nullptr, nullptr, ffREAD },
87 { efXVG, "-ot", "rkappa", ffOPTWR }, { efXVG, "-oe", "insteff", ffOPTWR },
88 { efDAT, "-o", "rkappa", ffOPTWR }, { efXVG, "-rhist", "rhist", ffOPTWR },
89 { efXVG, "-khist", "khist", ffOPTWR } };
90 #define NFILE asize(fnm)
93 const char *in_trajfile, *out_xvgrkfile = nullptr, *out_xvginstefffile = nullptr,
94 *out_xvgrhistfile = nullptr, *out_xvgkhistfile = nullptr,
95 *out_datfile = nullptr;
96 gmx_bool bHaveFirstFrame, bHaveNextFrame, indexOK = TRUE;
98 int * donindex, *accindex;
104 int allocblock = 1000;
105 real histexpand = 1e-6;
106 rvec donvec, accvec, donpos, accpos, dist, distnorm;
109 /*we rely on PBC autodetection (...currently)*/
112 real * rvalues = nullptr, *kappa2values = nullptr, *rhist = nullptr, *khist = nullptr;
113 t_pbc* pbc = nullptr;
115 FILE * rkfp = nullptr, *rhfp = nullptr, *khfp = nullptr, *datfp = nullptr, *iefp = nullptr;
116 gmx_bool bRKout, bRhistout, bKhistout, bDatout, bInstEffout, grident;
118 const char* rkleg[2] = { "R", "\\f{Symbol}k\\f{}\\S2\\N" };
119 const char* rhleg[1] = { "p(R)" };
120 const char* khleg[1] = { "p(\\f{Symbol}k\\f{}\\S2\\N)" };
121 const char* ieleg[1] = { "E\\sRET\\N(t)" };
123 real R, kappa2, insteff, Rs = 0., kappa2s = 0., insteffs = 0., rmax, rmin, kmin = 0., kmax = 4.,
124 rrange, krange, rincr, kincr, Rfrac;
125 int rkcount = 0, rblocksallocated = 0, kblocksallocated = 0;
127 if (!parse_common_args(&argc, argv, PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW | PCA_TIME_UNIT,
128 NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
134 /* Check command line options for filenames and set bool flags when switch used*/
135 in_trajfile = opt2fn("-f", NFILE, fnm);
136 out_xvgrkfile = opt2fn("-ot", NFILE, fnm);
137 out_xvgrhistfile = opt2fn("-rhist", NFILE, fnm);
138 out_xvgkhistfile = opt2fn("-khist", NFILE, fnm);
139 out_xvginstefffile = opt2fn("-oe", NFILE, fnm);
140 out_datfile = opt2fn("-o", NFILE, fnm);
142 bRKout = opt2bSet("-ot", NFILE, fnm);
143 bRhistout = opt2bSet("-rhist", NFILE, fnm);
144 bKhistout = opt2bSet("-khist", NFILE, fnm);
145 bDatout = opt2bSet("-o", NFILE, fnm);
146 bInstEffout = opt2bSet("-oe", NFILE, fnm);
152 printf("Calculating distances to periodic image.\n");
153 printf("Be careful! This produces only valid results for PBC in all three dimensions\n");
157 if (bInstEffout && R0 <= 0.)
159 gmx_fatal(FARGS, "You have to specify R0 and R0 has to be larger than 0 nm.\n\n");
162 printf("Select group with donor atom pairs defining the transition moment\n");
163 get_index(nullptr, ftp2fn_null(efNDX, NFILE, fnm), 1, &ndon, &donindex, &grpnm);
165 printf("Select group with acceptor atom pairs defining the transition moment\n");
166 get_index(nullptr, ftp2fn_null(efNDX, NFILE, fnm), 1, &nacc, &accindex, &grpnm);
168 /*check if groups are identical*/
173 for (i = 0; i < nacc; i++)
175 if (accindex[i] != donindex[i])
185 gmx_fatal(FARGS, "Donor and acceptor group are identical. This makes no sense.");
188 printf("Reading first frame\n");
189 /* open trx file for reading */
191 flags = flags | TRX_READ_X;
192 bHaveFirstFrame = read_first_frame(oenv, &status, in_trajfile, &fr, flags);
196 printf("First frame is OK\n");
198 if ((ndon % 2 != 0) || (nacc % 2 != 0))
204 for (i = 0; i < ndon; i++)
206 if (donindex[i] >= natoms)
211 for (i = 0; i < nacc; i++)
213 if (accindex[i] >= natoms)
225 datfp = gmx_ffopen(out_datfile, "w");
230 rkfp = xvgropen(out_xvgrkfile, "Distance and \\f{Symbol}k\\f{}\\S2\\N trajectory",
231 "Time (ps)", "Distance (nm) / \\f{Symbol}k\\f{}\\S2\\N", oenv);
232 xvgr_legend(rkfp, 2, rkleg, oenv);
237 iefp = xvgropen(out_xvginstefffile, "Instantaneous RET Efficiency", "Time (ps)",
238 "RET Efficiency", oenv);
239 xvgr_legend(iefp, 1, ieleg, oenv);
245 snew(rvalues, allocblock);
246 rblocksallocated += 1;
247 snew(rhist, histbins);
252 snew(kappa2values, allocblock);
253 kblocksallocated += 1;
254 snew(khist, histbins);
263 for (i = 0; i < ndon / 2; i++)
265 rvec_sub(donvec, fr.x[donindex[2 * i]], donvec);
266 rvec_add(donvec, fr.x[donindex[2 * i + 1]], donvec);
267 rvec_add(donpos, fr.x[donindex[2 * i]], donpos);
268 rvec_add(donpos, fr.x[donindex[2 * i + 1]], donpos);
271 for (i = 0; i < nacc / 2; i++)
273 rvec_sub(accvec, fr.x[accindex[2 * i]], accvec);
274 rvec_add(accvec, fr.x[accindex[2 * i + 1]], accvec);
275 rvec_add(accpos, fr.x[accindex[2 * i]], accpos);
276 rvec_add(accpos, fr.x[accindex[2 * i + 1]], accpos);
279 unitv(donvec, donvec);
280 unitv(accvec, accvec);
282 svmul(1.0 / ndon, donpos, donpos);
283 svmul(1.0 / nacc, accpos, accpos);
287 set_pbc(pbc, ePBC, fr.box);
288 pbc_dx(pbc, donpos, accpos, dist);
292 rvec_sub(donpos, accpos, dist);
295 unitv(dist, distnorm);
297 kappa2 = iprod(donvec, accvec) - 3. * (iprod(donvec, distnorm) * iprod(distnorm, accvec));
302 insteff = 1 / (1 + (Rfrac * Rfrac * Rfrac * Rfrac * Rfrac * Rfrac) * 2 / 3 / kappa2);
307 fprintf(iefp, "%12.7f %12.7f\n", fr.time, insteff);
318 fprintf(rkfp, "%12.7f %12.7f %12.7f\n", fr.time, R, kappa2);
323 fprintf(datfp, "%12.7f %12.7f %12.7f\n", fr.time, R, kappa2);
328 rvalues[rkcount - 1] = R;
329 if (rkcount % allocblock == 0)
331 srenew(rvalues, allocblock * (rblocksallocated + 1));
332 rblocksallocated += 1;
338 kappa2values[rkcount - 1] = kappa2;
339 if (rkcount % allocblock == 0)
341 srenew(kappa2values, allocblock * (kblocksallocated + 1));
342 kblocksallocated += 1;
346 bHaveNextFrame = read_next_frame(oenv, status, &fr);
347 } while (bHaveNextFrame);
367 printf("Writing R-Histogram\n");
370 for (i = 1; i < rkcount; i++)
372 if (rvalues[i] < rmin)
376 else if (rvalues[i] > rmax)
384 rrange = rmax - rmin;
385 rincr = rrange / histbins;
387 for (i = 1; i < rkcount; i++)
389 bin = static_cast<int>((rvalues[i] - rmin) / rincr);
394 for (i = 0; i < histbins; i++)
396 rhist[i] /= rkcount * rrange / histbins;
398 rhfp = xvgropen(out_xvgrhistfile, "Distance Distribution", "R (nm)",
399 "Normalized Probability", oenv);
403 rhfp = xvgropen(out_xvgrhistfile, "Distance Distribution", "R (nm)",
404 "Probability", oenv);
406 xvgr_legend(rhfp, 1, rhleg, oenv);
407 for (i = 0; i < histbins; i++)
409 fprintf(rhfp, "%12.7f %12.7f\n", (i + 0.5) * rincr + rmin, rhist[i]);
416 printf("Writing kappa^2-Histogram\n");
417 krange = kmax - kmin;
418 kincr = krange / histbins;
420 for (i = 1; i < rkcount; i++)
422 bin = static_cast<int>((kappa2values[i] - kmin) / kincr);
427 for (i = 0; i < histbins; i++)
429 khist[i] /= rkcount * krange / histbins;
431 khfp = xvgropen(out_xvgkhistfile, "\\f{Symbol}k\\f{}\\S2\\N Distribution",
432 "\\f{Symbol}k\\f{}\\S2\\N", "Normalized Probability", oenv);
436 khfp = xvgropen(out_xvgkhistfile, "\\f{Symbol}k\\f{}\\S2\\N Distribution",
437 "\\f{Symbol}k\\f{}\\S2\\N", "Probability", oenv);
439 xvgr_legend(khfp, 1, khleg, oenv);
440 for (i = 0; i < histbins; i++)
442 fprintf(khfp, "%12.7f %12.7f\n", (i + 0.5) * kincr + kmin, khist[i]);
447 printf("\nAverages:\n");
448 printf("R_avg = %8.4f nm\nKappa^2 = %8.4f\n", Rs / rkcount, kappa2s / rkcount);
451 printf("E_RETavg = %8.4f\n", insteffs / rkcount);
453 please_cite(stdout, "Hoefling2011");
457 gmx_fatal(FARGS, "Index file invalid, check your index file for correct pairs.\n");
462 gmx_fatal(FARGS, "Could not read first frame of the trajectory.\n");