2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
45 #include "gromacs/commandline/pargs.h"
47 #include "gromacs/utility/smalloc.h"
49 #include "gromacs/utility/fatalerror.h"
52 #include "gromacs/utility/futil.h"
54 #include "gromacs/fileio/pdbio.h"
55 #include "gromacs/fileio/confio.h"
56 #include "gromacs/fileio/tpxio.h"
57 #include "gromacs/fileio/trxio.h"
58 #include "gromacs/fileio/matio.h"
67 #include "gromacs/math/do_fit.h"
69 static void calc_entropy_qh(FILE *fp, int n, real eigval[], real temp, int nskip)
72 double hwkT, w, dS, S = 0;
75 hbar = PLANCK1/(2*M_PI);
76 for (i = 0; (i < n-nskip); i++)
80 lambda = eigval[i]*AMU;
81 w = sqrt(BOLTZMANN*temp/lambda)/NANO;
82 hwkT = (hbar*w)/(BOLTZMANN*temp);
83 dS = (hwkT/(exp(hwkT) - 1) - log(1-exp(-hwkT)));
87 fprintf(debug, "i = %5d w = %10g lam = %10g hwkT = %10g dS = %10g\n",
88 i, w, lambda, hwkT, dS);
93 fprintf(stderr, "eigval[%d] = %g\n", i, eigval[i]);
97 fprintf(fp, "The Entropy due to the Quasi Harmonic approximation is %g J/mol K\n",
101 static void calc_entropy_schlitter(FILE *fp, int n, int nskip,
102 real *eigval, real temp)
108 double hbar, kt, kteh, S;
110 hbar = PLANCK1/(2*M_PI);
112 kteh = kt*exp(2.0)/(hbar*hbar)*AMU*(NANO*NANO);
115 fprintf(debug, "n = %d, nskip = %d kteh = %g\n", n, nskip, kteh);
119 for (i = 0; (i < n-nskip); i++)
121 dd = 1+kteh*eigval[i];
126 fprintf(fp, "The Entropy due to the Schlitter formula is %g J/mol K\n", S);
129 const char *proj_unit;
131 static real tick_spacing(real range, int minticks)
140 sp = 0.2*exp(log(10)*ceil(log(range)/log(10)));
141 while (range/sp < minticks-1)
149 static void write_xvgr_graphs(const char *file, int ngraphs, int nsetspergraph,
150 const char *title, const char *subtitle,
151 const char *xlabel, const char **ylabel,
152 int n, real *x, real **y, real ***sy,
153 real scale_x, gmx_bool bZero, gmx_bool bSplit,
154 const output_env_t oenv)
158 real min, max, xsp, ysp;
160 out = gmx_ffopen(file, "w");
161 if (output_env_get_xvg_format(oenv) == exvgXMGRACE)
163 fprintf(out, "@ autoscale onread none\n");
165 for (g = 0; g < ngraphs; g++)
171 for (i = 0; i < n; i++)
187 for (s = 0; s < nsetspergraph; s++)
189 for (i = 0; i < n; i++)
191 if (sy[g][s][i] < min)
195 if (sy[g][s][i] > max)
208 min = min-0.1*(max-min);
210 max = max+0.1*(max-min);
211 xsp = tick_spacing((x[n-1]-x[0])*scale_x, 4);
212 ysp = tick_spacing(max-min, 3);
213 if (output_env_get_print_xvgr_codes(oenv))
215 fprintf(out, "@ with g%d\n@ g%d on\n", g, g);
218 fprintf(out, "@ title \"%s\"\n", title);
221 fprintf(out, "@ subtitle \"%s\"\n", subtitle);
226 fprintf(out, "@ xaxis label \"%s\"\n", xlabel);
230 fprintf(out, "@ xaxis ticklabel off\n");
234 fprintf(out, "@ world xmin %g\n", x[0]*scale_x);
235 fprintf(out, "@ world xmax %g\n", x[n-1]*scale_x);
236 fprintf(out, "@ world ymin %g\n", min);
237 fprintf(out, "@ world ymax %g\n", max);
239 fprintf(out, "@ view xmin 0.15\n");
240 fprintf(out, "@ view xmax 0.85\n");
241 fprintf(out, "@ view ymin %g\n", 0.15+(ngraphs-1-g)*0.7/ngraphs);
242 fprintf(out, "@ view ymax %g\n", 0.15+(ngraphs-g)*0.7/ngraphs);
243 fprintf(out, "@ yaxis label \"%s\"\n", ylabel[g]);
244 fprintf(out, "@ xaxis tick major %g\n", xsp);
245 fprintf(out, "@ xaxis tick minor %g\n", xsp/2);
246 fprintf(out, "@ xaxis ticklabel start type spec\n");
247 fprintf(out, "@ xaxis ticklabel start %g\n", ceil(min/xsp)*xsp);
248 fprintf(out, "@ yaxis tick major %g\n", ysp);
249 fprintf(out, "@ yaxis tick minor %g\n", ysp/2);
250 fprintf(out, "@ yaxis ticklabel start type spec\n");
251 fprintf(out, "@ yaxis ticklabel start %g\n", ceil(min/ysp)*ysp);
252 if ((min < 0) && (max > 0))
254 fprintf(out, "@ zeroxaxis bar on\n");
255 fprintf(out, "@ zeroxaxis bar linestyle 3\n");
258 for (s = 0; s < nsetspergraph; s++)
260 for (i = 0; i < n; i++)
262 if (bSplit && i > 0 && abs(x[i]) < 1e-5)
264 if (output_env_get_print_xvgr_codes(oenv))
269 fprintf(out, "%10.4f %10.5f\n",
270 x[i]*scale_x, y ? y[g][i] : sy[g][s][i]);
272 if (output_env_get_print_xvgr_codes(oenv))
282 compare(int natoms, int n1, rvec **eigvec1, int n2, rvec **eigvec2,
283 real *eigval1, int neig1, real *eigval2, int neig2)
287 double sum1, sum2, trace1, trace2, sab, samsb2, tmp, ip;
291 n = min(n, min(neig1, neig2));
292 fprintf(stdout, "Will compare the covariance matrices using %d dimensions\n", n);
295 for (i = 0; i < n; i++)
302 eigval1[i] = sqrt(eigval1[i]);
305 for (i = n; i < neig1; i++)
307 trace1 += eigval1[i];
310 for (i = 0; i < n; i++)
317 eigval2[i] = sqrt(eigval2[i]);
320 for (i = n; i < neig2; i++)
322 trace2 += eigval2[i];
325 fprintf(stdout, "Trace of the two matrices: %g and %g\n", sum1, sum2);
326 if (neig1 != n || neig2 != n)
328 fprintf(stdout, "this is %d%% and %d%% of the total trace\n",
329 (int)(100*sum1/trace1+0.5), (int)(100*sum2/trace2+0.5));
331 fprintf(stdout, "Square root of the traces: %g and %g\n",
332 sqrt(sum1), sqrt(sum2));
335 for (i = 0; i < n; i++)
338 for (j = 0; j < n; j++)
341 for (k = 0; k < natoms; k++)
343 ip += iprod(eigvec1[i][k], eigvec2[j][k]);
345 tmp += eigval2[j]*ip*ip;
347 sab += eigval1[i]*tmp;
350 samsb2 = sum1+sum2-2*sab;
356 fprintf(stdout, "The overlap of the covariance matrices:\n");
357 fprintf(stdout, " normalized: %.3f\n", 1-sqrt(samsb2/(sum1+sum2)));
358 tmp = 1-sab/sqrt(sum1*sum2);
363 fprintf(stdout, " shape: %.3f\n", 1-sqrt(tmp));
367 static void inprod_matrix(const char *matfile, int natoms,
368 int nvec1, int *eignr1, rvec **eigvec1,
369 int nvec2, int *eignr2, rvec **eigvec2,
370 gmx_bool bSelect, int noutvec, int *outvec)
374 int i, x1, y1, x, y, nlevels;
376 real inp, *t_x, *t_y, max;
384 for (y1 = 0; y1 < nx; y1++)
386 if (outvec[y1] < nvec2)
388 t_y[ny] = eignr2[outvec[y1]]+1;
397 for (y = 0; y < ny; y++)
399 t_y[y] = eignr2[y]+1;
403 fprintf(stderr, "Calculating inner-product matrix of %dx%d eigenvectors\n",
409 for (x1 = 0; x1 < nx; x1++)
420 t_x[x1] = eignr1[x]+1;
421 fprintf(stderr, " %d", eignr1[x]+1);
422 for (y1 = 0; y1 < ny; y1++)
427 while (outvec[y1] >= nvec2)
437 for (i = 0; i < natoms; i++)
439 inp += iprod(eigvec1[x][i], eigvec2[y][i]);
441 mat[x1][y1] = fabs(inp);
442 if (mat[x1][y1] > max)
448 fprintf(stderr, "\n");
449 rlo.r = 1; rlo.g = 1; rlo.b = 1;
450 rhi.r = 0; rhi.g = 0; rhi.b = 0;
452 out = gmx_ffopen(matfile, "w");
453 write_xpm(out, 0, "Eigenvector inner-products", "in.prod.", "run 1", "run 2",
454 nx, ny, t_x, t_y, mat, 0.0, max, rlo, rhi, &nlevels);
458 static void overlap(const char *outfile, int natoms,
460 int nvec2, int *eignr2, rvec **eigvec2,
461 int noutvec, int *outvec,
462 const output_env_t oenv)
468 fprintf(stderr, "Calculating overlap between eigenvectors of set 2 with eigenvectors\n");
469 for (i = 0; i < noutvec; i++)
471 fprintf(stderr, "%d ", outvec[i]+1);
473 fprintf(stderr, "\n");
475 out = xvgropen(outfile, "Subspace overlap",
476 "Eigenvectors of trajectory 2", "Overlap", oenv);
477 fprintf(out, "@ subtitle \"using %d eigenvectors of trajectory 1\"\n",
480 for (x = 0; x < nvec2; x++)
482 for (v = 0; v < noutvec; v++)
486 for (i = 0; i < natoms; i++)
488 inp += iprod(eigvec1[vec][i], eigvec2[x][i]);
492 fprintf(out, "%5d %5.3f\n", eignr2[x]+1, overlap/noutvec);
498 static void project(const char *trajfile, t_topology *top, int ePBC, matrix topbox,
499 const char *projfile, const char *twodplotfile,
500 const char *threedplotfile, const char *filterfile, int skip,
501 const char *extremefile, gmx_bool bExtrAll, real extreme,
502 int nextr, t_atoms *atoms, int natoms, atom_id *index,
503 gmx_bool bFit, rvec *xref, int nfit, atom_id *ifit, real *w_rls,
504 real *sqrtm, rvec *xav,
505 int *eignr, rvec **eigvec,
506 int noutvec, int *outvec, gmx_bool bSplit,
507 const output_env_t oenv)
509 FILE *xvgrout = NULL;
510 int nat, i, j, d, v, vec, nfr, nframes = 0, snew_size, frame;
511 t_trxstatus *out = NULL;
513 int noutvec_extr, imin, imax;
518 real t, inp, **inprod = NULL, min = 0, max = 0;
519 char str[STRLEN], str2[STRLEN], **ylabel, *c;
521 gmx_rmpbc_t gpbc = NULL;
527 noutvec_extr = noutvec;
537 snew(inprod, noutvec+1);
541 fprintf(stderr, "Writing a filtered trajectory to %s using eigenvectors\n",
543 for (i = 0; i < noutvec; i++)
545 fprintf(stderr, "%d ", outvec[i]+1);
547 fprintf(stderr, "\n");
548 out = open_trx(filterfile, "w");
553 nat = read_first_x(oenv, &status, trajfile, &t, &xread, box);
556 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);
562 gpbc = gmx_rmpbc_init(&top->idef, ePBC, nat);
565 for (i = 0; i < nat; i++)
575 gmx_rmpbc(gpbc, nat, box, xread);
577 if (nframes >= snew_size)
580 for (i = 0; i < noutvec+1; i++)
582 srenew(inprod[i], snew_size);
585 inprod[noutvec][nframes] = t;
586 /* calculate x: a fitted struture of the selected atoms */
589 reset_x(nfit, ifit, nat, NULL, xread, w_rls);
590 do_fit(nat, w_rls, xref, xread);
592 for (i = 0; i < natoms; i++)
594 copy_rvec(xread[index[i]], x[i]);
597 for (v = 0; v < noutvec; v++)
600 /* calculate (mass-weighted) projection */
602 for (i = 0; i < natoms; i++)
604 inp += (eigvec[vec][i][0]*(x[i][0]-xav[i][0])+
605 eigvec[vec][i][1]*(x[i][1]-xav[i][1])+
606 eigvec[vec][i][2]*(x[i][2]-xav[i][2]))*sqrtm[i];
608 inprod[v][nframes] = inp;
612 for (i = 0; i < natoms; i++)
614 for (d = 0; d < DIM; d++)
616 /* misuse xread for output */
617 xread[index[i]][d] = xav[i][d];
618 for (v = 0; v < noutvec; v++)
620 xread[index[i]][d] +=
621 inprod[v][nframes]*eigvec[outvec[v]][i][d]/sqrtm[i];
625 write_trx(out, natoms, index, atoms, 0, t, box, xread, NULL, NULL);
631 while (read_next_x(oenv, status, &t, xread, box));
641 snew(xread, atoms->nr);
646 gmx_rmpbc_done(gpbc);
652 snew(ylabel, noutvec);
653 for (v = 0; v < noutvec; v++)
655 sprintf(str, "vec %d", eignr[outvec[v]]+1);
656 ylabel[v] = strdup(str);
658 sprintf(str, "projection on eigenvectors (%s)", proj_unit);
659 write_xvgr_graphs(projfile, noutvec, 1, str, NULL, output_env_get_xvgr_tlabel(oenv),
660 (const char **)ylabel,
661 nframes, inprod[noutvec], inprod, NULL,
662 output_env_get_time_factor(oenv), FALSE, bSplit, oenv);
667 sprintf(str, "projection on eigenvector %d (%s)",
668 eignr[outvec[0]]+1, proj_unit);
669 sprintf(str2, "projection on eigenvector %d (%s)",
670 eignr[outvec[noutvec-1]]+1, proj_unit);
671 xvgrout = xvgropen(twodplotfile, "2D projection of trajectory", str, str2,
673 for (i = 0; i < nframes; i++)
675 if (bSplit && i > 0 && abs(inprod[noutvec][i]) < 1e-5)
677 fprintf(xvgrout, "&\n");
679 fprintf(xvgrout, "%10.5f %10.5f\n", inprod[0][i], inprod[noutvec-1][i]);
681 gmx_ffclose(xvgrout);
690 char *resnm, *atnm, pdbform[STRLEN];
696 gmx_fatal(FARGS, "You have selected less than 3 eigenvectors");
700 bPDB = fn2ftp(threedplotfile) == efPDB;
702 box[XX][XX] = box[YY][YY] = box[ZZ][ZZ] = 1;
704 b4D = bPDB && (noutvec >= 4);
707 fprintf(stderr, "You have selected four or more eigenvectors:\n"
708 "fourth eigenvector will be plotted "
709 "in bfactor field of pdb file\n");
710 sprintf(str, "4D proj. of traj. on eigenv. %d, %d, %d and %d",
711 eignr[outvec[0]]+1, eignr[outvec[1]]+1,
712 eignr[outvec[2]]+1, eignr[outvec[3]]+1);
716 sprintf(str, "3D proj. of traj. on eigenv. %d, %d and %d",
717 eignr[outvec[0]]+1, eignr[outvec[1]]+1, eignr[outvec[2]]+1);
719 init_t_atoms(&atoms, nframes, FALSE);
723 resnm = strdup("PRJ");
727 fact = 10000.0/nframes;
734 for (i = 0; i < nframes; i++)
736 atoms.atomname[i] = &atnm;
737 atoms.atom[i].resind = i;
738 atoms.resinfo[i].name = &resnm;
739 atoms.resinfo[i].nr = ceil(i*fact);
740 atoms.resinfo[i].ic = ' ';
741 x[i][XX] = inprod[0][i];
742 x[i][YY] = inprod[1][i];
743 x[i][ZZ] = inprod[2][i];
749 if ( ( b4D || bSplit ) && bPDB)
751 strcpy(pdbform, get_pdbformat());
752 strcat(pdbform, "%8.4f%8.4f\n");
754 out = gmx_ffopen(threedplotfile, "w");
755 fprintf(out, "HEADER %s\n", str);
758 fprintf(out, "REMARK %s\n", "fourth dimension plotted as B-factor");
761 for (i = 0; i < atoms.nr; i++)
763 if (j > 0 && bSplit && abs(inprod[noutvec][i]) < 1e-5)
765 fprintf(out, "TER\n");
768 fprintf(out, pdbform, "ATOM", i+1, "C", "PRJ", ' ', j+1,
769 10*x[i][XX], 10*x[i][YY], 10*x[i][ZZ], 1.0, 10*b[i]);
772 fprintf(out, "CONECT%5d%5d\n", i, i+1);
776 fprintf(out, "TER\n");
781 write_sto_conf(threedplotfile, str, &atoms, x, NULL, ePBC, box);
783 free_t_atoms(&atoms, FALSE);
788 snew(pmin, noutvec_extr);
789 snew(pmax, noutvec_extr);
792 fprintf(stderr, "%11s %17s %17s\n", "eigenvector", "Minimum", "Maximum");
794 "%11s %10s %10s %10s %10s\n", "", "value", "frame", "value", "frame");
797 for (v = 0; v < noutvec_extr; v++)
799 for (i = 0; i < nframes; i++)
801 if (inprod[v][i] < inprod[v][imin])
805 if (inprod[v][i] > inprod[v][imax])
810 pmin[v] = inprod[v][imin];
811 pmax[v] = inprod[v][imax];
812 fprintf(stderr, "%7d %10.6f %10d %10.6f %10d\n",
814 pmin[v], imin, pmax[v], imax);
822 /* build format string for filename: */
823 strcpy(str, extremefile); /* copy filename */
824 c = strrchr(str, '.'); /* find where extention begins */
825 strcpy(str2, c); /* get extention */
826 sprintf(c, "%%d%s", str2); /* append '%s' and extention to filename */
827 for (v = 0; v < noutvec_extr; v++)
829 /* make filename using format string */
830 if (noutvec_extr == 1)
832 strcpy(str2, extremefile);
836 sprintf(str2, str, eignr[outvec[v]]+1);
838 fprintf(stderr, "Writing %d frames along eigenvector %d to %s\n",
839 nextr, outvec[v]+1, str2);
840 out = open_trx(str2, "w");
841 for (frame = 0; frame < nextr; frame++)
843 if ((extreme == 0) && (nextr <= 3))
845 for (i = 0; i < natoms; i++)
847 atoms->resinfo[atoms->atom[index[i]].resind].chainid = 'A' + frame;
850 for (i = 0; i < natoms; i++)
852 for (d = 0; d < DIM; d++)
855 (xav[i][d] + (pmin[v]*(nextr-frame-1)+pmax[v]*frame)/(nextr-1)
856 *eigvec[outvec[v]][i][d]/sqrtm[i]);
859 write_trx(out, natoms, index, atoms, 0, frame, topbox, xread, NULL, NULL);
866 fprintf(stderr, "\n");
869 static void components(const char *outfile, int natoms,
870 int *eignr, rvec **eigvec,
871 int noutvec, int *outvec,
872 const output_env_t oenv)
876 char str[STRLEN], **ylabel;
878 fprintf(stderr, "Writing eigenvector components to %s\n", outfile);
880 snew(ylabel, noutvec);
883 for (i = 0; i < natoms; i++)
887 for (g = 0; g < noutvec; g++)
890 sprintf(str, "vec %d", eignr[v]+1);
891 ylabel[g] = strdup(str);
893 for (s = 0; s < 4; s++)
895 snew(y[g][s], natoms);
897 for (i = 0; i < natoms; i++)
899 y[g][0][i] = norm(eigvec[v][i]);
900 for (s = 0; s < 3; s++)
902 y[g][s+1][i] = eigvec[v][i][s];
906 write_xvgr_graphs(outfile, noutvec, 4, "Eigenvector components",
907 "black: total, red: x, green: y, blue: z",
908 "Atom number", (const char **)ylabel,
909 natoms, x, NULL, y, 1, FALSE, FALSE, oenv);
910 fprintf(stderr, "\n");
913 static void rmsf(const char *outfile, int natoms, real *sqrtm,
914 int *eignr, rvec **eigvec,
915 int noutvec, int *outvec,
916 real *eigval, int neig,
917 const output_env_t oenv)
921 char str[STRLEN], **ylabel;
923 for (i = 0; i < neig; i++)
931 fprintf(stderr, "Writing rmsf to %s\n", outfile);
933 snew(ylabel, noutvec);
936 for (i = 0; i < natoms; i++)
940 for (g = 0; g < noutvec; g++)
943 if (eignr[v] >= neig)
945 gmx_fatal(FARGS, "Selected vector %d is larger than the number of eigenvalues (%d)", eignr[v]+1, neig);
947 sprintf(str, "vec %d", eignr[v]+1);
948 ylabel[g] = strdup(str);
950 for (i = 0; i < natoms; i++)
952 y[g][i] = sqrt(eigval[eignr[v]]*norm2(eigvec[v][i]))/sqrtm[i];
955 write_xvgr_graphs(outfile, noutvec, 1, "RMS fluctuation (nm) ", NULL,
956 "Atom number", (const char **)ylabel,
957 natoms, x, y, NULL, 1, TRUE, FALSE, oenv);
958 fprintf(stderr, "\n");
961 int gmx_anaeig(int argc, char *argv[])
963 static const char *desc[] = {
964 "[THISMODULE] analyzes eigenvectors. The eigenvectors can be of a",
965 "covariance matrix ([gmx-covar]) or of a Normal Modes analysis",
966 "([gmx-nmeig]).[PAR]",
968 "When a trajectory is projected on eigenvectors, all structures are",
969 "fitted to the structure in the eigenvector file, if present, otherwise",
970 "to the structure in the structure file. When no run input file is",
971 "supplied, periodicity will not be taken into account. Most analyses",
972 "are performed on eigenvectors [TT]-first[tt] to [TT]-last[tt], but when",
973 "[TT]-first[tt] is set to -1 you will be prompted for a selection.[PAR]",
975 "[TT]-comp[tt]: plot the vector components per atom of eigenvectors",
976 "[TT]-first[tt] to [TT]-last[tt].[PAR]",
978 "[TT]-rmsf[tt]: plot the RMS fluctuation per atom of eigenvectors",
979 "[TT]-first[tt] to [TT]-last[tt] (requires [TT]-eig[tt]).[PAR]",
981 "[TT]-proj[tt]: calculate projections of a trajectory on eigenvectors",
982 "[TT]-first[tt] to [TT]-last[tt].",
983 "The projections of a trajectory on the eigenvectors of its",
984 "covariance matrix are called principal components (pc's).",
985 "It is often useful to check the cosine content of the pc's,",
986 "since the pc's of random diffusion are cosines with the number",
987 "of periods equal to half the pc index.",
988 "The cosine content of the pc's can be calculated with the program",
989 "[gmx-analyze].[PAR]",
991 "[TT]-2d[tt]: calculate a 2d projection of a trajectory on eigenvectors",
992 "[TT]-first[tt] and [TT]-last[tt].[PAR]",
994 "[TT]-3d[tt]: calculate a 3d projection of a trajectory on the first",
995 "three selected eigenvectors.[PAR]",
997 "[TT]-filt[tt]: filter the trajectory to show only the motion along",
998 "eigenvectors [TT]-first[tt] to [TT]-last[tt].[PAR]",
1000 "[TT]-extr[tt]: calculate the two extreme projections along a trajectory",
1001 "on the average structure and interpolate [TT]-nframes[tt] frames",
1002 "between them, or set your own extremes with [TT]-max[tt]. The",
1003 "eigenvector [TT]-first[tt] will be written unless [TT]-first[tt] and",
1004 "[TT]-last[tt] have been set explicitly, in which case all eigenvectors",
1005 "will be written to separate files. Chain identifiers will be added",
1006 "when writing a [TT].pdb[tt] file with two or three structures (you",
1007 "can use [TT]rasmol -nmrpdb[tt] to view such a [TT].pdb[tt] file).[PAR]",
1009 " Overlap calculations between covariance analysis:[BR]",
1010 " [BB]Note:[bb] the analysis should use the same fitting structure[PAR]",
1012 "[TT]-over[tt]: calculate the subspace overlap of the eigenvectors in",
1013 "file [TT]-v2[tt] with eigenvectors [TT]-first[tt] to [TT]-last[tt]",
1014 "in file [TT]-v[tt].[PAR]",
1016 "[TT]-inpr[tt]: calculate a matrix of inner-products between",
1017 "eigenvectors in files [TT]-v[tt] and [TT]-v2[tt]. All eigenvectors",
1018 "of both files will be used unless [TT]-first[tt] and [TT]-last[tt]",
1019 "have been set explicitly.[PAR]",
1021 "When [TT]-v[tt], [TT]-eig[tt], [TT]-v2[tt] and [TT]-eig2[tt] are given,",
1022 "a single number for the overlap between the covariance matrices is",
1023 "generated. The formulas are:[BR]",
1024 " difference = sqrt(tr((sqrt(M1) - sqrt(M2))^2))[BR]",
1025 "normalized overlap = 1 - difference/sqrt(tr(M1) + tr(M2))[BR]",
1026 " shape overlap = 1 - sqrt(tr((sqrt(M1/tr(M1)) - sqrt(M2/tr(M2)))^2))[BR]",
1027 "where M1 and M2 are the two covariance matrices and tr is the trace",
1028 "of a matrix. The numbers are proportional to the overlap of the square",
1029 "root of the fluctuations. The normalized overlap is the most useful",
1030 "number, it is 1 for identical matrices and 0 when the sampled",
1031 "subspaces are orthogonal.[PAR]",
1032 "When the [TT]-entropy[tt] flag is given an entropy estimate will be",
1033 "computed based on the Quasiharmonic approach and based on",
1034 "Schlitter's formula."
1036 static int first = 1, last = -1, skip = 1, nextr = 2, nskip = 6;
1037 static real max = 0.0, temp = 298.15;
1038 static gmx_bool bSplit = FALSE, bEntropy = FALSE;
1040 { "-first", FALSE, etINT, {&first},
1041 "First eigenvector for analysis (-1 is select)" },
1042 { "-last", FALSE, etINT, {&last},
1043 "Last eigenvector for analysis (-1 is till the last)" },
1044 { "-skip", FALSE, etINT, {&skip},
1045 "Only analyse every nr-th frame" },
1046 { "-max", FALSE, etREAL, {&max},
1047 "Maximum for projection of the eigenvector on the average structure, "
1048 "max=0 gives the extremes" },
1049 { "-nframes", FALSE, etINT, {&nextr},
1050 "Number of frames for the extremes output" },
1051 { "-split", FALSE, etBOOL, {&bSplit},
1052 "Split eigenvector projections where time is zero" },
1053 { "-entropy", FALSE, etBOOL, {&bEntropy},
1054 "Compute entropy according to the Quasiharmonic formula or Schlitter's method." },
1055 { "-temp", FALSE, etREAL, {&temp},
1056 "Temperature for entropy calculations" },
1057 { "-nevskip", FALSE, etINT, {&nskip},
1058 "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." }
1060 #define NPA asize(pa)
1066 t_atoms *atoms = NULL;
1067 rvec *xtop, *xref1, *xref2, *xrefp = NULL;
1068 gmx_bool bDMR1, bDMA1, bDMR2, bDMA2;
1069 int nvec1, nvec2, *eignr1 = NULL, *eignr2 = NULL;
1070 rvec *x, *xread, *xav1, *xav2, **eigvec1 = NULL, **eigvec2 = NULL;
1072 real xid, totmass, *sqrtm, *w_rls, t, lambda;
1075 const char *indexfile;
1078 int nout, *iout, noutvec, *outvec, nfit;
1079 atom_id *index, *ifit;
1080 const char *VecFile, *Vec2File, *topfile;
1081 const char *EigFile, *Eig2File;
1082 const char *CompFile, *RmsfFile, *ProjOnVecFile;
1083 const char *TwoDPlotFile, *ThreeDPlotFile;
1084 const char *FilterFile, *ExtremeFile;
1085 const char *OverlapFile, *InpMatFile;
1086 gmx_bool bFit1, bFit2, bM, bIndex, bTPS, bTop, bVec2, bProj;
1087 gmx_bool bFirstToLast, bFirstLastSet, bTraj, bCompare, bPDB3D;
1088 real *eigval1 = NULL, *eigval2 = NULL;
1095 { efTRN, "-v", "eigenvec", ffREAD },
1096 { efTRN, "-v2", "eigenvec2", ffOPTRD },
1097 { efTRX, "-f", NULL, ffOPTRD },
1098 { efTPS, NULL, NULL, ffOPTRD },
1099 { efNDX, NULL, NULL, ffOPTRD },
1100 { efXVG, "-eig", "eigenval", ffOPTRD },
1101 { efXVG, "-eig2", "eigenval2", ffOPTRD },
1102 { efXVG, "-comp", "eigcomp", ffOPTWR },
1103 { efXVG, "-rmsf", "eigrmsf", ffOPTWR },
1104 { efXVG, "-proj", "proj", ffOPTWR },
1105 { efXVG, "-2d", "2dproj", ffOPTWR },
1106 { efSTO, "-3d", "3dproj.pdb", ffOPTWR },
1107 { efTRX, "-filt", "filtered", ffOPTWR },
1108 { efTRX, "-extr", "extreme.pdb", ffOPTWR },
1109 { efXVG, "-over", "overlap", ffOPTWR },
1110 { efXPM, "-inpr", "inprod", ffOPTWR }
1112 #define NFILE asize(fnm)
1114 if (!parse_common_args(&argc, argv,
1115 PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW | PCA_BE_NICE,
1116 NFILE, fnm, NPA, pa, asize(desc), desc, 0, NULL, &oenv))
1121 indexfile = ftp2fn_null(efNDX, NFILE, fnm);
1123 VecFile = opt2fn("-v", NFILE, fnm);
1124 Vec2File = opt2fn_null("-v2", NFILE, fnm);
1125 topfile = ftp2fn(efTPS, NFILE, fnm);
1126 EigFile = opt2fn_null("-eig", NFILE, fnm);
1127 Eig2File = opt2fn_null("-eig2", NFILE, fnm);
1128 CompFile = opt2fn_null("-comp", NFILE, fnm);
1129 RmsfFile = opt2fn_null("-rmsf", NFILE, fnm);
1130 ProjOnVecFile = opt2fn_null("-proj", NFILE, fnm);
1131 TwoDPlotFile = opt2fn_null("-2d", NFILE, fnm);
1132 ThreeDPlotFile = opt2fn_null("-3d", NFILE, fnm);
1133 FilterFile = opt2fn_null("-filt", NFILE, fnm);
1134 ExtremeFile = opt2fn_null("-extr", NFILE, fnm);
1135 OverlapFile = opt2fn_null("-over", NFILE, fnm);
1136 InpMatFile = ftp2fn_null(efXPM, NFILE, fnm);
1138 bTop = fn2bTPX(topfile);
1139 bProj = ProjOnVecFile || TwoDPlotFile || ThreeDPlotFile
1140 || FilterFile || ExtremeFile;
1142 opt2parg_bSet("-first", NPA, pa) && opt2parg_bSet("-last", NPA, pa);
1143 bFirstToLast = CompFile || RmsfFile || ProjOnVecFile || FilterFile ||
1144 OverlapFile || ((ExtremeFile || InpMatFile) && bFirstLastSet);
1145 bVec2 = Vec2File || OverlapFile || InpMatFile;
1146 bM = RmsfFile || bProj;
1147 bTraj = ProjOnVecFile || FilterFile || (ExtremeFile && (max == 0))
1148 || TwoDPlotFile || ThreeDPlotFile;
1149 bIndex = bM || bProj;
1150 bTPS = ftp2bSet(efTPS, NFILE, fnm) || bM || bTraj ||
1151 FilterFile || (bIndex && indexfile);
1152 bCompare = Vec2File || Eig2File;
1153 bPDB3D = fn2ftp(ThreeDPlotFile) == efPDB;
1155 read_eigenvectors(VecFile, &natoms, &bFit1,
1156 &xref1, &bDMR1, &xav1, &bDMA1,
1157 &nvec1, &eignr1, &eigvec1, &eigval1);
1160 /* Overwrite eigenvalues from separate files if the user provides them */
1161 if (EigFile != NULL)
1163 int neig_tmp = read_xvg(EigFile, &xvgdata, &i);
1164 if (neig_tmp != neig1)
1166 fprintf(stderr, "Warning: number of eigenvalues in xvg file (%d) does not mtch trr file (%d)\n", neig1, natoms);
1169 srenew(eigval1, neig1);
1170 for (j = 0; j < neig1; j++)
1172 real tmp = eigval1[j];
1173 eigval1[j] = xvgdata[1][j];
1174 if (debug && (eigval1[j] != tmp))
1176 fprintf(debug, "Replacing eigenvalue %d. From trr: %10g, from xvg: %10g\n",
1177 j, tmp, eigval1[j]);
1180 for (j = 0; j < i; j++)
1185 fprintf(stderr, "Read %d eigenvalues from %s\n", neig1, EigFile);
1192 gmx_fatal(FARGS, "Can not calculate entropies from mass-weighted eigenvalues, redo the analysis without mass-weighting");
1194 calc_entropy_qh(stdout, neig1, eigval1, temp, nskip);
1195 calc_entropy_schlitter(stdout, neig1, nskip, eigval1, temp);
1202 gmx_fatal(FARGS, "Need a second eigenvector file to do this analysis.");
1204 read_eigenvectors(Vec2File, &neig2, &bFit2,
1205 &xref2, &bDMR2, &xav2, &bDMA2, &nvec2, &eignr2, &eigvec2, &eigval2);
1210 gmx_fatal(FARGS, "Dimensions in the eigenvector files don't match");
1214 if (Eig2File != NULL)
1216 neig2 = read_xvg(Eig2File, &xvgdata, &i);
1217 srenew(eigval2, neig2);
1218 for (j = 0; j < neig2; j++)
1220 eigval2[j] = xvgdata[1][j];
1222 for (j = 0; j < i; j++)
1227 fprintf(stderr, "Read %d eigenvalues from %s\n", neig2, Eig2File);
1231 if ((!bFit1 || xref1) && !bDMR1 && !bDMA1)
1235 if ((xref1 == NULL) && (bM || bTraj))
1251 bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm),
1252 title, &top, &ePBC, &xtop, NULL, topbox, bM);
1254 gpbc = gmx_rmpbc_init(&top.idef, ePBC, atoms->nr);
1255 gmx_rmpbc(gpbc, atoms->nr, topbox, xtop);
1256 /* Fitting is only required for the projection */
1261 printf("\nNote: the structure in %s should be the same\n"
1262 " as the one used for the fit in g_covar\n", topfile);
1264 printf("\nSelect the index group that was used for the least squares fit in g_covar\n");
1265 get_index(atoms, indexfile, 1, &nfit, &ifit, &grpname);
1267 snew(w_rls, atoms->nr);
1268 for (i = 0; (i < nfit); i++)
1272 w_rls[ifit[i]] = atoms->atom[ifit[i]].m;
1276 w_rls[ifit[i]] = 1.0;
1280 snew(xrefp, atoms->nr);
1283 /* Safety check between selected fit-group and reference structure read from the eigenvector file */
1286 gmx_fatal(FARGS, "you selected a group with %d elements instead of %d, your selection does not fit the reference structure in the eigenvector file.", nfit, natoms);
1288 for (i = 0; (i < nfit); i++)
1290 copy_rvec(xref1[i], xrefp[ifit[i]]);
1295 /* The top coordinates are the fitting reference */
1296 for (i = 0; (i < nfit); i++)
1298 copy_rvec(xtop[ifit[i]], xrefp[ifit[i]]);
1300 reset_x(nfit, ifit, atoms->nr, NULL, xrefp, w_rls);
1303 gmx_rmpbc_done(gpbc);
1308 printf("\nSelect an index group of %d elements that corresponds to the eigenvectors\n", natoms);
1309 get_index(atoms, indexfile, 1, &i, &index, &grpname);
1312 gmx_fatal(FARGS, "you selected a group with %d elements instead of %d", i, natoms);
1317 snew(sqrtm, natoms);
1320 proj_unit = "u\\S1/2\\Nnm";
1321 for (i = 0; (i < natoms); i++)
1323 sqrtm[i] = sqrt(atoms->atom[index[i]].m);
1329 for (i = 0; (i < natoms); i++)
1339 for (i = 0; (i < natoms); i++)
1341 for (d = 0; (d < DIM); d++)
1343 t += sqr((xav1[i][d]-xav2[i][d])*sqrtm[i]);
1344 totmass += sqr(sqrtm[i]);
1347 fprintf(stdout, "RMSD (without fit) between the two average structures:"
1348 " %.3f (nm)\n\n", sqrt(t/totmass));
1359 /* make an index from first to last */
1360 nout = last-first+1;
1362 for (i = 0; i < nout; i++)
1364 iout[i] = first-1+i;
1367 else if (ThreeDPlotFile)
1369 /* make an index of first+(0,1,2) and last */
1370 nout = bPDB3D ? 4 : 3;
1371 nout = min(last-first+1, nout);
1379 iout[nout-1] = last-1;
1383 /* make an index of first and last */
1392 printf("Select eigenvectors for output, end your selection with 0\n");
1399 srenew(iout, nout+1);
1400 if (1 != scanf("%d", &iout[nout]))
1402 gmx_fatal(FARGS, "Error reading user input");
1406 while (iout[nout] >= 0);
1410 /* make an index of the eigenvectors which are present */
1413 for (i = 0; i < nout; i++)
1416 while ((j < nvec1) && (eignr1[j] != iout[i]))
1420 if ((j < nvec1) && (eignr1[j] == iout[i]))
1422 outvec[noutvec] = j;
1426 fprintf(stderr, "%d eigenvectors selected for output", noutvec);
1429 fprintf(stderr, ":");
1430 for (j = 0; j < noutvec; j++)
1432 fprintf(stderr, " %d", eignr1[outvec[j]]+1);
1435 fprintf(stderr, "\n");
1439 components(CompFile, natoms, eignr1, eigvec1, noutvec, outvec, oenv);
1444 rmsf(RmsfFile, natoms, sqrtm, eignr1, eigvec1, noutvec, outvec, eigval1,
1450 project(bTraj ? opt2fn("-f", NFILE, fnm) : NULL,
1451 bTop ? &top : NULL, ePBC, topbox,
1452 ProjOnVecFile, TwoDPlotFile, ThreeDPlotFile, FilterFile, skip,
1453 ExtremeFile, bFirstLastSet, max, nextr, atoms, natoms, index,
1454 bFit1, xrefp, nfit, ifit, w_rls,
1455 sqrtm, xav1, eignr1, eigvec1, noutvec, outvec, bSplit,
1461 overlap(OverlapFile, natoms,
1462 eigvec1, nvec2, eignr2, eigvec2, noutvec, outvec, oenv);
1467 inprod_matrix(InpMatFile, natoms,
1468 nvec1, eignr1, eigvec1, nvec2, eignr2, eigvec2,
1469 bFirstLastSet, noutvec, outvec);
1474 compare(natoms, nvec1, eigvec1, nvec2, eigvec2, eigval1, neig1, eigval2, neig2);
1478 if (!CompFile && !bProj && !OverlapFile && !InpMatFile &&
1479 !bCompare && !bEntropy)
1481 fprintf(stderr, "\nIf you want some output,"
1482 " set one (or two or ...) of the output file options\n");
1486 view_all(oenv, NFILE, fnm);