Merge release-4-6 into release-5-0
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_rms.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
10  *
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.
15  *
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.
20  *
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.
25  *
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.
33  *
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.
36  */
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include "gromacs/utility/smalloc.h"
42 #include <math.h>
43 #include "macros.h"
44 #include "typedefs.h"
45 #include "xvgr.h"
46 #include "copyrite.h"
47 #include "gromacs/commandline/pargs.h"
48 #include "vec.h"
49 #include "index.h"
50 #include "gmx_fatal.h"
51 #include "gromacs/fileio/futil.h"
52 #include "princ.h"
53 #include "rmpbc.h"
54 #include "gromacs/fileio/matio.h"
55 #include "gromacs/fileio/tpxio.h"
56 #include "gromacs/fileio/trxio.h"
57 #include "cmat.h"
58 #include "viewit.h"
59 #include "gmx_ana.h"
60
61 #include "gromacs/math/do_fit.h"
62
63 static void norm_princ(t_atoms *atoms, int isize, atom_id *index, int natoms,
64                        rvec *x)
65 {
66     int  i, m;
67     rvec princ, vec;
68
69     /* equalize principal components: */
70     /* orient principal axes, get principal components */
71     orient_princ(atoms, isize, index, natoms, x, NULL, princ);
72
73     /* calc our own principal components */
74     clear_rvec(vec);
75     for (m = 0; m < DIM; m++)
76     {
77         for (i = 0; i < isize; i++)
78         {
79             vec[m] += sqr(x[index[i]][m]);
80         }
81         vec[m] = sqrt(vec[m] / isize);
82         /* calculate scaling constants */
83         vec[m] = 1 / (sqrt(3) * vec[m]);
84     }
85
86     /* scale coordinates */
87     for (i = 0; i < natoms; i++)
88     {
89         for (m = 0; m < DIM; m++)
90         {
91             x[i][m] *= vec[m];
92         }
93     }
94 }
95
96 int gmx_rms(int argc, char *argv[])
97 {
98     const char     *desc[] =
99     {
100         "[THISMODULE] compares two structures by computing the root mean square",
101         "deviation (RMSD), the size-independent [GRK]rho[grk] similarity parameter",
102         "([TT]rho[tt]) or the scaled [GRK]rho[grk] ([TT]rhosc[tt]), ",
103         "see Maiorov & Crippen, Proteins [BB]22[bb], 273 (1995).",
104         "This is selected by [TT]-what[tt].[PAR]"
105
106         "Each structure from a trajectory ([TT]-f[tt]) is compared to a",
107         "reference structure. The reference structure",
108         "is taken from the structure file ([TT]-s[tt]).[PAR]",
109
110         "With option [TT]-mir[tt] also a comparison with the mirror image of",
111         "the reference structure is calculated.",
112         "This is useful as a reference for 'significant' values, see",
113         "Maiorov & Crippen, Proteins [BB]22[bb], 273 (1995).[PAR]",
114
115         "Option [TT]-prev[tt] produces the comparison with a previous frame",
116         "the specified number of frames ago.[PAR]",
117
118         "Option [TT]-m[tt] produces a matrix in [TT].xpm[tt] format of",
119         "comparison values of each structure in the trajectory with respect to",
120         "each other structure. This file can be visualized with for instance",
121         "[TT]xv[tt] and can be converted to postscript with [gmx-xpm2ps].[PAR]",
122
123         "Option [TT]-fit[tt] controls the least-squares fitting of",
124         "the structures on top of each other: complete fit (rotation and",
125         "translation), translation only, or no fitting at all.[PAR]",
126
127         "Option [TT]-mw[tt] controls whether mass weighting is done or not.",
128         "If you select the option (default) and ",
129         "supply a valid [TT].tpr[tt] file masses will be taken from there, ",
130         "otherwise the masses will be deduced from the [TT]atommass.dat[tt] file in",
131         "[TT]GMXLIB[tt]. This is fine for proteins, but not",
132         "necessarily for other molecules. A default mass of 12.011 amu (carbon)",
133         "is assigned to unknown atoms. You can check whether this happend by",
134         "turning on the [TT]-debug[tt] flag and inspecting the log file.[PAR]",
135
136         "With [TT]-f2[tt], the 'other structures' are taken from a second",
137         "trajectory, this generates a comparison matrix of one trajectory",
138         "versus the other.[PAR]",
139
140         "Option [TT]-bin[tt] does a binary dump of the comparison matrix.[PAR]",
141
142         "Option [TT]-bm[tt] produces a matrix of average bond angle deviations",
143         "analogously to the [TT]-m[tt] option. Only bonds between atoms in the",
144         "comparison group are considered."
145     };
146     static gmx_bool bPBC              = TRUE, bFitAll = TRUE, bSplit = FALSE;
147     static gmx_bool bDeltaLog         = FALSE;
148     static int      prev              = 0, freq = 1, freq2 = 1, nlevels = 80, avl = 0;
149     static real     rmsd_user_max     = -1, rmsd_user_min = -1, bond_user_max = -1,
150                     bond_user_min     = -1, delta_maxy = 0.0;
151     /* strings and things for selecting difference method */
152     enum
153     {
154         ewSel, ewRMSD, ewRho, ewRhoSc, ewNR
155     };
156     int         ewhat;
157     const char *what[ewNR + 1] =
158     { NULL, "rmsd", "rho", "rhosc", NULL };
159     const char *whatname[ewNR] =
160     { NULL, "RMSD", "Rho", "Rho sc" };
161     const char *whatlabel[ewNR] =
162     { NULL, "RMSD (nm)", "Rho", "Rho sc" };
163     const char *whatxvgname[ewNR] =
164     { NULL, "RMSD", "\\8r\\4", "\\8r\\4\\ssc\\N" };
165     const char *whatxvglabel[ewNR] =
166     { NULL, "RMSD (nm)", "\\8r\\4", "\\8r\\4\\ssc\\N" };
167     /* strings and things for fitting methods */
168     enum
169     {
170         efSel, efFit, efReset, efNone, efNR
171     };
172     int             efit;
173     const char     *fit[efNR + 1] =
174     { NULL, "rot+trans", "translation", "none", NULL };
175     const char     *fitgraphlabel[efNR + 1] =
176     { NULL, "lsq fit", "translational fit", "no fit" };
177     static int      nrms          = 1;
178     static gmx_bool bMassWeighted = TRUE;
179     t_pargs         pa[]          =
180     {
181         { "-what", FALSE, etENUM,
182           { what }, "Structural difference measure" },
183         { "-pbc", FALSE, etBOOL,
184           { &bPBC }, "PBC check" },
185         { "-fit", FALSE, etENUM,
186           { fit }, "Fit to reference structure" },
187         { "-prev", FALSE, etINT,
188           { &prev }, "Compare with previous frame" },
189         { "-split", FALSE, etBOOL,
190           { &bSplit }, "Split graph where time is zero" },
191         { "-fitall", FALSE, etBOOL,
192           { &bFitAll }, "HIDDENFit all pairs of structures in matrix" },
193         { "-skip", FALSE, etINT,
194           { &freq }, "Only write every nr-th frame to matrix" },
195         { "-skip2", FALSE, etINT,
196           { &freq2 }, "Only write every nr-th frame to matrix" },
197         { "-max", FALSE, etREAL,
198           { &rmsd_user_max }, "Maximum level in comparison matrix" },
199         { "-min", FALSE, etREAL,
200           { &rmsd_user_min }, "Minimum level in comparison matrix" },
201         { "-bmax", FALSE, etREAL,
202           { &bond_user_max }, "Maximum level in bond angle matrix" },
203         { "-bmin", FALSE, etREAL,
204           { &bond_user_min }, "Minimum level in bond angle matrix" },
205         { "-mw", FALSE, etBOOL,
206           { &bMassWeighted }, "Use mass weighting for superposition" },
207         { "-nlevels", FALSE, etINT,
208           { &nlevels }, "Number of levels in the matrices" },
209         { "-ng", FALSE, etINT,
210           { &nrms }, "Number of groups to compute RMS between" },
211         { "-dlog", FALSE, etBOOL,
212           { &bDeltaLog },
213           "HIDDENUse a log x-axis in the delta t matrix" },
214         { "-dmax", FALSE, etREAL,
215           { &delta_maxy }, "HIDDENMaximum level in delta matrix" },
216         { "-aver", FALSE, etINT,
217           { &avl },
218           "HIDDENAverage over this distance in the RMSD matrix" }
219     };
220     int             natoms_trx, natoms_trx2, natoms;
221     int             i, j, k, m, teller, teller2, tel_mat, tel_mat2;
222 #define NFRAME 5000
223     int             maxframe = NFRAME, maxframe2 = NFRAME;
224     real            t, *w_rls, *w_rms, *w_rls_m = NULL, *w_rms_m = NULL;
225     gmx_bool        bNorm, bAv, bFreq2, bFile2, bMat, bBond, bDelta, bMirror, bMass;
226     gmx_bool        bFit, bReset;
227     t_topology      top;
228     int             ePBC;
229     t_iatom        *iatom = NULL;
230
231     matrix          box;
232     rvec           *x, *xp, *xm = NULL, **mat_x = NULL, **mat_x2, *mat_x2_j = NULL, vec1,
233                     vec2;
234     t_trxstatus    *status;
235     char            buf[256], buf2[256];
236     int             ncons = 0;
237     FILE           *fp;
238     real            rlstot = 0, **rls, **rlsm = NULL, *time, *time2, *rlsnorm = NULL,
239     **rmsd_mat             = NULL, **bond_mat = NULL, *axis, *axis2, *del_xaxis,
240     *del_yaxis, rmsd_max, rmsd_min, rmsd_avg, bond_max, bond_min, ang;
241     real       **rmsdav_mat = NULL, av_tot, weight, weight_tot;
242     real       **delta      = NULL, delta_max, delta_scalex = 0, delta_scaley = 0,
243     *delta_tot;
244     int          delta_xsize = 0, del_lev = 100, mx, my, abs_my;
245     gmx_bool     bA1, bA2, bPrev, bTop, *bInMat = NULL;
246     int          ifit, *irms, ibond = 0, *ind_bond1 = NULL, *ind_bond2 = NULL, n_ind_m =
247         0;
248     atom_id     *ind_fit, **ind_rms, *ind_m = NULL, *rev_ind_m = NULL, *ind_rms_m =
249         NULL;
250     char        *gn_fit, **gn_rms;
251     t_rgb        rlo, rhi;
252     output_env_t oenv;
253     gmx_rmpbc_t  gpbc = NULL;
254
255     t_filenm     fnm[] =
256     {
257         { efTPS, NULL, NULL, ffREAD },
258         { efTRX, "-f", NULL, ffREAD },
259         { efTRX, "-f2", NULL, ffOPTRD },
260         { efNDX, NULL, NULL, ffOPTRD },
261         { efXVG, NULL, "rmsd", ffWRITE },
262         { efXVG, "-mir", "rmsdmir", ffOPTWR },
263         { efXVG, "-a", "avgrp", ffOPTWR },
264         { efXVG, "-dist", "rmsd-dist", ffOPTWR },
265         { efXPM, "-m", "rmsd", ffOPTWR },
266         { efDAT, "-bin", "rmsd", ffOPTWR },
267         { efXPM, "-bm", "bond", ffOPTWR }
268     };
269 #define NFILE asize(fnm)
270
271     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW
272                            | PCA_BE_NICE, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL,
273                            &oenv))
274     {
275         return 0;
276     }
277     /* parse enumerated options: */
278     ewhat = nenum(what);
279     if (ewhat == ewRho || ewhat == ewRhoSc)
280     {
281         please_cite(stdout, "Maiorov95");
282     }
283     efit   = nenum(fit);
284     bFit   = efit == efFit;
285     bReset = efit == efReset;
286     if (bFit)
287     {
288         bReset = TRUE; /* for fit, reset *must* be set */
289     }
290     else
291     {
292         bFitAll = FALSE;
293     }
294
295     /* mark active cmdline options */
296     bMirror = opt2bSet("-mir", NFILE, fnm); /* calc RMSD vs mirror of ref. */
297     bFile2  = opt2bSet("-f2", NFILE, fnm);
298     bMat    = opt2bSet("-m", NFILE, fnm);
299     bBond   = opt2bSet("-bm", NFILE, fnm);
300     bDelta  = (delta_maxy > 0); /* calculate rmsd vs delta t matrix from *
301                                  *      your RMSD matrix (hidden option       */
302     bNorm   = opt2bSet("-a", NFILE, fnm);
303     bFreq2  = opt2parg_bSet("-skip2", asize(pa), pa);
304     if (freq <= 0)
305     {
306         fprintf(stderr, "The number of frames to skip is <= 0. "
307                 "Writing out all frames.\n\n");
308         freq = 1;
309     }
310     if (!bFreq2)
311     {
312         freq2 = freq;
313     }
314     else if (bFile2 && freq2 <= 0)
315     {
316         fprintf(stderr,
317                 "The number of frames to skip in second trajectory is <= 0.\n"
318                 "  Writing out all frames.\n\n");
319         freq2 = 1;
320     }
321
322     bPrev = (prev > 0);
323     if (bPrev)
324     {
325         prev = abs(prev);
326         if (freq != 1)
327         {
328             fprintf(stderr, "WARNING: option -skip also applies to -prev\n");
329         }
330     }
331
332     if (bFile2 && !bMat && !bBond)
333     {
334         fprintf(
335                 stderr,
336                 "WARNING: second trajectory (-f2) useless when not calculating matrix (-m/-bm),\n"
337                 "         will not read from %s\n", opt2fn("-f2", NFILE,
338                                                            fnm));
339         bFile2 = FALSE;
340     }
341
342     if (bDelta)
343     {
344         bMat = TRUE;
345         if (bFile2)
346         {
347             fprintf(stderr,
348                     "WARNING: second trajectory (-f2) useless when making delta matrix,\n"
349                     "         will not read from %s\n", opt2fn("-f2",
350                                                                NFILE, fnm));
351             bFile2 = FALSE;
352         }
353     }
354
355     bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), buf, &top, &ePBC, &xp,
356                          NULL, box, TRUE);
357     snew(w_rls, top.atoms.nr);
358     snew(w_rms, top.atoms.nr);
359
360     if (!bTop && bBond)
361     {
362         fprintf(stderr,
363                 "WARNING: Need a run input file for bond angle matrix,\n"
364                 "         will not calculate bond angle matrix.\n");
365         bBond = FALSE;
366     }
367
368     if (bReset)
369     {
370         fprintf(stderr, "Select group for %s fit\n", bFit ? "least squares"
371                 : "translational");
372         get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &ifit,
373                   &ind_fit, &gn_fit);
374     }
375     else
376     {
377         ifit = 0;
378     }
379
380     if (bReset)
381     {
382         if (bFit && ifit < 3)
383         {
384             gmx_fatal(FARGS, "Need >= 3 points to fit!\n" );
385         }
386
387         bMass = FALSE;
388         for (i = 0; i < ifit; i++)
389         {
390             if (bMassWeighted)
391             {
392                 w_rls[ind_fit[i]] = top.atoms.atom[ind_fit[i]].m;
393             }
394             else
395             {
396                 w_rls[ind_fit[i]] = 1;
397             }
398             bMass = bMass || (top.atoms.atom[ind_fit[i]].m != 0);
399         }
400         if (!bMass)
401         {
402             fprintf(stderr, "All masses in the fit group are 0, using masses of 1\n");
403             for (i = 0; i < ifit; i++)
404             {
405                 w_rls[ind_fit[i]] = 1;
406             }
407         }
408     }
409
410     if (bMat || bBond)
411     {
412         nrms = 1;
413     }
414
415     snew(gn_rms, nrms);
416     snew(ind_rms, nrms);
417     snew(irms, nrms);
418
419     fprintf(stderr, "Select group%s for %s calculation\n",
420             (nrms > 1) ? "s" : "", whatname[ewhat]);
421     get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm),
422               nrms, irms, ind_rms, gn_rms);
423
424     if (bNorm)
425     {
426         snew(rlsnorm, irms[0]);
427     }
428     snew(rls, nrms);
429     for (j = 0; j < nrms; j++)
430     {
431         snew(rls[j], maxframe);
432     }
433     if (bMirror)
434     {
435         snew(rlsm, nrms);
436         for (j = 0; j < nrms; j++)
437         {
438             snew(rlsm[j], maxframe);
439         }
440     }
441     snew(time, maxframe);
442     for (j = 0; j < nrms; j++)
443     {
444         bMass = FALSE;
445         for (i = 0; i < irms[j]; i++)
446         {
447             if (bMassWeighted)
448             {
449                 w_rms[ind_rms[j][i]] = top.atoms.atom[ind_rms[j][i]].m;
450             }
451             else
452             {
453                 w_rms[ind_rms[j][i]] = 1.0;
454             }
455             bMass = bMass || (top.atoms.atom[ind_rms[j][i]].m != 0);
456         }
457         if (!bMass)
458         {
459             fprintf(stderr, "All masses in group %d are 0, using masses of 1\n", j);
460             for (i = 0; i < irms[j]; i++)
461             {
462                 w_rms[ind_rms[j][i]] = 1;
463             }
464         }
465     }
466     /* Prepare reference frame */
467     if (bPBC)
468     {
469         gpbc = gmx_rmpbc_init(&top.idef, ePBC, top.atoms.nr);
470         gmx_rmpbc(gpbc, top.atoms.nr, box, xp);
471     }
472     if (bReset)
473     {
474         reset_x(ifit, ind_fit, top.atoms.nr, NULL, xp, w_rls);
475     }
476     if (bMirror)
477     {
478         /* generate reference structure mirror image: */
479         snew(xm, top.atoms.nr);
480         for (i = 0; i < top.atoms.nr; i++)
481         {
482             copy_rvec(xp[i], xm[i]);
483             xm[i][XX] = -xm[i][XX];
484         }
485     }
486     if (ewhat == ewRhoSc)
487     {
488         norm_princ(&top.atoms, ifit, ind_fit, top.atoms.nr, xp);
489     }
490
491     /* read first frame */
492     natoms_trx = read_first_x(oenv, &status, opt2fn("-f", NFILE, fnm), &t, &x, box);
493     if (natoms_trx != top.atoms.nr)
494     {
495         fprintf(stderr,
496                 "\nWARNING: topology has %d atoms, whereas trajectory has %d\n",
497                 top.atoms.nr, natoms_trx);
498     }
499     natoms = min(top.atoms.nr, natoms_trx);
500     if (bMat || bBond || bPrev)
501     {
502         snew(mat_x, NFRAME);
503
504         if (bPrev)
505         {
506             /* With -prev we use all atoms for simplicity */
507             n_ind_m = natoms;
508         }
509         else
510         {
511             /* Check which atoms we need (fit/rms) */
512             snew(bInMat, natoms);
513             for (i = 0; i < ifit; i++)
514             {
515                 bInMat[ind_fit[i]] = TRUE;
516             }
517             n_ind_m = ifit;
518             for (i = 0; i < irms[0]; i++)
519             {
520                 if (!bInMat[ind_rms[0][i]])
521                 {
522                     bInMat[ind_rms[0][i]] = TRUE;
523                     n_ind_m++;
524                 }
525             }
526         }
527         /* Make an index of needed atoms */
528         snew(ind_m, n_ind_m);
529         snew(rev_ind_m, natoms);
530         j = 0;
531         for (i = 0; i < natoms; i++)
532         {
533             if (bPrev || bInMat[i])
534             {
535                 ind_m[j]     = i;
536                 rev_ind_m[i] = j;
537                 j++;
538             }
539         }
540         snew(w_rls_m, n_ind_m);
541         snew(ind_rms_m, irms[0]);
542         snew(w_rms_m, n_ind_m);
543         for (i = 0; i < ifit; i++)
544         {
545             w_rls_m[rev_ind_m[ind_fit[i]]] = w_rls[ind_fit[i]];
546         }
547         for (i = 0; i < irms[0]; i++)
548         {
549             ind_rms_m[i]          = rev_ind_m[ind_rms[0][i]];
550             w_rms_m[ind_rms_m[i]] = w_rms[ind_rms[0][i]];
551         }
552         sfree(bInMat);
553     }
554
555     if (bBond)
556     {
557         ncons = 0;
558         for (k = 0; k < F_NRE; k++)
559         {
560             if (IS_CHEMBOND(k))
561             {
562                 iatom  = top.idef.il[k].iatoms;
563                 ncons += top.idef.il[k].nr/3;
564             }
565         }
566         fprintf(stderr, "Found %d bonds in topology\n", ncons);
567         snew(ind_bond1, ncons);
568         snew(ind_bond2, ncons);
569         ibond = 0;
570         for (k = 0; k < F_NRE; k++)
571         {
572             if (IS_CHEMBOND(k))
573             {
574                 iatom = top.idef.il[k].iatoms;
575                 ncons = top.idef.il[k].nr/3;
576                 for (i = 0; i < ncons; i++)
577                 {
578                     bA1 = FALSE;
579                     bA2 = FALSE;
580                     for (j = 0; j < irms[0]; j++)
581                     {
582                         if (iatom[3*i+1] == ind_rms[0][j])
583                         {
584                             bA1 = TRUE;
585                         }
586                         if (iatom[3*i+2] == ind_rms[0][j])
587                         {
588                             bA2 = TRUE;
589                         }
590                     }
591                     if (bA1 && bA2)
592                     {
593                         ind_bond1[ibond] = rev_ind_m[iatom[3*i+1]];
594                         ind_bond2[ibond] = rev_ind_m[iatom[3*i+2]];
595                         ibond++;
596                     }
597                 }
598             }
599         }
600         fprintf(stderr, "Using %d bonds for bond angle matrix\n", ibond);
601         if (ibond == 0)
602         {
603             gmx_fatal(FARGS, "0 bonds found");
604         }
605     }
606
607     /* start looping over frames: */
608     tel_mat = 0;
609     teller  = 0;
610     do
611     {
612         if (bPBC)
613         {
614             gmx_rmpbc(gpbc, natoms, box, x);
615         }
616
617         if (bReset)
618         {
619             reset_x(ifit, ind_fit, natoms, NULL, x, w_rls);
620         }
621         if (ewhat == ewRhoSc)
622         {
623             norm_princ(&top.atoms, ifit, ind_fit, natoms, x);
624         }
625
626         if (bFit)
627         {
628             /*do the least squares fit to original structure*/
629             do_fit(natoms, w_rls, xp, x);
630         }
631
632         if (teller % freq == 0)
633         {
634             /* keep frame for matrix calculation */
635             if (bMat || bBond || bPrev)
636             {
637                 if (tel_mat >= NFRAME)
638                 {
639                     srenew(mat_x, tel_mat+1);
640                 }
641                 snew(mat_x[tel_mat], n_ind_m);
642                 for (i = 0; i < n_ind_m; i++)
643                 {
644                     copy_rvec(x[ind_m[i]], mat_x[tel_mat][i]);
645                 }
646             }
647             tel_mat++;
648         }
649
650         /*calculate energy of root_least_squares*/
651         if (bPrev)
652         {
653             j = tel_mat-prev-1;
654             if (j < 0)
655             {
656                 j = 0;
657             }
658             for (i = 0; i < n_ind_m; i++)
659             {
660                 copy_rvec(mat_x[j][i], xp[ind_m[i]]);
661             }
662             if (bReset)
663             {
664                 reset_x(ifit, ind_fit, natoms, NULL, xp, w_rls);
665             }
666             if (bFit)
667             {
668                 do_fit(natoms, w_rls, x, xp);
669             }
670         }
671         for (j = 0; (j < nrms); j++)
672         {
673             rls[j][teller] =
674                 calc_similar_ind(ewhat != ewRMSD, irms[j], ind_rms[j], w_rms, x, xp);
675         }
676         if (bNorm)
677         {
678             for (j = 0; (j < irms[0]); j++)
679             {
680                 rlsnorm[j] +=
681                     calc_similar_ind(ewhat != ewRMSD, 1, &(ind_rms[0][j]), w_rms, x, xp);
682             }
683         }
684
685         if (bMirror)
686         {
687             if (bFit)
688             {
689                 /*do the least squares fit to mirror of original structure*/
690                 do_fit(natoms, w_rls, xm, x);
691             }
692
693             for (j = 0; j < nrms; j++)
694             {
695                 rlsm[j][teller] =
696                     calc_similar_ind(ewhat != ewRMSD, irms[j], ind_rms[j], w_rms, x, xm);
697             }
698         }
699         time[teller] = output_env_conv_time(oenv, t);
700
701         teller++;
702         if (teller >= maxframe)
703         {
704             maxframe += NFRAME;
705             srenew(time, maxframe);
706             for (j = 0; (j < nrms); j++)
707             {
708                 srenew(rls[j], maxframe);
709             }
710             if (bMirror)
711             {
712                 for (j = 0; (j < nrms); j++)
713                 {
714                     srenew(rlsm[j], maxframe);
715                 }
716             }
717         }
718     }
719     while (read_next_x(oenv, status, &t, x, box));
720     close_trj(status);
721
722     if (bFile2)
723     {
724         snew(time2, maxframe2);
725
726         fprintf(stderr, "\nWill read second trajectory file\n");
727         snew(mat_x2, NFRAME);
728         natoms_trx2 =
729             read_first_x(oenv, &status, opt2fn("-f2", NFILE, fnm), &t, &x, box);
730         if (natoms_trx2 != natoms_trx)
731         {
732             gmx_fatal(FARGS,
733                       "Second trajectory (%d atoms) does not match the first one"
734                       " (%d atoms)", natoms_trx2, natoms_trx);
735         }
736         tel_mat2 = 0;
737         teller2  = 0;
738         do
739         {
740             if (bPBC)
741             {
742                 gmx_rmpbc(gpbc, natoms, box, x);
743             }
744
745             if (bReset)
746             {
747                 reset_x(ifit, ind_fit, natoms, NULL, x, w_rls);
748             }
749             if (ewhat == ewRhoSc)
750             {
751                 norm_princ(&top.atoms, ifit, ind_fit, natoms, x);
752             }
753
754             if (bFit)
755             {
756                 /*do the least squares fit to original structure*/
757                 do_fit(natoms, w_rls, xp, x);
758             }
759
760             if (teller2 % freq2 == 0)
761             {
762                 /* keep frame for matrix calculation */
763                 if (bMat)
764                 {
765                     if (tel_mat2 >= NFRAME)
766                     {
767                         srenew(mat_x2, tel_mat2+1);
768                     }
769                     snew(mat_x2[tel_mat2], n_ind_m);
770                     for (i = 0; i < n_ind_m; i++)
771                     {
772                         copy_rvec(x[ind_m[i]], mat_x2[tel_mat2][i]);
773                     }
774                 }
775                 tel_mat2++;
776             }
777
778             time2[teller2] = output_env_conv_time(oenv, t);
779
780             teller2++;
781             if (teller2 >= maxframe2)
782             {
783                 maxframe2 += NFRAME;
784                 srenew(time2, maxframe2);
785             }
786         }
787         while (read_next_x(oenv, status, &t, x, box));
788         close_trj(status);
789     }
790     else
791     {
792         mat_x2   = mat_x;
793         time2    = time;
794         tel_mat2 = tel_mat;
795         freq2    = freq;
796     }
797     gmx_rmpbc_done(gpbc);
798
799     if (bMat || bBond)
800     {
801         /* calculate RMS matrix */
802         fprintf(stderr, "\n");
803         if (bMat)
804         {
805             fprintf(stderr, "Building %s matrix, %dx%d elements\n",
806                     whatname[ewhat], tel_mat, tel_mat2);
807             snew(rmsd_mat, tel_mat);
808         }
809         if (bBond)
810         {
811             fprintf(stderr, "Building bond angle matrix, %dx%d elements\n",
812                     tel_mat, tel_mat2);
813             snew(bond_mat, tel_mat);
814         }
815         snew(axis, tel_mat);
816         snew(axis2, tel_mat2);
817         rmsd_max = 0;
818         if (bFile2)
819         {
820             rmsd_min = 1e10;
821         }
822         else
823         {
824             rmsd_min = 0;
825         }
826         rmsd_avg = 0;
827         bond_max = 0;
828         bond_min = 1e10;
829         for (j = 0; j < tel_mat2; j++)
830         {
831             axis2[j] = time2[freq2*j];
832         }
833         if (bDelta)
834         {
835             if (bDeltaLog)
836             {
837                 delta_scalex = 8.0/log(2.0);
838                 delta_xsize  = (int)(log(tel_mat/2)*delta_scalex+0.5)+1;
839             }
840             else
841             {
842                 delta_xsize = tel_mat/2;
843             }
844             delta_scaley = 1.0/delta_maxy;
845             snew(delta, delta_xsize);
846             for (j = 0; j < delta_xsize; j++)
847             {
848                 snew(delta[j], del_lev+1);
849             }
850             if (avl > 0)
851             {
852                 snew(rmsdav_mat, tel_mat);
853                 for (j = 0; j < tel_mat; j++)
854                 {
855                     snew(rmsdav_mat[j], tel_mat);
856                 }
857             }
858         }
859
860         if (bFitAll)
861         {
862             snew(mat_x2_j, natoms);
863         }
864         for (i = 0; i < tel_mat; i++)
865         {
866             axis[i] = time[freq*i];
867             fprintf(stderr, "\r element %5d; time %5.2f  ", i, axis[i]);
868             if (bMat)
869             {
870                 snew(rmsd_mat[i], tel_mat2);
871             }
872             if (bBond)
873             {
874                 snew(bond_mat[i], tel_mat2);
875             }
876             for (j = 0; j < tel_mat2; j++)
877             {
878                 if (bFitAll)
879                 {
880                     for (k = 0; k < n_ind_m; k++)
881                     {
882                         copy_rvec(mat_x2[j][k], mat_x2_j[k]);
883                     }
884                     do_fit(n_ind_m, w_rls_m, mat_x[i], mat_x2_j);
885                 }
886                 else
887                 {
888                     mat_x2_j = mat_x2[j];
889                 }
890                 if (bMat)
891                 {
892                     if (bFile2 || (i < j))
893                     {
894                         rmsd_mat[i][j] =
895                             calc_similar_ind(ewhat != ewRMSD, irms[0], ind_rms_m,
896                                              w_rms_m, mat_x[i], mat_x2_j);
897                         if (rmsd_mat[i][j] > rmsd_max)
898                         {
899                             rmsd_max = rmsd_mat[i][j];
900                         }
901                         if (rmsd_mat[i][j] < rmsd_min)
902                         {
903                             rmsd_min = rmsd_mat[i][j];
904                         }
905                         rmsd_avg += rmsd_mat[i][j];
906                     }
907                     else
908                     {
909                         rmsd_mat[i][j] = rmsd_mat[j][i];
910                     }
911                 }
912                 if (bBond)
913                 {
914                     if (bFile2 || (i <= j))
915                     {
916                         ang = 0.0;
917                         for (m = 0; m < ibond; m++)
918                         {
919                             rvec_sub(mat_x[i][ind_bond1[m]], mat_x[i][ind_bond2[m]], vec1);
920                             rvec_sub(mat_x2_j[ind_bond1[m]], mat_x2_j[ind_bond2[m]], vec2);
921                             ang += acos(cos_angle(vec1, vec2));
922                         }
923                         bond_mat[i][j] = ang*180.0/(M_PI*ibond);
924                         if (bond_mat[i][j] > bond_max)
925                         {
926                             bond_max = bond_mat[i][j];
927                         }
928                         if (bond_mat[i][j] < bond_min)
929                         {
930                             bond_min = bond_mat[i][j];
931                         }
932                     }
933                     else
934                     {
935                         bond_mat[i][j] = bond_mat[j][i];
936                     }
937                 }
938             }
939         }
940         if (bFile2)
941         {
942             rmsd_avg /= tel_mat*tel_mat2;
943         }
944         else
945         {
946             rmsd_avg /= tel_mat*(tel_mat - 1)/2;
947         }
948         if (bMat && (avl > 0))
949         {
950             rmsd_max = 0.0;
951             rmsd_min = 0.0;
952             rmsd_avg = 0.0;
953             for (j = 0; j < tel_mat-1; j++)
954             {
955                 for (i = j+1; i < tel_mat; i++)
956                 {
957                     av_tot     = 0;
958                     weight_tot = 0;
959                     for (my = -avl; my <= avl; my++)
960                     {
961                         if ((j+my >= 0) && (j+my < tel_mat))
962                         {
963                             abs_my = abs(my);
964                             for (mx = -avl; mx <= avl; mx++)
965                             {
966                                 if ((i+mx >= 0) && (i+mx < tel_mat))
967                                 {
968                                     weight      = (real)(avl+1-max(abs(mx), abs_my));
969                                     av_tot     += weight*rmsd_mat[i+mx][j+my];
970                                     weight_tot += weight;
971                                 }
972                             }
973                         }
974                     }
975                     rmsdav_mat[i][j] = av_tot/weight_tot;
976                     rmsdav_mat[j][i] = rmsdav_mat[i][j];
977                     if (rmsdav_mat[i][j] > rmsd_max)
978                     {
979                         rmsd_max = rmsdav_mat[i][j];
980                     }
981                 }
982             }
983             rmsd_mat = rmsdav_mat;
984         }
985
986         if (bMat)
987         {
988             fprintf(stderr, "\n%s: Min %f, Max %f, Avg %f\n",
989                     whatname[ewhat], rmsd_min, rmsd_max, rmsd_avg);
990             rlo.r = 1; rlo.g = 1; rlo.b = 1;
991             rhi.r = 0; rhi.g = 0; rhi.b = 0;
992             if (rmsd_user_max != -1)
993             {
994                 rmsd_max = rmsd_user_max;
995             }
996             if (rmsd_user_min != -1)
997             {
998                 rmsd_min = rmsd_user_min;
999             }
1000             if ((rmsd_user_max !=  -1) || (rmsd_user_min != -1))
1001             {
1002                 fprintf(stderr, "Min and Max value set to resp. %f and %f\n",
1003                         rmsd_min, rmsd_max);
1004             }
1005             sprintf(buf, "%s %s matrix", gn_rms[0], whatname[ewhat]);
1006             write_xpm(opt2FILE("-m", NFILE, fnm, "w"), 0, buf, whatlabel[ewhat],
1007                       output_env_get_time_label(oenv), output_env_get_time_label(oenv), tel_mat, tel_mat2,
1008                       axis, axis2, rmsd_mat, rmsd_min, rmsd_max, rlo, rhi, &nlevels);
1009             /* Print the distribution of RMSD values */
1010             if (opt2bSet("-dist", NFILE, fnm))
1011             {
1012                 low_rmsd_dist(opt2fn("-dist", NFILE, fnm), rmsd_max, tel_mat, rmsd_mat, oenv);
1013             }
1014
1015             if (bDelta)
1016             {
1017                 snew(delta_tot, delta_xsize);
1018                 for (j = 0; j < tel_mat-1; j++)
1019                 {
1020                     for (i = j+1; i < tel_mat; i++)
1021                     {
1022                         mx = i-j;
1023                         if (mx < tel_mat/2)
1024                         {
1025                             if (bDeltaLog)
1026                             {
1027                                 mx = (int)(log(mx)*delta_scalex+0.5);
1028                             }
1029                             my             = (int)(rmsd_mat[i][j]*delta_scaley*del_lev+0.5);
1030                             delta_tot[mx] += 1.0;
1031                             if ((rmsd_mat[i][j] >= 0) && (rmsd_mat[i][j] <= delta_maxy))
1032                             {
1033                                 delta[mx][my] += 1.0;
1034                             }
1035                         }
1036                     }
1037                 }
1038                 delta_max = 0;
1039                 for (i = 0; i < delta_xsize; i++)
1040                 {
1041                     if (delta_tot[i] > 0.0)
1042                     {
1043                         delta_tot[i] = 1.0/delta_tot[i];
1044                         for (j = 0; j <= del_lev; j++)
1045                         {
1046                             delta[i][j] *= delta_tot[i];
1047                             if (delta[i][j] > delta_max)
1048                             {
1049                                 delta_max = delta[i][j];
1050                             }
1051                         }
1052                     }
1053                 }
1054                 fprintf(stderr, "Maximum in delta matrix: %f\n", delta_max);
1055                 snew(del_xaxis, delta_xsize);
1056                 snew(del_yaxis, del_lev+1);
1057                 for (i = 0; i < delta_xsize; i++)
1058                 {
1059                     del_xaxis[i] = axis[i]-axis[0];
1060                 }
1061                 for (i = 0; i < del_lev+1; i++)
1062                 {
1063                     del_yaxis[i] = delta_maxy*i/del_lev;
1064                 }
1065                 sprintf(buf, "%s %s vs. delta t", gn_rms[0], whatname[ewhat]);
1066                 fp = gmx_ffopen("delta.xpm", "w");
1067                 write_xpm(fp, 0, buf, "density", output_env_get_time_label(oenv), whatlabel[ewhat],
1068                           delta_xsize, del_lev+1, del_xaxis, del_yaxis,
1069                           delta, 0.0, delta_max, rlo, rhi, &nlevels);
1070                 gmx_ffclose(fp);
1071             }
1072             if (opt2bSet("-bin", NFILE, fnm))
1073             {
1074                 /* NB: File must be binary if we use fwrite */
1075                 fp = ftp2FILE(efDAT, NFILE, fnm, "wb");
1076                 for (i = 0; i < tel_mat; i++)
1077                 {
1078                     if (fwrite(rmsd_mat[i], sizeof(**rmsd_mat), tel_mat2, fp) != tel_mat2)
1079                     {
1080                         gmx_fatal(FARGS, "Error writing to output file");
1081                     }
1082                 }
1083                 gmx_ffclose(fp);
1084             }
1085         }
1086         if (bBond)
1087         {
1088             fprintf(stderr, "\nMin. angle: %f, Max. angle: %f\n", bond_min, bond_max);
1089             if (bond_user_max != -1)
1090             {
1091                 bond_max = bond_user_max;
1092             }
1093             if (bond_user_min != -1)
1094             {
1095                 bond_min = bond_user_min;
1096             }
1097             if ((bond_user_max !=  -1) || (bond_user_min != -1))
1098             {
1099                 fprintf(stderr, "Bond angle Min and Max set to:\n"
1100                         "Min. angle: %f, Max. angle: %f\n", bond_min, bond_max);
1101             }
1102             rlo.r = 1; rlo.g = 1; rlo.b = 1;
1103             rhi.r = 0; rhi.g = 0; rhi.b = 0;
1104             sprintf(buf, "%s av. bond angle deviation", gn_rms[0]);
1105             write_xpm(opt2FILE("-bm", NFILE, fnm, "w"), 0, buf, "degrees",
1106                       output_env_get_time_label(oenv), output_env_get_time_label(oenv), tel_mat, tel_mat2,
1107                       axis, axis2, bond_mat, bond_min, bond_max, rlo, rhi, &nlevels);
1108         }
1109     }
1110
1111     bAv = opt2bSet("-a", NFILE, fnm);
1112
1113     /* Write the RMSD's to file */
1114     if (!bPrev)
1115     {
1116         sprintf(buf, "%s", whatxvgname[ewhat]);
1117     }
1118     else
1119     {
1120         sprintf(buf, "%s with frame %g %s ago", whatxvgname[ewhat],
1121                 time[prev*freq]-time[0], output_env_get_time_label(oenv));
1122     }
1123     fp = xvgropen(opt2fn("-o", NFILE, fnm), buf, output_env_get_xvgr_tlabel(oenv),
1124                   whatxvglabel[ewhat], oenv);
1125     if (output_env_get_print_xvgr_codes(oenv))
1126     {
1127         fprintf(fp, "@ subtitle \"%s%s after %s%s%s\"\n",
1128                 (nrms == 1) ? "" : "of ", gn_rms[0], fitgraphlabel[efit],
1129                 bFit     ? " to " : "", bFit ? gn_fit : "");
1130     }
1131     if (nrms != 1)
1132     {
1133         xvgr_legend(fp, nrms, (const char**)gn_rms, oenv);
1134     }
1135     for (i = 0; (i < teller); i++)
1136     {
1137         if (bSplit && i > 0 &&
1138             fabs(time[bPrev ? freq*i : i]/output_env_get_time_factor(oenv)) < 1e-5)
1139         {
1140             fprintf(fp, "&\n");
1141         }
1142         fprintf(fp, "%12.7f", time[bPrev ? freq*i : i]);
1143         for (j = 0; (j < nrms); j++)
1144         {
1145             fprintf(fp, " %12.7f", rls[j][i]);
1146             if (bAv)
1147             {
1148                 rlstot += rls[j][i];
1149             }
1150         }
1151         fprintf(fp, "\n");
1152     }
1153     gmx_ffclose(fp);
1154
1155     if (bMirror)
1156     {
1157         /* Write the mirror RMSD's to file */
1158         sprintf(buf, "%s with Mirror", whatxvgname[ewhat]);
1159         sprintf(buf2, "Mirror %s", whatxvglabel[ewhat]);
1160         fp = xvgropen(opt2fn("-mir", NFILE, fnm), buf, output_env_get_xvgr_tlabel(oenv),
1161                       buf2, oenv);
1162         if (nrms == 1)
1163         {
1164             if (output_env_get_print_xvgr_codes(oenv))
1165             {
1166                 fprintf(fp, "@ subtitle \"of %s after lsq fit to mirror of %s\"\n",
1167                         gn_rms[0], gn_fit);
1168             }
1169         }
1170         else
1171         {
1172             if (output_env_get_print_xvgr_codes(oenv))
1173             {
1174                 fprintf(fp, "@ subtitle \"after lsq fit to mirror %s\"\n", gn_fit);
1175             }
1176             xvgr_legend(fp, nrms, (const char**)gn_rms, oenv);
1177         }
1178         for (i = 0; (i < teller); i++)
1179         {
1180             if (bSplit && i > 0 && fabs(time[i]) < 1e-5)
1181             {
1182                 fprintf(fp, "&\n");
1183             }
1184             fprintf(fp, "%12.7f", time[i]);
1185             for (j = 0; (j < nrms); j++)
1186             {
1187                 fprintf(fp, " %12.7f", rlsm[j][i]);
1188             }
1189             fprintf(fp, "\n");
1190         }
1191         gmx_ffclose(fp);
1192     }
1193
1194     if (bAv)
1195     {
1196         sprintf(buf, "Average %s", whatxvgname[ewhat]);
1197         sprintf(buf2, "Average %s", whatxvglabel[ewhat]);
1198         fp = xvgropen(opt2fn("-a", NFILE, fnm), buf, "Residue", buf2, oenv);
1199         for (j = 0; (j < nrms); j++)
1200         {
1201             fprintf(fp, "%10d  %10g\n", j, rlstot/teller);
1202         }
1203         gmx_ffclose(fp);
1204     }
1205
1206     if (bNorm)
1207     {
1208         fp = xvgropen("aver.xvg", gn_rms[0], "Residue", whatxvglabel[ewhat], oenv);
1209         for (j = 0; (j < irms[0]); j++)
1210         {
1211             fprintf(fp, "%10d  %10g\n", j, rlsnorm[j]/teller);
1212         }
1213         gmx_ffclose(fp);
1214     }
1215     do_view(oenv, opt2fn_null("-a", NFILE, fnm), "-graphtype bar");
1216     do_view(oenv, opt2fn("-o", NFILE, fnm), NULL);
1217     do_view(oenv, opt2fn_null("-mir", NFILE, fnm), NULL);
1218     do_view(oenv, opt2fn_null("-m", NFILE, fnm), NULL);
1219     do_view(oenv, opt2fn_null("-bm", NFILE, fnm), NULL);
1220     do_view(oenv, opt2fn_null("-dist", NFILE, fnm), NULL);
1221
1222     return 0;
1223 }