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.
43 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/fileio/confio.h"
45 #include "gromacs/fileio/matio.h"
46 #include "gromacs/fileio/pdbio.h"
47 #include "gromacs/fileio/tpxio.h"
48 #include "gromacs/fileio/trxio.h"
49 #include "gromacs/fileio/xvgr.h"
50 #include "gromacs/gmxana/eigio.h"
51 #include "gromacs/gmxana/gmx_ana.h"
52 #include "gromacs/legacyheaders/macros.h"
53 #include "gromacs/legacyheaders/txtdump.h"
54 #include "gromacs/legacyheaders/typedefs.h"
55 #include "gromacs/legacyheaders/viewit.h"
56 #include "gromacs/math/do_fit.h"
57 #include "gromacs/math/units.h"
58 #include "gromacs/math/vec.h"
59 #include "gromacs/pbcutil/rmpbc.h"
60 #include "gromacs/topology/index.h"
61 #include "gromacs/utility/fatalerror.h"
62 #include "gromacs/utility/futil.h"
63 #include "gromacs/utility/smalloc.h"
65 static void calc_entropy_qh(FILE *fp, int n, real eigval[], real temp, int nskip)
68 double hwkT, w, dS, S = 0;
71 hbar = PLANCK1/(2*M_PI);
72 for (i = 0; (i < n-nskip); i++)
76 lambda = eigval[i]*AMU;
77 w = sqrt(BOLTZMANN*temp/lambda)/NANO;
78 hwkT = (hbar*w)/(BOLTZMANN*temp);
79 dS = (hwkT/(exp(hwkT) - 1) - log(1-exp(-hwkT)));
83 fprintf(debug, "i = %5d w = %10g lam = %10g hwkT = %10g dS = %10g\n",
84 i, w, lambda, hwkT, dS);
89 fprintf(stderr, "eigval[%d] = %g\n", i, eigval[i]);
93 fprintf(fp, "The Entropy due to the Quasi Harmonic approximation is %g J/mol K\n",
97 static void calc_entropy_schlitter(FILE *fp, int n, int nskip,
98 real *eigval, real temp)
104 double hbar, kt, kteh, S;
106 hbar = PLANCK1/(2*M_PI);
108 kteh = kt*exp(2.0)/(hbar*hbar)*AMU*(NANO*NANO);
111 fprintf(debug, "n = %d, nskip = %d kteh = %g\n", n, nskip, kteh);
115 for (i = 0; (i < n-nskip); i++)
117 dd = 1+kteh*eigval[i];
122 fprintf(fp, "The Entropy due to the Schlitter formula is %g J/mol K\n", S);
125 const char *proj_unit;
127 static real tick_spacing(real range, int minticks)
136 sp = 0.2*exp(log(10)*ceil(log(range)/log(10)));
137 while (range/sp < minticks-1)
145 static void write_xvgr_graphs(const char *file, int ngraphs, int nsetspergraph,
146 const char *title, const char *subtitle,
147 const char *xlabel, const char **ylabel,
148 int n, real *x, real **y, real ***sy,
149 real scale_x, gmx_bool bZero, gmx_bool bSplit,
150 const output_env_t oenv)
154 real min, max, xsp, ysp;
156 out = gmx_ffopen(file, "w");
157 if (output_env_get_xvg_format(oenv) == exvgXMGRACE)
159 fprintf(out, "@ autoscale onread none\n");
161 for (g = 0; g < ngraphs; g++)
167 for (i = 0; i < n; i++)
183 for (s = 0; s < nsetspergraph; s++)
185 for (i = 0; i < n; i++)
187 if (sy[g][s][i] < min)
191 if (sy[g][s][i] > max)
204 min = min-0.1*(max-min);
206 max = max+0.1*(max-min);
207 xsp = tick_spacing((x[n-1]-x[0])*scale_x, 4);
208 ysp = tick_spacing(max-min, 3);
209 if (output_env_get_print_xvgr_codes(oenv))
211 fprintf(out, "@ with g%d\n@ g%d on\n", g, g);
214 fprintf(out, "@ title \"%s\"\n", title);
217 fprintf(out, "@ subtitle \"%s\"\n", subtitle);
222 fprintf(out, "@ xaxis label \"%s\"\n", xlabel);
226 fprintf(out, "@ xaxis ticklabel off\n");
230 fprintf(out, "@ world xmin %g\n", x[0]*scale_x);
231 fprintf(out, "@ world xmax %g\n", x[n-1]*scale_x);
232 fprintf(out, "@ world ymin %g\n", min);
233 fprintf(out, "@ world ymax %g\n", max);
235 fprintf(out, "@ view xmin 0.15\n");
236 fprintf(out, "@ view xmax 0.85\n");
237 fprintf(out, "@ view ymin %g\n", 0.15+(ngraphs-1-g)*0.7/ngraphs);
238 fprintf(out, "@ view ymax %g\n", 0.15+(ngraphs-g)*0.7/ngraphs);
239 fprintf(out, "@ yaxis label \"%s\"\n", ylabel[g]);
240 fprintf(out, "@ xaxis tick major %g\n", xsp);
241 fprintf(out, "@ xaxis tick minor %g\n", xsp/2);
242 fprintf(out, "@ xaxis ticklabel start type spec\n");
243 fprintf(out, "@ xaxis ticklabel start %g\n", ceil(min/xsp)*xsp);
244 fprintf(out, "@ yaxis tick major %g\n", ysp);
245 fprintf(out, "@ yaxis tick minor %g\n", ysp/2);
246 fprintf(out, "@ yaxis ticklabel start type spec\n");
247 fprintf(out, "@ yaxis ticklabel start %g\n", ceil(min/ysp)*ysp);
248 if ((min < 0) && (max > 0))
250 fprintf(out, "@ zeroxaxis bar on\n");
251 fprintf(out, "@ zeroxaxis bar linestyle 3\n");
254 for (s = 0; s < nsetspergraph; s++)
256 for (i = 0; i < n; i++)
258 if (bSplit && i > 0 && fabs(x[i]) < 1e-5)
260 fprintf(out, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
262 fprintf(out, "%10.4f %10.5f\n",
263 x[i]*scale_x, y ? y[g][i] : sy[g][s][i]);
265 fprintf(out, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
272 compare(int natoms, int n1, rvec **eigvec1, int n2, rvec **eigvec2,
273 real *eigval1, int neig1, real *eigval2, int neig2)
277 double sum1, sum2, trace1, trace2, sab, samsb2, tmp, ip;
281 n = min(n, min(neig1, neig2));
282 fprintf(stdout, "Will compare the covariance matrices using %d dimensions\n", n);
285 for (i = 0; i < n; i++)
292 eigval1[i] = sqrt(eigval1[i]);
295 for (i = n; i < neig1; i++)
297 trace1 += eigval1[i];
300 for (i = 0; i < n; i++)
307 eigval2[i] = sqrt(eigval2[i]);
310 for (i = n; i < neig2; i++)
312 trace2 += eigval2[i];
315 fprintf(stdout, "Trace of the two matrices: %g and %g\n", sum1, sum2);
316 if (neig1 != n || neig2 != n)
318 fprintf(stdout, "this is %d%% and %d%% of the total trace\n",
319 (int)(100*sum1/trace1+0.5), (int)(100*sum2/trace2+0.5));
321 fprintf(stdout, "Square root of the traces: %g and %g\n",
322 sqrt(sum1), sqrt(sum2));
325 for (i = 0; i < n; i++)
328 for (j = 0; j < n; j++)
331 for (k = 0; k < natoms; k++)
333 ip += iprod(eigvec1[i][k], eigvec2[j][k]);
335 tmp += eigval2[j]*ip*ip;
337 sab += eigval1[i]*tmp;
340 samsb2 = sum1+sum2-2*sab;
346 fprintf(stdout, "The overlap of the covariance matrices:\n");
347 fprintf(stdout, " normalized: %.3f\n", 1-sqrt(samsb2/(sum1+sum2)));
348 tmp = 1-sab/sqrt(sum1*sum2);
353 fprintf(stdout, " shape: %.3f\n", 1-sqrt(tmp));
357 static void inprod_matrix(const char *matfile, int natoms,
358 int nvec1, int *eignr1, rvec **eigvec1,
359 int nvec2, int *eignr2, rvec **eigvec2,
360 gmx_bool bSelect, int noutvec, int *outvec)
364 int i, x1, y1, x, y, nlevels;
366 real inp, *t_x, *t_y, max;
374 for (y1 = 0; y1 < nx; y1++)
376 if (outvec[y1] < nvec2)
378 t_y[ny] = eignr2[outvec[y1]]+1;
387 for (y = 0; y < ny; y++)
389 t_y[y] = eignr2[y]+1;
393 fprintf(stderr, "Calculating inner-product matrix of %dx%d eigenvectors\n",
399 for (x1 = 0; x1 < nx; x1++)
410 t_x[x1] = eignr1[x]+1;
411 fprintf(stderr, " %d", eignr1[x]+1);
412 for (y1 = 0; y1 < ny; y1++)
417 while (outvec[y1] >= nvec2)
427 for (i = 0; i < natoms; i++)
429 inp += iprod(eigvec1[x][i], eigvec2[y][i]);
431 mat[x1][y1] = fabs(inp);
432 if (mat[x1][y1] > max)
438 fprintf(stderr, "\n");
439 rlo.r = 1; rlo.g = 1; rlo.b = 1;
440 rhi.r = 0; rhi.g = 0; rhi.b = 0;
442 out = gmx_ffopen(matfile, "w");
443 write_xpm(out, 0, "Eigenvector inner-products", "in.prod.", "run 1", "run 2",
444 nx, ny, t_x, t_y, mat, 0.0, max, rlo, rhi, &nlevels);
448 static void overlap(const char *outfile, int natoms,
450 int nvec2, int *eignr2, rvec **eigvec2,
451 int noutvec, int *outvec,
452 const output_env_t oenv)
458 fprintf(stderr, "Calculating overlap between eigenvectors of set 2 with eigenvectors\n");
459 for (i = 0; i < noutvec; i++)
461 fprintf(stderr, "%d ", outvec[i]+1);
463 fprintf(stderr, "\n");
465 out = xvgropen(outfile, "Subspace overlap",
466 "Eigenvectors of trajectory 2", "Overlap", oenv);
467 if (output_env_get_print_xvgr_codes(oenv))
469 fprintf(out, "@ subtitle \"using %d eigenvectors of trajectory 1\"\n", noutvec);
472 for (x = 0; x < nvec2; x++)
474 for (v = 0; v < noutvec; v++)
478 for (i = 0; i < natoms; i++)
480 inp += iprod(eigvec1[vec][i], eigvec2[x][i]);
484 fprintf(out, "%5d %5.3f\n", eignr2[x]+1, overlap/noutvec);
490 static void project(const char *trajfile, t_topology *top, int ePBC, matrix topbox,
491 const char *projfile, const char *twodplotfile,
492 const char *threedplotfile, const char *filterfile, int skip,
493 const char *extremefile, gmx_bool bExtrAll, real extreme,
494 int nextr, t_atoms *atoms, int natoms, atom_id *index,
495 gmx_bool bFit, rvec *xref, int nfit, atom_id *ifit, real *w_rls,
496 real *sqrtm, rvec *xav,
497 int *eignr, rvec **eigvec,
498 int noutvec, int *outvec, gmx_bool bSplit,
499 const output_env_t oenv)
501 FILE *xvgrout = NULL;
502 int nat, i, j, d, v, vec, nfr, nframes = 0, snew_size, frame;
503 t_trxstatus *out = NULL;
505 int noutvec_extr, imin, imax;
510 real t, inp, **inprod = NULL, min = 0, max = 0;
511 char str[STRLEN], str2[STRLEN], **ylabel, *c;
513 gmx_rmpbc_t gpbc = NULL;
519 noutvec_extr = noutvec;
529 snew(inprod, noutvec+1);
533 fprintf(stderr, "Writing a filtered trajectory to %s using eigenvectors\n",
535 for (i = 0; i < noutvec; i++)
537 fprintf(stderr, "%d ", outvec[i]+1);
539 fprintf(stderr, "\n");
540 out = open_trx(filterfile, "w");
545 nat = read_first_x(oenv, &status, trajfile, &t, &xread, box);
548 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);
554 gpbc = gmx_rmpbc_init(&top->idef, ePBC, nat);
557 for (i = 0; i < nat; i++)
567 gmx_rmpbc(gpbc, nat, box, xread);
569 if (nframes >= snew_size)
572 for (i = 0; i < noutvec+1; i++)
574 srenew(inprod[i], snew_size);
577 inprod[noutvec][nframes] = t;
578 /* calculate x: a fitted struture of the selected atoms */
581 reset_x(nfit, ifit, nat, NULL, xread, w_rls);
582 do_fit(nat, w_rls, xref, xread);
584 for (i = 0; i < natoms; i++)
586 copy_rvec(xread[index[i]], x[i]);
589 for (v = 0; v < noutvec; v++)
592 /* calculate (mass-weighted) projection */
594 for (i = 0; i < natoms; i++)
596 inp += (eigvec[vec][i][0]*(x[i][0]-xav[i][0])+
597 eigvec[vec][i][1]*(x[i][1]-xav[i][1])+
598 eigvec[vec][i][2]*(x[i][2]-xav[i][2]))*sqrtm[i];
600 inprod[v][nframes] = inp;
604 for (i = 0; i < natoms; i++)
606 for (d = 0; d < DIM; d++)
608 /* misuse xread for output */
609 xread[index[i]][d] = xav[i][d];
610 for (v = 0; v < noutvec; v++)
612 xread[index[i]][d] +=
613 inprod[v][nframes]*eigvec[outvec[v]][i][d]/sqrtm[i];
617 write_trx(out, natoms, index, atoms, 0, t, box, xread, NULL, NULL);
623 while (read_next_x(oenv, status, &t, xread, box));
633 snew(xread, atoms->nr);
638 gmx_rmpbc_done(gpbc);
644 snew(ylabel, noutvec);
645 for (v = 0; v < noutvec; v++)
647 sprintf(str, "vec %d", eignr[outvec[v]]+1);
648 ylabel[v] = gmx_strdup(str);
650 sprintf(str, "projection on eigenvectors (%s)", proj_unit);
651 write_xvgr_graphs(projfile, noutvec, 1, str, NULL, output_env_get_xvgr_tlabel(oenv),
652 (const char **)ylabel,
653 nframes, inprod[noutvec], inprod, NULL,
654 output_env_get_time_factor(oenv), FALSE, bSplit, oenv);
659 sprintf(str, "projection on eigenvector %d (%s)",
660 eignr[outvec[0]]+1, proj_unit);
661 sprintf(str2, "projection on eigenvector %d (%s)",
662 eignr[outvec[noutvec-1]]+1, proj_unit);
663 xvgrout = xvgropen(twodplotfile, "2D projection of trajectory", str, str2,
665 for (i = 0; i < nframes; i++)
667 if (bSplit && i > 0 && fabs(inprod[noutvec][i]) < 1e-5)
669 fprintf(xvgrout, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
671 fprintf(xvgrout, "%10.5f %10.5f\n", inprod[0][i], inprod[noutvec-1][i]);
673 gmx_ffclose(xvgrout);
688 gmx_fatal(FARGS, "You have selected less than 3 eigenvectors");
692 bPDB = fn2ftp(threedplotfile) == efPDB;
694 box[XX][XX] = box[YY][YY] = box[ZZ][ZZ] = 1;
696 b4D = bPDB && (noutvec >= 4);
699 fprintf(stderr, "You have selected four or more eigenvectors:\n"
700 "fourth eigenvector will be plotted "
701 "in bfactor field of pdb file\n");
702 sprintf(str, "4D proj. of traj. on eigenv. %d, %d, %d and %d",
703 eignr[outvec[0]]+1, eignr[outvec[1]]+1,
704 eignr[outvec[2]]+1, eignr[outvec[3]]+1);
708 sprintf(str, "3D proj. of traj. on eigenv. %d, %d and %d",
709 eignr[outvec[0]]+1, eignr[outvec[1]]+1, eignr[outvec[2]]+1);
711 init_t_atoms(&atoms, nframes, FALSE);
714 atnm = gmx_strdup("C");
715 resnm = gmx_strdup("PRJ");
719 fact = 10000.0/nframes;
726 for (i = 0; i < nframes; i++)
728 atoms.atomname[i] = &atnm;
729 atoms.atom[i].resind = i;
730 atoms.resinfo[i].name = &resnm;
731 atoms.resinfo[i].nr = ceil(i*fact);
732 atoms.resinfo[i].ic = ' ';
733 x[i][XX] = inprod[0][i];
734 x[i][YY] = inprod[1][i];
735 x[i][ZZ] = inprod[2][i];
741 if ( ( b4D || bSplit ) && bPDB)
743 out = gmx_ffopen(threedplotfile, "w");
744 fprintf(out, "HEADER %s\n", str);
747 fprintf(out, "REMARK %s\n", "fourth dimension plotted as B-factor");
750 for (i = 0; i < atoms.nr; i++)
752 if (j > 0 && bSplit && fabs(inprod[noutvec][i]) < 1e-5)
754 fprintf(out, "TER\n");
757 gmx_fprintf_pdb_atomline(out, epdbATOM, i+1, "C", ' ', "PRJ", ' ', j+1, ' ',
758 10*x[i][XX], 10*x[i][YY], 10*x[i][ZZ], 1.0, 10*b[i], "");
761 fprintf(out, "CONECT%5d%5d\n", i, i+1);
765 fprintf(out, "TER\n");
770 write_sto_conf(threedplotfile, str, &atoms, x, NULL, ePBC, box);
772 free_t_atoms(&atoms, FALSE);
777 snew(pmin, noutvec_extr);
778 snew(pmax, noutvec_extr);
781 fprintf(stderr, "%11s %17s %17s\n", "eigenvector", "Minimum", "Maximum");
783 "%11s %10s %10s %10s %10s\n", "", "value", "frame", "value", "frame");
786 for (v = 0; v < noutvec_extr; v++)
788 for (i = 0; i < nframes; i++)
790 if (inprod[v][i] < inprod[v][imin])
794 if (inprod[v][i] > inprod[v][imax])
799 pmin[v] = inprod[v][imin];
800 pmax[v] = inprod[v][imax];
801 fprintf(stderr, "%7d %10.6f %10d %10.6f %10d\n",
803 pmin[v], imin, pmax[v], imax);
811 /* build format string for filename: */
812 strcpy(str, extremefile); /* copy filename */
813 c = strrchr(str, '.'); /* find where extention begins */
814 strcpy(str2, c); /* get extention */
815 sprintf(c, "%%d%s", str2); /* append '%s' and extention to filename */
816 for (v = 0; v < noutvec_extr; v++)
818 /* make filename using format string */
819 if (noutvec_extr == 1)
821 strcpy(str2, extremefile);
825 sprintf(str2, str, eignr[outvec[v]]+1);
827 fprintf(stderr, "Writing %d frames along eigenvector %d to %s\n",
828 nextr, outvec[v]+1, str2);
829 out = open_trx(str2, "w");
830 for (frame = 0; frame < nextr; frame++)
832 if ((extreme == 0) && (nextr <= 3))
834 for (i = 0; i < natoms; i++)
836 atoms->resinfo[atoms->atom[index[i]].resind].chainid = 'A' + frame;
839 for (i = 0; i < natoms; i++)
841 for (d = 0; d < DIM; d++)
844 (xav[i][d] + (pmin[v]*(nextr-frame-1)+pmax[v]*frame)/(nextr-1)
845 *eigvec[outvec[v]][i][d]/sqrtm[i]);
848 write_trx(out, natoms, index, atoms, 0, frame, topbox, xread, NULL, NULL);
855 fprintf(stderr, "\n");
858 static void components(const char *outfile, int natoms,
859 int *eignr, rvec **eigvec,
860 int noutvec, int *outvec,
861 const output_env_t oenv)
865 char str[STRLEN], **ylabel;
867 fprintf(stderr, "Writing eigenvector components to %s\n", outfile);
869 snew(ylabel, noutvec);
872 for (i = 0; i < natoms; i++)
876 for (g = 0; g < noutvec; g++)
879 sprintf(str, "vec %d", eignr[v]+1);
880 ylabel[g] = gmx_strdup(str);
882 for (s = 0; s < 4; s++)
884 snew(y[g][s], natoms);
886 for (i = 0; i < natoms; i++)
888 y[g][0][i] = norm(eigvec[v][i]);
889 for (s = 0; s < 3; s++)
891 y[g][s+1][i] = eigvec[v][i][s];
895 write_xvgr_graphs(outfile, noutvec, 4, "Eigenvector components",
896 "black: total, red: x, green: y, blue: z",
897 "Atom number", (const char **)ylabel,
898 natoms, x, NULL, y, 1, FALSE, FALSE, oenv);
899 fprintf(stderr, "\n");
902 static void rmsf(const char *outfile, int natoms, real *sqrtm,
903 int *eignr, rvec **eigvec,
904 int noutvec, int *outvec,
905 real *eigval, int neig,
906 const output_env_t oenv)
910 char str[STRLEN], **ylabel;
912 for (i = 0; i < neig; i++)
920 fprintf(stderr, "Writing rmsf to %s\n", outfile);
922 snew(ylabel, noutvec);
925 for (i = 0; i < natoms; i++)
929 for (g = 0; g < noutvec; g++)
932 if (eignr[v] >= neig)
934 gmx_fatal(FARGS, "Selected vector %d is larger than the number of eigenvalues (%d)", eignr[v]+1, neig);
936 sprintf(str, "vec %d", eignr[v]+1);
937 ylabel[g] = gmx_strdup(str);
939 for (i = 0; i < natoms; i++)
941 y[g][i] = sqrt(eigval[eignr[v]]*norm2(eigvec[v][i]))/sqrtm[i];
944 write_xvgr_graphs(outfile, noutvec, 1, "RMS fluctuation (nm) ", NULL,
945 "Atom number", (const char **)ylabel,
946 natoms, x, y, NULL, 1, TRUE, FALSE, oenv);
947 fprintf(stderr, "\n");
950 int gmx_anaeig(int argc, char *argv[])
952 static const char *desc[] = {
953 "[THISMODULE] analyzes eigenvectors. The eigenvectors can be of a",
954 "covariance matrix ([gmx-covar]) or of a Normal Modes analysis",
955 "([gmx-nmeig]).[PAR]",
957 "When a trajectory is projected on eigenvectors, all structures are",
958 "fitted to the structure in the eigenvector file, if present, otherwise",
959 "to the structure in the structure file. When no run input file is",
960 "supplied, periodicity will not be taken into account. Most analyses",
961 "are performed on eigenvectors [TT]-first[tt] to [TT]-last[tt], but when",
962 "[TT]-first[tt] is set to -1 you will be prompted for a selection.[PAR]",
964 "[TT]-comp[tt]: plot the vector components per atom of eigenvectors",
965 "[TT]-first[tt] to [TT]-last[tt].[PAR]",
967 "[TT]-rmsf[tt]: plot the RMS fluctuation per atom of eigenvectors",
968 "[TT]-first[tt] to [TT]-last[tt] (requires [TT]-eig[tt]).[PAR]",
970 "[TT]-proj[tt]: calculate projections of a trajectory on eigenvectors",
971 "[TT]-first[tt] to [TT]-last[tt].",
972 "The projections of a trajectory on the eigenvectors of its",
973 "covariance matrix are called principal components (pc's).",
974 "It is often useful to check the cosine content of the pc's,",
975 "since the pc's of random diffusion are cosines with the number",
976 "of periods equal to half the pc index.",
977 "The cosine content of the pc's can be calculated with the program",
978 "[gmx-analyze].[PAR]",
980 "[TT]-2d[tt]: calculate a 2d projection of a trajectory on eigenvectors",
981 "[TT]-first[tt] and [TT]-last[tt].[PAR]",
983 "[TT]-3d[tt]: calculate a 3d projection of a trajectory on the first",
984 "three selected eigenvectors.[PAR]",
986 "[TT]-filt[tt]: filter the trajectory to show only the motion along",
987 "eigenvectors [TT]-first[tt] to [TT]-last[tt].[PAR]",
989 "[TT]-extr[tt]: calculate the two extreme projections along a trajectory",
990 "on the average structure and interpolate [TT]-nframes[tt] frames",
991 "between them, or set your own extremes with [TT]-max[tt]. The",
992 "eigenvector [TT]-first[tt] will be written unless [TT]-first[tt] and",
993 "[TT]-last[tt] have been set explicitly, in which case all eigenvectors",
994 "will be written to separate files. Chain identifiers will be added",
995 "when writing a [TT].pdb[tt] file with two or three structures (you",
996 "can use [TT]rasmol -nmrpdb[tt] to view such a [TT].pdb[tt] file).[PAR]",
998 " Overlap calculations between covariance analysis:[BR]",
999 " [BB]Note:[bb] the analysis should use the same fitting structure[PAR]",
1001 "[TT]-over[tt]: calculate the subspace overlap of the eigenvectors in",
1002 "file [TT]-v2[tt] with eigenvectors [TT]-first[tt] to [TT]-last[tt]",
1003 "in file [TT]-v[tt].[PAR]",
1005 "[TT]-inpr[tt]: calculate a matrix of inner-products between",
1006 "eigenvectors in files [TT]-v[tt] and [TT]-v2[tt]. All eigenvectors",
1007 "of both files will be used unless [TT]-first[tt] and [TT]-last[tt]",
1008 "have been set explicitly.[PAR]",
1010 "When [TT]-v[tt], [TT]-eig[tt], [TT]-v2[tt] and [TT]-eig2[tt] are given,",
1011 "a single number for the overlap between the covariance matrices is",
1012 "generated. The formulas are:[BR]",
1013 " difference = sqrt(tr((sqrt(M1) - sqrt(M2))^2))[BR]",
1014 "normalized overlap = 1 - difference/sqrt(tr(M1) + tr(M2))[BR]",
1015 " shape overlap = 1 - sqrt(tr((sqrt(M1/tr(M1)) - sqrt(M2/tr(M2)))^2))[BR]",
1016 "where M1 and M2 are the two covariance matrices and tr is the trace",
1017 "of a matrix. The numbers are proportional to the overlap of the square",
1018 "root of the fluctuations. The normalized overlap is the most useful",
1019 "number, it is 1 for identical matrices and 0 when the sampled",
1020 "subspaces are orthogonal.[PAR]",
1021 "When the [TT]-entropy[tt] flag is given an entropy estimate will be",
1022 "computed based on the Quasiharmonic approach and based on",
1023 "Schlitter's formula."
1025 static int first = 1, last = -1, skip = 1, nextr = 2, nskip = 6;
1026 static real max = 0.0, temp = 298.15;
1027 static gmx_bool bSplit = FALSE, bEntropy = FALSE;
1029 { "-first", FALSE, etINT, {&first},
1030 "First eigenvector for analysis (-1 is select)" },
1031 { "-last", FALSE, etINT, {&last},
1032 "Last eigenvector for analysis (-1 is till the last)" },
1033 { "-skip", FALSE, etINT, {&skip},
1034 "Only analyse every nr-th frame" },
1035 { "-max", FALSE, etREAL, {&max},
1036 "Maximum for projection of the eigenvector on the average structure, "
1037 "max=0 gives the extremes" },
1038 { "-nframes", FALSE, etINT, {&nextr},
1039 "Number of frames for the extremes output" },
1040 { "-split", FALSE, etBOOL, {&bSplit},
1041 "Split eigenvector projections where time is zero" },
1042 { "-entropy", FALSE, etBOOL, {&bEntropy},
1043 "Compute entropy according to the Quasiharmonic formula or Schlitter's method." },
1044 { "-temp", FALSE, etREAL, {&temp},
1045 "Temperature for entropy calculations" },
1046 { "-nevskip", FALSE, etINT, {&nskip},
1047 "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." }
1049 #define NPA asize(pa)
1055 t_atoms *atoms = NULL;
1056 rvec *xtop, *xref1, *xref2, *xrefp = NULL;
1057 gmx_bool bDMR1, bDMA1, bDMR2, bDMA2;
1058 int nvec1, nvec2, *eignr1 = NULL, *eignr2 = NULL;
1059 rvec *x, *xread, *xav1, *xav2, **eigvec1 = NULL, **eigvec2 = NULL;
1061 real xid, totmass, *sqrtm, *w_rls, t, lambda;
1064 const char *indexfile;
1067 int nout, *iout, noutvec, *outvec, nfit;
1068 atom_id *index, *ifit;
1069 const char *VecFile, *Vec2File, *topfile;
1070 const char *EigFile, *Eig2File;
1071 const char *CompFile, *RmsfFile, *ProjOnVecFile;
1072 const char *TwoDPlotFile, *ThreeDPlotFile;
1073 const char *FilterFile, *ExtremeFile;
1074 const char *OverlapFile, *InpMatFile;
1075 gmx_bool bFit1, bFit2, bM, bIndex, bTPS, bTop, bVec2, bProj;
1076 gmx_bool bFirstToLast, bFirstLastSet, bTraj, bCompare, bPDB3D;
1077 real *eigval1 = NULL, *eigval2 = NULL;
1084 { efTRN, "-v", "eigenvec", ffREAD },
1085 { efTRN, "-v2", "eigenvec2", ffOPTRD },
1086 { efTRX, "-f", NULL, ffOPTRD },
1087 { efTPS, NULL, NULL, ffOPTRD },
1088 { efNDX, NULL, NULL, ffOPTRD },
1089 { efXVG, "-eig", "eigenval", ffOPTRD },
1090 { efXVG, "-eig2", "eigenval2", ffOPTRD },
1091 { efXVG, "-comp", "eigcomp", ffOPTWR },
1092 { efXVG, "-rmsf", "eigrmsf", ffOPTWR },
1093 { efXVG, "-proj", "proj", ffOPTWR },
1094 { efXVG, "-2d", "2dproj", ffOPTWR },
1095 { efSTO, "-3d", "3dproj.pdb", ffOPTWR },
1096 { efTRX, "-filt", "filtered", ffOPTWR },
1097 { efTRX, "-extr", "extreme.pdb", ffOPTWR },
1098 { efXVG, "-over", "overlap", ffOPTWR },
1099 { efXPM, "-inpr", "inprod", ffOPTWR }
1101 #define NFILE asize(fnm)
1103 if (!parse_common_args(&argc, argv,
1104 PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW,
1105 NFILE, fnm, NPA, pa, asize(desc), desc, 0, NULL, &oenv))
1110 indexfile = ftp2fn_null(efNDX, NFILE, fnm);
1112 VecFile = opt2fn("-v", NFILE, fnm);
1113 Vec2File = opt2fn_null("-v2", NFILE, fnm);
1114 topfile = ftp2fn(efTPS, NFILE, fnm);
1115 EigFile = opt2fn_null("-eig", NFILE, fnm);
1116 Eig2File = opt2fn_null("-eig2", NFILE, fnm);
1117 CompFile = opt2fn_null("-comp", NFILE, fnm);
1118 RmsfFile = opt2fn_null("-rmsf", NFILE, fnm);
1119 ProjOnVecFile = opt2fn_null("-proj", NFILE, fnm);
1120 TwoDPlotFile = opt2fn_null("-2d", NFILE, fnm);
1121 ThreeDPlotFile = opt2fn_null("-3d", NFILE, fnm);
1122 FilterFile = opt2fn_null("-filt", NFILE, fnm);
1123 ExtremeFile = opt2fn_null("-extr", NFILE, fnm);
1124 OverlapFile = opt2fn_null("-over", NFILE, fnm);
1125 InpMatFile = ftp2fn_null(efXPM, NFILE, fnm);
1127 bTop = fn2bTPX(topfile);
1128 bProj = ProjOnVecFile || TwoDPlotFile || ThreeDPlotFile
1129 || FilterFile || ExtremeFile;
1131 opt2parg_bSet("-first", NPA, pa) && opt2parg_bSet("-last", NPA, pa);
1132 bFirstToLast = CompFile || RmsfFile || ProjOnVecFile || FilterFile ||
1133 OverlapFile || ((ExtremeFile || InpMatFile) && bFirstLastSet);
1134 bVec2 = Vec2File || OverlapFile || InpMatFile;
1135 bM = RmsfFile || bProj;
1136 bTraj = ProjOnVecFile || FilterFile || (ExtremeFile && (max == 0))
1137 || TwoDPlotFile || ThreeDPlotFile;
1138 bIndex = bM || bProj;
1139 bTPS = ftp2bSet(efTPS, NFILE, fnm) || bM || bTraj ||
1140 FilterFile || (bIndex && indexfile);
1141 bCompare = Vec2File || Eig2File;
1142 bPDB3D = fn2ftp(ThreeDPlotFile) == efPDB;
1144 read_eigenvectors(VecFile, &natoms, &bFit1,
1145 &xref1, &bDMR1, &xav1, &bDMA1,
1146 &nvec1, &eignr1, &eigvec1, &eigval1);
1149 /* Overwrite eigenvalues from separate files if the user provides them */
1150 if (EigFile != NULL)
1152 int neig_tmp = read_xvg(EigFile, &xvgdata, &i);
1153 if (neig_tmp != neig1)
1155 fprintf(stderr, "Warning: number of eigenvalues in xvg file (%d) does not mtch trr file (%d)\n", neig1, natoms);
1158 srenew(eigval1, neig1);
1159 for (j = 0; j < neig1; j++)
1161 real tmp = eigval1[j];
1162 eigval1[j] = xvgdata[1][j];
1163 if (debug && (eigval1[j] != tmp))
1165 fprintf(debug, "Replacing eigenvalue %d. From trr: %10g, from xvg: %10g\n",
1166 j, tmp, eigval1[j]);
1169 for (j = 0; j < i; j++)
1174 fprintf(stderr, "Read %d eigenvalues from %s\n", neig1, EigFile);
1181 gmx_fatal(FARGS, "Can not calculate entropies from mass-weighted eigenvalues, redo the analysis without mass-weighting");
1183 calc_entropy_qh(stdout, neig1, eigval1, temp, nskip);
1184 calc_entropy_schlitter(stdout, neig1, nskip, eigval1, temp);
1191 gmx_fatal(FARGS, "Need a second eigenvector file to do this analysis.");
1193 read_eigenvectors(Vec2File, &neig2, &bFit2,
1194 &xref2, &bDMR2, &xav2, &bDMA2, &nvec2, &eignr2, &eigvec2, &eigval2);
1199 gmx_fatal(FARGS, "Dimensions in the eigenvector files don't match");
1203 if (Eig2File != NULL)
1205 neig2 = read_xvg(Eig2File, &xvgdata, &i);
1206 srenew(eigval2, neig2);
1207 for (j = 0; j < neig2; j++)
1209 eigval2[j] = xvgdata[1][j];
1211 for (j = 0; j < i; j++)
1216 fprintf(stderr, "Read %d eigenvalues from %s\n", neig2, Eig2File);
1220 if ((!bFit1 || xref1) && !bDMR1 && !bDMA1)
1224 if ((xref1 == NULL) && (bM || bTraj))
1240 bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm),
1241 title, &top, &ePBC, &xtop, NULL, topbox, bM);
1243 gpbc = gmx_rmpbc_init(&top.idef, ePBC, atoms->nr);
1244 gmx_rmpbc(gpbc, atoms->nr, topbox, xtop);
1245 /* Fitting is only required for the projection */
1250 printf("\nNote: the structure in %s should be the same\n"
1251 " as the one used for the fit in g_covar\n", topfile);
1253 printf("\nSelect the index group that was used for the least squares fit in g_covar\n");
1254 get_index(atoms, indexfile, 1, &nfit, &ifit, &grpname);
1256 snew(w_rls, atoms->nr);
1257 for (i = 0; (i < nfit); i++)
1261 w_rls[ifit[i]] = atoms->atom[ifit[i]].m;
1265 w_rls[ifit[i]] = 1.0;
1269 snew(xrefp, atoms->nr);
1272 /* Safety check between selected fit-group and reference structure read from the eigenvector file */
1275 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);
1277 for (i = 0; (i < nfit); i++)
1279 copy_rvec(xref1[i], xrefp[ifit[i]]);
1284 /* The top coordinates are the fitting reference */
1285 for (i = 0; (i < nfit); i++)
1287 copy_rvec(xtop[ifit[i]], xrefp[ifit[i]]);
1289 reset_x(nfit, ifit, atoms->nr, NULL, xrefp, w_rls);
1292 gmx_rmpbc_done(gpbc);
1297 printf("\nSelect an index group of %d elements that corresponds to the eigenvectors\n", natoms);
1298 get_index(atoms, indexfile, 1, &i, &index, &grpname);
1301 gmx_fatal(FARGS, "you selected a group with %d elements instead of %d", i, natoms);
1306 snew(sqrtm, natoms);
1309 proj_unit = "u\\S1/2\\Nnm";
1310 for (i = 0; (i < natoms); i++)
1312 sqrtm[i] = sqrt(atoms->atom[index[i]].m);
1318 for (i = 0; (i < natoms); i++)
1328 for (i = 0; (i < natoms); i++)
1330 for (d = 0; (d < DIM); d++)
1332 t += sqr((xav1[i][d]-xav2[i][d])*sqrtm[i]);
1333 totmass += sqr(sqrtm[i]);
1336 fprintf(stdout, "RMSD (without fit) between the two average structures:"
1337 " %.3f (nm)\n\n", sqrt(t/totmass));
1348 /* make an index from first to last */
1349 nout = last-first+1;
1351 for (i = 0; i < nout; i++)
1353 iout[i] = first-1+i;
1356 else if (ThreeDPlotFile)
1358 /* make an index of first+(0,1,2) and last */
1359 nout = bPDB3D ? 4 : 3;
1360 nout = min(last-first+1, nout);
1368 iout[nout-1] = last-1;
1372 /* make an index of first and last */
1381 printf("Select eigenvectors for output, end your selection with 0\n");
1388 srenew(iout, nout+1);
1389 if (1 != scanf("%d", &iout[nout]))
1391 gmx_fatal(FARGS, "Error reading user input");
1395 while (iout[nout] >= 0);
1399 /* make an index of the eigenvectors which are present */
1402 for (i = 0; i < nout; i++)
1405 while ((j < nvec1) && (eignr1[j] != iout[i]))
1409 if ((j < nvec1) && (eignr1[j] == iout[i]))
1411 outvec[noutvec] = j;
1415 fprintf(stderr, "%d eigenvectors selected for output", noutvec);
1418 fprintf(stderr, ":");
1419 for (j = 0; j < noutvec; j++)
1421 fprintf(stderr, " %d", eignr1[outvec[j]]+1);
1424 fprintf(stderr, "\n");
1428 components(CompFile, natoms, eignr1, eigvec1, noutvec, outvec, oenv);
1433 rmsf(RmsfFile, natoms, sqrtm, eignr1, eigvec1, noutvec, outvec, eigval1,
1439 project(bTraj ? opt2fn("-f", NFILE, fnm) : NULL,
1440 bTop ? &top : NULL, ePBC, topbox,
1441 ProjOnVecFile, TwoDPlotFile, ThreeDPlotFile, FilterFile, skip,
1442 ExtremeFile, bFirstLastSet, max, nextr, atoms, natoms, index,
1443 bFit1, xrefp, nfit, ifit, w_rls,
1444 sqrtm, xav1, eignr1, eigvec1, noutvec, outvec, bSplit,
1450 overlap(OverlapFile, natoms,
1451 eigvec1, nvec2, eignr2, eigvec2, noutvec, outvec, oenv);
1456 inprod_matrix(InpMatFile, natoms,
1457 nvec1, eignr1, eigvec1, nvec2, eignr2, eigvec2,
1458 bFirstLastSet, noutvec, outvec);
1463 compare(natoms, nvec1, eigvec1, nvec2, eigvec2, eigval1, neig1, eigval2, neig2);
1467 if (!CompFile && !bProj && !OverlapFile && !InpMatFile &&
1468 !bCompare && !bEntropy)
1470 fprintf(stderr, "\nIf you want some output,"
1471 " set one (or two or ...) of the output file options\n");
1475 view_all(oenv, NFILE, fnm);