Fixes #882 - looping bug in trxio.c
[gromacs.git] / src / tools / gmx_dist.c
blobe025c5ae9e5d171cb6079c22be5286d637c3870b
1 /*
2 *
3 * This source code is part of
4 *
5 * G R O M A C S
6 *
7 * GROningen MAchine for Chemical Simulations
8 *
9 * VERSION 3.2.0
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
32 * And Hey:
33 * Green Red Orange Magenta Azure Cyan Skyblue
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38 #include <typedefs.h>
40 #include "smalloc.h"
41 #include "macros.h"
42 #include "math.h"
43 #include "xvgr.h"
44 #include "copyrite.h"
45 #include "statutil.h"
46 #include "string2.h"
47 #include "vec.h"
48 #include "index.h"
49 #include "pbc.h"
50 #include "gmx_fatal.h"
51 #include "futil.h"
52 #include "gstat.h"
53 #include "gmx_ana.h"
56 static void add_contact_time(int **ccount,int *ccount_nalloc,int t)
58 int i;
60 if (t+2 >= *ccount_nalloc) {
61 srenew(*ccount,t+2);
62 for(i=*ccount_nalloc; i<t+2; i++)
63 (*ccount)[i] = 0;
64 *ccount_nalloc = t+2;
66 (*ccount)[t]++;
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.[PAR]",
81 "Other programs that calculate distances are [TT]g_mindist[tt]",
82 "and [TT]g_bond[tt]."
85 t_topology *top=NULL;
86 int ePBC;
87 real t,t0,cut2,dist2;
88 rvec *x=NULL,*v=NULL,dx;
89 matrix box;
90 t_trxstatus *status;
91 int natoms;
93 int g,d,i,j,res,teller=0;
94 atom_id aid;
96 int ngrps; /* the number of index groups */
97 atom_id **index,max; /* the index for the atom numbers */
98 int *isize; /* the size of each group */
99 char **grpname; /* the name of each group */
100 rvec *com;
101 real *mass;
102 FILE *fp=NULL,*fplt=NULL;
103 gmx_bool bCutoff,bPrintDist,bLifeTime;
104 t_pbc *pbc;
105 int *contact_time=NULL,*ccount=NULL,ccount_nalloc=0,sum;
106 char buf[STRLEN];
107 output_env_t oenv;
108 gmx_rmpbc_t gpbc=NULL;
110 const char *leg[4] = { "|d|","d\\sx\\N","d\\sy\\N","d\\sz\\N" };
112 static real cut=0;
114 static t_pargs pa[] = {
115 { "-dist", FALSE, etREAL, {&cut},
116 "Print all atoms in group 2 closer than dist to the center of mass of group 1" }
118 #define NPA asize(pa)
120 t_filenm fnm[] = {
121 { efTRX, "-f", NULL, ffREAD },
122 { efTPX, NULL, NULL, ffREAD },
123 { efNDX, NULL, NULL, ffOPTRD },
124 { efXVG, NULL, "dist", ffOPTWR },
125 { efXVG, "-lt", "lifetime", ffOPTWR },
127 #define NFILE asize(fnm)
130 CopyRight(stderr,argv[0]);
132 parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_BE_NICE,
133 NFILE,fnm,NPA,pa,asize(desc),desc,0,NULL,&oenv);
135 bCutoff = opt2parg_bSet("-dist",NPA,pa);
136 cut2 = cut*cut;
137 bLifeTime = opt2bSet("-lt",NFILE,fnm);
138 bPrintDist = (bCutoff && !bLifeTime);
140 top=read_top(ftp2fn(efTPX,NFILE,fnm),&ePBC);
142 /* read index files */
143 ngrps = 2;
144 snew(com,ngrps);
145 snew(grpname,ngrps);
146 snew(index,ngrps);
147 snew(isize,ngrps);
148 get_index(&top->atoms,ftp2fn(efNDX,NFILE,fnm),ngrps,isize,index,grpname);
150 /* calculate mass */
151 max=0;
152 snew(mass,ngrps);
153 for(g=0;(g<ngrps);g++) {
154 mass[g]=0;
155 for(i=0;(i<isize[g]);i++) {
156 if (index[g][i]>max)
157 max=index[g][i];
158 if (index[g][i] >= top->atoms.nr)
159 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);
160 mass[g]+=top->atoms.atom[index[g][i]].m;
164 natoms=read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box);
165 t0 = t;
167 if (max>=natoms)
168 gmx_fatal(FARGS,"Atom number %d in an index group is larger than number of atoms in the trajectory (%d)\n",(int)max+1,natoms);
170 if (!bCutoff) {
171 /* open output file */
172 fp = xvgropen(ftp2fn(efXVG,NFILE,fnm),
173 "Distance","Time (ps)","Distance (nm)",oenv);
174 xvgr_legend(fp,4,leg,oenv);
175 } else {
176 ngrps = 1;
177 if (bLifeTime)
178 snew(contact_time,isize[1]);
180 if (ePBC != epbcNONE)
181 snew(pbc,1);
182 else
183 pbc = NULL;
185 gpbc = gmx_rmpbc_init(&top->idef,ePBC,max,box);
186 do {
187 /* initialisation for correct distance calculations */
188 if (pbc) {
189 set_pbc(pbc,ePBC,box);
190 /* make molecules whole again */
191 gmx_rmpbc(gpbc,max,box,x);
193 /* calculate center of masses */
194 for(g=0;(g<ngrps);g++) {
195 if (isize[g] == 1) {
196 copy_rvec(x[index[g][0]],com[g]);
197 } else {
198 for(d=0;(d<DIM);d++) {
199 com[g][d]=0;
200 for(i=0;(i<isize[g]);i++) {
201 com[g][d] += x[index[g][i]][d] * top->atoms.atom[index[g][i]].m;
203 com[g][d] /= mass[g];
208 if (!bCutoff) {
209 /* write to output */
210 fprintf(fp,"%12.7f ",t);
211 for(g=0;(g<ngrps/2);g++) {
212 if (pbc)
213 pbc_dx(pbc,com[2*g],com[2*g+1],dx);
214 else
215 rvec_sub(com[2*g],com[2*g+1],dx);
217 fprintf(fp,"%12.7f %12.7f %12.7f %12.7f",
218 norm(dx),dx[XX],dx[YY],dx[ZZ]);
220 fprintf(fp,"\n");
221 } else {
222 for(i=0;(i<isize[1]);i++) {
223 j=index[1][i];
224 if (pbc)
225 pbc_dx(pbc,x[j],com[0],dx);
226 else
227 rvec_sub(x[j],com[0],dx);
229 dist2 = norm2(dx);
230 if (dist2<cut2) {
231 if (bPrintDist) {
232 res=top->atoms.atom[j].resind;
233 fprintf(stdout,"\rt: %g %d %s %d %s %g (nm)\n",
234 t,top->atoms.resinfo[res].nr,*top->atoms.resinfo[res].name,
235 j+1,*top->atoms.atomname[j],sqrt(dist2));
237 if (bLifeTime)
238 contact_time[i]++;
239 } else {
240 if (bLifeTime) {
241 if (contact_time[i]) {
242 add_contact_time(&ccount,&ccount_nalloc,contact_time[i]-1);
243 contact_time[i] = 0;
250 teller++;
251 } while (read_next_x(oenv,status,&t,natoms,x,box));
252 gmx_rmpbc_done(gpbc);
254 if (!bCutoff)
255 ffclose(fp);
257 close_trj(status);
259 if (bCutoff && bLifeTime) {
260 /* Add the contacts still present in the last frame */
261 for(i=0; i<isize[1]; i++)
262 if (contact_time[i])
263 add_contact_time(&ccount,&ccount_nalloc,contact_time[i]-1);
265 sprintf(buf,"%s - %s within %g nm",
266 grpname[0],grpname[1],cut);
267 fp = xvgropen(opt2fn("-lt",NFILE,fnm),
268 buf,"Time (ps)","Number of contacts",oenv);
269 for(i=0; i<min(ccount_nalloc,teller-1); i++) {
270 /* Account for all subintervals of longer intervals */
271 sum = 0;
272 for(j=i; j<ccount_nalloc; j++)
273 sum += (j-i+1)*ccount[j];
275 fprintf(fp,"%10.3f %10.3f\n",i*(t-t0)/(teller-1),sum/(double)(teller-i));
277 ffclose(fp);
280 thanx(stderr);
281 return 0;