4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Copyright (c) 1991-2001, University of Groningen, The Netherlands
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * If you want to redistribute modifications, please consider that
18 * scientific software is very special. Version control is crucial -
19 * bugs must be traceable. We will be happy to consider code for
20 * inclusion in the official distribution, but derived work must not
21 * be called official GROMACS. Details are found in the README & COPYING
22 * files - if they are missing, get the official version at www.gromacs.org.
24 * To help us fund GROMACS development, we humbly ask that you cite
25 * the papers on the package - you can find them in the top README file.
27 * For more info, check our website at http://www.gromacs.org
30 * Gromacs Runs One Microsecond At Cannonball Speeds
51 static void periodic_dist(matrix box
,rvec x
[],int n
,atom_id index
[],
52 real
*rmin
,real
*rmax
)
56 real sqr_box
,r2min
,r2max
,r2
;
57 rvec shift
[NSHIFT
],d0
,d
;
59 sqr_box
= sqr(min(box
[XX
][XX
],min(box
[YY
][YY
],box
[ZZ
][ZZ
])));
62 for(sz
=-1; sz
<=1; sz
++)
63 for(sy
=-1; sy
<=1; sy
++)
64 for(sx
=-1; sx
<=1; sx
++)
65 if (sx
!=0 || sy
!=0 || sz
!=0) {
67 shift
[s
][i
] = sx
*box
[XX
][i
]+sy
*box
[YY
][i
]+sz
*box
[ZZ
][i
];
75 for(j
=i
+1; j
<n
; j
++) {
76 rvec_sub(x
[index
[i
]],x
[index
[j
]],d0
);
80 for(s
=0; s
<NSHIFT
; s
++) {
81 rvec_add(d0
,shift
[s
],d
);
92 static void periodic_mindist_plot(char *trxfn
,char *outfn
,
93 t_topology
*top
,int n
,atom_id index
[],
97 char *leg
[5] = { "min per.","max int.","box1","box2","box3" };
103 real r
,rmin
,rmax
,rmint
,tmint
;
106 natoms
=read_first_x(&status
,trxfn
,&t
,&x
,box
);
108 check_index(NULL
,n
,index
,NULL
,natoms
);
110 out
= xvgropen(outfn
,"Minimum distance to periodic image",
111 time_label(),"Distance (nm)");
112 fprintf(out
,"@ subtitle \"and maximum internal distance\"\n");
113 xvgr_legend(out
,5,leg
);
120 rm_pbc(&(top
->idef
),natoms
,box
,x
,x
);
121 periodic_dist(box
,x
,n
,index
,&rmin
,&rmax
);
126 if ( bSplit
&& !bFirst
&& abs(t
/time_factor())<1e-5 )
128 fprintf(out
,"\t%g\t%6.3f %6.3f %6.3f %6.3f %6.3f\n",
129 convert_time(t
),rmin
,rmax
,norm(box
[0]),norm(box
[1]),norm(box
[2]));
131 } while(read_next_x(status
,&t
,natoms
,x
,box
));
136 "\nThe shortest periodic distance is %g (nm) at time %g (%s)\n",
137 rmint
,convert_time(tmint
),time_unit());
140 static void calc_dist(real rcut
, matrix box
, rvec x
[],
141 int nx1
,int nx2
, atom_id index1
[], atom_id index2
[],
142 real
*rmin
, real
*rmax
, int *nmin
, int *nmax
,
143 int *ixmin
, int *jxmin
, int *ixmax
, int *jxmax
)
149 real r2
,rmin2
,rmax2
,rcut2
;
160 /* Must init pbc every step because of pressure coupling */
174 for(i
=0; (i
< nx1
); i
++) {
178 for(j
=j0
; (j
< j1
); j
++) {
181 pbc_dx(x
[ix
],x
[jx
],dx
);
204 void dist_plot(char *fn
,char *afile
,char *dfile
,
205 char *nfile
,char *rfile
,char *xfile
,
206 real rcut
,bool bMat
,t_atoms
*atoms
,
207 int ng
,atom_id
*index
[],int gnx
[],char *grpn
[],bool bSplit
,
208 bool bMin
, int nres
, atom_id
*residue
)
210 FILE *atm
,*dist
,*num
;
215 real t
,md
,**mdist
=NULL
;
218 real t
,dmin
,dmax
,**mindres
,**maxdres
;
219 int nmin
,nmax
,status
;
222 int min1
,min2
,max1
,max2
;
229 if ((natoms
=read_first_x(&status
,fn
,&t
,&x0
,box
))==0)
230 fatal_error(0,"Could not read coordinates from statusfile\n");
232 sprintf(buf
,"%simum Distance",bMin
? "Min" : "Max");
233 dist
= xvgropen(dfile
,buf
,time_label(),"Distance (nm)");
234 sprintf(buf
,"Number of Contacts %s %g nm",bMin
? "<" : ">",rcut
);
235 num
= nfile
? xvgropen(nfile
,buf
,time_label(),"Number") : NULL
;
236 atm
= afile
? ffopen(afile
,"w") : NULL
;
237 trxout
= xfile
? open_trx(xfile
,"w") : NOTSET
;
242 sprintf(buf
,"Internal in %s",grpn
[0]);
244 xvgr_legend(dist
,0,leg
);
245 if (num
) xvgr_legend(num
,0,leg
);
248 snew(leg
,(ng
*(ng
-1))/2);
249 for(i
=j
=0; (i
<ng
-1); i
++) {
250 for(k
=i
+1; (k
<ng
); k
++,j
++) {
251 sprintf(buf
,"%s-%s",grpn
[i
],grpn
[k
]);
255 xvgr_legend(dist
,j
,leg
);
256 if (num
) xvgr_legend(num
,j
,leg
);
261 for(i
=0; (i
<ng
-1); i
++) {
262 sprintf(buf
,"%s-%s",grpn
[0],grpn
[i
+1]);
265 xvgr_legend(dist
,ng
-1,leg
);
266 if (num
) xvgr_legend(num
,ng
-1,leg
);
272 for(i
=1; i
<ng
; i
++) {
273 snew(mindres
[i
-1], nres
);
274 snew(maxdres
[i
-1], nres
);
275 for(j
=0; j
<nres
; j
++)
277 /* maxdres[*][*] is already 0 */
282 if ( bSplit
&& !bFirst
&& abs(t
/time_factor())<1e-5 ) {
283 fprintf(dist
, "&\n");
284 if (num
) fprintf(num
, "&\n");
285 if (atm
) fprintf(atm
, "&\n");
287 fprintf(dist
,"%12g",convert_time(t
));
288 if (num
) fprintf(num
,"%12g",convert_time(t
));
292 calc_dist(rcut
,box
,x0
,gnx
[0],gnx
[0],index
[0],index
[0],
293 &dmin
,&dmax
,&nmin
,&nmax
,&min1
,&min2
,&max1
,&max2
);
294 fprintf(dist
," %12g",bMin
?dmin
:dmax
);
295 if (num
) fprintf(num
," %8d",bMin
?nmin
:nmax
);
298 for(i
=0; (i
<ng
-1); i
++) {
299 for(k
=i
+1; (k
<ng
); k
++) {
300 calc_dist(rcut
,box
,x0
,gnx
[i
],gnx
[k
],index
[i
],index
[k
],
301 &dmin
,&dmax
,&nmin
,&nmax
,&min1
,&min2
,&max1
,&max2
);
302 fprintf(dist
," %12g",bMin
?dmin
:dmax
);
303 if (num
) fprintf(num
," %8d",bMin
?nmin
:nmax
);
309 for(i
=1; (i
<ng
); i
++) {
310 calc_dist(rcut
,box
,x0
,gnx
[0],gnx
[i
],index
[0],index
[i
],
311 &dmin
,&dmax
,&nmin
,&nmax
,&min1
,&min2
,&max1
,&max2
);
312 fprintf(dist
," %12g",bMin
?dmin
:dmax
);
313 if (num
) fprintf(num
," %8d",bMin
?nmin
:nmax
);
315 for(j
=0; j
<nres
; j
++) {
316 calc_dist(rcut
,box
,x0
,residue
[j
+1]-residue
[j
],gnx
[i
],
317 &(index
[0][residue
[j
]]),index
[i
],
318 &dmin
,&dmax
,&nmin
,&nmax
,&min1
,&min2
,&max1
,&max2
);
319 mindres
[i
-1][j
] = min(mindres
[i
-1][j
],dmin
);
320 maxdres
[i
-1][j
] = max(maxdres
[i
-1][j
],dmax
);
328 if ( bMin
?min1
:max1
!= -1 )
330 fprintf(atm
,"%12g %12d %12d\n",
331 convert_time(t
),bMin
?min1
:max1
+1,bMin
?min2
:max2
+1);
334 oindex
[0]=bMin
?min1
:max1
;
335 oindex
[1]=bMin
?min2
:max2
;
336 write_trx(trxout
,2,oindex
,atoms
,i
,t
,box
,x0
,NULL
);
339 } while (read_next_x(status
,&t
,natoms
,x0
,box
));
343 if (num
) fclose(num
);
344 if (atm
) fclose(atm
);
345 if (trxout
>=0) close_xtc(trxout
);
350 sprintf(buf
,"%simum Distance",bMin
? "Min" : "Max");
351 res
=xvgropen(rfile
,buf
,"Residue (#)","Distance (nm)");
352 xvgr_legend(res
,ng
-1,leg
);
353 for(j
=0; j
<nres
; j
++) {
354 fprintf(res
, "%4d", j
+1);
355 for(i
=1; i
<ng
; i
++) {
356 fprintf(res
, " %7g", bMin
? mindres
[i
-1][j
] : maxdres
[i
-1][j
]);
365 int find_residues(t_atoms
*atoms
, int n
, atom_id index
[], atom_id
**resindex
)
368 int nres
=0,resnr
, presnr
;
371 /* build index of first atom numbers for each residue */
373 snew(residx
, atoms
->nres
);
375 resnr
= atoms
->atom
[index
[i
]].resnr
;
376 if (resnr
!= presnr
) {
382 if (debug
) printf("Found %d residues out of %d (%d/%d atoms)\n",
383 nres
, atoms
->nres
, atoms
->nr
, n
);
384 srenew(residx
, nres
+1);
385 /* mark end of last residue */
391 void dump_res(FILE *out
, int nres
, atom_id
*resindex
, int n
, atom_id index
[])
395 for(i
=0; i
<nres
-1; i
++) {
396 fprintf(out
,"Res %d (%d):", i
, resindex
[i
+1]-resindex
[i
]);
397 for(j
=resindex
[i
]; j
<resindex
[i
+1]; j
++)
398 fprintf(out
," %d(%d)", j
, index
[j
]);
403 int main(int argc
,char *argv
[])
405 static char *desc
[] = {
406 "g_mindist computes the distance between one group and a number of",
408 "Both the minimum distance and the number of contacts within a given",
409 "distance are written to two separate output files.",
410 "With [TT]-or[tt], minimum distances to each residue in the first",
411 "group are determined and plotted as a function of reisdue number.[PAR]",
412 "With option [TT]-pi[tt] the minimum distance of a group to its",
413 "periodic image is plotted. This is useful for checking if a protein",
414 "has seen its periodic image during a simulation. Only one shift in",
415 "each direction is considered, giving a total of 26 shifts.",
416 "It also plots the maximum distance within the group and the lengths",
417 "of the three box vectors.[PAR]",
418 "Other programs that calculate distances are [TT]g_dist[tt]",
419 "and [TT]g_bond[tt]."
421 static char *bugs
[] = {
422 "The [TT]-pi[tt] option is very slow."
425 static bool bMat
=FALSE
,bPer
=FALSE
,bSplit
=FALSE
,bMax
=FALSE
;
426 static real rcutoff
=0.6;
428 { "-matrix", FALSE
, etBOOL
, {&bMat
},
429 "Calculate half a matrix of group-group distances" },
430 { "-max", FALSE
, etBOOL
, {&bMax
},
431 "Calculate *maximum* distance instead of minimum" },
432 { "-d", FALSE
, etREAL
, {&rcutoff
},
433 "Distance for contacts" },
434 { "-pi", FALSE
, etBOOL
, {&bPer
},
435 "Calculate minimum distance with periodic images" },
436 { "-split", FALSE
, etBOOL
, {&bSplit
},
437 "Split graph where time is zero" },
447 char *trxfnm
,*tpsfnm
,*ndxfnm
,*distfnm
,*numfnm
,*atmfnm
,*oxfnm
,*resfnm
;
450 atom_id
**index
, *residues
=NULL
;
452 { efTRX
, "-f", NULL
, ffREAD
},
453 { efTPS
, NULL
, NULL
, ffOPTRD
},
454 { efNDX
, NULL
, NULL
, ffOPTRD
},
455 { efXVG
, "-od","mindist", ffWRITE
},
456 { efXVG
, "-on","numcont", ffOPTWR
},
457 { efOUT
, "-o", "atm-pair", ffOPTWR
},
458 { efTRX
, "-ox","mindist", ffOPTWR
},
459 { efXVG
, "-or","mindistres", ffOPTWR
}
461 #define NFILE asize(fnm)
463 CopyRight(stderr
,argv
[0]);
464 parse_common_args(&argc
,argv
,
465 PCA_CAN_VIEW
| PCA_CAN_TIME
| PCA_TIME_UNIT
| PCA_BE_NICE
,
466 NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,0,NULL
);
468 trxfnm
= ftp2fn(efTRX
,NFILE
,fnm
);
469 tpsfnm
= ftp2fn_null(efTPS
,NFILE
,fnm
);
470 ndxfnm
= ftp2fn_null(efNDX
,NFILE
,fnm
);
471 distfnm
= opt2fn("-od",NFILE
,fnm
);
472 numfnm
= opt2fn_null("-on",NFILE
,fnm
);
473 atmfnm
= ftp2fn_null(efOUT
,NFILE
,fnm
);
474 oxfnm
= opt2fn_null("-ox",NFILE
,fnm
);
475 resfnm
= opt2fn_null("-or",NFILE
,fnm
);
479 fprintf(stderr
,"Choose a group for distance calculation\n");
482 fprintf(stderr
,"You can compute all distances between a number of groups\n"
483 "How many groups do you want (>= 1) ?\n");
485 fprintf(stderr
,"You can compute the distances between a first group\n"
486 "and a number of other groups.\n"
487 "How many other groups do you want (>= 1) ?\n");
499 if (tpsfnm
|| !ndxfnm
)
500 read_tps_conf(tpsfnm
,title
,&top
,&x
,NULL
,box
,FALSE
);
502 get_index(&top
.atoms
,ndxfnm
,ng
,gnx
,index
,grpname
);
504 if (bMat
&& (ng
== 1)) {
506 printf("Special case: making distance matrix between all atoms in group %s\n",
511 for(i
=1; (i
<ng
); i
++) {
513 grpname
[i
] = grpname
[0];
515 index
[i
][0] = index
[0][i
];
521 nres
=find_residues(&top
.atoms
, gnx
[0], index
[0], &residues
);
522 if (debug
) dump_res(debug
, nres
, residues
, gnx
[0], index
[0]);
526 periodic_mindist_plot(trxfnm
,distfnm
,&top
,gnx
[0],index
[0],bSplit
);
528 dist_plot(trxfnm
,atmfnm
,distfnm
,numfnm
,resfnm
,oxfnm
,
529 rcutoff
,bMat
,&top
.atoms
,ng
,index
,gnx
,grpname
,bSplit
,
530 !bMax
, nres
, residues
);
532 do_view(distfnm
,"-nxy");
534 do_view(numfnm
,"-nxy");