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) {
62 for(i=*ccount_nalloc; i<t+2; i++)
69 int gmx_dist(int argc,char *argv[])
71 const char *desc[] = {
72 "[TT]g_dist[tt] can calculate the distance between the centers of mass of two",
73 "groups of atoms as a function of time. The total distance and its",
74 "[IT]x[it]-, [IT]y[it]-, and [IT]z[it]-components are plotted.[PAR]",
75 "Or when [TT]-dist[tt] is set, print all the atoms in group 2 that are",
76 "closer than a certain distance to the center of mass of group 1.[PAR]",
77 "With options [TT]-lt[tt] and [TT]-dist[tt] the number of contacts",
78 "of all atoms in group 2 that are closer than a certain distance",
79 "to the center of mass of group 1 are plotted as a function of the time",
80 "that the contact was continuously present. The [TT]-intra[tt] switch enables",
81 "calculations of intramolecular distances avoiding distance calculation to its",
82 "periodic images. For a proper function, the molecule in the input trajectory",
83 "should be whole (e.g. by preprocessing with [TT]trjconv -pbc[tt]) or a matching",
84 "topology should be provided. The [TT]-intra[tt] switch will only give",
85 "meaningful results for intramolecular and not intermolecular distances.[PAR]",
86 "Other programs that calculate distances are [TT]g_mindist[tt]",
93 rvec *x=NULL,*v=NULL,dx;
98 int g,d,i,j,res,teller=0;
101 int ngrps; /* the number of index groups */
102 atom_id **index, natoms_groups; /* the index for the atom numbers */
103 int *isize; /* the size of each group */
104 char **grpname; /* the name of each group */
107 FILE *fp=NULL,*fplt=NULL;
108 gmx_bool bCutoff,bPrintDist,bLifeTime,bIntra=FALSE;
110 int *contact_time=NULL,*ccount=NULL,ccount_nalloc=0,sum;
113 gmx_rmpbc_t gpbc=NULL;
115 const char *leg[4] = { "|d|","d\\sx\\N","d\\sy\\N","d\\sz\\N" };
120 { "-intra", FALSE, etBOOL, {&bIntra},
121 "Calculate distances without considering periodic boundaries, e.g. intramolecular." },
122 { "-dist", FALSE, etREAL, {&cut},
123 "Print all atoms in group 2 closer than dist to the center of mass of group 1" }
125 #define NPA asize(pa)
128 { efTRX, "-f", NULL, ffREAD },
129 { efTPX, NULL, NULL, ffREAD },
130 { efNDX, NULL, NULL, ffOPTRD },
131 { efXVG, NULL, "dist", ffOPTWR },
132 { efXVG, "-lt", "lifetime", ffOPTWR },
134 #define NFILE asize(fnm)
137 CopyRight(stderr,argv[0]);
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 */
155 get_index(&top->atoms,ftp2fn_null(efNDX,NFILE,fnm),ngrps,isize,index,grpname);
160 for(g=0;(g<ngrps);g++) {
162 for(i=0;(i<isize[g]);i++) {
163 if (index[g][i]>natoms_groups)
164 natoms_groups=index[g][i];
165 if (index[g][i] >= top->atoms.nr)
166 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);
167 mass[g]+=top->atoms.atom[index[g][i]].m;
170 /* The number is one more than the highest index */
173 natoms=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box);
176 if (natoms_groups>natoms)
177 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);
180 /* open output file */
181 fp = xvgropen(ftp2fn(efXVG,NFILE,fnm),
182 "Distance","Time (ps)","Distance (nm)",oenv);
183 xvgr_legend(fp,4,leg,oenv);
187 snew(contact_time,isize[1]);
189 if (ePBC != epbcNONE)
194 gpbc = gmx_rmpbc_init(&top->idef,ePBC,natoms,box);
196 /* initialisation for correct distance calculations */
198 set_pbc(pbc,ePBC,box);
199 /* make molecules whole again */
200 gmx_rmpbc(gpbc,natoms,box,x);
202 /* calculate center of masses */
203 for(g=0;(g<ngrps);g++) {
205 copy_rvec(x[index[g][0]],com[g]);
207 for(d=0;(d<DIM);d++) {
209 for(i=0;(i<isize[g]);i++) {
210 com[g][d] += x[index[g][i]][d] * top->atoms.atom[index[g][i]].m;
212 com[g][d] /= mass[g];
218 /* write to output */
219 fprintf(fp,"%12.7f ",t);
220 for(g=0;(g<ngrps/2);g++) {
221 if (pbc && (!bIntra))
222 pbc_dx(pbc,com[2*g],com[2*g+1],dx);
224 rvec_sub(com[2*g],com[2*g+1],dx);
226 fprintf(fp,"%12.7f %12.7f %12.7f %12.7f",
227 norm(dx),dx[XX],dx[YY],dx[ZZ]);
231 for(i=0;(i<isize[1]);i++) {
233 if (pbc && (!bIntra))
234 pbc_dx(pbc,x[j],com[0],dx);
236 rvec_sub(x[j],com[0],dx);
241 res=top->atoms.atom[j].resind;
242 fprintf(stdout,"\rt: %g %d %s %d %s %g (nm)\n",
243 t,top->atoms.resinfo[res].nr,*top->atoms.resinfo[res].name,
244 j+1,*top->atoms.atomname[j],sqrt(dist2));
250 if (contact_time[i]) {
251 add_contact_time(&ccount,&ccount_nalloc,contact_time[i]-1);
260 } while (read_next_x(oenv,status,&t,natoms,x,box));
261 gmx_rmpbc_done(gpbc);
268 if (bCutoff && bLifeTime) {
269 /* Add the contacts still present in the last frame */
270 for(i=0; i<isize[1]; i++)
272 add_contact_time(&ccount,&ccount_nalloc,contact_time[i]-1);
274 sprintf(buf,"%s - %s within %g nm",
275 grpname[0],grpname[1],cut);
276 fp = xvgropen(opt2fn("-lt",NFILE,fnm),
277 buf,"Time (ps)","Number of contacts",oenv);
278 for(i=0; i<min(ccount_nalloc,teller-1); i++) {
279 /* Account for all subintervals of longer intervals */
281 for(j=i; j<ccount_nalloc; j++)
282 sum += (j-i+1)*ccount[j];
284 fprintf(fp,"%10.3f %10.3f\n",i*(t-t0)/(teller-1),sum/(double)(teller-i));