3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * Green Red Orange Magenta Azure Cyan Skyblue
50 #include "gmx_fatal.h"
56 static void add_contact_time(int **ccount, int *ccount_nalloc, int t)
60 if (t+2 >= *ccount_nalloc)
63 for (i = *ccount_nalloc; i < t+2; i++)
72 int gmx_dist(int argc, char *argv[])
74 const char *desc[] = {
75 "[TT]g_dist[tt] can calculate the distance between the centers of mass of two",
76 "groups of atoms as a function of time. The total distance and its",
77 "[IT]x[it]-, [IT]y[it]-, and [IT]z[it]-components are plotted.[PAR]",
78 "Or when [TT]-dist[tt] is set, print all the atoms in group 2 that are",
79 "closer than a certain distance to the center of mass of group 1.[PAR]",
80 "With options [TT]-lt[tt] and [TT]-dist[tt] the number of contacts",
81 "of all atoms in group 2 that are closer than a certain distance",
82 "to the center of mass of group 1 are plotted as a function of the time",
83 "that the contact was continuously present. The [TT]-intra[tt] switch enables",
84 "calculations of intramolecular distances avoiding distance calculation to its",
85 "periodic images. For a proper function, the molecule in the input trajectory",
86 "should be whole (e.g. by preprocessing with [TT]trjconv -pbc[tt]) or a matching",
87 "topology should be provided. The [TT]-intra[tt] switch will only give",
88 "meaningful results for intramolecular and not intermolecular distances.[PAR]",
89 "Other programs that calculate distances are [TT]g_mindist[tt]",
93 t_topology *top = NULL;
95 real t, t0, cut2, dist2;
96 rvec *x = NULL, *v = NULL, dx;
101 int g, d, i, j, res, teller = 0;
104 int ngrps; /* the number of index groups */
105 atom_id **index, natoms_groups; /* the index for the atom numbers */
106 int *isize; /* the size of each group */
107 char **grpname; /* the name of each group */
110 FILE *fp = NULL, *fplt = NULL;
111 gmx_bool bCutoff, bPrintDist, bLifeTime, bIntra = FALSE;
113 int *contact_time = NULL, *ccount = NULL, ccount_nalloc = 0, sum;
116 gmx_rmpbc_t gpbc = NULL;
118 const char *leg[4] = { "|d|", "d\\sx\\N", "d\\sy\\N", "d\\sz\\N" };
123 { "-intra", FALSE, etBOOL, {&bIntra},
124 "Calculate distances without considering periodic boundaries, e.g. intramolecular." },
125 { "-dist", FALSE, etREAL, {&cut},
126 "Print all atoms in group 2 closer than dist to the center of mass of group 1" }
128 #define NPA asize(pa)
131 { efTRX, "-f", NULL, ffREAD },
132 { efTPX, NULL, NULL, ffREAD },
133 { efNDX, NULL, NULL, ffOPTRD },
134 { efXVG, NULL, "dist", ffOPTWR },
135 { efXVG, "-lt", "lifetime", ffOPTWR },
137 #define NFILE asize(fnm)
139 parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_BE_NICE,
140 NFILE, fnm, NPA, pa, asize(desc), desc, 0, NULL, &oenv);
142 bCutoff = opt2parg_bSet("-dist", NPA, pa);
144 bLifeTime = opt2bSet("-lt", NFILE, fnm);
145 bPrintDist = (bCutoff && !bLifeTime);
147 top = read_top(ftp2fn(efTPX, NFILE, fnm), &ePBC);
149 /* read index files */
152 snew(grpname, ngrps);
155 get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm), ngrps, isize, index, grpname);
160 for (g = 0; (g < ngrps); g++)
163 for (i = 0; (i < isize[g]); i++)
165 if (index[g][i] > natoms_groups)
167 natoms_groups = index[g][i];
169 if (index[g][i] >= top->atoms.nr)
171 gmx_fatal(FARGS, "Atom number %d, item %d of group %d, is larger than number of atoms in the topolgy (%d)\n", index[g][i]+1, i+1, g+1, top->atoms.nr+1);
173 mass[g] += top->atoms.atom[index[g][i]].m;
176 /* The number is one more than the highest index */
179 natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
182 if (natoms_groups > natoms)
184 gmx_fatal(FARGS, "Atom number %d in an index group is larger than number of atoms in the trajectory (%d)\n", (int)natoms_groups, natoms);
189 /* open output file */
190 fp = xvgropen(ftp2fn(efXVG, NFILE, fnm),
191 "Distance", "Time (ps)", "Distance (nm)", oenv);
192 xvgr_legend(fp, 4, leg, oenv);
199 snew(contact_time, isize[1]);
202 if (ePBC != epbcNONE)
211 gpbc = gmx_rmpbc_init(&top->idef, ePBC, natoms, box);
214 /* initialisation for correct distance calculations */
217 set_pbc(pbc, ePBC, box);
218 /* make molecules whole again */
219 gmx_rmpbc(gpbc, natoms, box, x);
221 /* calculate center of masses */
222 for (g = 0; (g < ngrps); g++)
226 copy_rvec(x[index[g][0]], com[g]);
230 for (d = 0; (d < DIM); d++)
233 for (i = 0; (i < isize[g]); i++)
235 com[g][d] += x[index[g][i]][d] * top->atoms.atom[index[g][i]].m;
237 com[g][d] /= mass[g];
244 /* write to output */
245 fprintf(fp, "%12.7f ", t);
246 for (g = 0; (g < ngrps/2); g++)
248 if (pbc && (!bIntra))
250 pbc_dx(pbc, com[2*g], com[2*g+1], dx);
254 rvec_sub(com[2*g], com[2*g+1], dx);
257 fprintf(fp, "%12.7f %12.7f %12.7f %12.7f",
258 norm(dx), dx[XX], dx[YY], dx[ZZ]);
264 for (i = 0; (i < isize[1]); i++)
267 if (pbc && (!bIntra))
269 pbc_dx(pbc, x[j], com[0], dx);
273 rvec_sub(x[j], com[0], dx);
281 res = top->atoms.atom[j].resind;
282 fprintf(stdout, "\rt: %g %d %s %d %s %g (nm)\n",
283 t, top->atoms.resinfo[res].nr, *top->atoms.resinfo[res].name,
284 j+1, *top->atoms.atomname[j], sqrt(dist2));
297 add_contact_time(&ccount, &ccount_nalloc, contact_time[i]-1);
307 while (read_next_x(oenv, status, &t, natoms, x, box));
308 gmx_rmpbc_done(gpbc);
317 if (bCutoff && bLifeTime)
319 /* Add the contacts still present in the last frame */
320 for (i = 0; i < isize[1]; i++)
324 add_contact_time(&ccount, &ccount_nalloc, contact_time[i]-1);
328 sprintf(buf, "%s - %s within %g nm",
329 grpname[0], grpname[1], cut);
330 fp = xvgropen(opt2fn("-lt", NFILE, fnm),
331 buf, "Time (ps)", "Number of contacts", oenv);
332 for (i = 0; i < min(ccount_nalloc, teller-1); i++)
334 /* Account for all subintervals of longer intervals */
336 for (j = i; j < ccount_nalloc; j++)
338 sum += (j-i+1)*ccount[j];
341 fprintf(fp, "%10.3f %10.3f\n", i*(t-t0)/(teller-1), sum/(double)(teller-i));