Don't use POSIX fnmatch() for pattern matching.
[gromacs/qmmm-gamess-us.git] / src / tools / gmx_covar.c
blob0b741be87bb536ea5296cf29f4825660c2a25c3c
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 <time.h>
42 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
43 #include <direct.h>
44 #include <io.h>
45 #endif
47 #include "statutil.h"
48 #include "sysstuff.h"
49 #include "typedefs.h"
50 #include "smalloc.h"
51 #include "macros.h"
52 #include "vec.h"
53 #include "pbc.h"
54 #include "copyrite.h"
55 #include "futil.h"
56 #include "statutil.h"
57 #include "index.h"
58 #include "confio.h"
59 #include "trnio.h"
60 #include "mshift.h"
61 #include "xvgr.h"
62 #include "do_fit.h"
63 #include "rmpbc.h"
64 #include "txtdump.h"
65 #include "matio.h"
66 #include "eigio.h"
67 #include "eigensolver.h"
68 #include "physics.h"
70 int gmx_covar(int argc,char *argv[])
72 const char *desc[] = {
73 "[TT]g_covar[tt] calculates and diagonalizes the (mass-weighted)",
74 "covariance matrix.",
75 "All structures are fitted to the structure in the structure file.",
76 "When this is not a run input file periodicity will not be taken into",
77 "account. When the fit and analysis groups are identical and the analysis",
78 "is non mass-weighted, the fit will also be non mass-weighted.",
79 "[PAR]",
80 "The eigenvectors are written to a trajectory file ([TT]-v[tt]).",
81 "When the same atoms are used for the fit and the covariance analysis,",
82 "the reference structure for the fit is written first with t=-1.",
83 "The average (or reference when [TT]-ref[tt] is used) structure is",
84 "written with t=0, the eigenvectors",
85 "are written as frames with the eigenvector number as timestamp.",
86 "[PAR]",
87 "The eigenvectors can be analyzed with [TT]g_anaeig[tt].",
88 "[PAR]",
89 "Option [TT]-ascii[tt] writes the whole covariance matrix to",
90 "an ASCII file. The order of the elements is: x1x1, x1y1, x1z1, x1x2, ...",
91 "[PAR]",
92 "Option [TT]-xpm[tt] writes the whole covariance matrix to an xpm file.",
93 "[PAR]",
94 "Option [TT]-xpma[tt] writes the atomic covariance matrix to an xpm file,",
95 "i.e. for each atom pair the sum of the xx, yy and zz covariances is",
96 "written."
98 static bool bFit=TRUE,bRef=FALSE,bM=FALSE,bPBC=TRUE;
99 static int end=-1;
100 t_pargs pa[] = {
101 { "-fit", FALSE, etBOOL, {&bFit},
102 "Fit to a reference structure"},
103 { "-ref", FALSE, etBOOL, {&bRef},
104 "Use the deviation from the conformation in the structure file instead of from the average" },
105 { "-mwa", FALSE, etBOOL, {&bM},
106 "Mass-weighted covariance analysis"},
107 { "-last", FALSE, etINT, {&end},
108 "Last eigenvector to write away (-1 is till the last)" },
109 { "-pbc", FALSE, etBOOL, {&bPBC},
110 "Apply corrections for periodic boundary conditions" }
112 FILE *out;
113 int status,trjout;
114 t_topology top;
115 int ePBC;
116 t_atoms *atoms;
117 rvec *x,*xread,*xref,*xav,*xproj;
118 matrix box,zerobox;
119 real *sqrtm,*mat,*eigval,sum,trace,inv_nframes;
120 real t,tstart,tend,**mat2;
121 real xj,*w_rls=NULL;
122 real min,max,*axis;
123 int ntopatoms,step;
124 int natoms,nat,count,nframes0,nframes,nlevels;
125 gmx_large_int_t ndim,i,j,k,l;
126 int WriteXref;
127 const char *fitfile,*trxfile,*ndxfile;
128 const char *eigvalfile,*eigvecfile,*averfile,*logfile;
129 const char *asciifile,*xpmfile,*xpmafile;
130 char str[STRLEN],*fitname,*ananame,*pcwd;
131 int d,dj,nfit;
132 atom_id *index,*ifit;
133 bool bDiffMass1,bDiffMass2;
134 time_t now;
135 t_rgb rlo,rmi,rhi;
136 real *tmp;
137 output_env_t oenv;
139 t_filenm fnm[] = {
140 { efTRX, "-f", NULL, ffREAD },
141 { efTPS, NULL, NULL, ffREAD },
142 { efNDX, NULL, NULL, ffOPTRD },
143 { efXVG, NULL, "eigenval", ffWRITE },
144 { efTRN, "-v", "eigenvec", ffWRITE },
145 { efSTO, "-av", "average.pdb", ffWRITE },
146 { efLOG, NULL, "covar", ffWRITE },
147 { efDAT, "-ascii","covar", ffOPTWR },
148 { efXPM, "-xpm","covar", ffOPTWR },
149 { efXPM, "-xpma","covara", ffOPTWR }
151 #define NFILE asize(fnm)
153 CopyRight(stderr,argv[0]);
154 parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_TIME_UNIT | PCA_BE_NICE,
155 NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv);
157 clear_mat(zerobox);
159 fitfile = ftp2fn(efTPS,NFILE,fnm);
160 trxfile = ftp2fn(efTRX,NFILE,fnm);
161 ndxfile = ftp2fn_null(efNDX,NFILE,fnm);
162 eigvalfile = ftp2fn(efXVG,NFILE,fnm);
163 eigvecfile = ftp2fn(efTRN,NFILE,fnm);
164 averfile = ftp2fn(efSTO,NFILE,fnm);
165 logfile = ftp2fn(efLOG,NFILE,fnm);
166 asciifile = opt2fn_null("-ascii",NFILE,fnm);
167 xpmfile = opt2fn_null("-xpm",NFILE,fnm);
168 xpmafile = opt2fn_null("-xpma",NFILE,fnm);
170 read_tps_conf(fitfile,str,&top,&ePBC,&xref,NULL,box,TRUE);
171 atoms=&top.atoms;
173 if (bFit) {
174 printf("\nChoose a group for the least squares fit\n");
175 get_index(atoms,ndxfile,1,&nfit,&ifit,&fitname);
176 if (nfit < 3)
177 gmx_fatal(FARGS,"Need >= 3 points to fit!\n");
178 } else
179 nfit=0;
180 printf("\nChoose a group for the covariance analysis\n");
181 get_index(atoms,ndxfile,1,&natoms,&index,&ananame);
183 bDiffMass1=FALSE;
184 if (bFit) {
185 snew(w_rls,atoms->nr);
186 for(i=0; (i<nfit); i++) {
187 w_rls[ifit[i]]=atoms->atom[ifit[i]].m;
188 if (i)
189 bDiffMass1 = bDiffMass1 || (w_rls[ifit[i]]!=w_rls[ifit[i-1]]);
192 bDiffMass2=FALSE;
193 snew(sqrtm,natoms);
194 for(i=0; (i<natoms); i++)
195 if (bM) {
196 sqrtm[i]=sqrt(atoms->atom[index[i]].m);
197 if (i)
198 bDiffMass2 = bDiffMass2 || (sqrtm[i]!=sqrtm[i-1]);
200 else
201 sqrtm[i]=1.0;
203 if (bFit && bDiffMass1 && !bDiffMass2) {
204 bDiffMass1 = natoms != nfit;
205 i=0;
206 for (i=0; (i<natoms) && !bDiffMass1; i++)
207 bDiffMass1 = index[i] != ifit[i];
208 if (!bDiffMass1) {
209 fprintf(stderr,"\n"
210 "Note: the fit and analysis group are identical,\n"
211 " while the fit is mass weighted and the analysis is not.\n"
212 " Making the fit non mass weighted.\n\n");
213 for(i=0; (i<nfit); i++)
214 w_rls[ifit[i]]=1.0;
218 /* Prepare reference frame */
219 if (bPBC)
220 rm_pbc(&(top.idef),ePBC,atoms->nr,box,xref,xref);
221 if (bFit)
222 reset_x(nfit,ifit,atoms->nr,NULL,xref,w_rls);
224 snew(x,natoms);
225 snew(xav,natoms);
226 ndim=natoms*DIM;
227 if (sqrt(LARGE_INT_MAX)<ndim) {
228 gmx_fatal(FARGS,"Number of degrees of freedoms to large for matrix.\n");
230 snew(mat,ndim*ndim);
232 fprintf(stderr,"Calculating the average structure ...\n");
233 nframes0 = 0;
234 nat=read_first_x(oenv,&status,trxfile,&t,&xread,box);
235 if (nat != atoms->nr)
236 fprintf(stderr,"\nWARNING: number of atoms in tpx (%d) and trajectory (%d) do not match\n",natoms,nat);
237 do {
238 nframes0++;
239 /* calculate x: a fitted struture of the selected atoms */
240 if (bPBC)
241 rm_pbc(&(top.idef),ePBC,nat,box,xread,xread);
242 if (bFit) {
243 reset_x(nfit,ifit,nat,NULL,xread,w_rls);
244 do_fit(nat,w_rls,xref,xread);
246 for (i=0; i<natoms; i++)
247 rvec_inc(xav[i],xread[index[i]]);
248 } while (read_next_x(oenv,status,&t,nat,xread,box));
249 close_trj(status);
251 inv_nframes = 1.0/nframes0;
252 for(i=0; i<natoms; i++)
253 for(d=0; d<DIM; d++) {
254 xav[i][d] *= inv_nframes;
255 xread[index[i]][d] = xav[i][d];
257 write_sto_conf_indexed(opt2fn("-av",NFILE,fnm),"Average structure",
258 atoms,xread,NULL,epbcNONE,zerobox,natoms,index);
259 sfree(xread);
261 fprintf(stderr,"Constructing covariance matrix (%dx%d) ...\n",(int)ndim,(int)ndim);
262 nframes=0;
263 nat=read_first_x(oenv,&status,trxfile,&t,&xread,box);
264 tstart = t;
265 do {
266 nframes++;
267 tend = t;
268 /* calculate x: a (fitted) structure of the selected atoms */
269 if (bPBC)
270 rm_pbc(&(top.idef),ePBC,nat,box,xread,xread);
271 if (bFit) {
272 reset_x(nfit,ifit,nat,NULL,xread,w_rls);
273 do_fit(nat,w_rls,xref,xread);
275 if (bRef)
276 for (i=0; i<natoms; i++)
277 rvec_sub(xread[index[i]],xref[index[i]],x[i]);
278 else
279 for (i=0; i<natoms; i++)
280 rvec_sub(xread[index[i]],xav[i],x[i]);
282 for (j=0; j<natoms; j++) {
283 for (dj=0; dj<DIM; dj++) {
284 k=ndim*(DIM*j+dj);
285 xj=x[j][dj];
286 for (i=j; i<natoms; i++) {
287 l=k+DIM*i;
288 for(d=0; d<DIM; d++)
289 mat[l+d] += x[i][d]*xj;
293 } while (read_next_x(oenv,status,&t,nat,xread,box) &&
294 (bRef || nframes < nframes0));
295 close_trj(status);
297 fprintf(stderr,"Read %d frames\n",nframes);
299 if (bRef) {
300 /* copy the reference structure to the ouput array x */
301 snew(xproj,natoms);
302 for (i=0; i<natoms; i++)
303 copy_rvec(xref[index[i]],xproj[i]);
304 } else {
305 xproj = xav;
308 /* correct the covariance matrix for the mass */
309 inv_nframes = 1.0/nframes;
310 for (j=0; j<natoms; j++)
311 for (dj=0; dj<DIM; dj++)
312 for (i=j; i<natoms; i++) {
313 k = ndim*(DIM*j+dj)+DIM*i;
314 for (d=0; d<DIM; d++)
315 mat[k+d] = mat[k+d]*inv_nframes*sqrtm[i]*sqrtm[j];
318 /* symmetrize the matrix */
319 for (j=0; j<ndim; j++)
320 for (i=j; i<ndim; i++)
321 mat[ndim*i+j]=mat[ndim*j+i];
323 trace=0;
324 for(i=0; i<ndim; i++)
325 trace+=mat[i*ndim+i];
326 fprintf(stderr,"\nTrace of the covariance matrix: %g (%snm^2)\n",
327 trace,bM ? "u " : "");
329 if (asciifile) {
330 out = ffopen(asciifile,"w");
331 for (j=0; j<ndim; j++) {
332 for (i=0; i<ndim; i+=3)
333 fprintf(out,"%g %g %g\n",
334 mat[ndim*j+i],mat[ndim*j+i+1],mat[ndim*j+i+2]);
336 fclose(out);
339 if (xpmfile) {
340 min = 0;
341 max = 0;
342 snew(mat2,ndim);
343 for (j=0; j<ndim; j++) {
344 mat2[j] = &(mat[ndim*j]);
345 for (i=0; i<=j; i++) {
346 if (mat2[j][i] < min)
347 min = mat2[j][i];
348 if (mat2[j][j] > max)
349 max = mat2[j][i];
352 snew(axis,ndim);
353 for(i=0; i<ndim; i++)
354 axis[i] = i+1;
355 rlo.r = 0; rlo.g = 0; rlo.b = 1;
356 rmi.r = 1; rmi.g = 1; rmi.b = 1;
357 rhi.r = 1; rhi.g = 0; rhi.b = 0;
358 out = ffopen(xpmfile,"w");
359 nlevels = 80;
360 write_xpm3(out,0,"Covariance",bM ? "u nm^2" : "nm^2",
361 "dim","dim",ndim,ndim,axis,axis,
362 mat2,min,0.0,max,rlo,rmi,rhi,&nlevels);
363 fclose(out);
364 sfree(axis);
365 sfree(mat2);
368 if (xpmafile) {
369 min = 0;
370 max = 0;
371 snew(mat2,ndim/DIM);
372 for (i=0; i<ndim/DIM; i++)
373 snew(mat2[i],ndim/DIM);
374 for (j=0; j<ndim/DIM; j++) {
375 for (i=0; i<=j; i++) {
376 mat2[j][i] = 0;
377 for(d=0; d<DIM; d++)
378 mat2[j][i] += mat[ndim*(DIM*j+d)+DIM*i+d];
379 if (mat2[j][i] < min)
380 min = mat2[j][i];
381 if (mat2[j][j] > max)
382 max = mat2[j][i];
383 mat2[i][j] = mat2[j][i];
386 snew(axis,ndim/DIM);
387 for(i=0; i<ndim/DIM; i++)
388 axis[i] = i+1;
389 rlo.r = 0; rlo.g = 0; rlo.b = 1;
390 rmi.r = 1; rmi.g = 1; rmi.b = 1;
391 rhi.r = 1; rhi.g = 0; rhi.b = 0;
392 out = ffopen(xpmafile,"w");
393 nlevels = 80;
394 write_xpm3(out,0,"Covariance",bM ? "u nm^2" : "nm^2",
395 "atom","atom",ndim/DIM,ndim/DIM,axis,axis,
396 mat2,min,0.0,max,rlo,rmi,rhi,&nlevels);
397 fclose(out);
398 sfree(axis);
399 for (i=0; i<ndim/DIM; i++)
400 sfree(mat2[i]);
401 sfree(mat2);
405 /* call diagonalization routine */
407 fprintf(stderr,"\nDiagonalizing ...\n");
408 fflush(stderr);
410 snew(eigval,ndim);
411 snew(tmp,ndim*ndim);
412 memcpy(tmp,mat,ndim*ndim*sizeof(real));
413 eigensolver(tmp,ndim,0,ndim,eigval,mat);
414 sfree(tmp);
416 /* now write the output */
418 sum=0;
419 for(i=0; i<ndim; i++)
420 sum+=eigval[i];
421 fprintf(stderr,"\nSum of the eigenvalues: %g (%snm^2)\n",
422 sum,bM ? "u " : "");
423 if (fabs(trace-sum)>0.01*trace)
424 fprintf(stderr,"\nWARNING: eigenvalue sum deviates from the trace of the covariance matrix\n");
426 fprintf(stderr,"\nWriting eigenvalues to %s\n",eigvalfile);
428 sprintf(str,"(%snm\\S2\\N)",bM ? "u " : "");
429 out=xvgropen(eigvalfile,
430 "Eigenvalues of the covariance matrix",
431 "Eigenvector index",str,oenv);
432 for (i=0; (i<ndim); i++)
433 fprintf (out,"%10d %g\n",(int)i+1,eigval[ndim-1-i]);
434 fclose(out);
436 if (end==-1) {
437 if (nframes-1 < ndim)
438 end=nframes-1;
439 else
440 end=ndim;
442 if (bFit) {
443 /* misuse lambda: 0/1 mass weighted analysis no/yes */
444 if (nfit==natoms) {
445 WriteXref = eWXR_YES;
446 for(i=0; i<nfit; i++)
447 copy_rvec(xref[ifit[i]],x[i]);
448 } else
449 WriteXref = eWXR_NO;
450 } else {
451 /* misuse lambda: -1 for no fit */
452 WriteXref = eWXR_NOFIT;
455 write_eigenvectors(eigvecfile,natoms,mat,TRUE,1,end,
456 WriteXref,x,bDiffMass1,xproj,bM,eigval);
458 out = ffopen(logfile,"w");
460 now = time(NULL);
461 fprintf(out,"Covariance analysis log, written %s\n",
462 ctime(&now));
463 fprintf(out,"Program: %s\n",argv[0]);
464 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
465 pcwd=_getcwd(str,STRLEN);
466 #else
467 pcwd=getcwd(str,STRLEN);
468 #endif
469 if(NULL==pcwd)
471 gmx_fatal(FARGS,"Current working directory is undefined");
474 fprintf(out,"Working directory: %s\n\n",str);
476 fprintf(out,"Read %d frames from %s (time %g to %g %s)\n",nframes,trxfile,
477 conv_time(oenv,tstart),conv_time(oenv,tend),get_time_unit(oenv));
478 if (bFit)
479 fprintf(out,"Read reference structure for fit from %s\n",fitfile);
480 if (ndxfile)
481 fprintf(out,"Read index groups from %s\n",ndxfile);
482 fprintf(out,"\n");
484 fprintf(out,"Analysis group is '%s' (%d atoms)\n",ananame,natoms);
485 if (bFit)
486 fprintf(out,"Fit group is '%s' (%d atoms)\n",fitname,nfit);
487 else
488 fprintf(out,"No fit was used\n");
489 fprintf(out,"Analysis is %smass weighted\n", bDiffMass2 ? "":"non-");
490 if (bFit)
491 fprintf(out,"Fit is %smass weighted\n", bDiffMass1 ? "":"non-");
492 fprintf(out,"Diagonalized the %dx%d covariance matrix\n",(int)ndim,(int)ndim);
493 fprintf(out,"Trace of the covariance matrix before diagonalizing: %g\n",
494 trace);
495 fprintf(out,"Trace of the covariance matrix after diagonalizing: %g\n\n",
496 sum);
498 fprintf(out,"Wrote %d eigenvalues to %s\n",(int)ndim,eigvalfile);
499 if (WriteXref == eWXR_YES)
500 fprintf(out,"Wrote reference structure to %s\n",eigvecfile);
501 fprintf(out,"Wrote average structure to %s and %s\n",averfile,eigvecfile);
502 fprintf(out,"Wrote eigenvectors %d to %d to %s\n",1,end,eigvecfile);
504 fclose(out);
506 fprintf(stderr,"Wrote the log to %s\n",logfile);
508 thanx(stderr);
510 return 0;