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,2015,2016,2017 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
45 #include "gromacs/commandline/pargs.h"
46 #include "gromacs/commandline/viewit.h"
47 #include "gromacs/fileio/confio.h"
48 #include "gromacs/fileio/matio.h"
49 #include "gromacs/fileio/trxio.h"
50 #include "gromacs/fileio/xvgr.h"
51 #include "gromacs/gmxana/cmat.h"
52 #include "gromacs/gmxana/gmx_ana.h"
53 #include "gromacs/gmxana/princ.h"
54 #include "gromacs/math/do_fit.h"
55 #include "gromacs/math/functions.h"
56 #include "gromacs/math/units.h"
57 #include "gromacs/math/utilities.h"
58 #include "gromacs/math/vec.h"
59 #include "gromacs/pbcutil/rmpbc.h"
60 #include "gromacs/topology/ifunc.h"
61 #include "gromacs/topology/index.h"
62 #include "gromacs/topology/topology.h"
63 #include "gromacs/utility/arraysize.h"
64 #include "gromacs/utility/fatalerror.h"
65 #include "gromacs/utility/futil.h"
66 #include "gromacs/utility/pleasecite.h"
67 #include "gromacs/utility/smalloc.h"
69 static void norm_princ(const t_atoms* atoms, int isize, int* index, int natoms, rvec* x)
74 /* equalize principal components: */
75 /* orient principal axes, get principal components */
76 orient_princ(atoms, isize, index, natoms, x, nullptr, princ);
78 /* calc our own principal components */
80 for (m = 0; m < DIM; m++)
82 for (i = 0; i < isize; i++)
84 vec[m] += gmx::square(x[index[i]][m]);
86 vec[m] = std::sqrt(vec[m] / static_cast<real>(isize));
87 /* calculate scaling constants */
88 vec[m] = 1.0 / (std::sqrt(3.0) * vec[m]);
91 /* scale coordinates */
92 for (i = 0; i < natoms; i++)
94 for (m = 0; m < DIM; m++)
101 int gmx_rms(int argc, char* argv[])
103 const char* desc[] = {
104 "[THISMODULE] compares two structures by computing the root mean square",
105 "deviation (RMSD), the size-independent [GRK]rho[grk] similarity parameter",
106 "([TT]rho[tt]) or the scaled [GRK]rho[grk] ([TT]rhosc[tt]), ",
107 "see Maiorov & Crippen, Proteins [BB]22[bb], 273 (1995).",
108 "This is selected by [TT]-what[tt].[PAR]",
110 "Each structure from a trajectory ([TT]-f[tt]) is compared to a",
111 "reference structure. The reference structure",
112 "is taken from the structure file ([TT]-s[tt]).[PAR]",
114 "With option [TT]-mir[tt] also a comparison with the mirror image of",
115 "the reference structure is calculated.",
116 "This is useful as a reference for 'significant' values, see",
117 "Maiorov & Crippen, Proteins [BB]22[bb], 273 (1995).[PAR]",
119 "Option [TT]-prev[tt] produces the comparison with a previous frame",
120 "the specified number of frames ago.[PAR]",
122 "Option [TT]-m[tt] produces a matrix in [REF].xpm[ref] format of",
123 "comparison values of each structure in the trajectory with respect to",
124 "each other structure. This file can be visualized with for instance",
125 "[TT]xv[tt] and can be converted to postscript with [gmx-xpm2ps].[PAR]",
127 "Option [TT]-fit[tt] controls the least-squares fitting of",
128 "the structures on top of each other: complete fit (rotation and",
129 "translation), translation only, or no fitting at all.[PAR]",
131 "Option [TT]-mw[tt] controls whether mass weighting is done or not.",
132 "If you select the option (default) and ",
133 "supply a valid [REF].tpr[ref] file masses will be taken from there, ",
134 "otherwise the masses will be deduced from the [TT]atommass.dat[tt] file in",
135 "[TT]GMXLIB[tt]. This is fine for proteins, but not",
136 "necessarily for other molecules. A default mass of 12.011 amu (carbon)",
137 "is assigned to unknown atoms. You can check whether this happened by",
138 "turning on the [TT]-debug[tt] flag and inspecting the log file.[PAR]",
140 "With [TT]-f2[tt], the 'other structures' are taken from a second",
141 "trajectory, this generates a comparison matrix of one trajectory",
142 "versus the other.[PAR]",
144 "Option [TT]-bin[tt] does a binary dump of the comparison matrix.[PAR]",
146 "Option [TT]-bm[tt] produces a matrix of average bond angle deviations",
147 "analogously to the [TT]-m[tt] option. Only bonds between atoms in the",
148 "comparison group are considered."
150 static gmx_bool bPBC = TRUE, bFitAll = TRUE, bSplit = FALSE;
151 static gmx_bool bDeltaLog = FALSE;
152 static int prev = 0, freq = 1, freq2 = 1, nlevels = 80, avl = 0;
153 static real rmsd_user_max = -1, rmsd_user_min = -1, bond_user_max = -1, bond_user_min = -1,
155 /* strings and things for selecting difference method */
165 const char* what[ewNR + 1] = { nullptr, "rmsd", "rho", "rhosc", nullptr };
166 const char* whatname[ewNR] = { nullptr, "RMSD", "Rho", "Rho sc" };
167 const char* whatlabel[ewNR] = { nullptr, "RMSD (nm)", "Rho", "Rho sc" };
168 const char* whatxvgname[ewNR] = { nullptr, "RMSD", "\\8r\\4", "\\8r\\4\\ssc\\N" };
169 const char* whatxvglabel[ewNR] = { nullptr, "RMSD (nm)", "\\8r\\4", "\\8r\\4\\ssc\\N" };
170 /* strings and things for fitting methods */
180 const char* fit[efNR + 1] = { nullptr, "rot+trans", "translation", "none", nullptr };
181 const char* fitgraphlabel[efNR + 1] = { nullptr, "lsq fit", "translational fit", "no fit" };
183 static gmx_bool bMassWeighted = TRUE;
185 { "-what", FALSE, etENUM, { what }, "Structural difference measure" },
186 { "-pbc", FALSE, etBOOL, { &bPBC }, "PBC check" },
187 { "-fit", FALSE, etENUM, { fit }, "Fit to reference structure" },
188 { "-prev", FALSE, etINT, { &prev }, "Compare with previous frame" },
189 { "-split", FALSE, etBOOL, { &bSplit }, "Split graph where time is zero" },
190 { "-fitall", FALSE, etBOOL, { &bFitAll }, "HIDDENFit all pairs of structures in matrix" },
191 { "-skip", FALSE, etINT, { &freq }, "Only write every nr-th frame to matrix" },
192 { "-skip2", FALSE, etINT, { &freq2 }, "Only write every nr-th frame to matrix" },
193 { "-max", FALSE, etREAL, { &rmsd_user_max }, "Maximum level in comparison matrix" },
194 { "-min", FALSE, etREAL, { &rmsd_user_min }, "Minimum level in comparison matrix" },
195 { "-bmax", FALSE, etREAL, { &bond_user_max }, "Maximum level in bond angle matrix" },
196 { "-bmin", FALSE, etREAL, { &bond_user_min }, "Minimum level in bond angle matrix" },
197 { "-mw", FALSE, etBOOL, { &bMassWeighted }, "Use mass weighting for superposition" },
198 { "-nlevels", FALSE, etINT, { &nlevels }, "Number of levels in the matrices" },
199 { "-ng", FALSE, etINT, { &nrms }, "Number of groups to compute RMS between" },
200 { "-dlog", FALSE, etBOOL, { &bDeltaLog }, "HIDDENUse a log x-axis in the delta t matrix" },
201 { "-dmax", FALSE, etREAL, { &delta_maxy }, "HIDDENMaximum level in delta matrix" },
202 { "-aver", FALSE, etINT, { &avl }, "HIDDENAverage over this distance in the RMSD matrix" }
204 int natoms_trx, natoms_trx2, natoms;
207 int maxframe = NFRAME, maxframe2 = NFRAME;
208 real t, *w_rls, *w_rms, *w_rls_m = nullptr, *w_rms_m = nullptr;
209 gmx_bool bNorm, bAv, bFreq2, bFile2, bMat, bBond, bDelta, bMirror, bMass;
210 gmx_bool bFit, bReset;
213 t_iatom* iatom = nullptr;
215 matrix box = { { 0 } };
216 rvec * x, *xp, *xm = nullptr, **mat_x = nullptr, **mat_x2, *mat_x2_j = nullptr, vec1, vec2;
218 char buf[256], buf2[256];
221 real rlstot = 0, **rls, **rlsm = nullptr, *time, *time2, *rlsnorm = nullptr,
222 **rmsd_mat = nullptr, **bond_mat = nullptr, *axis, *axis2, *del_xaxis, *del_yaxis,
223 rmsd_max, rmsd_min, rmsd_avg, bond_max, bond_min, ang;
224 real ** rmsdav_mat = nullptr, av_tot, weight, weight_tot;
225 real ** delta = nullptr, delta_max, delta_scalex = 0, delta_scaley = 0, *delta_tot;
226 int delta_xsize = 0, del_lev = 100, mx, my, abs_my;
227 gmx_bool bA1, bA2, bPrev, bTop, *bInMat = nullptr;
228 int ifit, *irms, ibond = 0, *ind_bond1 = nullptr, *ind_bond2 = nullptr, n_ind_m = 0;
229 int * ind_fit, **ind_rms, *ind_m = nullptr, *rev_ind_m = nullptr, *ind_rms_m = nullptr;
230 char * gn_fit, **gn_rms;
232 gmx_output_env_t* oenv;
233 gmx_rmpbc_t gpbc = nullptr;
236 { efTPS, nullptr, nullptr, ffREAD }, { efTRX, "-f", nullptr, ffREAD },
237 { efTRX, "-f2", nullptr, ffOPTRD }, { efNDX, nullptr, nullptr, ffOPTRD },
238 { efXVG, nullptr, "rmsd", ffWRITE }, { efXVG, "-mir", "rmsdmir", ffOPTWR },
239 { efXVG, "-a", "avgrp", ffOPTWR }, { efXVG, "-dist", "rmsd-dist", ffOPTWR },
240 { efXPM, "-m", "rmsd", ffOPTWR }, { efDAT, "-bin", "rmsd", ffOPTWR },
241 { efXPM, "-bm", "bond", ffOPTWR }
243 #define NFILE asize(fnm)
245 if (!parse_common_args(&argc,
247 PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW,
260 /* parse enumerated options: */
262 if (ewhat == ewRho || ewhat == ewRhoSc)
264 please_cite(stdout, "Maiorov95");
267 bFit = efit == efFit;
268 bReset = efit == efReset;
271 bReset = TRUE; /* for fit, reset *must* be set */
278 /* mark active cmdline options */
279 bMirror = opt2bSet("-mir", NFILE, fnm); /* calc RMSD vs mirror of ref. */
280 bFile2 = opt2bSet("-f2", NFILE, fnm);
281 bMat = opt2bSet("-m", NFILE, fnm);
282 bBond = opt2bSet("-bm", NFILE, fnm);
283 bDelta = (delta_maxy > 0); /* calculate rmsd vs delta t matrix from *
284 * your RMSD matrix (hidden option */
285 bNorm = opt2bSet("-a", NFILE, fnm);
286 bFreq2 = opt2parg_bSet("-skip2", asize(pa), pa);
290 "The number of frames to skip is <= 0. "
291 "Writing out all frames.\n\n");
298 else if (bFile2 && freq2 <= 0)
301 "The number of frames to skip in second trajectory is <= 0.\n"
302 " Writing out all frames.\n\n");
310 "WARNING: using option -prev with large trajectories will\n"
311 " require a lot of memory and could lead to crashes\n");
315 fprintf(stderr, "WARNING: option -skip also applies to -prev\n");
319 if (bFile2 && !bMat && !bBond)
322 "WARNING: second trajectory (-f2) useless when not calculating matrix (-m/-bm),\n"
323 " will not read from %s\n",
324 opt2fn("-f2", NFILE, fnm));
334 "WARNING: second trajectory (-f2) useless when making delta matrix,\n"
335 " will not read from %s\n",
336 opt2fn("-f2", NFILE, fnm));
341 bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &pbcType, &xp, nullptr, box, TRUE);
342 snew(w_rls, top.atoms.nr);
343 snew(w_rms, top.atoms.nr);
348 "WARNING: Need a run input file for bond angle matrix,\n"
349 " will not calculate bond angle matrix.\n");
355 fprintf(stderr, "Select group for %s fit\n", bFit ? "least squares" : "translational");
356 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &ifit, &ind_fit, &gn_fit);
365 if (bFit && ifit < 3)
367 gmx_fatal(FARGS, "Need >= 3 points to fit!\n");
371 for (i = 0; i < ifit; i++)
375 w_rls[ind_fit[i]] = top.atoms.atom[ind_fit[i]].m;
379 w_rls[ind_fit[i]] = 1;
381 bMass = bMass || (top.atoms.atom[ind_fit[i]].m != 0);
385 fprintf(stderr, "All masses in the fit group are 0, using masses of 1\n");
386 for (i = 0; i < ifit; i++)
388 w_rls[ind_fit[i]] = 1;
402 fprintf(stderr, "Select group%s for %s calculation\n", (nrms > 1) ? "s" : "", whatname[ewhat]);
403 get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), nrms, irms, ind_rms, gn_rms);
407 snew(rlsnorm, irms[0]);
410 for (j = 0; j < nrms; j++)
412 snew(rls[j], maxframe);
417 for (j = 0; j < nrms; j++)
419 snew(rlsm[j], maxframe);
422 snew(time, maxframe);
423 for (j = 0; j < nrms; j++)
426 for (i = 0; i < irms[j]; i++)
430 w_rms[ind_rms[j][i]] = top.atoms.atom[ind_rms[j][i]].m;
434 w_rms[ind_rms[j][i]] = 1.0;
436 bMass = bMass || (top.atoms.atom[ind_rms[j][i]].m != 0);
440 fprintf(stderr, "All masses in group %d are 0, using masses of 1\n", j);
441 for (i = 0; i < irms[j]; i++)
443 w_rms[ind_rms[j][i]] = 1;
447 /* Prepare reference frame */
450 gpbc = gmx_rmpbc_init(&top.idef, pbcType, top.atoms.nr);
451 gmx_rmpbc(gpbc, top.atoms.nr, box, xp);
455 reset_x(ifit, ind_fit, top.atoms.nr, nullptr, xp, w_rls);
459 /* generate reference structure mirror image: */
460 snew(xm, top.atoms.nr);
461 for (i = 0; i < top.atoms.nr; i++)
463 copy_rvec(xp[i], xm[i]);
464 xm[i][XX] = -xm[i][XX];
467 if (ewhat == ewRhoSc)
469 norm_princ(&top.atoms, ifit, ind_fit, top.atoms.nr, xp);
472 /* read first frame */
473 natoms_trx = read_first_x(oenv, &status, opt2fn("-f", NFILE, fnm), &t, &x, box);
474 if (natoms_trx != top.atoms.nr)
476 fprintf(stderr, "\nWARNING: topology has %d atoms, whereas trajectory has %d\n", top.atoms.nr, natoms_trx);
478 natoms = std::min(top.atoms.nr, natoms_trx);
479 if (bMat || bBond || bPrev)
485 /* With -prev we use all atoms for simplicity */
490 /* Check which atoms we need (fit/rms) */
491 snew(bInMat, natoms);
492 for (i = 0; i < ifit; i++)
494 bInMat[ind_fit[i]] = TRUE;
497 for (i = 0; i < irms[0]; i++)
499 if (!bInMat[ind_rms[0][i]])
501 bInMat[ind_rms[0][i]] = TRUE;
506 /* Make an index of needed atoms */
507 snew(ind_m, n_ind_m);
508 snew(rev_ind_m, natoms);
510 for (i = 0; i < natoms; i++)
512 if (bPrev || bInMat[i])
519 snew(w_rls_m, n_ind_m);
520 snew(ind_rms_m, irms[0]);
521 snew(w_rms_m, n_ind_m);
522 for (i = 0; i < ifit; i++)
524 w_rls_m[rev_ind_m[ind_fit[i]]] = w_rls[ind_fit[i]];
526 for (i = 0; i < irms[0]; i++)
528 ind_rms_m[i] = rev_ind_m[ind_rms[0][i]];
529 w_rms_m[ind_rms_m[i]] = w_rms[ind_rms[0][i]];
537 for (k = 0; k < F_NRE; k++)
541 ncons += top.idef.il[k].nr / 3;
544 fprintf(stderr, "Found %d bonds in topology\n", ncons);
545 snew(ind_bond1, ncons);
546 snew(ind_bond2, ncons);
548 for (k = 0; k < F_NRE; k++)
552 iatom = top.idef.il[k].iatoms;
553 ncons = top.idef.il[k].nr / 3;
554 for (i = 0; i < ncons; i++)
558 for (j = 0; j < irms[0]; j++)
560 if (iatom[3 * i + 1] == ind_rms[0][j])
564 if (iatom[3 * i + 2] == ind_rms[0][j])
571 ind_bond1[ibond] = rev_ind_m[iatom[3 * i + 1]];
572 ind_bond2[ibond] = rev_ind_m[iatom[3 * i + 2]];
578 fprintf(stderr, "Using %d bonds for bond angle matrix\n", ibond);
581 gmx_fatal(FARGS, "0 bonds found");
585 /* start looping over frames: */
593 gmx_rmpbc(gpbc, natoms, box, x);
598 reset_x(ifit, ind_fit, natoms, nullptr, x, w_rls);
600 if (ewhat == ewRhoSc)
602 norm_princ(&top.atoms, ifit, ind_fit, natoms, x);
607 /*do the least squares fit to original structure*/
608 do_fit(natoms, w_rls, xp, x);
611 if (frame % freq == 0)
613 /* keep frame for matrix calculation */
614 if (bMat || bBond || bPrev)
616 if (tel_mat >= NFRAME)
618 srenew(mat_x, tel_mat + 1);
620 snew(mat_x[tel_mat], n_ind_m);
621 for (i = 0; i < n_ind_m; i++)
623 copy_rvec(x[ind_m[i]], mat_x[tel_mat][i]);
628 /*calculate energy of root_least_squares*/
631 j = tel_mat - prev - 1;
636 for (i = 0; i < n_ind_m; i++)
638 copy_rvec(mat_x[j][i], xp[ind_m[i]]);
642 reset_x(ifit, ind_fit, natoms, nullptr, xp, w_rls);
646 do_fit(natoms, w_rls, x, xp);
649 for (j = 0; (j < nrms); j++)
651 rls[j][teller] = calc_similar_ind(ewhat != ewRMSD, irms[j], ind_rms[j], w_rms, x, xp);
655 for (j = 0; (j < irms[0]); j++)
657 rlsnorm[j] += calc_similar_ind(ewhat != ewRMSD, 1, &(ind_rms[0][j]), w_rms, x, xp);
665 /*do the least squares fit to mirror of original structure*/
666 do_fit(natoms, w_rls, xm, x);
669 for (j = 0; j < nrms; j++)
672 calc_similar_ind(ewhat != ewRMSD, irms[j], ind_rms[j], w_rms, x, xm);
675 time[teller] = output_env_conv_time(oenv, t);
680 if (teller >= maxframe)
683 srenew(time, maxframe);
684 for (j = 0; (j < nrms); j++)
686 srenew(rls[j], maxframe);
690 for (j = 0; (j < nrms); j++)
692 srenew(rlsm[j], maxframe);
696 } while (read_next_x(oenv, status, &t, x, box));
704 snew(time2, maxframe2);
706 fprintf(stderr, "\nWill read second trajectory file\n");
707 snew(mat_x2, NFRAME);
708 natoms_trx2 = read_first_x(oenv, &status, opt2fn("-f2", NFILE, fnm), &t, &x, box);
709 if (natoms_trx2 != natoms_trx)
712 "Second trajectory (%d atoms) does not match the first one"
722 gmx_rmpbc(gpbc, natoms, box, x);
727 reset_x(ifit, ind_fit, natoms, nullptr, x, w_rls);
729 if (ewhat == ewRhoSc)
731 norm_princ(&top.atoms, ifit, ind_fit, natoms, x);
736 /*do the least squares fit to original structure*/
737 do_fit(natoms, w_rls, xp, x);
740 if (frame2 % freq2 == 0)
742 /* keep frame for matrix calculation */
745 if (tel_mat2 >= NFRAME)
747 srenew(mat_x2, tel_mat2 + 1);
749 snew(mat_x2[tel_mat2], n_ind_m);
750 for (i = 0; i < n_ind_m; i++)
752 copy_rvec(x[ind_m[i]], mat_x2[tel_mat2][i]);
757 time2[teller2] = output_env_conv_time(oenv, t);
762 if (teller2 >= maxframe2)
765 srenew(time2, maxframe2);
767 } while (read_next_x(oenv, status, &t, x, box));
777 gmx_rmpbc_done(gpbc);
781 /* calculate RMS matrix */
782 fprintf(stderr, "\n");
785 fprintf(stderr, "Building %s matrix, %dx%d elements\n", whatname[ewhat], tel_mat, tel_mat2);
786 snew(rmsd_mat, tel_mat);
790 fprintf(stderr, "Building bond angle matrix, %dx%d elements\n", tel_mat, tel_mat2);
791 snew(bond_mat, tel_mat);
794 snew(axis2, tel_mat2);
807 for (j = 0; j < tel_mat2; j++)
809 axis2[j] = time2[freq2 * j];
815 delta_scalex = 8.0 / std::log(2.0);
816 delta_xsize = gmx::roundToInt(std::log(tel_mat / 2.) * delta_scalex) + 1;
820 delta_xsize = tel_mat / 2;
822 delta_scaley = 1.0 / delta_maxy;
823 snew(delta, delta_xsize);
824 for (j = 0; j < delta_xsize; j++)
826 snew(delta[j], del_lev + 1);
830 snew(rmsdav_mat, tel_mat);
831 for (j = 0; j < tel_mat; j++)
833 snew(rmsdav_mat[j], tel_mat);
840 snew(mat_x2_j, natoms);
842 for (i = 0; i < tel_mat; i++)
844 axis[i] = time[freq * i];
845 fprintf(stderr, "\r element %5d; time %5.2f ", i, axis[i]);
849 snew(rmsd_mat[i], tel_mat2);
853 snew(bond_mat[i], tel_mat2);
855 for (j = 0; j < tel_mat2; j++)
859 for (k = 0; k < n_ind_m; k++)
861 copy_rvec(mat_x2[j][k], mat_x2_j[k]);
863 do_fit(n_ind_m, w_rls_m, mat_x[i], mat_x2_j);
867 mat_x2_j = mat_x2[j];
871 if (bFile2 || (i < j))
873 rmsd_mat[i][j] = calc_similar_ind(
874 ewhat != ewRMSD, irms[0], ind_rms_m, w_rms_m, mat_x[i], mat_x2_j);
875 if (rmsd_mat[i][j] > rmsd_max)
877 rmsd_max = rmsd_mat[i][j];
879 if (rmsd_mat[i][j] < rmsd_min)
881 rmsd_min = rmsd_mat[i][j];
883 rmsd_avg += rmsd_mat[i][j];
887 rmsd_mat[i][j] = rmsd_mat[j][i];
892 if (bFile2 || (i <= j))
895 for (m = 0; m < ibond; m++)
897 rvec_sub(mat_x[i][ind_bond1[m]], mat_x[i][ind_bond2[m]], vec1);
898 rvec_sub(mat_x2_j[ind_bond1[m]], mat_x2_j[ind_bond2[m]], vec2);
899 ang += std::acos(cos_angle(vec1, vec2));
901 bond_mat[i][j] = ang * 180.0 / (M_PI * ibond);
902 if (bond_mat[i][j] > bond_max)
904 bond_max = bond_mat[i][j];
906 if (bond_mat[i][j] < bond_min)
908 bond_min = bond_mat[i][j];
913 bond_mat[i][j] = bond_mat[j][i];
920 rmsd_avg /= static_cast<real>(tel_mat) * static_cast<real>(tel_mat2);
924 rmsd_avg /= tel_mat * (tel_mat - 1) / 2.;
926 if (bMat && (avl > 0))
931 for (j = 0; j < tel_mat - 1; j++)
933 for (i = j + 1; i < tel_mat; i++)
937 for (my = -avl; my <= avl; my++)
939 if ((j + my >= 0) && (j + my < tel_mat))
941 abs_my = std::abs(my);
942 for (mx = -avl; mx <= avl; mx++)
944 if ((i + mx >= 0) && (i + mx < tel_mat))
946 weight = avl + 1.0 - std::max(std::abs(mx), abs_my);
947 av_tot += weight * rmsd_mat[i + mx][j + my];
948 weight_tot += weight;
953 rmsdav_mat[i][j] = av_tot / weight_tot;
954 rmsdav_mat[j][i] = rmsdav_mat[i][j];
955 if (rmsdav_mat[i][j] > rmsd_max)
957 rmsd_max = rmsdav_mat[i][j];
961 rmsd_mat = rmsdav_mat;
966 fprintf(stderr, "\n%s: Min %f, Max %f, Avg %f\n", whatname[ewhat], rmsd_min, rmsd_max, rmsd_avg);
973 if (rmsd_user_max != -1)
975 rmsd_max = rmsd_user_max;
977 if (rmsd_user_min != -1)
979 rmsd_min = rmsd_user_min;
981 if ((rmsd_user_max != -1) || (rmsd_user_min != -1))
983 fprintf(stderr, "Min and Max value set to resp. %f and %f\n", rmsd_min, rmsd_max);
985 sprintf(buf, "%s %s matrix", gn_rms[0], whatname[ewhat]);
986 write_xpm(opt2FILE("-m", NFILE, fnm, "w"),
990 output_env_get_time_label(oenv),
991 output_env_get_time_label(oenv),
1002 /* Print the distribution of RMSD values */
1003 if (opt2bSet("-dist", NFILE, fnm))
1005 low_rmsd_dist(opt2fn("-dist", NFILE, fnm), rmsd_max, tel_mat, rmsd_mat, oenv);
1010 snew(delta_tot, delta_xsize);
1011 for (j = 0; j < tel_mat - 1; j++)
1013 for (i = j + 1; i < tel_mat; i++)
1016 if (mx < tel_mat / 2)
1020 mx = gmx::roundToInt(std::log(static_cast<real>(mx)) * delta_scalex);
1022 my = gmx::roundToInt(rmsd_mat[i][j] * delta_scaley * static_cast<real>(del_lev));
1023 delta_tot[mx] += 1.0;
1024 if ((rmsd_mat[i][j] >= 0) && (rmsd_mat[i][j] <= delta_maxy))
1026 delta[mx][my] += 1.0;
1032 for (i = 0; i < delta_xsize; i++)
1034 if (delta_tot[i] > 0.0)
1036 delta_tot[i] = 1.0 / delta_tot[i];
1037 for (j = 0; j <= del_lev; j++)
1039 delta[i][j] *= delta_tot[i];
1040 if (delta[i][j] > delta_max)
1042 delta_max = delta[i][j];
1047 fprintf(stderr, "Maximum in delta matrix: %f\n", delta_max);
1048 snew(del_xaxis, delta_xsize);
1049 snew(del_yaxis, del_lev + 1);
1050 for (i = 0; i < delta_xsize; i++)
1052 del_xaxis[i] = axis[i] - axis[0];
1054 for (i = 0; i < del_lev + 1; i++)
1056 del_yaxis[i] = delta_maxy * static_cast<real>(i) / static_cast<real>(del_lev);
1058 sprintf(buf, "%s %s vs. delta t", gn_rms[0], whatname[ewhat]);
1059 fp = gmx_ffopen("delta.xpm", "w");
1064 output_env_get_time_label(oenv),
1078 if (opt2bSet("-bin", NFILE, fnm))
1080 /* NB: File must be binary if we use fwrite */
1081 fp = ftp2FILE(efDAT, NFILE, fnm, "wb");
1082 for (i = 0; i < tel_mat; i++)
1084 if (static_cast<int>(fwrite(rmsd_mat[i], sizeof(**rmsd_mat), tel_mat2, fp)) != tel_mat2)
1086 gmx_fatal(FARGS, "Error writing to output file");
1094 fprintf(stderr, "\nMin. angle: %f, Max. angle: %f\n", bond_min, bond_max);
1095 if (bond_user_max != -1)
1097 bond_max = bond_user_max;
1099 if (bond_user_min != -1)
1101 bond_min = bond_user_min;
1103 if ((bond_user_max != -1) || (bond_user_min != -1))
1106 "Bond angle Min and Max set to:\n"
1107 "Min. angle: %f, Max. angle: %f\n",
1117 sprintf(buf, "%s av. bond angle deviation", gn_rms[0]);
1118 write_xpm(opt2FILE("-bm", NFILE, fnm, "w"),
1122 output_env_get_time_label(oenv),
1123 output_env_get_time_label(oenv),
1137 bAv = opt2bSet("-a", NFILE, fnm);
1139 /* Write the RMSD's to file */
1142 sprintf(buf, "%s", whatxvgname[ewhat]);
1147 "%s with frame %g %s ago",
1149 time[prev * freq] - time[0],
1150 output_env_get_time_label(oenv).c_str());
1152 fp = xvgropen(opt2fn("-o", NFILE, fnm), buf, output_env_get_xvgr_tlabel(oenv), whatxvglabel[ewhat], oenv);
1153 if (output_env_get_print_xvgr_codes(oenv))
1156 "@ subtitle \"%s%s after %s%s%s\"\n",
1157 (nrms == 1) ? "" : "of ",
1159 fitgraphlabel[efit],
1161 bFit ? gn_fit : "");
1165 xvgr_legend(fp, nrms, gn_rms, oenv);
1167 for (i = 0; (i < teller); i++)
1169 if (bSplit && i > 0 && std::abs(time[bPrev ? freq * i : i] / output_env_get_time_factor(oenv)) < 1e-5)
1171 fprintf(fp, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
1173 fprintf(fp, "%12.7f", time[bPrev ? freq * i : i]);
1174 for (j = 0; (j < nrms); j++)
1176 fprintf(fp, " %12.7f", rls[j][i]);
1179 rlstot += rls[j][i];
1188 /* Write the mirror RMSD's to file */
1189 sprintf(buf, "%s with Mirror", whatxvgname[ewhat]);
1190 sprintf(buf2, "Mirror %s", whatxvglabel[ewhat]);
1191 fp = xvgropen(opt2fn("-mir", NFILE, fnm), buf, output_env_get_xvgr_tlabel(oenv), buf2, oenv);
1194 if (output_env_get_print_xvgr_codes(oenv))
1196 fprintf(fp, "@ subtitle \"of %s after lsq fit to mirror of %s\"\n", gn_rms[0], bFit ? gn_fit : "");
1201 if (output_env_get_print_xvgr_codes(oenv))
1203 fprintf(fp, "@ subtitle \"after lsq fit to mirror %s\"\n", bFit ? gn_fit : "");
1205 xvgr_legend(fp, nrms, gn_rms, oenv);
1207 for (i = 0; (i < teller); i++)
1209 if (bSplit && i > 0 && std::abs(time[i]) < 1e-5)
1211 fprintf(fp, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
1213 fprintf(fp, "%12.7f", time[i]);
1214 for (j = 0; (j < nrms); j++)
1216 fprintf(fp, " %12.7f", rlsm[j][i]);
1225 sprintf(buf, "Average %s", whatxvgname[ewhat]);
1226 sprintf(buf2, "Average %s", whatxvglabel[ewhat]);
1227 fp = xvgropen(opt2fn("-a", NFILE, fnm), buf, "Residue", buf2, oenv);
1228 for (j = 0; (j < nrms); j++)
1230 fprintf(fp, "%10d %10g\n", j, rlstot / static_cast<real>(teller));
1237 fp = xvgropen("aver.xvg", gn_rms[0], "Residue", whatxvglabel[ewhat], oenv);
1238 for (j = 0; (j < irms[0]); j++)
1240 fprintf(fp, "%10d %10g\n", j, rlsnorm[j] / static_cast<real>(teller));
1244 do_view(oenv, opt2fn_null("-a", NFILE, fnm), "-graphtype bar");
1245 do_view(oenv, opt2fn("-o", NFILE, fnm), nullptr);
1246 do_view(oenv, opt2fn_null("-mir", NFILE, fnm), nullptr);
1247 do_view(oenv, opt2fn_null("-m", NFILE, fnm), nullptr);
1248 do_view(oenv, opt2fn_null("-bm", NFILE, fnm), nullptr);
1249 do_view(oenv, opt2fn_null("-dist", NFILE, fnm), nullptr);