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"
50 #include "gromacs/math/vec.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"
60 #include "gromacs/fileio/xvgr.h"
68 #include "gromacs/math/do_fit.h"
70 static void calc_entropy_qh(FILE *fp, int n, real eigval[], real temp, int nskip)
73 double hwkT, w, dS, S = 0;
76 hbar = PLANCK1/(2*M_PI);
77 for (i = 0; (i < n-nskip); i++)
81 lambda = eigval[i]*AMU;
82 w = sqrt(BOLTZMANN*temp/lambda)/NANO;
83 hwkT = (hbar*w)/(BOLTZMANN*temp);
84 dS = (hwkT/(exp(hwkT) - 1) - log(1-exp(-hwkT)));
88 fprintf(debug, "i = %5d w = %10g lam = %10g hwkT = %10g dS = %10g\n",
89 i, w, lambda, hwkT, dS);
94 fprintf(stderr, "eigval[%d] = %g\n", i, eigval[i]);
98 fprintf(fp, "The Entropy due to the Quasi Harmonic approximation is %g J/mol K\n",
102 static void calc_entropy_schlitter(FILE *fp, int n, int nskip,
103 real *eigval, real temp)
109 double hbar, kt, kteh, S;
111 hbar = PLANCK1/(2*M_PI);
113 kteh = kt*exp(2.0)/(hbar*hbar)*AMU*(NANO*NANO);
116 fprintf(debug, "n = %d, nskip = %d kteh = %g\n", n, nskip, kteh);
120 for (i = 0; (i < n-nskip); i++)
122 dd = 1+kteh*eigval[i];
127 fprintf(fp, "The Entropy due to the Schlitter formula is %g J/mol K\n", S);
130 const char *proj_unit;
132 static real tick_spacing(real range, int minticks)
141 sp = 0.2*exp(log(10)*ceil(log(range)/log(10)));
142 while (range/sp < minticks-1)
150 static void write_xvgr_graphs(const char *file, int ngraphs, int nsetspergraph,
151 const char *title, const char *subtitle,
152 const char *xlabel, const char **ylabel,
153 int n, real *x, real **y, real ***sy,
154 real scale_x, gmx_bool bZero, gmx_bool bSplit,
155 const output_env_t oenv)
159 real min, max, xsp, ysp;
161 out = gmx_ffopen(file, "w");
162 if (output_env_get_xvg_format(oenv) == exvgXMGRACE)
164 fprintf(out, "@ autoscale onread none\n");
166 for (g = 0; g < ngraphs; g++)
172 for (i = 0; i < n; i++)
188 for (s = 0; s < nsetspergraph; s++)
190 for (i = 0; i < n; i++)
192 if (sy[g][s][i] < min)
196 if (sy[g][s][i] > max)
209 min = min-0.1*(max-min);
211 max = max+0.1*(max-min);
212 xsp = tick_spacing((x[n-1]-x[0])*scale_x, 4);
213 ysp = tick_spacing(max-min, 3);
214 if (output_env_get_print_xvgr_codes(oenv))
216 fprintf(out, "@ with g%d\n@ g%d on\n", g, g);
219 fprintf(out, "@ title \"%s\"\n", title);
222 fprintf(out, "@ subtitle \"%s\"\n", subtitle);
227 fprintf(out, "@ xaxis label \"%s\"\n", xlabel);
231 fprintf(out, "@ xaxis ticklabel off\n");
235 fprintf(out, "@ world xmin %g\n", x[0]*scale_x);
236 fprintf(out, "@ world xmax %g\n", x[n-1]*scale_x);
237 fprintf(out, "@ world ymin %g\n", min);
238 fprintf(out, "@ world ymax %g\n", max);
240 fprintf(out, "@ view xmin 0.15\n");
241 fprintf(out, "@ view xmax 0.85\n");
242 fprintf(out, "@ view ymin %g\n", 0.15+(ngraphs-1-g)*0.7/ngraphs);
243 fprintf(out, "@ view ymax %g\n", 0.15+(ngraphs-g)*0.7/ngraphs);
244 fprintf(out, "@ yaxis label \"%s\"\n", ylabel[g]);
245 fprintf(out, "@ xaxis tick major %g\n", xsp);
246 fprintf(out, "@ xaxis tick minor %g\n", xsp/2);
247 fprintf(out, "@ xaxis ticklabel start type spec\n");
248 fprintf(out, "@ xaxis ticklabel start %g\n", ceil(min/xsp)*xsp);
249 fprintf(out, "@ yaxis tick major %g\n", ysp);
250 fprintf(out, "@ yaxis tick minor %g\n", ysp/2);
251 fprintf(out, "@ yaxis ticklabel start type spec\n");
252 fprintf(out, "@ yaxis ticklabel start %g\n", ceil(min/ysp)*ysp);
253 if ((min < 0) && (max > 0))
255 fprintf(out, "@ zeroxaxis bar on\n");
256 fprintf(out, "@ zeroxaxis bar linestyle 3\n");
259 for (s = 0; s < nsetspergraph; s++)
261 for (i = 0; i < n; i++)
263 if (bSplit && i > 0 && fabs(x[i]) < 1e-5)
265 if (output_env_get_print_xvgr_codes(oenv))
270 fprintf(out, "%10.4f %10.5f\n",
271 x[i]*scale_x, y ? y[g][i] : sy[g][s][i]);
273 if (output_env_get_print_xvgr_codes(oenv))
283 compare(int natoms, int n1, rvec **eigvec1, int n2, rvec **eigvec2,
284 real *eigval1, int neig1, real *eigval2, int neig2)
288 double sum1, sum2, trace1, trace2, sab, samsb2, tmp, ip;
292 n = min(n, min(neig1, neig2));
293 fprintf(stdout, "Will compare the covariance matrices using %d dimensions\n", n);
296 for (i = 0; i < n; i++)
303 eigval1[i] = sqrt(eigval1[i]);
306 for (i = n; i < neig1; i++)
308 trace1 += eigval1[i];
311 for (i = 0; i < n; i++)
318 eigval2[i] = sqrt(eigval2[i]);
321 for (i = n; i < neig2; i++)
323 trace2 += eigval2[i];
326 fprintf(stdout, "Trace of the two matrices: %g and %g\n", sum1, sum2);
327 if (neig1 != n || neig2 != n)
329 fprintf(stdout, "this is %d%% and %d%% of the total trace\n",
330 (int)(100*sum1/trace1+0.5), (int)(100*sum2/trace2+0.5));
332 fprintf(stdout, "Square root of the traces: %g and %g\n",
333 sqrt(sum1), sqrt(sum2));
336 for (i = 0; i < n; i++)
339 for (j = 0; j < n; j++)
342 for (k = 0; k < natoms; k++)
344 ip += iprod(eigvec1[i][k], eigvec2[j][k]);
346 tmp += eigval2[j]*ip*ip;
348 sab += eigval1[i]*tmp;
351 samsb2 = sum1+sum2-2*sab;
357 fprintf(stdout, "The overlap of the covariance matrices:\n");
358 fprintf(stdout, " normalized: %.3f\n", 1-sqrt(samsb2/(sum1+sum2)));
359 tmp = 1-sab/sqrt(sum1*sum2);
364 fprintf(stdout, " shape: %.3f\n", 1-sqrt(tmp));
368 static void inprod_matrix(const char *matfile, int natoms,
369 int nvec1, int *eignr1, rvec **eigvec1,
370 int nvec2, int *eignr2, rvec **eigvec2,
371 gmx_bool bSelect, int noutvec, int *outvec)
375 int i, x1, y1, x, y, nlevels;
377 real inp, *t_x, *t_y, max;
385 for (y1 = 0; y1 < nx; y1++)
387 if (outvec[y1] < nvec2)
389 t_y[ny] = eignr2[outvec[y1]]+1;
398 for (y = 0; y < ny; y++)
400 t_y[y] = eignr2[y]+1;
404 fprintf(stderr, "Calculating inner-product matrix of %dx%d eigenvectors\n",
410 for (x1 = 0; x1 < nx; x1++)
421 t_x[x1] = eignr1[x]+1;
422 fprintf(stderr, " %d", eignr1[x]+1);
423 for (y1 = 0; y1 < ny; y1++)
428 while (outvec[y1] >= nvec2)
438 for (i = 0; i < natoms; i++)
440 inp += iprod(eigvec1[x][i], eigvec2[y][i]);
442 mat[x1][y1] = fabs(inp);
443 if (mat[x1][y1] > max)
449 fprintf(stderr, "\n");
450 rlo.r = 1; rlo.g = 1; rlo.b = 1;
451 rhi.r = 0; rhi.g = 0; rhi.b = 0;
453 out = gmx_ffopen(matfile, "w");
454 write_xpm(out, 0, "Eigenvector inner-products", "in.prod.", "run 1", "run 2",
455 nx, ny, t_x, t_y, mat, 0.0, max, rlo, rhi, &nlevels);
459 static void overlap(const char *outfile, int natoms,
461 int nvec2, int *eignr2, rvec **eigvec2,
462 int noutvec, int *outvec,
463 const output_env_t oenv)
469 fprintf(stderr, "Calculating overlap between eigenvectors of set 2 with eigenvectors\n");
470 for (i = 0; i < noutvec; i++)
472 fprintf(stderr, "%d ", outvec[i]+1);
474 fprintf(stderr, "\n");
476 out = xvgropen(outfile, "Subspace overlap",
477 "Eigenvectors of trajectory 2", "Overlap", oenv);
478 fprintf(out, "@ subtitle \"using %d eigenvectors of trajectory 1\"\n",
481 for (x = 0; x < nvec2; x++)
483 for (v = 0; v < noutvec; v++)
487 for (i = 0; i < natoms; i++)
489 inp += iprod(eigvec1[vec][i], eigvec2[x][i]);
493 fprintf(out, "%5d %5.3f\n", eignr2[x]+1, overlap/noutvec);
499 static void project(const char *trajfile, t_topology *top, int ePBC, matrix topbox,
500 const char *projfile, const char *twodplotfile,
501 const char *threedplotfile, const char *filterfile, int skip,
502 const char *extremefile, gmx_bool bExtrAll, real extreme,
503 int nextr, t_atoms *atoms, int natoms, atom_id *index,
504 gmx_bool bFit, rvec *xref, int nfit, atom_id *ifit, real *w_rls,
505 real *sqrtm, rvec *xav,
506 int *eignr, rvec **eigvec,
507 int noutvec, int *outvec, gmx_bool bSplit,
508 const output_env_t oenv)
510 FILE *xvgrout = NULL;
511 int nat, i, j, d, v, vec, nfr, nframes = 0, snew_size, frame;
512 t_trxstatus *out = NULL;
514 int noutvec_extr, imin, imax;
519 real t, inp, **inprod = NULL, min = 0, max = 0;
520 char str[STRLEN], str2[STRLEN], **ylabel, *c;
522 gmx_rmpbc_t gpbc = NULL;
528 noutvec_extr = noutvec;
538 snew(inprod, noutvec+1);
542 fprintf(stderr, "Writing a filtered trajectory to %s using eigenvectors\n",
544 for (i = 0; i < noutvec; i++)
546 fprintf(stderr, "%d ", outvec[i]+1);
548 fprintf(stderr, "\n");
549 out = open_trx(filterfile, "w");
554 nat = read_first_x(oenv, &status, trajfile, &t, &xread, box);
557 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);
563 gpbc = gmx_rmpbc_init(&top->idef, ePBC, nat);
566 for (i = 0; i < nat; i++)
576 gmx_rmpbc(gpbc, nat, box, xread);
578 if (nframes >= snew_size)
581 for (i = 0; i < noutvec+1; i++)
583 srenew(inprod[i], snew_size);
586 inprod[noutvec][nframes] = t;
587 /* calculate x: a fitted struture of the selected atoms */
590 reset_x(nfit, ifit, nat, NULL, xread, w_rls);
591 do_fit(nat, w_rls, xref, xread);
593 for (i = 0; i < natoms; i++)
595 copy_rvec(xread[index[i]], x[i]);
598 for (v = 0; v < noutvec; v++)
601 /* calculate (mass-weighted) projection */
603 for (i = 0; i < natoms; i++)
605 inp += (eigvec[vec][i][0]*(x[i][0]-xav[i][0])+
606 eigvec[vec][i][1]*(x[i][1]-xav[i][1])+
607 eigvec[vec][i][2]*(x[i][2]-xav[i][2]))*sqrtm[i];
609 inprod[v][nframes] = inp;
613 for (i = 0; i < natoms; i++)
615 for (d = 0; d < DIM; d++)
617 /* misuse xread for output */
618 xread[index[i]][d] = xav[i][d];
619 for (v = 0; v < noutvec; v++)
621 xread[index[i]][d] +=
622 inprod[v][nframes]*eigvec[outvec[v]][i][d]/sqrtm[i];
626 write_trx(out, natoms, index, atoms, 0, t, box, xread, NULL, NULL);
632 while (read_next_x(oenv, status, &t, xread, box));
642 snew(xread, atoms->nr);
647 gmx_rmpbc_done(gpbc);
653 snew(ylabel, noutvec);
654 for (v = 0; v < noutvec; v++)
656 sprintf(str, "vec %d", eignr[outvec[v]]+1);
657 ylabel[v] = strdup(str);
659 sprintf(str, "projection on eigenvectors (%s)", proj_unit);
660 write_xvgr_graphs(projfile, noutvec, 1, str, NULL, output_env_get_xvgr_tlabel(oenv),
661 (const char **)ylabel,
662 nframes, inprod[noutvec], inprod, NULL,
663 output_env_get_time_factor(oenv), FALSE, bSplit, oenv);
668 sprintf(str, "projection on eigenvector %d (%s)",
669 eignr[outvec[0]]+1, proj_unit);
670 sprintf(str2, "projection on eigenvector %d (%s)",
671 eignr[outvec[noutvec-1]]+1, proj_unit);
672 xvgrout = xvgropen(twodplotfile, "2D projection of trajectory", str, str2,
674 for (i = 0; i < nframes; i++)
676 if (bSplit && i > 0 && fabs(inprod[noutvec][i]) < 1e-5)
678 fprintf(xvgrout, "&\n");
680 fprintf(xvgrout, "%10.5f %10.5f\n", inprod[0][i], inprod[noutvec-1][i]);
682 gmx_ffclose(xvgrout);
691 char *resnm, *atnm, pdbform[STRLEN];
697 gmx_fatal(FARGS, "You have selected less than 3 eigenvectors");
701 bPDB = fn2ftp(threedplotfile) == efPDB;
703 box[XX][XX] = box[YY][YY] = box[ZZ][ZZ] = 1;
705 b4D = bPDB && (noutvec >= 4);
708 fprintf(stderr, "You have selected four or more eigenvectors:\n"
709 "fourth eigenvector will be plotted "
710 "in bfactor field of pdb file\n");
711 sprintf(str, "4D proj. of traj. on eigenv. %d, %d, %d and %d",
712 eignr[outvec[0]]+1, eignr[outvec[1]]+1,
713 eignr[outvec[2]]+1, eignr[outvec[3]]+1);
717 sprintf(str, "3D proj. of traj. on eigenv. %d, %d and %d",
718 eignr[outvec[0]]+1, eignr[outvec[1]]+1, eignr[outvec[2]]+1);
720 init_t_atoms(&atoms, nframes, FALSE);
724 resnm = strdup("PRJ");
728 fact = 10000.0/nframes;
735 for (i = 0; i < nframes; i++)
737 atoms.atomname[i] = &atnm;
738 atoms.atom[i].resind = i;
739 atoms.resinfo[i].name = &resnm;
740 atoms.resinfo[i].nr = ceil(i*fact);
741 atoms.resinfo[i].ic = ' ';
742 x[i][XX] = inprod[0][i];
743 x[i][YY] = inprod[1][i];
744 x[i][ZZ] = inprod[2][i];
750 if ( ( b4D || bSplit ) && bPDB)
752 strcpy(pdbform, get_pdbformat());
753 strcat(pdbform, "%8.4f%8.4f\n");
755 out = gmx_ffopen(threedplotfile, "w");
756 fprintf(out, "HEADER %s\n", str);
759 fprintf(out, "REMARK %s\n", "fourth dimension plotted as B-factor");
762 for (i = 0; i < atoms.nr; i++)
764 if (j > 0 && bSplit && fabs(inprod[noutvec][i]) < 1e-5)
766 fprintf(out, "TER\n");
769 fprintf(out, pdbform, "ATOM", i+1, "C", "PRJ", ' ', j+1,
770 10*x[i][XX], 10*x[i][YY], 10*x[i][ZZ], 1.0, 10*b[i]);
773 fprintf(out, "CONECT%5d%5d\n", i, i+1);
777 fprintf(out, "TER\n");
782 write_sto_conf(threedplotfile, str, &atoms, x, NULL, ePBC, box);
784 free_t_atoms(&atoms, FALSE);
789 snew(pmin, noutvec_extr);
790 snew(pmax, noutvec_extr);
793 fprintf(stderr, "%11s %17s %17s\n", "eigenvector", "Minimum", "Maximum");
795 "%11s %10s %10s %10s %10s\n", "", "value", "frame", "value", "frame");
798 for (v = 0; v < noutvec_extr; v++)
800 for (i = 0; i < nframes; i++)
802 if (inprod[v][i] < inprod[v][imin])
806 if (inprod[v][i] > inprod[v][imax])
811 pmin[v] = inprod[v][imin];
812 pmax[v] = inprod[v][imax];
813 fprintf(stderr, "%7d %10.6f %10d %10.6f %10d\n",
815 pmin[v], imin, pmax[v], imax);
823 /* build format string for filename: */
824 strcpy(str, extremefile); /* copy filename */
825 c = strrchr(str, '.'); /* find where extention begins */
826 strcpy(str2, c); /* get extention */
827 sprintf(c, "%%d%s", str2); /* append '%s' and extention to filename */
828 for (v = 0; v < noutvec_extr; v++)
830 /* make filename using format string */
831 if (noutvec_extr == 1)
833 strcpy(str2, extremefile);
837 sprintf(str2, str, eignr[outvec[v]]+1);
839 fprintf(stderr, "Writing %d frames along eigenvector %d to %s\n",
840 nextr, outvec[v]+1, str2);
841 out = open_trx(str2, "w");
842 for (frame = 0; frame < nextr; frame++)
844 if ((extreme == 0) && (nextr <= 3))
846 for (i = 0; i < natoms; i++)
848 atoms->resinfo[atoms->atom[index[i]].resind].chainid = 'A' + frame;
851 for (i = 0; i < natoms; i++)
853 for (d = 0; d < DIM; d++)
856 (xav[i][d] + (pmin[v]*(nextr-frame-1)+pmax[v]*frame)/(nextr-1)
857 *eigvec[outvec[v]][i][d]/sqrtm[i]);
860 write_trx(out, natoms, index, atoms, 0, frame, topbox, xread, NULL, NULL);
867 fprintf(stderr, "\n");
870 static void components(const char *outfile, int natoms,
871 int *eignr, rvec **eigvec,
872 int noutvec, int *outvec,
873 const output_env_t oenv)
877 char str[STRLEN], **ylabel;
879 fprintf(stderr, "Writing eigenvector components to %s\n", outfile);
881 snew(ylabel, noutvec);
884 for (i = 0; i < natoms; i++)
888 for (g = 0; g < noutvec; g++)
891 sprintf(str, "vec %d", eignr[v]+1);
892 ylabel[g] = strdup(str);
894 for (s = 0; s < 4; s++)
896 snew(y[g][s], natoms);
898 for (i = 0; i < natoms; i++)
900 y[g][0][i] = norm(eigvec[v][i]);
901 for (s = 0; s < 3; s++)
903 y[g][s+1][i] = eigvec[v][i][s];
907 write_xvgr_graphs(outfile, noutvec, 4, "Eigenvector components",
908 "black: total, red: x, green: y, blue: z",
909 "Atom number", (const char **)ylabel,
910 natoms, x, NULL, y, 1, FALSE, FALSE, oenv);
911 fprintf(stderr, "\n");
914 static void rmsf(const char *outfile, int natoms, real *sqrtm,
915 int *eignr, rvec **eigvec,
916 int noutvec, int *outvec,
917 real *eigval, int neig,
918 const output_env_t oenv)
922 char str[STRLEN], **ylabel;
924 for (i = 0; i < neig; i++)
932 fprintf(stderr, "Writing rmsf to %s\n", outfile);
934 snew(ylabel, noutvec);
937 for (i = 0; i < natoms; i++)
941 for (g = 0; g < noutvec; g++)
944 if (eignr[v] >= neig)
946 gmx_fatal(FARGS, "Selected vector %d is larger than the number of eigenvalues (%d)", eignr[v]+1, neig);
948 sprintf(str, "vec %d", eignr[v]+1);
949 ylabel[g] = strdup(str);
951 for (i = 0; i < natoms; i++)
953 y[g][i] = sqrt(eigval[eignr[v]]*norm2(eigvec[v][i]))/sqrtm[i];
956 write_xvgr_graphs(outfile, noutvec, 1, "RMS fluctuation (nm) ", NULL,
957 "Atom number", (const char **)ylabel,
958 natoms, x, y, NULL, 1, TRUE, FALSE, oenv);
959 fprintf(stderr, "\n");
962 int gmx_anaeig(int argc, char *argv[])
964 static const char *desc[] = {
965 "[THISMODULE] analyzes eigenvectors. The eigenvectors can be of a",
966 "covariance matrix ([gmx-covar]) or of a Normal Modes analysis",
967 "([gmx-nmeig]).[PAR]",
969 "When a trajectory is projected on eigenvectors, all structures are",
970 "fitted to the structure in the eigenvector file, if present, otherwise",
971 "to the structure in the structure file. When no run input file is",
972 "supplied, periodicity will not be taken into account. Most analyses",
973 "are performed on eigenvectors [TT]-first[tt] to [TT]-last[tt], but when",
974 "[TT]-first[tt] is set to -1 you will be prompted for a selection.[PAR]",
976 "[TT]-comp[tt]: plot the vector components per atom of eigenvectors",
977 "[TT]-first[tt] to [TT]-last[tt].[PAR]",
979 "[TT]-rmsf[tt]: plot the RMS fluctuation per atom of eigenvectors",
980 "[TT]-first[tt] to [TT]-last[tt] (requires [TT]-eig[tt]).[PAR]",
982 "[TT]-proj[tt]: calculate projections of a trajectory on eigenvectors",
983 "[TT]-first[tt] to [TT]-last[tt].",
984 "The projections of a trajectory on the eigenvectors of its",
985 "covariance matrix are called principal components (pc's).",
986 "It is often useful to check the cosine content of the pc's,",
987 "since the pc's of random diffusion are cosines with the number",
988 "of periods equal to half the pc index.",
989 "The cosine content of the pc's can be calculated with the program",
990 "[gmx-analyze].[PAR]",
992 "[TT]-2d[tt]: calculate a 2d projection of a trajectory on eigenvectors",
993 "[TT]-first[tt] and [TT]-last[tt].[PAR]",
995 "[TT]-3d[tt]: calculate a 3d projection of a trajectory on the first",
996 "three selected eigenvectors.[PAR]",
998 "[TT]-filt[tt]: filter the trajectory to show only the motion along",
999 "eigenvectors [TT]-first[tt] to [TT]-last[tt].[PAR]",
1001 "[TT]-extr[tt]: calculate the two extreme projections along a trajectory",
1002 "on the average structure and interpolate [TT]-nframes[tt] frames",
1003 "between them, or set your own extremes with [TT]-max[tt]. The",
1004 "eigenvector [TT]-first[tt] will be written unless [TT]-first[tt] and",
1005 "[TT]-last[tt] have been set explicitly, in which case all eigenvectors",
1006 "will be written to separate files. Chain identifiers will be added",
1007 "when writing a [TT].pdb[tt] file with two or three structures (you",
1008 "can use [TT]rasmol -nmrpdb[tt] to view such a [TT].pdb[tt] file).[PAR]",
1010 " Overlap calculations between covariance analysis:[BR]",
1011 " [BB]Note:[bb] the analysis should use the same fitting structure[PAR]",
1013 "[TT]-over[tt]: calculate the subspace overlap of the eigenvectors in",
1014 "file [TT]-v2[tt] with eigenvectors [TT]-first[tt] to [TT]-last[tt]",
1015 "in file [TT]-v[tt].[PAR]",
1017 "[TT]-inpr[tt]: calculate a matrix of inner-products between",
1018 "eigenvectors in files [TT]-v[tt] and [TT]-v2[tt]. All eigenvectors",
1019 "of both files will be used unless [TT]-first[tt] and [TT]-last[tt]",
1020 "have been set explicitly.[PAR]",
1022 "When [TT]-v[tt], [TT]-eig[tt], [TT]-v2[tt] and [TT]-eig2[tt] are given,",
1023 "a single number for the overlap between the covariance matrices is",
1024 "generated. The formulas are:[BR]",
1025 " difference = sqrt(tr((sqrt(M1) - sqrt(M2))^2))[BR]",
1026 "normalized overlap = 1 - difference/sqrt(tr(M1) + tr(M2))[BR]",
1027 " shape overlap = 1 - sqrt(tr((sqrt(M1/tr(M1)) - sqrt(M2/tr(M2)))^2))[BR]",
1028 "where M1 and M2 are the two covariance matrices and tr is the trace",
1029 "of a matrix. The numbers are proportional to the overlap of the square",
1030 "root of the fluctuations. The normalized overlap is the most useful",
1031 "number, it is 1 for identical matrices and 0 when the sampled",
1032 "subspaces are orthogonal.[PAR]",
1033 "When the [TT]-entropy[tt] flag is given an entropy estimate will be",
1034 "computed based on the Quasiharmonic approach and based on",
1035 "Schlitter's formula."
1037 static int first = 1, last = -1, skip = 1, nextr = 2, nskip = 6;
1038 static real max = 0.0, temp = 298.15;
1039 static gmx_bool bSplit = FALSE, bEntropy = FALSE;
1041 { "-first", FALSE, etINT, {&first},
1042 "First eigenvector for analysis (-1 is select)" },
1043 { "-last", FALSE, etINT, {&last},
1044 "Last eigenvector for analysis (-1 is till the last)" },
1045 { "-skip", FALSE, etINT, {&skip},
1046 "Only analyse every nr-th frame" },
1047 { "-max", FALSE, etREAL, {&max},
1048 "Maximum for projection of the eigenvector on the average structure, "
1049 "max=0 gives the extremes" },
1050 { "-nframes", FALSE, etINT, {&nextr},
1051 "Number of frames for the extremes output" },
1052 { "-split", FALSE, etBOOL, {&bSplit},
1053 "Split eigenvector projections where time is zero" },
1054 { "-entropy", FALSE, etBOOL, {&bEntropy},
1055 "Compute entropy according to the Quasiharmonic formula or Schlitter's method." },
1056 { "-temp", FALSE, etREAL, {&temp},
1057 "Temperature for entropy calculations" },
1058 { "-nevskip", FALSE, etINT, {&nskip},
1059 "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." }
1061 #define NPA asize(pa)
1067 t_atoms *atoms = NULL;
1068 rvec *xtop, *xref1, *xref2, *xrefp = NULL;
1069 gmx_bool bDMR1, bDMA1, bDMR2, bDMA2;
1070 int nvec1, nvec2, *eignr1 = NULL, *eignr2 = NULL;
1071 rvec *x, *xread, *xav1, *xav2, **eigvec1 = NULL, **eigvec2 = NULL;
1073 real xid, totmass, *sqrtm, *w_rls, t, lambda;
1076 const char *indexfile;
1079 int nout, *iout, noutvec, *outvec, nfit;
1080 atom_id *index, *ifit;
1081 const char *VecFile, *Vec2File, *topfile;
1082 const char *EigFile, *Eig2File;
1083 const char *CompFile, *RmsfFile, *ProjOnVecFile;
1084 const char *TwoDPlotFile, *ThreeDPlotFile;
1085 const char *FilterFile, *ExtremeFile;
1086 const char *OverlapFile, *InpMatFile;
1087 gmx_bool bFit1, bFit2, bM, bIndex, bTPS, bTop, bVec2, bProj;
1088 gmx_bool bFirstToLast, bFirstLastSet, bTraj, bCompare, bPDB3D;
1089 real *eigval1 = NULL, *eigval2 = NULL;
1096 { efTRN, "-v", "eigenvec", ffREAD },
1097 { efTRN, "-v2", "eigenvec2", ffOPTRD },
1098 { efTRX, "-f", NULL, ffOPTRD },
1099 { efTPS, NULL, NULL, ffOPTRD },
1100 { efNDX, NULL, NULL, ffOPTRD },
1101 { efXVG, "-eig", "eigenval", ffOPTRD },
1102 { efXVG, "-eig2", "eigenval2", ffOPTRD },
1103 { efXVG, "-comp", "eigcomp", ffOPTWR },
1104 { efXVG, "-rmsf", "eigrmsf", ffOPTWR },
1105 { efXVG, "-proj", "proj", ffOPTWR },
1106 { efXVG, "-2d", "2dproj", ffOPTWR },
1107 { efSTO, "-3d", "3dproj.pdb", ffOPTWR },
1108 { efTRX, "-filt", "filtered", ffOPTWR },
1109 { efTRX, "-extr", "extreme.pdb", ffOPTWR },
1110 { efXVG, "-over", "overlap", ffOPTWR },
1111 { efXPM, "-inpr", "inprod", ffOPTWR }
1113 #define NFILE asize(fnm)
1115 if (!parse_common_args(&argc, argv,
1116 PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW | PCA_BE_NICE,
1117 NFILE, fnm, NPA, pa, asize(desc), desc, 0, NULL, &oenv))
1122 indexfile = ftp2fn_null(efNDX, NFILE, fnm);
1124 VecFile = opt2fn("-v", NFILE, fnm);
1125 Vec2File = opt2fn_null("-v2", NFILE, fnm);
1126 topfile = ftp2fn(efTPS, NFILE, fnm);
1127 EigFile = opt2fn_null("-eig", NFILE, fnm);
1128 Eig2File = opt2fn_null("-eig2", NFILE, fnm);
1129 CompFile = opt2fn_null("-comp", NFILE, fnm);
1130 RmsfFile = opt2fn_null("-rmsf", NFILE, fnm);
1131 ProjOnVecFile = opt2fn_null("-proj", NFILE, fnm);
1132 TwoDPlotFile = opt2fn_null("-2d", NFILE, fnm);
1133 ThreeDPlotFile = opt2fn_null("-3d", NFILE, fnm);
1134 FilterFile = opt2fn_null("-filt", NFILE, fnm);
1135 ExtremeFile = opt2fn_null("-extr", NFILE, fnm);
1136 OverlapFile = opt2fn_null("-over", NFILE, fnm);
1137 InpMatFile = ftp2fn_null(efXPM, NFILE, fnm);
1139 bTop = fn2bTPX(topfile);
1140 bProj = ProjOnVecFile || TwoDPlotFile || ThreeDPlotFile
1141 || FilterFile || ExtremeFile;
1143 opt2parg_bSet("-first", NPA, pa) && opt2parg_bSet("-last", NPA, pa);
1144 bFirstToLast = CompFile || RmsfFile || ProjOnVecFile || FilterFile ||
1145 OverlapFile || ((ExtremeFile || InpMatFile) && bFirstLastSet);
1146 bVec2 = Vec2File || OverlapFile || InpMatFile;
1147 bM = RmsfFile || bProj;
1148 bTraj = ProjOnVecFile || FilterFile || (ExtremeFile && (max == 0))
1149 || TwoDPlotFile || ThreeDPlotFile;
1150 bIndex = bM || bProj;
1151 bTPS = ftp2bSet(efTPS, NFILE, fnm) || bM || bTraj ||
1152 FilterFile || (bIndex && indexfile);
1153 bCompare = Vec2File || Eig2File;
1154 bPDB3D = fn2ftp(ThreeDPlotFile) == efPDB;
1156 read_eigenvectors(VecFile, &natoms, &bFit1,
1157 &xref1, &bDMR1, &xav1, &bDMA1,
1158 &nvec1, &eignr1, &eigvec1, &eigval1);
1161 /* Overwrite eigenvalues from separate files if the user provides them */
1162 if (EigFile != NULL)
1164 int neig_tmp = read_xvg(EigFile, &xvgdata, &i);
1165 if (neig_tmp != neig1)
1167 fprintf(stderr, "Warning: number of eigenvalues in xvg file (%d) does not mtch trr file (%d)\n", neig1, natoms);
1170 srenew(eigval1, neig1);
1171 for (j = 0; j < neig1; j++)
1173 real tmp = eigval1[j];
1174 eigval1[j] = xvgdata[1][j];
1175 if (debug && (eigval1[j] != tmp))
1177 fprintf(debug, "Replacing eigenvalue %d. From trr: %10g, from xvg: %10g\n",
1178 j, tmp, eigval1[j]);
1181 for (j = 0; j < i; j++)
1186 fprintf(stderr, "Read %d eigenvalues from %s\n", neig1, EigFile);
1193 gmx_fatal(FARGS, "Can not calculate entropies from mass-weighted eigenvalues, redo the analysis without mass-weighting");
1195 calc_entropy_qh(stdout, neig1, eigval1, temp, nskip);
1196 calc_entropy_schlitter(stdout, neig1, nskip, eigval1, temp);
1203 gmx_fatal(FARGS, "Need a second eigenvector file to do this analysis.");
1205 read_eigenvectors(Vec2File, &neig2, &bFit2,
1206 &xref2, &bDMR2, &xav2, &bDMA2, &nvec2, &eignr2, &eigvec2, &eigval2);
1211 gmx_fatal(FARGS, "Dimensions in the eigenvector files don't match");
1215 if (Eig2File != NULL)
1217 neig2 = read_xvg(Eig2File, &xvgdata, &i);
1218 srenew(eigval2, neig2);
1219 for (j = 0; j < neig2; j++)
1221 eigval2[j] = xvgdata[1][j];
1223 for (j = 0; j < i; j++)
1228 fprintf(stderr, "Read %d eigenvalues from %s\n", neig2, Eig2File);
1232 if ((!bFit1 || xref1) && !bDMR1 && !bDMA1)
1236 if ((xref1 == NULL) && (bM || bTraj))
1252 bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm),
1253 title, &top, &ePBC, &xtop, NULL, topbox, bM);
1255 gpbc = gmx_rmpbc_init(&top.idef, ePBC, atoms->nr);
1256 gmx_rmpbc(gpbc, atoms->nr, topbox, xtop);
1257 /* Fitting is only required for the projection */
1262 printf("\nNote: the structure in %s should be the same\n"
1263 " as the one used for the fit in g_covar\n", topfile);
1265 printf("\nSelect the index group that was used for the least squares fit in g_covar\n");
1266 get_index(atoms, indexfile, 1, &nfit, &ifit, &grpname);
1268 snew(w_rls, atoms->nr);
1269 for (i = 0; (i < nfit); i++)
1273 w_rls[ifit[i]] = atoms->atom[ifit[i]].m;
1277 w_rls[ifit[i]] = 1.0;
1281 snew(xrefp, atoms->nr);
1284 /* Safety check between selected fit-group and reference structure read from the eigenvector file */
1287 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);
1289 for (i = 0; (i < nfit); i++)
1291 copy_rvec(xref1[i], xrefp[ifit[i]]);
1296 /* The top coordinates are the fitting reference */
1297 for (i = 0; (i < nfit); i++)
1299 copy_rvec(xtop[ifit[i]], xrefp[ifit[i]]);
1301 reset_x(nfit, ifit, atoms->nr, NULL, xrefp, w_rls);
1304 gmx_rmpbc_done(gpbc);
1309 printf("\nSelect an index group of %d elements that corresponds to the eigenvectors\n", natoms);
1310 get_index(atoms, indexfile, 1, &i, &index, &grpname);
1313 gmx_fatal(FARGS, "you selected a group with %d elements instead of %d", i, natoms);
1318 snew(sqrtm, natoms);
1321 proj_unit = "u\\S1/2\\Nnm";
1322 for (i = 0; (i < natoms); i++)
1324 sqrtm[i] = sqrt(atoms->atom[index[i]].m);
1330 for (i = 0; (i < natoms); i++)
1340 for (i = 0; (i < natoms); i++)
1342 for (d = 0; (d < DIM); d++)
1344 t += sqr((xav1[i][d]-xav2[i][d])*sqrtm[i]);
1345 totmass += sqr(sqrtm[i]);
1348 fprintf(stdout, "RMSD (without fit) between the two average structures:"
1349 " %.3f (nm)\n\n", sqrt(t/totmass));
1360 /* make an index from first to last */
1361 nout = last-first+1;
1363 for (i = 0; i < nout; i++)
1365 iout[i] = first-1+i;
1368 else if (ThreeDPlotFile)
1370 /* make an index of first+(0,1,2) and last */
1371 nout = bPDB3D ? 4 : 3;
1372 nout = min(last-first+1, nout);
1380 iout[nout-1] = last-1;
1384 /* make an index of first and last */
1393 printf("Select eigenvectors for output, end your selection with 0\n");
1400 srenew(iout, nout+1);
1401 if (1 != scanf("%d", &iout[nout]))
1403 gmx_fatal(FARGS, "Error reading user input");
1407 while (iout[nout] >= 0);
1411 /* make an index of the eigenvectors which are present */
1414 for (i = 0; i < nout; i++)
1417 while ((j < nvec1) && (eignr1[j] != iout[i]))
1421 if ((j < nvec1) && (eignr1[j] == iout[i]))
1423 outvec[noutvec] = j;
1427 fprintf(stderr, "%d eigenvectors selected for output", noutvec);
1430 fprintf(stderr, ":");
1431 for (j = 0; j < noutvec; j++)
1433 fprintf(stderr, " %d", eignr1[outvec[j]]+1);
1436 fprintf(stderr, "\n");
1440 components(CompFile, natoms, eignr1, eigvec1, noutvec, outvec, oenv);
1445 rmsf(RmsfFile, natoms, sqrtm, eignr1, eigvec1, noutvec, outvec, eigval1,
1451 project(bTraj ? opt2fn("-f", NFILE, fnm) : NULL,
1452 bTop ? &top : NULL, ePBC, topbox,
1453 ProjOnVecFile, TwoDPlotFile, ThreeDPlotFile, FilterFile, skip,
1454 ExtremeFile, bFirstLastSet, max, nextr, atoms, natoms, index,
1455 bFit1, xrefp, nfit, ifit, w_rls,
1456 sqrtm, xav1, eignr1, eigvec1, noutvec, outvec, bSplit,
1462 overlap(OverlapFile, natoms,
1463 eigvec1, nvec2, eignr2, eigvec2, noutvec, outvec, oenv);
1468 inprod_matrix(InpMatFile, natoms,
1469 nvec1, eignr1, eigvec1, nvec2, eignr2, eigvec2,
1470 bFirstLastSet, noutvec, outvec);
1475 compare(natoms, nvec1, eigvec1, nvec2, eigvec2, eigval1, neig1, eigval2, neig2);
1479 if (!CompFile && !bProj && !OverlapFile && !InpMatFile &&
1480 !bCompare && !bEntropy)
1482 fprintf(stderr, "\nIf you want some output,"
1483 " set one (or two or ...) of the output file options\n");
1487 view_all(oenv, NFILE, fnm);