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