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
42 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
67 #include "eigensolver.h"
70 int gmx_covar(int argc
,char *argv
[])
72 const char *desc
[] = {
73 "[TT]g_covar[tt] calculates and diagonalizes the (mass-weighted)",
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.",
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.",
87 "The eigenvectors can be analyzed with [TT]g_anaeig[tt].",
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, ...",
92 "Option [TT]-xpm[tt] writes the whole covariance matrix to an xpm file.",
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",
98 static bool bFit
=TRUE
,bRef
=FALSE
,bM
=FALSE
,bPBC
=TRUE
;
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" }
117 rvec
*x
,*xread
,*xref
,*xav
,*xproj
;
119 real
*sqrtm
,*mat
,*eigval
,sum
,trace
,inv_nframes
;
120 real t
,tstart
,tend
,**mat2
;
124 int natoms
,nat
,count
,nframes0
,nframes
,nlevels
;
125 gmx_large_int_t ndim
,i
,j
,k
,l
;
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
;
132 atom_id
*index
,*ifit
;
133 bool bDiffMass1
,bDiffMass2
;
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
);
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
);
174 printf("\nChoose a group for the least squares fit\n");
175 get_index(atoms
,ndxfile
,1,&nfit
,&ifit
,&fitname
);
177 gmx_fatal(FARGS
,"Need >= 3 points to fit!\n");
180 printf("\nChoose a group for the covariance analysis\n");
181 get_index(atoms
,ndxfile
,1,&natoms
,&index
,&ananame
);
185 snew(w_rls
,atoms
->nr
);
186 for(i
=0; (i
<nfit
); i
++) {
187 w_rls
[ifit
[i
]]=atoms
->atom
[ifit
[i
]].m
;
189 bDiffMass1
= bDiffMass1
|| (w_rls
[ifit
[i
]]!=w_rls
[ifit
[i
-1]]);
194 for(i
=0; (i
<natoms
); i
++)
196 sqrtm
[i
]=sqrt(atoms
->atom
[index
[i
]].m
);
198 bDiffMass2
= bDiffMass2
|| (sqrtm
[i
]!=sqrtm
[i
-1]);
203 if (bFit
&& bDiffMass1
&& !bDiffMass2
) {
204 bDiffMass1
= natoms
!= nfit
;
206 for (i
=0; (i
<natoms
) && !bDiffMass1
; i
++)
207 bDiffMass1
= index
[i
] != ifit
[i
];
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
++)
218 /* Prepare reference frame */
220 rm_pbc(&(top
.idef
),ePBC
,atoms
->nr
,box
,xref
,xref
);
222 reset_x(nfit
,ifit
,atoms
->nr
,NULL
,xref
,w_rls
);
227 if (sqrt(LARGE_INT_MAX
)<ndim
) {
228 gmx_fatal(FARGS
,"Number of degrees of freedoms to large for matrix.\n");
232 fprintf(stderr
,"Calculating the average structure ...\n");
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
);
239 /* calculate x: a fitted struture of the selected atoms */
241 rm_pbc(&(top
.idef
),ePBC
,nat
,box
,xread
,xread
);
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
));
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
);
261 fprintf(stderr
,"Constructing covariance matrix (%dx%d) ...\n",(int)ndim
,(int)ndim
);
263 nat
=read_first_x(oenv
,&status
,trxfile
,&t
,&xread
,box
);
268 /* calculate x: a (fitted) structure of the selected atoms */
270 rm_pbc(&(top
.idef
),ePBC
,nat
,box
,xread
,xread
);
272 reset_x(nfit
,ifit
,nat
,NULL
,xread
,w_rls
);
273 do_fit(nat
,w_rls
,xref
,xread
);
276 for (i
=0; i
<natoms
; i
++)
277 rvec_sub(xread
[index
[i
]],xref
[index
[i
]],x
[i
]);
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
++) {
286 for (i
=j
; i
<natoms
; i
++) {
289 mat
[l
+d
] += x
[i
][d
]*xj
;
293 } while (read_next_x(oenv
,status
,&t
,nat
,xread
,box
) &&
294 (bRef
|| nframes
< nframes0
));
297 fprintf(stderr
,"Read %d frames\n",nframes
);
300 /* copy the reference structure to the ouput array x */
302 for (i
=0; i
<natoms
; i
++)
303 copy_rvec(xref
[index
[i
]],xproj
[i
]);
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
];
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 " : "");
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]);
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
)
348 if (mat2
[j
][j
] > max
)
353 for(i
=0; i
<ndim
; i
++)
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");
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
);
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
++) {
378 mat2
[j
][i
] += mat
[ndim
*(DIM
*j
+d
)+DIM
*i
+d
];
379 if (mat2
[j
][i
] < min
)
381 if (mat2
[j
][j
] > max
)
383 mat2
[i
][j
] = mat2
[j
][i
];
387 for(i
=0; i
<ndim
/DIM
; i
++)
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");
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
);
399 for (i
=0; i
<ndim
/DIM
; i
++)
405 /* call diagonalization routine */
407 fprintf(stderr
,"\nDiagonalizing ...\n");
412 memcpy(tmp
,mat
,ndim
*ndim
*sizeof(real
));
413 eigensolver(tmp
,ndim
,0,ndim
,eigval
,mat
);
416 /* now write the output */
419 for(i
=0; i
<ndim
; i
++)
421 fprintf(stderr
,"\nSum of the eigenvalues: %g (%snm^2)\n",
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
]);
437 if (nframes
-1 < ndim
)
443 /* misuse lambda: 0/1 mass weighted analysis no/yes */
445 WriteXref
= eWXR_YES
;
446 for(i
=0; i
<nfit
; i
++)
447 copy_rvec(xref
[ifit
[i
]],x
[i
]);
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");
461 fprintf(out
,"Covariance analysis log, written %s\n",
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
);
467 pcwd
=getcwd(str
,STRLEN
);
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
));
479 fprintf(out
,"Read reference structure for fit from %s\n",fitfile
);
481 fprintf(out
,"Read index groups from %s\n",ndxfile
);
484 fprintf(out
,"Analysis group is '%s' (%d atoms)\n",ananame
,natoms
);
486 fprintf(out
,"Fit group is '%s' (%d atoms)\n",fitname
,nfit
);
488 fprintf(out
,"No fit was used\n");
489 fprintf(out
,"Analysis is %smass weighted\n", bDiffMass2
? "":"non-");
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",
495 fprintf(out
,"Trace of the covariance matrix after diagonalizing: %g\n\n",
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
);
506 fprintf(stderr
,"Wrote the log to %s\n",logfile
);