Merge branch 'master' of git://git.gromacs.org/gromacs
[gromacs/adressmacs.git] / src / tools / gmx_rmsf.c
blobd9783b4dba71dad09e0eb29ceb81fb23a0858b41
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
39 #include "smalloc.h"
40 #include "math.h"
41 #include "macros.h"
42 #include "typedefs.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 "pdbio.h"
50 #include "tpxio.h"
51 #include "pbc.h"
52 #include "gmx_fatal.h"
53 #include "futil.h"
54 #include "do_fit.h"
55 #include "princ.h"
56 #include "rmpbc.h"
57 #include "confio.h"
58 #include "eigensolver.h"
59 #include "gmx_ana.h"
62 static real find_pdb_bfac(t_atoms *atoms,t_resinfo *ri,char *atomnm)
64 char rresnm[8];
65 int i;
67 strcpy(rresnm,*ri->name);
68 rresnm[3]='\0';
69 for(i=0; (i<atoms->nr); i++) {
70 if ((ri->nr == atoms->resinfo[atoms->atom[i].resind].nr) &&
71 (ri->ic == atoms->resinfo[atoms->atom[i].resind].ic) &&
72 (strcmp(*atoms->resinfo[atoms->atom[i].resind].name,rresnm) == 0) &&
73 (strstr(*atoms->atomname[i],atomnm) != NULL))
74 break;
76 if (i == atoms->nr) {
77 fprintf(stderr,"\rCan not find %s%d-%s in pdbfile\n",
78 rresnm,ri->nr,atomnm);
79 return 0.0;
82 return atoms->pdbinfo[i].bfac;
85 void correlate_aniso(const char *fn,t_atoms *ref,t_atoms *calc,
86 const output_env_t oenv)
88 FILE *fp;
89 int i,j;
91 fp = xvgropen(fn,"Correlation between X-Ray and Computed Uij","X-Ray",
92 "Computed",oenv);
93 for(i=0; (i<ref->nr); i++) {
94 if (ref->pdbinfo[i].bAnisotropic) {
95 for(j=U11; (j<=U23); j++)
96 fprintf(fp,"%10d %10d\n",ref->pdbinfo[i].uij[j],calc->pdbinfo[i].uij[j]);
99 ffclose(fp);
102 static void average_residues(double f[],double **U,int uind,
103 int isize,atom_id index[],real w_rls[],
104 t_atoms *atoms)
106 int i,j,start;
107 double av,m;
109 start = 0;
110 av = 0;
111 m = 0;
112 for(i=0; i<isize; i++) {
113 av += w_rls[index[i]]*(f != NULL ? f[i] : U[i][uind]);
114 m += w_rls[index[i]];
115 if (i+1==isize ||
116 atoms->atom[index[i]].resind!=atoms->atom[index[i+1]].resind) {
117 av /= m;
118 if (f != NULL) {
119 for(j=start; j<=i; j++)
120 f[i] = av;
121 } else {
122 for(j=start; j<=i; j++)
123 U[j][uind] = av;
125 start = i+1;
126 av = 0;
127 m = 0;
132 void print_dir(FILE *fp,real *Uaver)
134 real eigvec[DIM*DIM];
135 real tmp[DIM*DIM];
136 rvec eigval;
137 int d,m;
139 fprintf(fp,"MSF X Y Z\n");
140 for(d=0; d<DIM; d++)
142 fprintf(fp," %c ",'X'+d-XX);
143 for(m=0; m<DIM; m++)
144 fprintf(fp," %9.2e",Uaver[3*m+d]);
145 fprintf(fp,"%s\n",m==DIM ? " (nm^2)" : "");
148 for(m=0; m<DIM*DIM; m++)
149 tmp[m] = Uaver[m];
152 eigensolver(tmp,DIM,0,DIM,eigval,eigvec);
154 fprintf(fp,"\n Eigenvectors\n\n");
155 fprintf(fp,"Eigv %-8.2e %-8.2e %-8.2e (nm^2)\n\n",
156 eigval[2],eigval[1],eigval[0]);
157 for(d=0; d<DIM; d++)
159 fprintf(fp," %c ",'X'+d-XX);
160 for(m=DIM-1; m>=0; m--)
161 fprintf(fp,"%7.4f ",eigvec[3*m+d]);
162 fprintf(fp,"\n");
166 int gmx_rmsf(int argc,char *argv[])
168 const char *desc[] = {
169 "g_rmsf computes the root mean square fluctuation (RMSF, i.e. standard ",
170 "deviation) of atomic positions ",
171 "after (optionally) fitting to a reference frame.[PAR]",
172 "With option [TT]-oq[tt] the RMSF values are converted to B-factor",
173 "values, which are written to a pdb file with the coordinates, of the",
174 "structure file, or of a pdb file when [TT]-q[tt] is specified.",
175 "Option [TT]-ox[tt] writes the B-factors to a file with the average",
176 "coordinates.[PAR]",
177 "With the option [TT]-od[tt] the root mean square deviation with",
178 "respect to the reference structure is calculated.[PAR]",
179 "With the option [TT]aniso[tt] g_rmsf will compute anisotropic",
180 "temperature factors and then it will also output average coordinates",
181 "and a pdb file with ANISOU records (corresonding to the [TT]-oq[tt]",
182 "or [TT]-ox[tt] option). Please note that the U values",
183 "are orientation dependent, so before comparison with experimental data",
184 "you should verify that you fit to the experimental coordinates.[PAR]",
185 "When a pdb input file is passed to the program and the [TT]-aniso[tt]",
186 "flag is set",
187 "a correlation plot of the Uij will be created, if any anisotropic",
188 "temperature factors are present in the pdb file.[PAR]",
189 "With option [TT]-dir[tt] the average MSF (3x3) matrix is diagonalized.",
190 "This shows the directions in which the atoms fluctuate the most and",
191 "the least."
193 static gmx_bool bRes=FALSE,bAniso=FALSE,bdevX=FALSE,bFit=TRUE;
194 t_pargs pargs[] = {
195 { "-res", FALSE, etBOOL, {&bRes},
196 "Calculate averages for each residue" },
197 { "-aniso",FALSE, etBOOL, {&bAniso},
198 "Compute anisotropic termperature factors" },
199 { "-fit", FALSE, etBOOL, {&bFit},
200 "Do a least squares superposition before computing RMSF. Without this you must make sure that the reference structure and the trajectory match." }
202 int natom;
203 int step,nre,natoms,i,g,m,teller=0;
204 real t,lambda,*w_rls,*w_rms;
206 t_tpxheader header;
207 t_inputrec ir;
208 t_topology top;
209 int ePBC;
210 t_atoms *pdbatoms,*refatoms;
211 gmx_bool bCont;
213 matrix box,pdbbox;
214 rvec *x,*pdbx,*xref;
215 t_trxstatus *status;
216 int npdbatoms,res0;
217 char buf[256];
218 const char *label;
219 char title[STRLEN];
221 FILE *fp; /* the graphics file */
222 const char *devfn,*dirfn;
223 int resind;
225 gmx_bool bReadPDB;
226 atom_id *index;
227 int isize;
228 char *grpnames;
230 real bfac,pdb_bfac,*Uaver;
231 double **U,*xav;
232 atom_id aid;
233 rvec *rmsd_x=NULL;
234 double *rmsf,invcount,totmass;
235 int d;
236 real count=0;
237 rvec xcm;
238 gmx_rmpbc_t gpbc=NULL;
240 output_env_t oenv;
242 const char *leg[2] = { "MD", "X-Ray" };
244 t_filenm fnm[] = {
245 { efTRX, "-f", NULL, ffREAD },
246 { efTPS, NULL, NULL, ffREAD },
247 { efNDX, NULL, NULL, ffOPTRD },
248 { efPDB, "-q", NULL, ffOPTRD },
249 { efPDB, "-oq", "bfac", ffOPTWR },
250 { efPDB, "-ox", "xaver", ffOPTWR },
251 { efXVG, "-o", "rmsf", ffWRITE },
252 { efXVG, "-od", "rmsdev", ffOPTWR },
253 { efXVG, "-oc", "correl", ffOPTWR },
254 { efLOG, "-dir", "rmsf", ffOPTWR }
256 #define NFILE asize(fnm)
258 CopyRight(stderr,argv[0]);
259 parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE ,
260 NFILE,fnm,asize(pargs),pargs,asize(desc),desc,0,NULL,
261 &oenv);
263 bReadPDB = ftp2bSet(efPDB,NFILE,fnm);
264 devfn = opt2fn_null("-od",NFILE,fnm);
265 dirfn = opt2fn_null("-dir",NFILE,fnm);
267 read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&xref,NULL,box,TRUE);
268 snew(w_rls,top.atoms.nr);
270 fprintf(stderr,"Select group(s) for root mean square calculation\n");
271 get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&isize,&index,&grpnames);
273 /* Set the weight */
274 for(i=0; i<isize; i++)
275 w_rls[index[i]]=top.atoms.atom[index[i]].m;
277 /* Malloc the rmsf arrays */
278 snew(xav,isize*DIM);
279 snew(U,isize);
280 for(i=0; i<isize; i++)
281 snew(U[i],DIM*DIM);
282 snew(rmsf,isize);
283 if (devfn)
284 snew(rmsd_x, isize);
286 if (bReadPDB) {
287 get_stx_coordnum(opt2fn("-q",NFILE,fnm),&npdbatoms);
288 snew(pdbatoms,1);
289 snew(refatoms,1);
290 init_t_atoms(pdbatoms,npdbatoms,TRUE);
291 init_t_atoms(refatoms,npdbatoms,TRUE);
292 snew(pdbx,npdbatoms);
293 /* Read coordinates twice */
294 read_stx_conf(opt2fn("-q",NFILE,fnm),title,pdbatoms,pdbx,NULL,NULL,pdbbox);
295 read_stx_conf(opt2fn("-q",NFILE,fnm),title,refatoms,pdbx,NULL,NULL,pdbbox);
296 } else {
297 pdbatoms = &top.atoms;
298 refatoms = &top.atoms;
299 pdbx = xref;
300 npdbatoms = pdbatoms->nr;
301 snew(pdbatoms->pdbinfo,npdbatoms);
302 copy_mat(box,pdbbox);
305 if (bFit) {
306 sub_xcm(xref,isize,index,top.atoms.atom,xcm,FALSE);
309 natom = read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box);
311 if (bFit) {
312 gpbc = gmx_rmpbc_init(&top.idef,ePBC,natom,box);
315 /* Now read the trj again to compute fluctuations */
316 teller = 0;
317 do {
318 if (bFit) {
319 /* Remove periodic boundary */
320 gmx_rmpbc(gpbc,natom,box,x);
322 /* Set center of mass to zero */
323 sub_xcm(x,isize,index,top.atoms.atom,xcm,FALSE);
325 /* Fit to reference structure */
326 do_fit(natom,w_rls,xref,x);
329 /* Calculate Anisotropic U Tensor */
330 for(i=0; i<isize; i++) {
331 aid = index[i];
332 for(d=0; d<DIM; d++) {
333 xav[i*DIM + d] += x[aid][d];
334 for(m=0; m<DIM; m++)
335 U[i][d*DIM + m] += x[aid][d]*x[aid][m];
339 if (devfn) {
340 /* Calculate RMS Deviation */
341 for(i=0;(i<isize);i++) {
342 aid = index[i];
343 for(d=0;(d<DIM);d++) {
344 rmsd_x[i][d] += sqr(x[aid][d]-xref[aid][d]);
348 count += 1.0;
349 teller++;
350 } while(read_next_x(oenv,status,&t,natom,x,box));
351 close_trj(status);
353 if (bFit)
354 gmx_rmpbc_done(gpbc);
357 invcount = 1.0/count;
358 snew(Uaver,DIM*DIM);
359 totmass = 0;
360 for(i=0; i<isize; i++) {
361 for(d=0; d<DIM; d++)
362 xav[i*DIM + d] *= invcount;
363 for(d=0; d<DIM; d++)
364 for(m=0; m<DIM; m++) {
365 U[i][d*DIM + m] = U[i][d*DIM + m]*invcount
366 - xav[i*DIM + d]*xav[i*DIM + m];
367 Uaver[3*d+m] += top.atoms.atom[index[i]].m*U[i][d*DIM + m];
369 totmass += top.atoms.atom[index[i]].m;
371 for(d=0; d<DIM*DIM; d++)
372 Uaver[d] /= totmass;
374 if (bRes) {
375 for(d=0; d<DIM*DIM; d++) {
376 average_residues(NULL,U,d,isize,index,w_rls,&top.atoms);
380 if (bAniso) {
381 for(i=0; i<isize; i++) {
382 aid = index[i];
383 pdbatoms->pdbinfo[aid].bAnisotropic = TRUE;
384 pdbatoms->pdbinfo[aid].uij[U11] = 1e6*U[i][XX*DIM + XX];
385 pdbatoms->pdbinfo[aid].uij[U22] = 1e6*U[i][YY*DIM + YY];
386 pdbatoms->pdbinfo[aid].uij[U33] = 1e6*U[i][ZZ*DIM + ZZ];
387 pdbatoms->pdbinfo[aid].uij[U12] = 1e6*U[i][XX*DIM + YY];
388 pdbatoms->pdbinfo[aid].uij[U13] = 1e6*U[i][XX*DIM + ZZ];
389 pdbatoms->pdbinfo[aid].uij[U23] = 1e6*U[i][YY*DIM + ZZ];
392 if (bRes) {
393 label = "Residue";
394 } else
395 label = "Atom";
397 for(i=0; i<isize; i++)
398 rmsf[i] = U[i][XX*DIM + XX] + U[i][YY*DIM + YY] + U[i][ZZ*DIM + ZZ];
400 if (dirfn) {
401 fprintf(stdout,"\n");
402 print_dir(stdout,Uaver);
403 fp = ffopen(dirfn,"w");
404 print_dir(fp,Uaver);
405 ffclose(fp);
408 for(i=0; i<isize; i++)
409 sfree(U[i]);
410 sfree(U);
412 /* Write RMSF output */
413 if (bReadPDB) {
414 bfac = 8.0*M_PI*M_PI/3.0*100;
415 fp = xvgropen(ftp2fn(efXVG,NFILE,fnm),"B-Factors",
416 label,"(A\\b\\S\\So\\N\\S2\\N)",oenv);
417 xvgr_legend(fp,2,leg,oenv);
418 for(i=0;(i<isize);i++) {
419 if (!bRes || i+1==isize ||
420 top.atoms.atom[index[i]].resind!=top.atoms.atom[index[i+1]].resind) {
421 resind = top.atoms.atom[index[i]].resind;
422 pdb_bfac = find_pdb_bfac(pdbatoms,&top.atoms.resinfo[resind],
423 *(top.atoms.atomname[index[i]]));
425 fprintf(fp,"%5d %10.5f %10.5f\n",
426 bRes ? top.atoms.resinfo[top.atoms.atom[index[i]].resind].nr : i+1,rmsf[i]*bfac,
427 pdb_bfac);
430 ffclose(fp);
431 } else {
432 fp = xvgropen(ftp2fn(efXVG,NFILE,fnm),"RMS fluctuation",label,"(nm)",oenv);
433 for(i=0; i<isize; i++)
434 if (!bRes || i+1==isize ||
435 top.atoms.atom[index[i]].resind!=top.atoms.atom[index[i+1]].resind)
436 fprintf(fp,"%5d %8.4f\n",
437 bRes ? top.atoms.resinfo[top.atoms.atom[index[i]].resind].nr : i+1,sqrt(rmsf[i]));
438 ffclose(fp);
441 for(i=0; i<isize; i++)
442 pdbatoms->pdbinfo[index[i]].bfac = 800*M_PI*M_PI/3.0*rmsf[i];
444 if (devfn) {
445 for(i=0; i<isize; i++)
446 rmsf[i] = (rmsd_x[i][XX]+rmsd_x[i][YY]+rmsd_x[i][ZZ])/count;
447 if (bRes)
448 average_residues(rmsf,NULL,0,isize,index,w_rls,&top.atoms);
449 /* Write RMSD output */
450 fp = xvgropen(devfn,"RMS Deviation",label,"(nm)",oenv);
451 for(i=0; i<isize; i++)
452 if (!bRes || i+1==isize ||
453 top.atoms.atom[index[i]].resind!=top.atoms.atom[index[i+1]].resind)
454 fprintf(fp,"%5d %8.4f\n",
455 bRes ? top.atoms.resinfo[top.atoms.atom[index[i]].resind].nr : i+1,sqrt(rmsf[i]));
456 ffclose(fp);
459 if (opt2bSet("-oq",NFILE,fnm)) {
460 /* Write a pdb file with B-factors and optionally anisou records */
461 for(i=0; i<isize; i++)
462 rvec_inc(xref[index[i]],xcm);
463 write_sto_conf_indexed(opt2fn("-oq",NFILE,fnm),title,pdbatoms,pdbx,
464 NULL,ePBC,pdbbox,isize,index);
466 if (opt2bSet("-ox",NFILE,fnm)) {
467 /* Misuse xref as a temporary array */
468 for(i=0; i<isize; i++)
469 for(d=0; d<DIM; d++)
470 xref[index[i]][d] = xcm[d] + xav[i*DIM + d];
471 /* Write a pdb file with B-factors and optionally anisou records */
472 write_sto_conf_indexed(opt2fn("-ox",NFILE,fnm),title,pdbatoms,xref,NULL,
473 ePBC,pdbbox,isize,index);
475 if (bAniso) {
476 correlate_aniso(opt2fn("-oc",NFILE,fnm),refatoms,pdbatoms,oenv);
477 do_view(oenv,opt2fn("-oc",NFILE,fnm),"-nxy");
479 do_view(oenv,opt2fn("-o",NFILE,fnm),"-nxy");
480 if (devfn)
481 do_view(oenv,opt2fn("-od",NFILE,fnm),"-nxy");
483 thanx(stderr);
485 return 0;