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"
58 int gmx_helixorient(int argc
,char *argv
[])
60 const char *desc
[] = {
61 "g_helixorient calculates coordinates and direction of the average",
62 "axis inside an alpha helix, and the direction/vectors of both the",
63 "alpha carbon and (optionally) a sidechain atom relative to the axis.[PAR]",
64 "As input, you need to specify an index group with alpha carbon atoms",
65 "corresponding to an alpha helix of continuous residues. Sidechain",
66 "directions require a second index group of the same size, containing",
67 "the heavy atom in each residue that should represent the sidechain.[PAR]"
68 "Note that this program does not do any fitting of structures.[PAR]",
69 "We need four Calpha coordinates to define the local direction of the helix",
71 "The tilt/rotation is calculated from Euler rotations, where we define",
72 "the helix axis as the local X axis, the residues/CA-vector as Y, and the",
73 "Z axis from their cross product. We use the Euler Y-Z-X rotation, meaning",
74 "we first tilt the helix axis (1) around and (2) orthogonal to the residues",
75 "vector, and finally apply the (3) rotation around it. For debugging or other",
76 "purposes, we also write out the actual Euler rotation angles as theta1-3.xvg"
85 real theta1
,theta2
,theta3
;
94 rvec v1
,v2
,p1
,p2
,vtmp
,vproj
;
102 rvec
*residuehelixaxis
;
105 rvec
*sidechainvector
;
109 rvec
*residuehelixaxis_t0
;
110 rvec
*residuevector_t0
;
112 rvec
*residuehelixaxis_tlast
;
113 rvec
*residuevector_tlast
;
115 rvec refaxes
[3],newaxes
[3];
117 rvec rot_refaxes
[3],rot_newaxes
[3];
121 real
*twist
,*residuetwist
;
122 real
*radius
,*residueradius
;
123 real
*rise
,*residuerise
;
124 real
*residuebending
;
131 FILE *fpaxis
,*fpcenter
,*fptilt
,*fprotation
;
132 FILE *fpradius
,*fprise
,*fptwist
;
133 FILE *fptheta1
,*fptheta2
,*fptheta3
;
139 static bool bSC
=FALSE
;
140 static bool bIncremental
= FALSE
;
142 static t_pargs pa
[] = {
143 { "-sidechain", FALSE
, etBOOL
, {&bSC
},
144 "Calculate sidechain directions relative to helix axis too." },
145 { "-incremental", FALSE
, etBOOL
, {&bIncremental
},
146 "Calculate incremental rather than total rotation/tilt." },
148 #define NPA asize(pa)
151 { efTPX
, NULL
, NULL
, ffREAD
},
152 { efTRX
, "-f", NULL
, ffREAD
},
153 { efNDX
, NULL
, NULL
, ffOPTRD
},
154 { efDAT
, "-oaxis", "helixaxis", ffWRITE
},
155 { efDAT
, "-ocenter", "center", ffWRITE
},
156 { efXVG
, "-orise", "rise",ffWRITE
},
157 { efXVG
, "-oradius", "radius",ffWRITE
},
158 { efXVG
, "-otwist", "twist",ffWRITE
},
159 { efXVG
, "-obending", "bending",ffWRITE
},
160 { efXVG
, "-otilt", "tilt", ffWRITE
},
161 { efXVG
, "-orot", "rotation",ffWRITE
}
163 #define NFILE asize(fnm)
166 CopyRight(stderr
,argv
[0]);
168 parse_common_args(&argc
,argv
,PCA_CAN_TIME
| PCA_BE_NICE
,
169 NFILE
,fnm
,NPA
,pa
,asize(desc
),desc
,0,NULL
,&oenv
);
171 top
=read_top(ftp2fn(efTPX
,NFILE
,fnm
),&ePBC
);
176 /* read index files */
177 printf("Select a group of Calpha atoms corresponding to a single continuous helix:\n");
178 get_index(&(top
->atoms
),ftp2fn_null(efNDX
,NFILE
,fnm
),1,&iCA
,&ind_CA
,&gn_CA
);
180 snew(x_SC
,iCA
); /* sic! */
187 snew(helixaxis
,iCA
-3);
189 snew(residuetwist
,iCA
);
191 snew(residueradius
,iCA
);
193 snew(residuerise
,iCA
);
194 snew(residueorigin
,iCA
);
195 snew(residuehelixaxis
,iCA
);
196 snew(residuevector
,iCA
);
197 snew(sidechainvector
,iCA
);
198 snew(residuebending
,iCA
);
199 snew(residuehelixaxis_t0
,iCA
);
200 snew(residuevector_t0
,iCA
);
202 snew(residuehelixaxis_tlast
,iCA
);
203 snew(residuevector_tlast
,iCA
);
204 snew(axis3_tlast
,iCA
);
209 printf("Select a group of atoms defining the sidechain direction (1/residue):\n");
210 get_index(&(top
->atoms
),ftp2fn_null(efNDX
,NFILE
,fnm
),1,&iSC
,&ind_SC
,&gn_SC
);
212 gmx_fatal(FARGS
,"Number of sidechain atoms (%d) != number of CA atoms (%d)",iSC
,iCA
);
216 natoms
=read_first_x(oenv
,&status
,ftp2fn(efTRX
,NFILE
,fnm
),&t
,&x
,box
);
218 fpaxis
=ffopen(opt2fn("-oaxis",NFILE
,fnm
),"w");
219 fpcenter
=ffopen(opt2fn("-ocenter",NFILE
,fnm
),"w");
220 fprise
=ffopen(opt2fn("-orise",NFILE
,fnm
),"w");
221 fpradius
=ffopen(opt2fn("-oradius",NFILE
,fnm
),"w");
222 fptwist
=ffopen(opt2fn("-otwist",NFILE
,fnm
),"w");
223 fpbending
=ffopen(opt2fn("-obending",NFILE
,fnm
),"w");
225 fptheta1
=ffopen("theta1.xvg","w");
226 fptheta2
=ffopen("theta2.xvg","w");
227 fptheta3
=ffopen("theta3.xvg","w");
231 fptilt
=xvgropen(opt2fn("-otilt",NFILE
,fnm
),
232 "Incremental local helix tilt","Time(ps)","Tilt (degrees)",
234 fprotation
=xvgropen(opt2fn("-orot",NFILE
,fnm
),
235 "Incremental local helix rotation","Time(ps)",
236 "Rotation (degrees)",oenv
);
240 fptilt
=xvgropen(opt2fn("-otilt",NFILE
,fnm
),
241 "Cumulative local helix tilt","Time(ps)","Tilt (degrees)",oenv
);
242 fprotation
=xvgropen(opt2fn("-orot",NFILE
,fnm
),
243 "Cumulative local helix rotation","Time(ps)",
244 "Rotation (degrees)",oenv
);
247 clear_rvecs(3,unitaxes
);
254 /* initialisation for correct distance calculations */
255 set_pbc(&pbc
,ePBC
,box
);
256 /* make molecules whole again */
257 rm_pbc(&top
->idef
,ePBC
,natoms
,box
,x
,x
);
259 /* copy coords to our smaller arrays */
262 copy_rvec(x
[ind_CA
[i
]],x_CA
[i
]);
265 copy_rvec(x
[ind_SC
[i
]],x_SC
[i
]);
271 rvec_sub(x_CA
[i
+1],x_CA
[i
],r12
[i
]);
272 rvec_sub(x_CA
[i
+2],x_CA
[i
+1],r23
[i
]);
273 rvec_sub(x_CA
[i
+3],x_CA
[i
+2],r34
[i
]);
274 rvec_sub(r12
[i
],r23
[i
],diff13
[i
]);
275 rvec_sub(r23
[i
],r34
[i
],diff24
[i
]);
276 /* calculate helix axis */
277 cprod(diff13
[i
],diff24
[i
],helixaxis
[i
]);
278 svmul(1.0/norm(helixaxis
[i
]),helixaxis
[i
],helixaxis
[i
]);
280 tmp
= cos_angle(diff13
[i
],diff24
[i
]);
281 twist
[i
] = 180.0/M_PI
* acos( tmp
);
282 radius
[i
] = sqrt( norm(diff13
[i
])*norm(diff24
[i
]) ) / (2.0* (1.0-tmp
) );
283 rise
[i
]=fabs(iprod(r23
[i
],helixaxis
[i
]));
285 svmul(radius
[i
]/norm(diff13
[i
]),diff13
[i
],v1
);
286 svmul(radius
[i
]/norm(diff24
[i
]),diff24
[i
],v2
);
288 rvec_sub(x_CA
[i
+1],v1
,residueorigin
[i
+1]);
289 rvec_sub(x_CA
[i
+2],v2
,residueorigin
[i
+2]);
291 residueradius
[0]=residuetwist
[0]=residuerise
[0]=0;
293 residueradius
[1]=radius
[0];
294 residuetwist
[1]=twist
[0];
295 residuerise
[1]=rise
[0];
297 residuebending
[0]=residuebending
[1]=0;
300 residueradius
[i
]=0.5*(radius
[i
-2]+radius
[i
-1]);
301 residuetwist
[i
]=0.5*(twist
[i
-2]+twist
[i
-1]);
302 residuerise
[i
]=0.5*(rise
[i
-2]+rise
[i
-1]);
303 residuebending
[i
] = 180.0/M_PI
*acos( cos_angle(helixaxis
[i
-2],helixaxis
[i
-1]) );
305 residueradius
[iCA
-2]=radius
[iCA
-4];
306 residuetwist
[iCA
-2]=twist
[iCA
-4];
307 residuerise
[iCA
-2]=rise
[iCA
-4];
308 residueradius
[iCA
-1]=residuetwist
[iCA
-1]=residuerise
[iCA
-1]=0;
309 residuebending
[iCA
-2]=residuebending
[iCA
-1]=0;
311 clear_rvec(residueorigin
[0]);
312 clear_rvec(residueorigin
[iCA
-1]);
314 /* average helix axes to define them on the residues.
315 * Just extrapolate second first/list atom.
317 copy_rvec(helixaxis
[0],residuehelixaxis
[0]);
318 copy_rvec(helixaxis
[0],residuehelixaxis
[1]);
322 rvec_add(helixaxis
[i
-2],helixaxis
[i
-1],residuehelixaxis
[i
]);
323 svmul(0.5,residuehelixaxis
[i
],residuehelixaxis
[i
]);
325 copy_rvec(helixaxis
[iCA
-4],residuehelixaxis
[iCA
-2]);
326 copy_rvec(helixaxis
[iCA
-4],residuehelixaxis
[iCA
-1]);
328 /* Normalize the axis */
331 svmul(1.0/norm(residuehelixaxis
[i
]),residuehelixaxis
[i
],residuehelixaxis
[i
]);
334 /* calculate vector from origin to residue CA */
335 fprintf(fpaxis
,"%15.12g ",t
);
336 fprintf(fpcenter
,"%15.12g ",t
);
337 fprintf(fprise
,"%15.12g ",t
);
338 fprintf(fpradius
,"%15.12g ",t
);
339 fprintf(fptwist
,"%15.12g ",t
);
340 fprintf(fpbending
,"%15.12g ",t
);
346 fprintf(fpaxis
,"%15.12g %15.12g %15.12g ",0.0,0.0,0.0);
347 fprintf(fpcenter
,"%15.12g %15.12g %15.12g ",0.0,0.0,0.0);
348 fprintf(fprise
,"%15.12g ",0.0);
349 fprintf(fpradius
,"%15.12g ",0.0);
350 fprintf(fptwist
,"%15.12g ",0.0);
351 fprintf(fpbending
,"%15.12g ",0.0);
355 rvec_sub( bSC
? x_SC
[i
] : x_CA
[i
] ,residueorigin
[i
], residuevector
[i
]);
356 svmul(1.0/norm(residuevector
[i
]),residuevector
[i
],residuevector
[i
]);
357 cprod(residuehelixaxis
[i
],residuevector
[i
],axis3
[i
]);
358 fprintf(fpaxis
,"%15.12g %15.12g %15.12g ",residuehelixaxis
[i
][0],residuehelixaxis
[i
][1],residuehelixaxis
[i
][2]);
359 fprintf(fpcenter
,"%15.12g %15.12g %15.12g ",residueorigin
[i
][0],residueorigin
[i
][1],residueorigin
[i
][2]);
361 fprintf(fprise
,"%15.12g ",residuerise
[i
]);
362 fprintf(fpradius
,"%15.12g ",residueradius
[i
]);
363 fprintf(fptwist
,"%15.12g ",residuetwist
[i
]);
364 fprintf(fpbending
,"%15.12g ",residuebending
[i
]);
366 /* angle with local vector? */
368 printf("res[%2d]: axis: %g %g %g origin: %g %g %g vector: %g %g %g angle: %g\n",i,
369 residuehelixaxis[i][0],
370 residuehelixaxis[i][1],
371 residuehelixaxis[i][2],
378 180.0/M_PI*acos( cos_angle(residuevector[i],residuehelixaxis[i]) ));
380 /* fprintf(fp,"%15.12g %15.12g %15.12g %15.12g %15.12g %15.12g\n",
381 residuehelixaxis[i][0],
382 residuehelixaxis[i][1],
383 residuehelixaxis[i][2],
386 residuevector[i][2]);
390 fprintf(fprise
,"\n");
391 fprintf(fpradius
,"\n");
392 fprintf(fpaxis
,"\n");
393 fprintf(fpcenter
,"\n");
394 fprintf(fptwist
,"\n");
395 fprintf(fpbending
,"\n");
401 copy_rvec(residuehelixaxis
[i
],residuehelixaxis_t0
[i
]);
402 copy_rvec(residuevector
[i
],residuevector_t0
[i
]);
403 copy_rvec(axis3
[i
],axis3_t0
[i
]);
408 fprintf(fptilt
,"%15.12g ",t
);
409 fprintf(fprotation
,"%15.12g ",t
);
410 fprintf(fptheta1
,"%15.12g ",t
);
411 fprintf(fptheta2
,"%15.12g ",t
);
412 fprintf(fptheta3
,"%15.12g ",t
);
424 /* Total rotation & tilt */
425 copy_rvec(residuehelixaxis_t0
[i
],refaxes
[0]);
426 copy_rvec(residuevector_t0
[i
],refaxes
[1]);
427 copy_rvec(axis3_t0
[i
],refaxes
[2]);
431 /* Rotation/tilt since last step */
432 copy_rvec(residuehelixaxis_tlast
[i
],refaxes
[0]);
433 copy_rvec(residuevector_tlast
[i
],refaxes
[1]);
434 copy_rvec(axis3_tlast
[i
],refaxes
[2]);
436 copy_rvec(residuehelixaxis
[i
],newaxes
[0]);
437 copy_rvec(residuevector
[i
],newaxes
[1]);
438 copy_rvec(axis3
[i
],newaxes
[2]);
441 printf("frame %d, i=%d:\n old: %g %g %g , %g %g %g , %g %g %g\n new: %g %g %g , %g %g %g , %g %g %g\n",
443 refaxes[0][0],refaxes[0][1],refaxes[0][2],
444 refaxes[1][0],refaxes[1][1],refaxes[1][2],
445 refaxes[2][0],refaxes[2][1],refaxes[2][2],
446 newaxes[0][0],newaxes[0][1],newaxes[0][2],
447 newaxes[1][0],newaxes[1][1],newaxes[1][2],
448 newaxes[2][0],newaxes[2][1],newaxes[2][2]);
451 /* rotate reference frame onto unit axes */
452 calc_fit_R(3,3,weight
,unitaxes
,refaxes
,A
);
455 mvmul(A
,refaxes
[j
],rot_refaxes
[j
]);
456 mvmul(A
,newaxes
[j
],rot_newaxes
[j
]);
459 /* Determine local rotation matrix A */
460 calc_fit_R(3,3,weight
,rot_newaxes
,rot_refaxes
,A
);
461 /* Calculate euler angles, from rotation order y-z-x, where
462 * x is helixaxis, y residuevector, and z axis3.
464 * A contains rotation column vectors.
468 printf("frame %d, i=%d, A: %g %g %g , %g %g %g , %g %g %g\n",
469 teller,i,A[0][0],A[0][1],A[0][2],A[1][0],A[1][1],A[1][2],A[2][0],A[2][1],A[2][2]);
472 theta1
= 180.0/M_PI
*atan2(A
[0][2],A
[0][0]);
473 theta2
= 180.0/M_PI
*asin(-A
[0][1]);
474 theta3
= 180.0/M_PI
*atan2(A
[2][1],A
[1][1]);
476 tilt
= sqrt(theta1
*theta1
+theta2
*theta2
);
478 fprintf(fptheta1
,"%15.12g ",theta1
);
479 fprintf(fptheta2
,"%15.12g ",theta2
);
480 fprintf(fptheta3
,"%15.12g ",theta3
);
483 fprintf(fptilt
,"%15.12g ",tilt
);
484 fprintf(fprotation
,"%15.12g ",rotation
);
486 fprintf(fptilt
,"\n");
487 fprintf(fprotation
,"\n");
488 fprintf(fptheta1
,"\n");
489 fprintf(fptheta2
,"\n");
490 fprintf(fptheta3
,"\n");
495 copy_rvec(residuehelixaxis
[i
],residuehelixaxis_tlast
[i
]);
496 copy_rvec(residuevector
[i
],residuevector_tlast
[i
]);
497 copy_rvec(axis3
[i
],axis3_tlast
[i
]);
501 } while (read_next_x(oenv
,status
,&t
,natoms
,x
,box
));