Don't use POSIX fnmatch() for pattern matching.
[gromacs/qmmm-gamess-us.git] / src / tools / gmx_anaeig.c
blobb580303c3676cc4a2b12207cc11f39c28ae9ea69
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 <math.h>
39 #include <string.h>
40 #include "statutil.h"
41 #include "sysstuff.h"
42 #include "typedefs.h"
43 #include "smalloc.h"
44 #include "macros.h"
45 #include "gmx_fatal.h"
46 #include "vec.h"
47 #include "pbc.h"
48 #include "copyrite.h"
49 #include "futil.h"
50 #include "statutil.h"
51 #include "index.h"
52 #include "pdbio.h"
53 #include "confio.h"
54 #include "tpxio.h"
55 #include "matio.h"
56 #include "mshift.h"
57 #include "xvgr.h"
58 #include "do_fit.h"
59 #include "rmpbc.h"
60 #include "txtdump.h"
61 #include "eigio.h"
62 #include "physics.h"
64 static void calc_entropy_qh(FILE *fp,int n,real eigval[],real temp,int nskip)
66 int i;
67 double hwkT,w,dS,S=0;
68 double hbar,lambda;
70 hbar = PLANCK1/(2*M_PI);
71 for(i=0; (i<n-nskip); i++) {
72 if (eigval[i] > 0) {
73 lambda = eigval[i]*AMU;
74 w = sqrt(BOLTZMANN*temp/lambda)/NANO;
75 hwkT = (hbar*w)/(BOLTZMANN*temp);
76 dS = (hwkT/(exp(hwkT) - 1) - log(1-exp(-hwkT)));
77 S += dS;
78 if (debug)
79 fprintf(debug,"i = %5d w = %10g lam = %10g hwkT = %10g dS = %10g\n",
80 i,w,lambda,hwkT,dS);
82 else {
83 fprintf(stderr,"eigval[%d] = %g\n",i,eigval[i]);
84 w = 0;
87 fprintf(fp,"The Entropy due to the Quasi Harmonic approximation is %g J/mol K\n",
88 S*RGAS);
91 static void calc_entropy_schlitter(FILE *fp,int n,int nskip,
92 real *eigval,real temp)
94 double dd,deter;
95 int *indx;
96 int i,j,k,m;
97 char buf[256];
98 double hbar,kt,kteh,S;
100 hbar = PLANCK1/(2*M_PI);
101 kt = BOLTZMANN*temp;
102 kteh = kt*exp(2.0)/(hbar*hbar)*AMU*sqr(NANO);
103 if (debug)
104 fprintf(debug,"n = %d, nskip = %d kteh = %g\n",n,nskip,kteh);
106 deter = 0;
107 for(i=0; (i<n-nskip); i++) {
108 dd = 1+kteh*eigval[i];
109 deter += log(dd);
111 S = 0.5*RGAS*deter;
113 fprintf(fp,"The Entropy due to the Schlitter formula is %g J/mol K\n",S);
116 const char *proj_unit;
118 static real tick_spacing(real range,int minticks)
120 real sp;
122 sp = 0.2*exp(log(10)*ceil(log(range)/log(10)));
123 while (range/sp < minticks-1)
124 sp = sp/2;
126 return sp;
129 static void write_xvgr_graphs(const char *file, int ngraphs, int nsetspergraph,
130 const char *title, const char *subtitle,
131 const char *xlabel, const char **ylabel,
132 int n, real *x, real **y, real ***sy,
133 real scale_x, bool bZero, bool bSplit,
134 const output_env_t oenv)
136 FILE *out;
137 int g,s,i;
138 real min,max,xsp,ysp;
140 out=ffopen(file,"w");
141 if (!use_xmgr() && get_print_xvgr_codes(oenv))
142 fprintf(out,"@ autoscale onread none\n");
143 for(g=0; g<ngraphs; g++) {
144 if (y) {
145 min=y[g][0];
146 max=y[g][0];
147 for(i=0; i<n; i++) {
148 if (y[g][i]<min) min=y[g][i];
149 if (y[g][i]>max) max=y[g][i];
151 } else {
152 min=sy[g][0][0];
153 max=sy[g][0][0];
154 for(s=0; s<nsetspergraph; s++)
155 for(i=0; i<n; i++) {
156 if (sy[g][s][i]<min) min=sy[g][s][i];
157 if (sy[g][s][i]>max) max=sy[g][s][i];
160 if (bZero)
161 min=0;
162 else
163 min=min-0.1*(max-min);
164 max=max+0.1*(max-min);
165 xsp=tick_spacing((x[n-1]-x[0])*scale_x,4);
166 ysp=tick_spacing(max-min,3);
167 if (get_print_xvgr_codes(oenv)) {
168 fprintf(out,"@ with g%d\n@ g%d on\n",g,g);
169 if (g==0) {
170 fprintf(out,"@ title \"%s\"\n",title);
171 if (subtitle)
172 fprintf(out,"@ subtitle \"%s\"\n",subtitle);
174 if (g==ngraphs-1)
175 fprintf(out,"@ xaxis label \"%s\"\n",xlabel);
176 else
177 fprintf(out,"@ xaxis ticklabel off\n");
178 fprintf(out,"@ world xmin %g\n",x[0]*scale_x);
179 fprintf(out,"@ world xmax %g\n",x[n-1]*scale_x);
180 fprintf(out,"@ world ymin %g\n",min);
181 fprintf(out,"@ world ymax %g\n",max);
182 fprintf(out,"@ view xmin 0.15\n");
183 fprintf(out,"@ view xmax 0.85\n");
184 fprintf(out,"@ view ymin %g\n",0.15+(ngraphs-1-g)*0.7/ngraphs);
185 fprintf(out,"@ view ymax %g\n",0.15+(ngraphs-g)*0.7/ngraphs);
186 fprintf(out,"@ yaxis label \"%s\"\n",ylabel[g]);
187 fprintf(out,"@ xaxis tick major %g\n",xsp);
188 fprintf(out,"@ xaxis tick minor %g\n",xsp/2);
189 fprintf(out,"@ xaxis ticklabel start type spec\n");
190 fprintf(out,"@ xaxis ticklabel start %g\n",ceil(min/xsp)*xsp);
191 fprintf(out,"@ yaxis tick major %g\n",ysp);
192 fprintf(out,"@ yaxis tick minor %g\n",ysp/2);
193 fprintf(out,"@ yaxis ticklabel start type spec\n");
194 fprintf(out,"@ yaxis ticklabel start %g\n",ceil(min/ysp)*ysp);
195 if ((min<0) && (max>0)) {
196 fprintf(out,"@ zeroxaxis bar on\n");
197 fprintf(out,"@ zeroxaxis bar linestyle 3\n");
200 for(s=0; s<nsetspergraph; s++) {
201 for(i=0; i<n; i++) {
202 if ( bSplit && i>0 && abs(x[i])<1e-5 )
204 if (get_print_xvgr_codes(oenv))
205 fprintf(out,"&\n");
207 fprintf(out,"%10.4f %10.5f\n",
208 x[i]*scale_x,y ? y[g][i] : sy[g][s][i]);
210 if (get_print_xvgr_codes(oenv))
211 fprintf(out,"&\n");
214 fclose(out);
217 static void
218 compare(int natoms,int n1,rvec **eigvec1,int n2,rvec **eigvec2,
219 real *eigval1, int neig1, real *eigval2, int neig2)
221 int n,nrow;
222 int i,j,k;
223 double sum1,sum2,trace1,trace2,sab,samsb2,tmp,ip;
225 n = min(n1,n2);
227 n = min(n,min(neig1,neig2));
228 fprintf(stdout,"Will compare the covariance matrices using %d dimensions\n",n);
230 sum1 = 0;
231 for(i=0; i<n; i++)
233 if (eigval1[i] < 0)
234 eigval1[i] = 0;
235 sum1 += eigval1[i];
236 eigval1[i] = sqrt(eigval1[i]);
238 trace1 = sum1;
239 for(i=n; i<neig1; i++)
240 trace1 += eigval1[i];
241 sum2 = 0;
242 for(i=0; i<n; i++)
244 if (eigval2[i] < 0)
245 eigval2[i] = 0;
246 sum2 += eigval2[i];
247 eigval2[i] = sqrt(eigval2[i]);
249 trace2 = sum2;
250 for(i=n; i<neig2; i++)
251 trace2 += eigval2[i];
253 fprintf(stdout,"Trace of the two matrices: %g and %g\n",sum1,sum2);
254 if (neig1!=n || neig2!=n)
255 fprintf(stdout,"this is %d%% and %d%% of the total trace\n",
256 (int)(100*sum1/trace1+0.5),(int)(100*sum2/trace2+0.5));
257 fprintf(stdout,"Square root of the traces: %g and %g\n",
258 sqrt(sum1),sqrt(sum2));
260 sab = 0;
261 for(i=0; i<n; i++)
263 tmp = 0;
264 for(j=0; j<n; j++)
266 ip = 0;
267 for(k=0; k<natoms; k++)
268 ip += iprod(eigvec1[i][k],eigvec2[j][k]);
269 tmp += eigval2[j]*ip*ip;
271 sab += eigval1[i]*tmp;
274 samsb2 = sum1+sum2-2*sab;
275 if (samsb2 < 0)
276 samsb2 = 0;
278 fprintf(stdout,"The overlap of the covariance matrices:\n");
279 fprintf(stdout," normalized: %.3f\n",1-sqrt(samsb2/(sum1+sum2)));
280 tmp = 1-sab/sqrt(sum1*sum2);
281 if (tmp < 0)
282 tmp = 0;
283 fprintf(stdout," shape: %.3f\n",1-sqrt(tmp));
287 static void inprod_matrix(const char *matfile,int natoms,
288 int nvec1,int *eignr1,rvec **eigvec1,
289 int nvec2,int *eignr2,rvec **eigvec2,
290 bool bSelect,int noutvec,int *outvec)
292 FILE *out;
293 real **mat;
294 int i,x1,y1,x,y,nlevels;
295 int nx,ny;
296 real inp,*t_x,*t_y,max;
297 t_rgb rlo,rhi;
299 snew(t_y,nvec2);
300 if (bSelect) {
301 nx = noutvec;
302 ny = 0;
303 for(y1=0; y1<nx; y1++)
304 if (outvec[y1] < nvec2) {
305 t_y[ny] = eignr2[outvec[y1]]+1;
306 ny++;
308 } else {
309 nx = nvec1;
310 ny = nvec2;
311 for(y=0; y<ny; y++)
312 t_y[y] = eignr2[y]+1;
315 fprintf(stderr,"Calculating inner-product matrix of %dx%d eigenvectors\n",
316 nx,nvec2);
318 snew(mat,nx);
319 snew(t_x,nx);
320 max = 0;
321 for(x1=0; x1<nx; x1++) {
322 snew(mat[x1],ny);
323 if (bSelect)
324 x = outvec[x1];
325 else
326 x = x1;
327 t_x[x1] = eignr1[x]+1;
328 fprintf(stderr," %d",eignr1[x]+1);
329 for(y1=0; y1<ny; y1++) {
330 inp = 0;
331 if (bSelect) {
332 while (outvec[y1] >= nvec2)
333 y1++;
334 y= outvec[y1];
335 } else
336 y = y1;
337 for(i=0; i<natoms; i++)
338 inp += iprod(eigvec1[x][i],eigvec2[y][i]);
339 mat[x1][y1] = fabs(inp);
340 if (mat[x1][y1]>max)
341 max = mat[x1][y1];
344 fprintf(stderr,"\n");
345 rlo.r = 1; rlo.g = 1; rlo.b = 1;
346 rhi.r = 0; rhi.g = 0; rhi.b = 0;
347 nlevels = 41;
348 out = ffopen(matfile,"w");
349 write_xpm(out,0,"Eigenvector inner-products","in.prod.","run 1","run 2",
350 nx,ny,t_x,t_y,mat,0.0,max,rlo,rhi,&nlevels);
351 fclose(out);
354 static void overlap(const char *outfile,int natoms,
355 rvec **eigvec1,
356 int nvec2,int *eignr2,rvec **eigvec2,
357 int noutvec,int *outvec,
358 const output_env_t oenv)
360 FILE *out;
361 int i,v,vec,x;
362 real overlap,inp;
364 fprintf(stderr,"Calculating overlap between eigenvectors of set 2 with eigenvectors\n");
365 for(i=0; i<noutvec; i++)
366 fprintf(stderr,"%d ",outvec[i]+1);
367 fprintf(stderr,"\n");
369 out=xvgropen(outfile,"Subspace overlap",
370 "Eigenvectors of trajectory 2","Overlap",oenv);
371 fprintf(out,"@ subtitle \"using %d eigenvectors of trajectory 1\"\n",
372 noutvec);
373 overlap=0;
374 for(x=0; x<nvec2; x++) {
375 for(v=0; v<noutvec; v++) {
376 vec=outvec[v];
377 inp=0;
378 for(i=0; i<natoms; i++)
379 inp+=iprod(eigvec1[vec][i],eigvec2[x][i]);
380 overlap+=sqr(inp);
382 fprintf(out,"%5d %5.3f\n",eignr2[x]+1,overlap/noutvec);
385 fclose(out);
388 static void project(const char *trajfile,t_topology *top,int ePBC,
389 matrix topbox, rvec *xtop,
390 const char *projfile,const char *twodplotfile,
391 const char *threedplotfile, const char *filterfile,int skip,
392 const char *extremefile,bool bExtrAll,real extreme,
393 int nextr, t_atoms *atoms,int natoms,atom_id *index,
394 bool bFit,rvec *xref,int nfit,atom_id *ifit,real *w_rls,
395 real *sqrtm,rvec *xav,
396 int *eignr,rvec **eigvec,
397 int noutvec,int *outvec, bool bSplit,
398 const output_env_t oenv)
400 FILE *xvgrout=NULL;
401 int status,out=0,nat,i,j,d,v,vec,nfr,nframes=0,snew_size,frame;
402 int noutvec_extr,*imin,*imax;
403 atom_id *all_at;
404 matrix box;
405 rvec *xread,*x;
406 real t,inp,**inprod=NULL,min=0,max=0;
407 char str[STRLEN],str2[STRLEN],**ylabel,*c;
408 real fact;
410 snew(x,natoms);
412 if (bExtrAll)
413 noutvec_extr=noutvec;
414 else
415 noutvec_extr=1;
418 if (trajfile) {
419 snew(inprod,noutvec+1);
421 if (filterfile) {
422 fprintf(stderr,"Writing a filtered trajectory to %s using eigenvectors\n",
423 filterfile);
424 for(i=0; i<noutvec; i++)
425 fprintf(stderr,"%d ",outvec[i]+1);
426 fprintf(stderr,"\n");
427 out=open_trx(filterfile,"w");
429 snew_size=0;
430 nfr=0;
431 nframes=0;
432 nat=read_first_x(oenv,&status,trajfile,&t,&xread,box);
433 if (nat>atoms->nr)
434 gmx_fatal(FARGS,"the number of atoms in your trajectory (%d) is larger than the number of atoms in your structure file (%d)",nat,atoms->nr);
435 snew(all_at,nat);
436 for(i=0; i<nat; i++)
437 all_at[i]=i;
438 do {
439 if (nfr % skip == 0) {
440 if (top)
441 rm_pbc(&(top->idef),ePBC,nat,box,xread,xread);
442 if (nframes>=snew_size) {
443 snew_size+=100;
444 for(i=0; i<noutvec+1; i++)
445 srenew(inprod[i],snew_size);
447 inprod[noutvec][nframes]=t;
448 /* calculate x: a fitted struture of the selected atoms */
449 if (bFit && (xref==NULL)) {
450 reset_x(nfit,ifit,nat,NULL,xread,w_rls);
451 do_fit(nat,w_rls,xtop,xread);
453 for (i=0; i<natoms; i++)
454 copy_rvec(xread[index[i]],x[i]);
455 if (bFit && xref) {
456 reset_x(natoms,all_at,natoms,NULL,x,w_rls);
457 do_fit(natoms,w_rls,xref,x);
460 for(v=0; v<noutvec; v++) {
461 vec=outvec[v];
462 /* calculate (mass-weighted) projection */
463 inp=0;
464 for (i=0; i<natoms; i++) {
465 inp+=(eigvec[vec][i][0]*(x[i][0]-xav[i][0])+
466 eigvec[vec][i][1]*(x[i][1]-xav[i][1])+
467 eigvec[vec][i][2]*(x[i][2]-xav[i][2]))*sqrtm[i];
469 inprod[v][nframes]=inp;
471 if (filterfile) {
472 for(i=0; i<natoms; i++)
473 for(d=0; d<DIM; d++) {
474 /* misuse xread for output */
475 xread[index[i]][d] = xav[i][d];
476 for(v=0; v<noutvec; v++)
477 xread[index[i]][d] +=
478 inprod[v][nframes]*eigvec[outvec[v]][i][d]/sqrtm[i];
480 write_trx(out,natoms,index,atoms,0,t,box,xread,NULL,NULL);
482 nframes++;
484 nfr++;
485 } while (read_next_x(oenv,status,&t,nat,xread,box));
486 close_trj(status);
487 sfree(x);
488 if (filterfile)
489 close_trx(out);
491 else
492 snew(xread,atoms->nr);
495 if (projfile) {
496 snew(ylabel,noutvec);
497 for(v=0; v<noutvec; v++) {
498 sprintf(str,"vec %d",eignr[outvec[v]]+1);
499 ylabel[v]=strdup(str);
501 sprintf(str,"projection on eigenvectors (%s)",proj_unit);
502 write_xvgr_graphs(projfile, noutvec, 1, str, NULL, get_xvgr_tlabel(oenv),
503 (const char **)ylabel,
504 nframes, inprod[noutvec], inprod, NULL,
505 get_time_factor(oenv), FALSE, bSplit,oenv);
508 if (twodplotfile) {
509 sprintf(str,"projection on eigenvector %d (%s)",
510 eignr[outvec[0]]+1,proj_unit);
511 sprintf(str2,"projection on eigenvector %d (%s)",
512 eignr[outvec[noutvec-1]]+1,proj_unit);
513 xvgrout=xvgropen(twodplotfile,"2D projection of trajectory",str,str2,
514 oenv);
515 for(i=0; i<nframes; i++) {
516 if ( bSplit && i>0 && abs(inprod[noutvec][i])<1e-5 )
517 fprintf(xvgrout,"&\n");
518 fprintf(xvgrout,"%10.5f %10.5f\n",inprod[0][i],inprod[noutvec-1][i]);
520 fclose(xvgrout);
523 if (threedplotfile) {
524 t_atoms atoms;
525 rvec *x;
526 real *b=NULL;
527 matrix box;
528 char *resnm,*atnm, pdbform[STRLEN];
529 bool bPDB, b4D;
530 FILE *out;
532 if (noutvec < 3)
533 gmx_fatal(FARGS,"You have selected less than 3 eigenvectors");
535 /* initialize */
536 bPDB = fn2ftp(threedplotfile)==efPDB;
537 clear_mat(box);
538 box[XX][XX] = box[YY][YY] = box[ZZ][ZZ] = 1;
540 b4D = bPDB && (noutvec >= 4);
541 if (b4D) {
542 fprintf(stderr, "You have selected four or more eigenvectors:\n"
543 "fourth eigenvector will be plotted "
544 "in bfactor field of pdb file\n");
545 sprintf(str,"4D proj. of traj. on eigenv. %d, %d, %d and %d",
546 eignr[outvec[0]]+1,eignr[outvec[1]]+1,
547 eignr[outvec[2]]+1,eignr[outvec[3]]+1);
548 } else {
549 sprintf(str,"3D proj. of traj. on eigenv. %d, %d and %d",
550 eignr[outvec[0]]+1,eignr[outvec[1]]+1,eignr[outvec[2]]+1);
552 init_t_atoms(&atoms,nframes,FALSE);
553 snew(x,nframes);
554 snew(b,nframes);
555 atnm=strdup("C");
556 resnm=strdup("PRJ");
558 if(nframes>10000)
559 fact=10000.0/nframes;
560 else
561 fact=1.0;
563 for(i=0; i<nframes; i++) {
564 atoms.atomname[i] = &atnm;
565 atoms.atom[i].resind = i;
566 atoms.resinfo[i].name = &resnm;
567 atoms.resinfo[i].nr = ceil(i*fact);
568 atoms.resinfo[i].ic = ' ';
569 x[i][XX]=inprod[0][i];
570 x[i][YY]=inprod[1][i];
571 x[i][ZZ]=inprod[2][i];
572 if (b4D)
573 b[i] =inprod[3][i];
575 if ( ( b4D || bSplit ) && bPDB ) {
576 strcpy(pdbform,pdbformat);
577 strcat(pdbform,"%8.4f%8.4f\n");
579 out=ffopen(threedplotfile,"w");
580 fprintf(out,"HEADER %s\n",str);
581 if ( b4D )
582 fprintf(out,"REMARK %s\n","fourth dimension plotted as B-factor");
583 j=0;
584 for(i=0; i<atoms.nr; i++) {
585 if ( j>0 && bSplit && abs(inprod[noutvec][i])<1e-5 ) {
586 fprintf(out,"TER\n");
587 j=0;
589 fprintf(out,pdbform,"ATOM",i+1,"C","PRJ",' ',j+1,
590 PR_VEC(10*x[i]), 1.0, 10*b[i]);
591 if (j>0)
592 fprintf(out,"CONECT%5d%5d\n", i, i+1);
593 j++;
595 fprintf(out,"TER\n");
596 fclose(out);
597 } else
598 write_sto_conf(threedplotfile,str,&atoms,x,NULL,ePBC,box);
599 free_t_atoms(&atoms,FALSE);
602 if (extremefile) {
603 if (extreme==0) {
604 fprintf(stderr,"%11s %17s %17s\n","eigenvector","Minimum","Maximum");
605 fprintf(stderr,
606 "%11s %10s %10s %10s %10s\n","","value","time","value","time");
607 snew(imin,noutvec_extr);
608 snew(imax,noutvec_extr);
609 for(v=0; v<noutvec_extr; v++) {
610 for(i=0; i<nframes; i++) {
611 if (inprod[v][i]<inprod[v][imin[v]])
612 imin[v]=i;
613 if (inprod[v][i]>inprod[v][imax[v]])
614 imax[v]=i;
616 min=inprod[v][imin[v]];
617 max=inprod[v][imax[v]];
618 fprintf(stderr,"%7d %10.6f %10.1f %10.6f %10.1f\n",
619 eignr[outvec[v]]+1,
620 min,inprod[noutvec][imin[v]],max,inprod[noutvec][imax[v]]);
623 else {
624 min=-extreme;
625 max=+extreme;
627 /* build format string for filename: */
628 strcpy(str,extremefile);/* copy filename */
629 c=strrchr(str,'.'); /* find where extention begins */
630 strcpy(str2,c); /* get extention */
631 sprintf(c,"%%d%s",str2); /* append '%s' and extention to filename */
632 for(v=0; v<noutvec_extr; v++) {
633 /* make filename using format string */
634 if (noutvec_extr==1)
635 strcpy(str2,extremefile);
636 else
637 sprintf(str2,str,eignr[outvec[v]]+1);
638 fprintf(stderr,"Writing %d frames along eigenvector %d to %s\n",
639 nextr,outvec[v]+1,str2);
640 out=open_trx(str2,"w");
641 for(frame=0; frame<nextr; frame++) {
642 if ((extreme==0) && (nextr<=3))
643 for(i=0; i<natoms; i++) {
644 atoms->resinfo[atoms->atom[index[i]].resind].chain = 'A' + frame;
646 for(i=0; i<natoms; i++)
647 for(d=0; d<DIM; d++)
648 xread[index[i]][d] =
649 (xav[i][d] + (min*(nextr-frame-1)+max*frame)/(nextr-1)
650 *eigvec[outvec[v]][i][d]/sqrtm[i]);
651 write_trx(out,natoms,index,atoms,0,frame,topbox,xread,NULL,NULL);
653 close_trx(out);
656 fprintf(stderr,"\n");
659 static void components(const char *outfile,int natoms,
660 int *eignr,rvec **eigvec,
661 int noutvec,int *outvec,
662 const output_env_t oenv)
664 int g,s,v,i;
665 real *x,***y;
666 char str[STRLEN],**ylabel;
668 fprintf(stderr,"Writing eigenvector components to %s\n",outfile);
670 snew(ylabel,noutvec);
671 snew(y,noutvec);
672 snew(x,natoms);
673 for(i=0; i<natoms; i++)
674 x[i]=i+1;
675 for(g=0; g<noutvec; g++) {
676 v=outvec[g];
677 sprintf(str,"vec %d",eignr[v]+1);
678 ylabel[g]=strdup(str);
679 snew(y[g],4);
680 for(s=0; s<4; s++) {
681 snew(y[g][s],natoms);
683 for(i=0; i<natoms; i++) {
684 y[g][0][i] = norm(eigvec[v][i]);
685 for(s=0; s<3; s++)
686 y[g][s+1][i] = eigvec[v][i][s];
689 write_xvgr_graphs(outfile,noutvec,4,"Eigenvector components",
690 "black: total, red: x, green: y, blue: z",
691 "Atom number",(const char **)ylabel,
692 natoms,x,NULL,y,1,FALSE,FALSE,oenv);
693 fprintf(stderr,"\n");
696 static void rmsf(const char *outfile,int natoms,real *sqrtm,
697 int *eignr,rvec **eigvec,
698 int noutvec,int *outvec,
699 real *eigval, int neig,
700 const output_env_t oenv)
702 int nrow,g,v,i;
703 real *x,**y;
704 char str[STRLEN],**ylabel;
706 for(i=0; i<neig; i++)
707 if (eigval[i] < 0)
708 eigval[i] = 0;
710 fprintf(stderr,"Writing rmsf to %s\n",outfile);
712 snew(ylabel,noutvec);
713 snew(y,noutvec);
714 snew(x,natoms);
715 for(i=0; i<natoms; i++)
716 x[i]=i+1;
717 for(g=0; g<noutvec; g++) {
718 v=outvec[g];
719 if (eignr[v] >= neig)
720 gmx_fatal(FARGS,"Selected vector %d is larger than the number of eigenvalues (%d)",eignr[v]+1,neig);
721 sprintf(str,"vec %d",eignr[v]+1);
722 ylabel[g]=strdup(str);
723 snew(y[g],natoms);
724 for(i=0; i<natoms; i++)
725 y[g][i] = sqrt(eigval[eignr[v]]*norm2(eigvec[v][i]))/sqrtm[i];
727 write_xvgr_graphs(outfile,noutvec,1,"RMS fluctuation (nm) ",NULL,
728 "Atom number",(const char **)ylabel,
729 natoms,x,y,NULL,1,TRUE,FALSE,oenv);
730 fprintf(stderr,"\n");
733 int gmx_anaeig(int argc,char *argv[])
735 static const char *desc[] = {
736 "[TT]g_anaeig[tt] analyzes eigenvectors. The eigenvectors can be of a",
737 "covariance matrix ([TT]g_covar[tt]) or of a Normal Modes anaysis",
738 "([TT]g_nmeig[tt]).[PAR]",
740 "When a trajectory is projected on eigenvectors, all structures are",
741 "fitted to the structure in the eigenvector file, if present, otherwise",
742 "to the structure in the structure file. When no run input file is",
743 "supplied, periodicity will not be taken into account. Most analyses",
744 "are performed on eigenvectors [TT]-first[tt] to [TT]-last[tt], but when",
745 "[TT]-first[tt] is set to -1 you will be prompted for a selection.[PAR]",
747 "[TT]-comp[tt]: plot the vector components per atom of eigenvectors",
748 "[TT]-first[tt] to [TT]-last[tt].[PAR]",
750 "[TT]-rmsf[tt]: plot the RMS fluctuation per atom of eigenvectors",
751 "[TT]-first[tt] to [TT]-last[tt] (requires [TT]-eig[tt]).[PAR]",
753 "[TT]-proj[tt]: calculate projections of a trajectory on eigenvectors",
754 "[TT]-first[tt] to [TT]-last[tt].",
755 "The projections of a trajectory on the eigenvectors of its",
756 "covariance matrix are called principal components (pc's).",
757 "It is often useful to check the cosine content the pc's,",
758 "since the pc's of random diffusion are cosines with the number",
759 "of periods equal to half the pc index.",
760 "The cosine content of the pc's can be calculated with the program",
761 "[TT]g_analyze[tt].[PAR]",
763 "[TT]-2d[tt]: calculate a 2d projection of a trajectory on eigenvectors",
764 "[TT]-first[tt] and [TT]-last[tt].[PAR]",
766 "[TT]-3d[tt]: calculate a 3d projection of a trajectory on the first",
767 "three selected eigenvectors.[PAR]",
769 "[TT]-filt[tt]: filter the trajectory to show only the motion along",
770 "eigenvectors [TT]-first[tt] to [TT]-last[tt].[PAR]",
772 "[TT]-extr[tt]: calculate the two extreme projections along a trajectory",
773 "on the average structure and interpolate [TT]-nframes[tt] frames",
774 "between them, or set your own extremes with [TT]-max[tt]. The",
775 "eigenvector [TT]-first[tt] will be written unless [TT]-first[tt] and",
776 "[TT]-last[tt] have been set explicitly, in which case all eigenvectors",
777 "will be written to separate files. Chain identifiers will be added",
778 "when writing a [TT].pdb[tt] file with two or three structures (you",
779 "can use [TT]rasmol -nmrpdb[tt] to view such a pdb file).[PAR]",
781 " Overlap calculations between covariance analysis:[BR]",
782 " NOTE: the analysis should use the same fitting structure[PAR]",
784 "[TT]-over[tt]: calculate the subspace overlap of the eigenvectors in",
785 "file [TT]-v2[tt] with eigenvectors [TT]-first[tt] to [TT]-last[tt]",
786 "in file [TT]-v[tt].[PAR]",
788 "[TT]-inpr[tt]: calculate a matrix of inner-products between",
789 "eigenvectors in files [TT]-v[tt] and [TT]-v2[tt]. All eigenvectors",
790 "of both files will be used unless [TT]-first[tt] and [TT]-last[tt]",
791 "have been set explicitly.[PAR]",
793 "When [TT]-v[tt], [TT]-eig[tt], [TT]-v2[tt] and [TT]-eig2[tt] are given,",
794 "a single number for the overlap between the covariance matrices is",
795 "generated. The formulas are:[BR]",
796 " difference = sqrt(tr((sqrt(M1) - sqrt(M2))^2))[BR]",
797 "normalized overlap = 1 - difference/sqrt(tr(M1) + tr(M2))[BR]",
798 " shape overlap = 1 - sqrt(tr((sqrt(M1/tr(M1)) - sqrt(M2/tr(M2)))^2))[BR]",
799 "where M1 and M2 are the two covariance matrices and tr is the trace",
800 "of a matrix. The numbers are proportional to the overlap of the square",
801 "root of the fluctuations. The normalized overlap is the most useful",
802 "number, it is 1 for identical matrices and 0 when the sampled",
803 "subspaces are orthogonal.[PAR]",
804 "When the [TT]-entropy[tt] flag is given an entropy estimate will be",
805 "computed based on the Quasiharmonic approach and based on",
806 "Schlitter's formula."
808 static int first=1,last=8,skip=1,nextr=2,nskip=6;
809 static real max=0.0,temp=298.15;
810 static bool bSplit=FALSE,bEntropy=FALSE;
811 t_pargs pa[] = {
812 { "-first", FALSE, etINT, {&first},
813 "First eigenvector for analysis (-1 is select)" },
814 { "-last", FALSE, etINT, {&last},
815 "Last eigenvector for analysis (-1 is till the last)" },
816 { "-skip", FALSE, etINT, {&skip},
817 "Only analyse every nr-th frame" },
818 { "-max", FALSE, etREAL, {&max},
819 "Maximum for projection of the eigenvector on the average structure, "
820 "max=0 gives the extremes" },
821 { "-nframes", FALSE, etINT, {&nextr},
822 "Number of frames for the extremes output" },
823 { "-split", FALSE, etBOOL, {&bSplit},
824 "Split eigenvector projections where time is zero" },
825 { "-entropy", FALSE, etBOOL, {&bEntropy},
826 "Compute entropy according to the Quasiharmonic formula or Schlitter's method." },
827 { "-temp", FALSE, etREAL, {&temp},
828 "Temperature for entropy calculations" },
829 { "-nevskip", FALSE, etINT, {&nskip},
830 "Number of eigenvalues to skip when computing the entropy due to the quasi harmonic approximation. When you do a rotational and/or translational fit prior to the covariance analysis, you get 3 or 6 eigenvalues that are very close to zero, and which should not be taken into account when computing the entropy." }
832 #define NPA asize(pa)
834 FILE *out;
835 int status,trjout;
836 t_topology top;
837 int ePBC=-1;
838 t_atoms *atoms=NULL;
839 rvec *xtop,*xref1,*xref2;
840 bool bDMR1,bDMA1,bDMR2,bDMA2;
841 int nvec1,nvec2,*eignr1=NULL,*eignr2=NULL;
842 rvec *x,*xread,*xav1,*xav2,**eigvec1=NULL,**eigvec2=NULL;
843 matrix topbox;
844 real xid,totmass,*sqrtm,*w_rls,t,lambda;
845 int natoms,step;
846 char *grpname;
847 const char *indexfile;
848 char title[STRLEN];
849 int i,j,d;
850 int nout,*iout,noutvec,*outvec,nfit;
851 atom_id *index,*ifit;
852 const char *VecFile,*Vec2File,*topfile;
853 const char *EigFile,*Eig2File;
854 const char *CompFile,*RmsfFile,*ProjOnVecFile;
855 const char *TwoDPlotFile,*ThreeDPlotFile;
856 const char *FilterFile,*ExtremeFile;
857 const char *OverlapFile,*InpMatFile;
858 bool bFit1,bFit2,bM,bIndex,bTPS,bTop,bVec2,bProj;
859 bool bFirstToLast,bFirstLastSet,bTraj,bCompare,bPDB3D;
860 real *eigval1=NULL,*eigval2=NULL;
861 int neig1,neig2;
862 double **xvgdata;
863 output_env_t oenv;
865 t_filenm fnm[] = {
866 { efTRN, "-v", "eigenvec", ffREAD },
867 { efTRN, "-v2", "eigenvec2", ffOPTRD },
868 { efTRX, "-f", NULL, ffOPTRD },
869 { efTPS, NULL, NULL, ffOPTRD },
870 { efNDX, NULL, NULL, ffOPTRD },
871 { efXVG, "-eig", "eigenval", ffOPTRD },
872 { efXVG, "-eig2", "eigenval2", ffOPTRD },
873 { efXVG, "-comp", "eigcomp", ffOPTWR },
874 { efXVG, "-rmsf", "eigrmsf", ffOPTWR },
875 { efXVG, "-proj", "proj", ffOPTWR },
876 { efXVG, "-2d", "2dproj", ffOPTWR },
877 { efSTO, "-3d", "3dproj.pdb", ffOPTWR },
878 { efTRX, "-filt", "filtered", ffOPTWR },
879 { efTRX, "-extr", "extreme.pdb", ffOPTWR },
880 { efXVG, "-over", "overlap", ffOPTWR },
881 { efXPM, "-inpr", "inprod", ffOPTWR }
883 #define NFILE asize(fnm)
885 CopyRight(stderr,argv[0]);
886 parse_common_args(&argc,argv,
887 PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW | PCA_BE_NICE ,
888 NFILE,fnm,NPA,pa,asize(desc),desc,0,NULL,&oenv);
890 indexfile=ftp2fn_null(efNDX,NFILE,fnm);
892 VecFile = opt2fn("-v",NFILE,fnm);
893 Vec2File = opt2fn_null("-v2",NFILE,fnm);
894 topfile = ftp2fn(efTPS,NFILE,fnm);
895 EigFile = opt2fn_null("-eig",NFILE,fnm);
896 Eig2File = opt2fn_null("-eig2",NFILE,fnm);
897 CompFile = opt2fn_null("-comp",NFILE,fnm);
898 RmsfFile = opt2fn_null("-rmsf",NFILE,fnm);
899 ProjOnVecFile = opt2fn_null("-proj",NFILE,fnm);
900 TwoDPlotFile = opt2fn_null("-2d",NFILE,fnm);
901 ThreeDPlotFile = opt2fn_null("-3d",NFILE,fnm);
902 FilterFile = opt2fn_null("-filt",NFILE,fnm);
903 ExtremeFile = opt2fn_null("-extr",NFILE,fnm);
904 OverlapFile = opt2fn_null("-over",NFILE,fnm);
905 InpMatFile = ftp2fn_null(efXPM,NFILE,fnm);
907 bTop = fn2bTPX(topfile);
908 bProj = ProjOnVecFile || TwoDPlotFile || ThreeDPlotFile
909 || FilterFile || ExtremeFile;
910 bFirstLastSet =
911 opt2parg_bSet("-first",NPA,pa) && opt2parg_bSet("-last",NPA,pa);
912 bFirstToLast = CompFile || RmsfFile || ProjOnVecFile || FilterFile ||
913 OverlapFile || ((ExtremeFile || InpMatFile) && bFirstLastSet);
914 bVec2 = Vec2File || OverlapFile || InpMatFile;
915 bM = RmsfFile || bProj;
916 bTraj = ProjOnVecFile || FilterFile || (ExtremeFile && (max==0))
917 || TwoDPlotFile || ThreeDPlotFile;
918 bIndex = bM || bProj;
919 bTPS = ftp2bSet(efTPS,NFILE,fnm) || bM || bTraj ||
920 FilterFile || (bIndex && indexfile);
921 bCompare = Vec2File || Eig2File;
922 bPDB3D = fn2ftp(ThreeDPlotFile)==efPDB;
924 read_eigenvectors(VecFile,&natoms,&bFit1,
925 &xref1,&bDMR1,&xav1,&bDMA1,
926 &nvec1,&eignr1,&eigvec1,&eigval1);
927 neig1 = DIM*natoms;
929 /* Overwrite eigenvalues from separate files if the user provides them */
930 if (EigFile != NULL) {
931 int neig_tmp = read_xvg(EigFile,&xvgdata,&i);
932 if (neig_tmp != neig1)
933 fprintf(stderr,"Warning: number of eigenvalues in xvg file (%d) does not mtch trr file (%d)\n",neig1,natoms);
934 neig1 = neig_tmp;
935 srenew(eigval1,neig1);
936 for(j=0;j<neig1;j++) {
937 real tmp = eigval1[j];
938 eigval1[j]=xvgdata[1][j];
939 if (debug && (eigval1[j] != tmp))
940 fprintf(debug,"Replacing eigenvalue %d. From trr: %10g, from xvg: %10g\n",
941 j,tmp,eigval1[j]);
943 for(j=0;j<i;j++)
944 sfree(xvgdata[j]);
945 sfree(xvgdata);
946 fprintf(stderr,"Read %d eigenvalues from %s\n",neig1,EigFile);
949 if (bEntropy) {
950 calc_entropy_qh(stdout,neig1,eigval1,temp,nskip);
951 calc_entropy_schlitter(stdout,neig1,nskip,eigval1,temp);
954 if (bVec2) {
955 if (!Vec2File)
956 gmx_fatal(FARGS,"Need a second eigenvector file to do this analysis.");
957 read_eigenvectors(Vec2File,&neig2,&bFit2,
958 &xref2,&bDMR2,&xav2,&bDMA2,&nvec2,&eignr2,&eigvec2,&eigval2);
960 neig2 = DIM*neig2;
961 if (neig2 != neig1)
962 gmx_fatal(FARGS,"Dimensions in the eigenvector files don't match");
965 if(Eig2File != NULL) {
966 neig2 = read_xvg(Eig2File,&xvgdata,&i);
967 srenew(eigval2,neig2);
968 for(j=0;j<neig2;j++)
969 eigval2[j]=xvgdata[1][j];
970 for(j=0;j<i;j++)
971 sfree(xvgdata[j]);
972 sfree(xvgdata);
973 fprintf(stderr,"Read %d eigenvalues from %s\n",neig2,Eig2File);
977 if ((!bFit1 || xref1) && !bDMR1 && !bDMA1)
978 bM=FALSE;
979 if ((xref1==NULL) && (bM || bTraj))
980 bTPS=TRUE;
982 xtop=NULL;
983 nfit=0;
984 ifit=NULL;
985 w_rls=NULL;
986 if (!bTPS)
987 bTop=FALSE;
988 else {
989 bTop=read_tps_conf(ftp2fn(efTPS,NFILE,fnm),
990 title,&top,&ePBC,&xtop,NULL,topbox,bM);
991 atoms=&top.atoms;
992 rm_pbc(&(top.idef),ePBC,atoms->nr,topbox,xtop,xtop);
993 /* Fitting is only needed when we need to read a trajectory */
994 if (bTraj) {
995 if ((xref1==NULL) || (bM && bDMR1)) {
996 if (bFit1) {
997 printf("\nNote: the structure in %s should be the same\n"
998 " as the one used for the fit in g_covar\n",topfile);
999 printf("\nSelect the index group that was used for the least squares fit in g_covar\n");
1000 get_index(atoms,indexfile,1,&nfit,&ifit,&grpname);
1001 snew(w_rls,atoms->nr);
1002 for(i=0; (i<nfit); i++) {
1003 if (bM && bDMR1)
1004 w_rls[ifit[i]]=atoms->atom[ifit[i]].m;
1005 else
1006 w_rls[ifit[i]]=1.0;
1009 else {
1010 /* make the fit index in xref instead of xtop */
1011 nfit=natoms;
1012 snew(ifit,natoms);
1013 snew(w_rls,nfit);
1014 for(i=0; (i<nfit); i++) {
1015 ifit[i]=i;
1016 w_rls[i]=atoms->atom[ifit[i]].m;
1020 else {
1021 /* make the fit non mass weighted on xref */
1022 nfit=natoms;
1023 snew(ifit,nfit);
1024 snew(w_rls,nfit);
1025 for(i=0; i<nfit; i++) {
1026 ifit[i]=i;
1027 w_rls[i]=1.0;
1033 if (bIndex) {
1034 printf("\nSelect an index group of %d elements that corresponds to the eigenvectors\n",natoms);
1035 get_index(atoms,indexfile,1,&i,&index,&grpname);
1036 if (i!=natoms)
1037 gmx_fatal(FARGS,"you selected a group with %d elements instead of %d",i,natoms);
1038 printf("\n");
1041 snew(sqrtm,natoms);
1042 if (bM && bDMA1) {
1043 proj_unit="u\\S1/2\\Nnm";
1044 for(i=0; (i<natoms); i++)
1045 sqrtm[i]=sqrt(atoms->atom[index[i]].m);
1047 else {
1048 proj_unit="nm";
1049 for(i=0; (i<natoms); i++)
1050 sqrtm[i]=1.0;
1053 if (bVec2) {
1054 t=0;
1055 totmass=0;
1056 for(i=0; (i<natoms); i++)
1057 for(d=0;(d<DIM);d++) {
1058 t+=sqr((xav1[i][d]-xav2[i][d])*sqrtm[i]);
1059 totmass+=sqr(sqrtm[i]);
1061 fprintf(stdout,"RMSD (without fit) between the two average structures:"
1062 " %.3f (nm)\n\n",sqrt(t/totmass));
1065 if (last==-1)
1066 last=natoms*DIM;
1067 if (first>-1) {
1068 if (bFirstToLast) {
1069 /* make an index from first to last */
1070 nout=last-first+1;
1071 snew(iout,nout);
1072 for(i=0; i<nout; i++)
1073 iout[i]=first-1+i;
1075 else if (ThreeDPlotFile) {
1076 /* make an index of first+(0,1,2) and last */
1077 nout = bPDB3D ? 4 : 3;
1078 nout = min(last-first+1, nout);
1079 snew(iout,nout);
1080 iout[0]=first-1;
1081 iout[1]=first;
1082 if (nout>3)
1083 iout[2]=first+1;
1084 iout[nout-1]=last-1;
1086 else {
1087 /* make an index of first and last */
1088 nout=2;
1089 snew(iout,nout);
1090 iout[0]=first-1;
1091 iout[1]=last-1;
1094 else {
1095 printf("Select eigenvectors for output, end your selection with 0\n");
1096 nout=-1;
1097 iout=NULL;
1099 do {
1100 nout++;
1101 srenew(iout,nout+1);
1102 if(1 != scanf("%d",&iout[nout]))
1104 gmx_fatal(FARGS,"Error reading user input");
1106 iout[nout]--;
1108 while (iout[nout]>=0);
1110 printf("\n");
1112 /* make an index of the eigenvectors which are present */
1113 snew(outvec,nout);
1114 noutvec=0;
1115 for(i=0; i<nout; i++)
1117 j=0;
1118 while ((j<nvec1) && (eignr1[j]!=iout[i]))
1119 j++;
1120 if ((j<nvec1) && (eignr1[j]==iout[i]))
1122 outvec[noutvec]=j;
1123 noutvec++;
1126 fprintf(stderr,"%d eigenvectors selected for output",noutvec);
1127 if (noutvec <= 100)
1129 fprintf(stderr,":");
1130 for(j=0; j<noutvec; j++)
1131 fprintf(stderr," %d",eignr1[outvec[j]]+1);
1133 fprintf(stderr,"\n");
1135 if (CompFile)
1136 components(CompFile,natoms,eignr1,eigvec1,noutvec,outvec,oenv);
1138 if (RmsfFile)
1139 rmsf(RmsfFile,natoms,sqrtm,eignr1,eigvec1,noutvec,outvec,eigval1,
1140 neig1,oenv);
1142 if (bProj)
1143 project(bTraj ? opt2fn("-f",NFILE,fnm) : NULL,
1144 bTop ? &top : NULL,ePBC,topbox,xtop,
1145 ProjOnVecFile,TwoDPlotFile,ThreeDPlotFile,FilterFile,skip,
1146 ExtremeFile,bFirstLastSet,max,nextr,atoms,natoms,index,
1147 bFit1,xref1,nfit,ifit,w_rls,
1148 sqrtm,xav1,eignr1,eigvec1,noutvec,outvec,bSplit,
1149 oenv);
1151 if (OverlapFile)
1152 overlap(OverlapFile,natoms,
1153 eigvec1,nvec2,eignr2,eigvec2,noutvec,outvec,oenv);
1155 if (InpMatFile)
1156 inprod_matrix(InpMatFile,natoms,
1157 nvec1,eignr1,eigvec1,nvec2,eignr2,eigvec2,
1158 bFirstLastSet,noutvec,outvec);
1160 if (bCompare)
1161 compare(natoms,nvec1,eigvec1,nvec2,eigvec2,eigval1,neig1,eigval2,neig2);
1164 if (!CompFile && !bProj && !OverlapFile && !InpMatFile &&
1165 !bCompare && !bEntropy)
1167 fprintf(stderr,"\nIf you want some output,"
1168 " set one (or two or ...) of the output file options\n");
1172 view_all(oenv,NFILE, fnm);
1174 thanx(stdout);
1176 return 0;