2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
5 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
38 #include "gromacs/commandline/filenm.h"
39 #include "gromacs/commandline/pargs.h"
40 #include "gromacs/fileio/trxio.h"
41 #include "gromacs/fileio/xvgr.h"
42 #include "gromacs/gmxana/gmx_ana.h"
43 #include "gromacs/math/vec.h"
44 #include "gromacs/pbcutil/pbc.h"
45 #include "gromacs/topology/index.h"
46 #include "gromacs/trajectory/trajectoryframe.h"
47 #include "gromacs/utility/arraysize.h"
48 #include "gromacs/utility/fatalerror.h"
49 #include "gromacs/utility/futil.h"
50 #include "gromacs/utility/pleasecite.h"
51 #include "gromacs/utility/smalloc.h"
53 int gmx_dyecoupl(int argc, char* argv[])
55 const char* desc[] = {
56 "[THISMODULE] extracts dye dynamics from trajectory files.",
57 "Currently, R and kappa^2 between dyes is extracted for (F)RET",
58 "simulations with assumed dipolar coupling as in the Foerster equation.",
59 "It further allows the calculation of R(t) and kappa^2(t), R and",
60 "kappa^2 histograms and averages, as well as the instantaneous FRET",
61 "efficiency E(t) for a specified Foerster radius R_0 (switch [TT]-R0[tt]).",
62 "The input dyes have to be whole (see res and mol pbc options",
63 "in [TT]trjconv[tt]).",
64 "The dye transition dipole moment has to be defined by at least",
65 "a single atom pair, however multiple atom pairs can be provided ",
66 "in the index file. The distance R is calculated on the basis of",
67 "the COMs of the given atom pairs.",
68 "The [TT]-pbcdist[tt] option calculates distances to the nearest periodic",
69 "image instead to the distance in the box. This works however only,",
70 "for periodic boundaries in all 3 dimensions.",
71 "The [TT]-norm[tt] option (area-) normalizes the histograms."
74 static gmx_bool bPBCdist = FALSE, bNormHist = FALSE;
76 gmx_output_env_t* oenv;
80 { "-pbcdist", FALSE, etBOOL, { &bPBCdist }, "Distance R based on PBC" },
81 { "-norm", FALSE, etBOOL, { &bNormHist }, "Normalize histograms" },
82 { "-bins", FALSE, etINT, { &histbins }, "# of histogram bins" },
83 { "-R0", FALSE, etREAL, { &R0 }, "Foerster radius including kappa^2=2/3 in nm" }
87 t_filenm fnm[] = { { efTRX, "-f", nullptr, ffREAD }, { efNDX, nullptr, nullptr, ffREAD },
88 { efXVG, "-ot", "rkappa", ffOPTWR }, { efXVG, "-oe", "insteff", ffOPTWR },
89 { efDAT, "-o", "rkappa", ffOPTWR }, { efXVG, "-rhist", "rhist", ffOPTWR },
90 { efXVG, "-khist", "khist", ffOPTWR } };
91 #define NFILE asize(fnm)
94 const char *in_trajfile, *out_xvgrkfile = nullptr, *out_xvginstefffile = nullptr,
95 *out_xvgrhistfile = nullptr, *out_xvgkhistfile = nullptr,
96 *out_datfile = nullptr;
97 gmx_bool bHaveFirstFrame, bHaveNextFrame, indexOK = TRUE;
99 int * donindex, *accindex;
105 int allocblock = 1000;
106 real histexpand = 1e-6;
107 rvec donvec, accvec, donpos, accpos, dist, distnorm;
110 /*we rely on PBC autodetection (...currently)*/
111 PbcType pbcType = PbcType::Unset;
113 real * rvalues = nullptr, *kappa2values = nullptr, *rhist = nullptr, *khist = nullptr;
114 t_pbc* pbc = nullptr;
116 FILE * rkfp = nullptr, *rhfp = nullptr, *khfp = nullptr, *datfp = nullptr, *iefp = nullptr;
117 gmx_bool bRKout, bRhistout, bKhistout, bDatout, bInstEffout, grident;
119 const char* rkleg[2] = { "R", "\\f{Symbol}k\\f{}\\S2\\N" };
120 const char* rhleg[1] = { "p(R)" };
121 const char* khleg[1] = { "p(\\f{Symbol}k\\f{}\\S2\\N)" };
122 const char* ieleg[1] = { "E\\sRET\\N(t)" };
124 real R, kappa2, insteff, Rs = 0., kappa2s = 0., insteffs = 0., rmax, rmin, kmin = 0., kmax = 4.,
125 rrange, krange, rincr, kincr, Rfrac;
126 int rkcount = 0, rblocksallocated = 0, kblocksallocated = 0;
128 if (!parse_common_args(&argc,
130 PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW | PCA_TIME_UNIT,
145 /* Check command line options for filenames and set bool flags when switch used*/
146 in_trajfile = opt2fn("-f", NFILE, fnm);
147 out_xvgrkfile = opt2fn("-ot", NFILE, fnm);
148 out_xvgrhistfile = opt2fn("-rhist", NFILE, fnm);
149 out_xvgkhistfile = opt2fn("-khist", NFILE, fnm);
150 out_xvginstefffile = opt2fn("-oe", NFILE, fnm);
151 out_datfile = opt2fn("-o", NFILE, fnm);
153 bRKout = opt2bSet("-ot", NFILE, fnm);
154 bRhistout = opt2bSet("-rhist", NFILE, fnm);
155 bKhistout = opt2bSet("-khist", NFILE, fnm);
156 bDatout = opt2bSet("-o", NFILE, fnm);
157 bInstEffout = opt2bSet("-oe", NFILE, fnm);
163 printf("Calculating distances to periodic image.\n");
164 printf("Be careful! This produces only valid results for PBC in all three dimensions\n");
168 if (bInstEffout && R0 <= 0.)
170 gmx_fatal(FARGS, "You have to specify R0 and R0 has to be larger than 0 nm.\n\n");
173 printf("Select group with donor atom pairs defining the transition moment\n");
174 get_index(nullptr, ftp2fn_null(efNDX, NFILE, fnm), 1, &ndon, &donindex, &grpnm);
176 printf("Select group with acceptor atom pairs defining the transition moment\n");
177 get_index(nullptr, ftp2fn_null(efNDX, NFILE, fnm), 1, &nacc, &accindex, &grpnm);
179 /*check if groups are identical*/
184 for (i = 0; i < nacc; i++)
186 if (accindex[i] != donindex[i])
196 gmx_fatal(FARGS, "Donor and acceptor group are identical. This makes no sense.");
199 printf("Reading first frame\n");
200 /* open trx file for reading */
202 flags = flags | TRX_READ_X;
203 bHaveFirstFrame = read_first_frame(oenv, &status, in_trajfile, &fr, flags);
207 printf("First frame is OK\n");
209 if ((ndon % 2 != 0) || (nacc % 2 != 0))
215 for (i = 0; i < ndon; i++)
217 if (donindex[i] >= natoms)
222 for (i = 0; i < nacc; i++)
224 if (accindex[i] >= natoms)
236 datfp = gmx_ffopen(out_datfile, "w");
241 rkfp = xvgropen(out_xvgrkfile,
242 "Distance and \\f{Symbol}k\\f{}\\S2\\N trajectory",
244 "Distance (nm) / \\f{Symbol}k\\f{}\\S2\\N",
246 xvgr_legend(rkfp, 2, rkleg, oenv);
251 iefp = xvgropen(out_xvginstefffile,
252 "Instantaneous RET Efficiency",
256 xvgr_legend(iefp, 1, ieleg, oenv);
262 snew(rvalues, allocblock);
263 rblocksallocated += 1;
264 snew(rhist, histbins);
269 snew(kappa2values, allocblock);
270 kblocksallocated += 1;
271 snew(khist, histbins);
280 for (i = 0; i < ndon / 2; i++)
282 rvec_sub(donvec, fr.x[donindex[2 * i]], donvec);
283 rvec_add(donvec, fr.x[donindex[2 * i + 1]], donvec);
284 rvec_add(donpos, fr.x[donindex[2 * i]], donpos);
285 rvec_add(donpos, fr.x[donindex[2 * i + 1]], donpos);
288 for (i = 0; i < nacc / 2; i++)
290 rvec_sub(accvec, fr.x[accindex[2 * i]], accvec);
291 rvec_add(accvec, fr.x[accindex[2 * i + 1]], accvec);
292 rvec_add(accpos, fr.x[accindex[2 * i]], accpos);
293 rvec_add(accpos, fr.x[accindex[2 * i + 1]], accpos);
296 unitv(donvec, donvec);
297 unitv(accvec, accvec);
299 svmul(1.0 / ndon, donpos, donpos);
300 svmul(1.0 / nacc, accpos, accpos);
304 set_pbc(pbc, pbcType, fr.box);
305 pbc_dx(pbc, donpos, accpos, dist);
309 rvec_sub(donpos, accpos, dist);
312 unitv(dist, distnorm);
314 kappa2 = iprod(donvec, accvec) - 3. * (iprod(donvec, distnorm) * iprod(distnorm, accvec));
319 insteff = 1 / (1 + (Rfrac * Rfrac * Rfrac * Rfrac * Rfrac * Rfrac) * 2 / 3 / kappa2);
324 fprintf(iefp, "%12.7f %12.7f\n", fr.time, insteff);
335 fprintf(rkfp, "%12.7f %12.7f %12.7f\n", fr.time, R, kappa2);
340 fprintf(datfp, "%12.7f %12.7f %12.7f\n", fr.time, R, kappa2);
345 rvalues[rkcount - 1] = R;
346 if (rkcount % allocblock == 0)
348 srenew(rvalues, allocblock * (rblocksallocated + 1));
349 rblocksallocated += 1;
355 kappa2values[rkcount - 1] = kappa2;
356 if (rkcount % allocblock == 0)
358 srenew(kappa2values, allocblock * (kblocksallocated + 1));
359 kblocksallocated += 1;
363 bHaveNextFrame = read_next_frame(oenv, status, &fr);
364 } while (bHaveNextFrame);
384 printf("Writing R-Histogram\n");
387 for (i = 1; i < rkcount; i++)
389 if (rvalues[i] < rmin)
393 else if (rvalues[i] > rmax)
401 rrange = rmax - rmin;
402 rincr = rrange / histbins;
404 for (i = 1; i < rkcount; i++)
406 bin = static_cast<int>((rvalues[i] - rmin) / rincr);
411 for (i = 0; i < histbins; i++)
413 rhist[i] /= rkcount * rrange / histbins;
415 rhfp = xvgropen(out_xvgrhistfile,
416 "Distance Distribution",
418 "Normalized Probability",
424 out_xvgrhistfile, "Distance Distribution", "R (nm)", "Probability", oenv);
426 xvgr_legend(rhfp, 1, rhleg, oenv);
427 for (i = 0; i < histbins; i++)
429 fprintf(rhfp, "%12.7f %12.7f\n", (i + 0.5) * rincr + rmin, rhist[i]);
436 printf("Writing kappa^2-Histogram\n");
437 krange = kmax - kmin;
438 kincr = krange / histbins;
440 for (i = 1; i < rkcount; i++)
442 bin = static_cast<int>((kappa2values[i] - kmin) / kincr);
447 for (i = 0; i < histbins; i++)
449 khist[i] /= rkcount * krange / histbins;
451 khfp = xvgropen(out_xvgkhistfile,
452 "\\f{Symbol}k\\f{}\\S2\\N Distribution",
453 "\\f{Symbol}k\\f{}\\S2\\N",
454 "Normalized Probability",
459 khfp = xvgropen(out_xvgkhistfile,
460 "\\f{Symbol}k\\f{}\\S2\\N Distribution",
461 "\\f{Symbol}k\\f{}\\S2\\N",
465 xvgr_legend(khfp, 1, khleg, oenv);
466 for (i = 0; i < histbins; i++)
468 fprintf(khfp, "%12.7f %12.7f\n", (i + 0.5) * kincr + kmin, khist[i]);
473 printf("\nAverages:\n");
474 printf("R_avg = %8.4f nm\nKappa^2 = %8.4f\n", Rs / rkcount, kappa2s / rkcount);
477 printf("E_RETavg = %8.4f\n", insteffs / rkcount);
479 please_cite(stdout, "Hoefling2011");
483 gmx_fatal(FARGS, "Index file invalid, check your index file for correct pairs.\n");
488 gmx_fatal(FARGS, "Could not read first frame of the trajectory.\n");