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
54 /* this version only works correctly if one of the entries in the index file
55 is a plane (three atoms specified) and the other a vector. Distance
56 is calculated from the center of the plane to both atoms of the vector */
58 static void print_types(atom_id index1
[], int gnx1
, char *group1
,
59 atom_id index2
[], int gnx2
, char *group2
,
65 fprintf(stderr
,"Group %s contains the following atoms: \n",group1
);
67 fprintf(stderr
,"Atomname %d: %s\n",i
,*(top
->atoms
.atomname
[index1
[i
]]));
70 fprintf(stderr
,"Group %s contains the following atoms: \n",group2
);
72 fprintf(stderr
,"Atomname %d: %s\n",j
,*(top
->atoms
.atomname
[index2
[j
]]));
75 fprintf(stderr
,"Careful: distance only makes sense in some situations.\n\n");
78 static void calculate_normal(atom_id index
[],rvec x
[],rvec result
,rvec center
)
83 /* calculate centroid of triangle spanned by the three points */
85 center
[i
] = (x
[index
[0]][i
] + x
[index
[1]][i
] + x
[index
[2]][i
])/3;
87 /* use P1P2 x P1P3 to calculate normal, given three points P1-P3 */
88 rvec_sub(x
[index
[1]],x
[index
[0]],c1
); /* find two vectors */
89 rvec_sub(x
[index
[2]],x
[index
[0]],c2
);
91 cprod(c1
,c2
,result
); /* take crossproduct between these */
94 /* calculate the angle and distance between the two groups */
95 static void calc_angle(int ePBC
,matrix box
,rvec x
[], atom_id index1
[],
96 atom_id index2
[], int gnx1
, int gnx2
,
97 real
*angle
, real
*distance
,
98 real
*distance1
, real
*distance2
)
100 /* distance is distance between centers, distance 1 between center of plane
101 and atom one of vector, distance 2 same for atom two
106 normal1
,normal2
, /* normals on planes of interest */
107 center1
,center2
, /* center of triangle of points given to define plane,*/
108 /* or center of vector if a vector is given */
109 h1
,h2
,h3
,h4
,h5
; /* temp. vectors */
112 set_pbc(&pbc
,ePBC
,box
);
116 case 3: /* group 1 defines plane */
117 calculate_normal(index1
,x
,normal1
,center1
);
119 case 2: /* group 1 defines vector */
120 rvec_sub(x
[index1
[0]],x
[index1
[1]],normal1
);
121 rvec_add(x
[index1
[0]],x
[index1
[1]],h1
);
122 svmul(0.5,h1
,center1
); /* center is geometric mean */
124 default: /* group 1 does none of the above */
125 gmx_fatal(FARGS
,"Something wrong with contents of index file.\n");
130 case 3: /* group 2 defines plane */
131 calculate_normal(index2
,x
,normal2
,center2
);
133 case 2: /* group 2 defines vector */
134 rvec_sub(x
[index2
[0]],x
[index2
[1]],normal2
);
135 rvec_add(x
[index2
[0]],x
[index2
[1]],h2
);
136 svmul(0.5,h2
,center2
); /* center is geometric mean */
146 default: /* group 2 does none of the above */
147 gmx_fatal(FARGS
,"Something wrong with contents of index file.\n");
150 *angle
= cos_angle(normal1
,normal2
);
153 pbc_dx(&pbc
,center1
,center2
,h3
);
155 rvec_sub(center1
,center2
,h3
);
156 *distance
= norm(h3
);
158 if (gnx1
== 3 && gnx2
== 2) {
160 pbc_dx(&pbc
,center1
,x
[index2
[0]],h4
);
161 pbc_dx(&pbc
,center1
,x
[index2
[1]],h5
);
163 rvec_sub(center1
,x
[index2
[0]],h4
);
164 rvec_sub(center1
,x
[index2
[1]],h5
);
166 *distance1
= norm(h4
);
167 *distance2
= norm(h5
);
169 else if (gnx1
== 2 && gnx2
==3) {
170 rvec_sub(center1
,x
[index1
[0]],h4
);
171 rvec_sub(center1
,x
[index1
[1]],h5
);
172 *distance1
= norm(h4
);
173 *distance2
= norm(h5
);
176 *distance1
= 0; *distance2
= 0;
180 void sgangle_plot(const char *fn
,const char *afile
,const char *dfile
,
181 const char *d1file
, const char *d2file
,
182 atom_id index1
[], int gnx1
, char *grpn1
,
183 atom_id index2
[], int gnx2
, char *grpn2
,
184 t_topology
*top
,int ePBC
,const output_env_t oenv
)
187 *sg_angle
, /* xvgr file with angles */
188 *sg_distance
= NULL
, /* xvgr file with distances */
189 *sg_distance1
= NULL
,/* xvgr file with distance between plane and atom */
190 *sg_distance2
= NULL
;/* xvgr file with distance between plane and atom2 */
193 angle
, /* cosine of angle between two groups */
194 distance
, /* distance between two groups. */
195 distance1
, /* distance between plane and one of two atoms */
196 distance2
; /* same for second of two atoms */
197 int status
,natoms
,teller
=0;
198 rvec
*x0
; /* coordinates, and coordinates corrected for pb */
200 char buf
[256]; /* for xvgr title */
202 if ((natoms
= read_first_x(oenv
,&status
,fn
,&t
,&x0
,box
)) == 0)
203 gmx_fatal(FARGS
,"Could not read coordinates from statusfile\n");
205 sprintf(buf
,"Angle between %s and %s",grpn1
,grpn2
);
206 sg_angle
= xvgropen(afile
,buf
,"Time (ps)","Angle (degrees)",oenv
);
209 sprintf(buf
,"Distance between %s and %s",grpn1
,grpn2
);
210 sg_distance
= xvgropen(dfile
,buf
,"Time (ps)","Distance (nm)",oenv
);
214 sprintf(buf
,"Distance between plane and first atom of vector");
215 sg_distance1
= xvgropen(d1file
,buf
,"Time (ps)","Distance (nm)",oenv
);
219 sprintf(buf
,"Distance between plane and second atom of vector");
220 sg_distance2
= xvgropen(d2file
,buf
,"Time (ps","Distance (nm)",oenv
);
227 rm_pbc(&(top
->idef
),ePBC
,natoms
,box
,x0
,x0
);
229 calc_angle(ePBC
,box
,x0
,index1
,index2
,gnx1
,gnx2
,&angle
,
230 &distance
,&distance1
,&distance2
);
232 fprintf(sg_angle
,"%12g %12g %12g\n",t
,angle
,acos(angle
)*180.0/M_PI
);
234 fprintf(sg_distance
,"%12g %12g\n",t
,distance
);
236 fprintf(sg_distance1
,"%12g %12g\n",t
,distance1
);
238 fprintf(sg_distance2
,"%12g %12g\n",t
,distance1
);
240 } while (read_next_x(oenv
,status
,&t
,natoms
,x0
,box
));
242 fprintf(stderr
,"\n");
248 fclose(sg_distance1
);
250 fclose(sg_distance2
);
255 static void calc_angle_single(int ePBC
,
270 /* distance is distance between centers, distance 1 between center of plane
271 and atom one of vector, distance 2 same for atom two
274 rvec normal1
,normal2
; /* normals on planes of interest */
275 rvec center1
,center2
;
276 /* center of triangle of pts to define plane,
277 * or center of vector if a vector is given
279 rvec h1
,h2
,h3
,h4
,h5
; /* temp. vectors */
282 set_pbc(&pbc
,ePBC
,box
);
285 case 3: /* group 1 defines plane */
286 calculate_normal(index1
,xzero
,normal1
,center1
);
288 case 2: /* group 1 defines vector */
289 rvec_sub(xzero
[index1
[0]],xzero
[index1
[1]],normal1
);
290 rvec_add(xzero
[index1
[0]],xzero
[index1
[1]],h1
);
291 svmul(0.5,h1
,center1
); /* center is geometric mean */
293 default: /* group 1 does none of the above */
294 gmx_fatal(FARGS
,"Something wrong with contents of index file.\n");
298 case 3: /* group 2 defines plane */
299 calculate_normal(index2
,x
,normal2
,center2
);
301 case 2: /* group 2 defines vector */
302 rvec_sub(x
[index2
[0]],x
[index2
[1]],normal2
);
303 rvec_add(x
[index2
[0]],x
[index2
[1]],h2
);
304 svmul(0.5,h2
,center2
); /* center is geometric mean */
306 default: /* group 2 does none of the above */
307 gmx_fatal(FARGS
,"Something wrong with contents of index file.\n");
310 *angle
= cos_angle(normal1
,normal2
);
313 pbc_dx(&pbc
,center1
,center2
,h3
);
315 rvec_sub(center1
,center2
,h3
);
316 *distance
= norm(h3
);
318 if (gnx1
== 3 && gnx2
== 2) {
320 pbc_dx(&pbc
,center1
,x
[index2
[0]],h4
);
321 pbc_dx(&pbc
,center1
,x
[index2
[1]],h5
);
323 rvec_sub(center1
,x
[index2
[0]],h4
);
324 rvec_sub(center1
,x
[index2
[1]],h5
);
326 *distance1
= norm(h4
);
327 *distance2
= norm(h5
);
328 } else if (gnx1
== 2 && gnx2
==3) {
329 rvec_sub(center1
,xzero
[index1
[0]],h4
);
330 rvec_sub(center1
,xzero
[index1
[1]],h5
);
331 *distance1
= norm(h4
);
332 *distance2
= norm(h5
);
334 *distance1
= 0; *distance2
= 0;
339 void sgangle_plot_single(const char *fn
,const char *afile
,const char *dfile
,
340 const char *d1file
, const char *d2file
,
341 atom_id index1
[], int gnx1
, char *grpn1
,
342 atom_id index2
[], int gnx2
, char *grpn2
,
343 t_topology
*top
,int ePBC
, const output_env_t oenv
)
346 *sg_angle
, /* xvgr file with angles */
347 *sg_distance
= NULL
, /* xvgr file with distances */
348 *sg_distance1
= NULL
,/* xvgr file with distance between plane and atom */
349 *sg_distance2
= NULL
;/* xvgr file with distance between plane and atom2 */
352 angle
, /* cosine of angle between two groups */
353 distance
, /* distance between two groups. */
354 distance1
, /* distance between plane and one of two atoms */
355 distance2
; /* same for second of two atoms */
356 int status
,natoms
,teller
=0;
358 rvec
*x0
; /* coordinates, and coordinates corrected for pb */
361 char buf
[256]; /* for xvgr title */
363 if ((natoms
= read_first_x(oenv
,&status
,fn
,&t
,&x0
,box
)) == 0)
364 gmx_fatal(FARGS
,"Could not read coordinates from statusfile\n");
366 sprintf(buf
,"Angle between %s and %s",grpn1
,grpn2
);
367 sg_angle
= xvgropen(afile
,buf
,"Time (ps)","Cos(angle) ",oenv
);
370 sprintf(buf
,"Distance between %s and %s",grpn1
,grpn2
);
371 sg_distance
= xvgropen(dfile
,buf
,"Time (ps)","Distance (nm)",oenv
);
375 sprintf(buf
,"Distance between plane and first atom of vector");
376 sg_distance1
= xvgropen(d1file
,buf
,"Time (ps)","Distance (nm)",oenv
);
380 sprintf(buf
,"Distance between plane and second atom of vector");
381 sg_distance2
= xvgropen(d2file
,buf
,"Time (ps","Distance (nm)",oenv
);
389 rm_pbc(&(top
->idef
),ePBC
,natoms
,box
,x0
,x0
);
391 for(i
=0;i
<natoms
;i
++)
392 copy_rvec(x0
[i
],xzero
[i
]);
396 calc_angle_single(ePBC
,box
,
397 xzero
,x0
,index1
,index2
,gnx1
,gnx2
,&angle
,
398 &distance
,&distance1
,&distance2
);
400 fprintf(sg_angle
,"%12g %12g %12g\n",t
,angle
,acos(angle
)*180.0/M_PI
);
402 fprintf(sg_distance
,"%12g %12g\n",t
,distance
);
404 fprintf(sg_distance1
,"%12g %12g\n",t
,distance1
);
406 fprintf(sg_distance2
,"%12g %12g\n",t
,distance1
);
408 } while (read_next_x(oenv
,status
,&t
,natoms
,x0
,box
));
410 fprintf(stderr
,"\n");
416 fclose(sg_distance1
);
418 fclose(sg_distance2
);
425 int gmx_sgangle(int argc
,char *argv
[])
427 const char *desc
[] = {
428 "Compute the angle and distance between two groups. ",
429 "The groups are defined by a number of atoms given in an index file and",
430 "may be two or three atoms in size.",
431 "If -one is set, only one group should be specified in the index",
432 "file and the angle between this group at time 0 and t will be computed.",
433 "The angles calculated depend on the order in which the atoms are ",
434 "given. Giving for instance 5 6 will rotate the vector 5-6 with ",
435 "180 degrees compared to giving 6 5. [PAR]If three atoms are given, ",
436 "the normal on the plane spanned by those three atoms will be",
437 "calculated, using the formula P1P2 x P1P3.",
438 "The cos of the angle is calculated, using the inproduct of the two",
439 "normalized vectors.[PAR]",
440 "Here is what some of the file options do:[BR]",
441 "-oa: Angle between the two groups specified in the index file. If a group contains three atoms the normal to the plane defined by those three atoms will be used. If a group contains two atoms, the vector defined by those two atoms will be used.[BR]",
442 "-od: Distance between two groups. Distance is taken from the center of one group to the center of the other group.[BR]",
443 "-od1: If one plane and one vector is given, the distances for each of the atoms from the center of the plane is given seperately.[BR]",
444 "-od2: For two planes this option has no meaning."
448 const char *fna
, *fnd
, *fnd1
, *fnd2
;
449 char * grpname
[2]; /* name of the two groups */
450 int gnx
[2]; /* size of the two groups */
451 t_topology
*top
; /* topology */
454 static bool bOne
= FALSE
, bZ
=FALSE
;
456 { "-one", FALSE
, etBOOL
, {&bOne
},
457 "Only one group compute angle between vector at time zero and time t"},
458 { "-z", FALSE
, etBOOL
, {&bZ
},
459 "Use the Z-axis as reference" }
461 #define NPA asize(pa)
463 t_filenm fnm
[] = { /* files for g_sgangle */
464 { efTRX
, "-f", NULL
, ffREAD
}, /* trajectory file */
465 { efNDX
, NULL
, NULL
, ffREAD
}, /* index file */
466 { efTPX
, NULL
, NULL
, ffREAD
}, /* topology file */
467 { efXVG
,"-oa","sg_angle",ffWRITE
}, /* xvgr output file */
468 { efXVG
, "-od","sg_dist",ffOPTWR
}, /* xvgr output file */
469 { efXVG
, "-od1", "sg_dist1",ffOPTWR
}, /* xvgr output file */
470 { efXVG
, "-od2", "sg_dist2",ffOPTWR
} /* xvgr output file */
473 #define NFILE asize(fnm)
475 CopyRight(stderr
,argv
[0]);
476 parse_common_args(&argc
,argv
,PCA_CAN_VIEW
| PCA_CAN_TIME
| PCA_BE_NICE
,
477 NFILE
,fnm
,NPA
,pa
,asize(desc
),desc
,0,NULL
,&oenv
);
480 top
= read_top(ftp2fn(efTPX
,NFILE
,fnm
),&ePBC
); /* read topology file */
482 fna
= opt2fn("-oa",NFILE
,fnm
);
483 fnd
= opt2fn_null("-od",NFILE
,fnm
);
484 fnd1
= opt2fn_null("-od1",NFILE
,fnm
);
485 fnd2
= opt2fn_null("-od2",NFILE
,fnm
);
487 /* read index file. */
489 rd_index(ftp2fn(efNDX
,NFILE
,fnm
),1,gnx
,index
,grpname
);
490 print_types(index
[0],gnx
[0],grpname
[0],
491 index
[0],gnx
[0],grpname
[0],top
);
493 sgangle_plot_single(ftp2fn(efTRX
,NFILE
,fnm
), fna
, fnd
, fnd1
, fnd2
,
494 index
[0],gnx
[0],grpname
[0],
495 index
[0],gnx
[0],grpname
[0],
498 rd_index(ftp2fn(efNDX
,NFILE
,fnm
),bZ
? 1 : 2,gnx
,index
,grpname
);
500 print_types(index
[0],gnx
[0],grpname
[0],
501 index
[1],gnx
[1],grpname
[1],top
);
504 grpname
[1] = strdup("Z-axis");
506 sgangle_plot(ftp2fn(efTRX
,NFILE
,fnm
), fna
, fnd
, fnd1
, fnd2
,
507 index
[0],gnx
[0],grpname
[0],
508 index
[1],gnx
[1],grpname
[1],
512 do_view(oenv
,fna
,"-nxy"); /* view xvgr file */
513 do_view(oenv
,fnd
,"-nxy"); /* view xvgr file */
514 do_view(oenv
,fnd1
,"-nxy"); /* view xvgr file */
515 do_view(oenv
,fnd2
,"-nxy"); /* view xvgr file */