a363bb4a29b33c1f251b12136aff9378fcbd0e7d
[alexxy/gromacs.git] / src / tools / 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             vec[m] += sqr(x[index[i]][m]);
77         vec[m] = sqrt(vec[m] / isize);
78         /* calculate scaling constants */
79         vec[m] = 1 / (sqrt(3) * vec[m]);
80     }
81
82     /* scale coordinates */
83     for (i = 0; i < natoms; i++)
84     {
85         for (m = 0; m < DIM; m++)
86         {
87             x[i][m] *= vec[m];
88         }
89     }
90 }
91
92 int gmx_rms(int argc, char *argv[])
93 {
94     const char
95         *desc[] =
96             {
97                 "[TT]g_rms[tt] compares two structures by computing the root mean square",
98                 "deviation (RMSD), the size-independent 'rho' similarity parameter",
99                 "(rho) or the scaled rho (rhosc), ",
100                 "see Maiorov & Crippen, PROTEINS [BB]22[bb], 273 (1995).",
101                 "This is selected by [TT]-what[tt].[PAR]"
102
103                     "Each structure from a trajectory ([TT]-f[tt]) is compared to a",
104                 "reference structure. The reference structure",
105                 "is taken from the structure file ([TT]-s[tt]).[PAR]",
106
107                 "With option [TT]-mir[tt] also a comparison with the mirror image of",
108                 "the reference structure is calculated.",
109                 "This is useful as a reference for 'significant' values, see",
110                 "Maiorov & Crippen, PROTEINS [BB]22[bb], 273 (1995).[PAR]",
111
112                 "Option [TT]-prev[tt] produces the comparison with a previous frame",
113                 "the specified number of frames ago.[PAR]",
114
115                 "Option [TT]-m[tt] produces a matrix in [TT].xpm[tt] format of",
116                 "comparison values of each structure in the trajectory with respect to",
117                 "each other structure. This file can be visualized with for instance",
118                 "[TT]xv[tt] and can be converted to postscript with [TT]xpm2ps[tt].[PAR]",
119
120                 "Option [TT]-fit[tt] controls the least-squares fitting of",
121                 "the structures on top of each other: complete fit (rotation and",
122                 "translation), translation only, or no fitting at all.[PAR]",
123
124                 "Option [TT]-mw[tt] controls whether mass weighting is done or not.",
125                 "If you select the option (default) and ",
126                 "supply a valid [TT].tpr[tt] file masses will be taken from there, ",
127                 "otherwise the masses will be deduced from the atommass.dat file in",
128                 "the GROMACS library directory. This is fine for proteins but not",
129                 "necessarily for other molecules. A default mass of 12.011 amu (Carbon)",
130                 "is assigned to unknown atoms. You can check whether this happend by",
131                 "turning on the [TT]-debug[tt] flag and inspecting the log file.[PAR]",
132
133                 "With [TT]-f2[tt], the 'other structures' are taken from a second",
134                 "trajectory, this generates a comparison matrix of one trajectory",
135                 "versus the other.[PAR]",
136
137                 "Option [TT]-bin[tt] does a binary dump of the comparison matrix.[PAR]",
138
139                 "Option [TT]-bm[tt] produces a matrix of average bond angle deviations",
140                 "analogously to the [TT]-m[tt] option. Only bonds between atoms in the",
141                 "comparison group are considered." };
142     static gmx_bool bPBC = TRUE, bFitAll = TRUE, bSplit = FALSE;
143     static gmx_bool bDeltaLog = FALSE;
144     static int prev = 0, freq = 1, freq2 = 1, nlevels = 80, avl = 0;
145     static real rmsd_user_max = -1, rmsd_user_min = -1, bond_user_max = -1,
146         bond_user_min = -1, delta_maxy = 0.0;
147     /* strings and things for selecting difference method */
148     enum
149     {
150         ewSel, ewRMSD, ewRho, ewRhoSc, ewNR
151     };
152     int ewhat;
153     const char *what[ewNR + 1] =
154         { NULL, "rmsd", "rho", "rhosc", NULL };
155     const char *whatname[ewNR] =
156         { NULL, "RMSD", "Rho", "Rho sc" };
157     const char *whatlabel[ewNR] =
158         { NULL, "RMSD (nm)", "Rho", "Rho sc" };
159     const char *whatxvgname[ewNR] =
160         { NULL, "RMSD", "\\8r\\4", "\\8r\\4\\ssc\\N" };
161     const char *whatxvglabel[ewNR] =
162         { NULL, "RMSD (nm)", "\\8r\\4", "\\8r\\4\\ssc\\N" };
163     /* strings and things for fitting methods */
164     enum
165     {
166         efSel, efFit, efReset, efNone, efNR
167     };
168     int efit;
169     const char *fit[efNR + 1] =
170         { NULL, "rot+trans", "translation", "none", NULL };
171     const char *fitgraphlabel[efNR + 1] =
172         { NULL, "lsq fit", "translational fit", "no fit" };
173     static int nrms = 1;
174     static gmx_bool bMassWeighted = TRUE;
175     t_pargs pa[] =
176         {
177             { "-what", FALSE, etENUM,
178                 { what }, "Structural difference measure" },
179             { "-pbc", FALSE, etBOOL,
180                 { &bPBC }, "PBC check" },
181             { "-fit", FALSE, etENUM,
182                 { fit }, "Fit to reference structure" },
183             { "-prev", FALSE, etINT,
184                 { &prev }, "Compare with previous frame" },
185             { "-split", FALSE, etBOOL,
186                 { &bSplit }, "Split graph where time is zero" },
187             { "-fitall", FALSE, etBOOL,
188                 { &bFitAll }, "HIDDENFit all pairs of structures in matrix" },
189             { "-skip", FALSE, etINT,
190                 { &freq }, "Only write every nr-th frame to matrix" },
191             { "-skip2", FALSE, etINT,
192                 { &freq2 }, "Only write every nr-th frame to matrix" },
193             { "-max", FALSE, etREAL,
194                 { &rmsd_user_max }, "Maximum level in comparison matrix" },
195             { "-min", FALSE, etREAL,
196                 { &rmsd_user_min }, "Minimum level in comparison matrix" },
197             { "-bmax", FALSE, etREAL,
198                 { &bond_user_max }, "Maximum level in bond angle matrix" },
199             { "-bmin", FALSE, etREAL,
200                 { &bond_user_min }, "Minimum level in bond angle matrix" },
201             { "-mw", FALSE, etBOOL,
202                 { &bMassWeighted }, "Use mass weighting for superposition" },
203             { "-nlevels", FALSE, etINT,
204                 { &nlevels }, "Number of levels in the matrices" },
205             { "-ng", FALSE, etINT,
206                 { &nrms }, "Number of groups to compute RMS between" },
207             { "-dlog", FALSE, etBOOL,
208                 { &bDeltaLog },
209                 "HIDDENUse a log x-axis in the delta t matrix" },
210             { "-dmax", FALSE, etREAL,
211                 { &delta_maxy }, "HIDDENMaximum level in delta matrix" },
212             { "-aver", FALSE, etINT,
213                 { &avl },
214                 "HIDDENAverage over this distance in the RMSD matrix" } };
215     int natoms_trx, natoms_trx2, natoms;
216     int i, j, k, m, teller, teller2, tel_mat, tel_mat2;
217 #define NFRAME 5000
218     int maxframe = NFRAME, maxframe2 = NFRAME;
219     real t, *w_rls, *w_rms, *w_rls_m = NULL, *w_rms_m = NULL;
220     gmx_bool bNorm, bAv, bFreq2, bFile2, bMat, bBond, bDelta, bMirror, bMass;
221     gmx_bool bFit, bReset;
222     t_topology top;
223     int ePBC;
224     t_iatom *iatom = NULL;
225
226     matrix box;
227     rvec *x, *xp, *xm = NULL, **mat_x = NULL, **mat_x2, *mat_x2_j = NULL, vec1,
228         vec2;
229     t_trxstatus *status;
230     char buf[256], buf2[256];
231     int ncons = 0;
232     FILE *fp;
233     real rlstot = 0, **rls, **rlsm = NULL, *time, *time2, *rlsnorm = NULL,
234         **rmsd_mat = NULL, **bond_mat = NULL, *axis, *axis2, *del_xaxis,
235         *del_yaxis, rmsd_max, rmsd_min, rmsd_avg, bond_max, bond_min, ang;
236     real **rmsdav_mat = NULL, av_tot, weight, weight_tot;
237     real **delta = NULL, delta_max, delta_scalex = 0, delta_scaley = 0,
238         *delta_tot;
239     int delta_xsize = 0, del_lev = 100, mx, my, abs_my;
240     gmx_bool bA1, bA2, bPrev, bTop, *bInMat = NULL;
241     int ifit, *irms, ibond = 0, *ind_bond1 = NULL, *ind_bond2 = NULL, n_ind_m =
242         0;
243     atom_id *ind_fit, **ind_rms, *ind_m = NULL, *rev_ind_m = NULL, *ind_rms_m =
244         NULL;
245     char *gn_fit, **gn_rms;
246     t_rgb rlo, rhi;
247     output_env_t oenv;
248     gmx_rmpbc_t  gpbc=NULL;
249
250     t_filenm fnm[] =
251         {
252             { efTPS, NULL, NULL, ffREAD },
253             { efTRX, "-f", NULL, ffREAD },
254             { efTRX, "-f2", NULL, ffOPTRD },
255             { efNDX, NULL, NULL, ffOPTRD },
256             { efXVG, NULL, "rmsd", ffWRITE },
257             { efXVG, "-mir", "rmsdmir", ffOPTWR },
258             { efXVG, "-a", "avgrp", ffOPTWR },
259             { efXVG, "-dist", "rmsd-dist", ffOPTWR },
260             { efXPM, "-m", "rmsd", ffOPTWR },
261             { efDAT, "-bin", "rmsd", ffOPTWR },
262             { efXPM, "-bm", "bond", ffOPTWR } };
263 #define NFILE asize(fnm)
264
265     CopyRight(stderr, argv[0]);
266     parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW
267         | PCA_BE_NICE, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL,
268                       &oenv);
269     /* parse enumerated options: */
270     ewhat = nenum(what);
271     if (ewhat == ewRho || ewhat == ewRhoSc)
272         please_cite(stdout, "Maiorov95");
273     efit = nenum(fit);
274     bFit = efit == efFit;
275     bReset = efit == efReset;
276     if (bFit)
277     {
278         bReset = TRUE; /* for fit, reset *must* be set */
279     }
280     else
281     {
282         bFitAll = FALSE;
283     }
284
285     /* mark active cmdline options */
286     bMirror = opt2bSet("-mir", NFILE, fnm); /* calc RMSD vs mirror of ref. */
287     bFile2 = opt2bSet("-f2", NFILE, fnm);
288     bMat = opt2bSet("-m", NFILE, fnm);
289     bBond = opt2bSet("-bm", NFILE, fnm);
290     bDelta = (delta_maxy > 0); /* calculate rmsd vs delta t matrix from *
291      *  your RMSD matrix (hidden option       */
292     bNorm = opt2bSet("-a", NFILE, fnm);
293     bFreq2 = opt2parg_bSet("-skip2", asize(pa), pa);
294     if (freq <= 0)
295     {
296         fprintf(stderr, "The number of frames to skip is <= 0. "
297             "Writing out all frames.\n\n");
298         freq = 1;
299     }
300     if (!bFreq2)
301     {
302         freq2 = freq;
303     }
304     else if (bFile2 && freq2 <= 0)
305     {
306         fprintf(stderr,
307                 "The number of frames to skip in second trajectory is <= 0.\n"
308                     "  Writing out all frames.\n\n");
309         freq2 = 1;
310     }
311
312     bPrev = (prev > 0);
313     if (bPrev)
314     {
315         prev = abs(prev);
316         if (freq != 1)
317             fprintf(stderr, "WARNING: option -skip also applies to -prev\n");
318     }
319
320     if (bFile2 && !bMat && !bBond)
321     {
322         fprintf(
323                 stderr,
324                 "WARNING: second trajectory (-f2) useless when not calculating matrix (-m/-bm),\n"
325                     "         will not read from %s\n", opt2fn("-f2", NFILE,
326                                                                fnm));
327         bFile2 = FALSE;
328     }
329
330     if (bDelta)
331     {
332         bMat = TRUE;
333         if (bFile2)
334         {
335             fprintf(stderr,
336                     "WARNING: second trajectory (-f2) useless when making delta matrix,\n"
337                         "         will not read from %s\n", opt2fn("-f2",
338                                                                    NFILE, fnm));
339             bFile2 = FALSE;
340         }
341     }
342
343     bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), buf, &top, &ePBC, &xp,
344                          NULL, box, TRUE);
345     snew(w_rls,top.atoms.nr);
346     snew(w_rms,top.atoms.nr);
347
348     if (!bTop && bBond)
349     {
350         fprintf(stderr,
351                 "WARNING: Need a run input file for bond angle matrix,\n"
352                     "         will not calculate bond angle matrix.\n");
353         bBond = FALSE;
354     }
355
356     if (bReset)
357     {
358         fprintf(stderr, "Select group for %s fit\n", bFit ? "least squares"
359             : "translational");
360         get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm), 1, &ifit,
361                   &ind_fit, &gn_fit);
362     }
363     else
364         ifit = 0;
365
366     if (bReset)
367     {
368         if (bFit && ifit < 3)
369             gmx_fatal(FARGS,"Need >= 3 points to fit!\n" );
370
371         bMass = FALSE;
372         for(i=0; i<ifit; i++)
373         {
374             if (bMassWeighted)
375                 w_rls[ind_fit[i]] = top.atoms.atom[ind_fit[i]].m;
376             else
377                 w_rls[ind_fit[i]] = 1;
378             bMass = bMass || (top.atoms.atom[ind_fit[i]].m != 0);
379         }
380         if (!bMass)
381         {
382             fprintf(stderr,"All masses in the fit group are 0, using masses of 1\n");
383             for(i=0; i<ifit; i++)
384             {
385                 w_rls[ind_fit[i]] = 1;
386             }
387         }
388     }
389
390     if (bMat || bBond)
391         nrms=1;
392
393     snew(gn_rms,nrms);
394     snew(ind_rms,nrms);
395     snew(irms,nrms);
396
397     fprintf(stderr,"Select group%s for %s calculation\n",
398             (nrms>1) ? "s" : "",whatname[ewhat]);
399     get_index(&(top.atoms),ftp2fn_null(efNDX,NFILE,fnm),
400               nrms,irms,ind_rms,gn_rms);
401
402     if (bNorm)
403     {
404         snew(rlsnorm,irms[0]);
405     }
406     snew(rls,nrms);
407     for(j=0; j<nrms; j++)
408         snew(rls[j],maxframe);
409     if (bMirror)
410     {
411         snew(rlsm,nrms);
412         for(j=0; j<nrms; j++)
413             snew(rlsm[j],maxframe);
414     }
415     snew(time,maxframe);
416     for(j=0; j<nrms; j++)
417     {
418         bMass = FALSE;
419         for(i=0; i<irms[j]; i++)
420         {
421             if (bMassWeighted)
422                 w_rms[ind_rms[j][i]] = top.atoms.atom[ind_rms[j][i]].m;
423             else
424                 w_rms[ind_rms[j][i]] = 1.0;
425             bMass = bMass || (top.atoms.atom[ind_rms[j][i]].m != 0);
426         }
427         if (!bMass) {
428             fprintf(stderr,"All masses in group %d are 0, using masses of 1\n",j);
429             for(i=0; i<irms[j]; i++)
430                 w_rms[ind_rms[j][i]] = 1;
431         }
432     }
433     /* Prepare reference frame */
434     if (bPBC) {
435       gpbc = gmx_rmpbc_init(&top.idef,ePBC,top.atoms.nr,box);
436       gmx_rmpbc(gpbc,top.atoms.nr,box,xp);
437     }
438     if (bReset)
439         reset_x(ifit,ind_fit,top.atoms.nr,NULL,xp,w_rls);
440     if (bMirror) {
441         /* generate reference structure mirror image: */
442         snew(xm, top.atoms.nr);
443         for(i=0; i<top.atoms.nr; i++) {
444             copy_rvec(xp[i],xm[i]);
445             xm[i][XX] = -xm[i][XX];
446         }
447     }
448     if (ewhat==ewRhoSc)
449         norm_princ(&top.atoms, ifit, ind_fit, top.atoms.nr, xp);
450
451     /* read first frame */
452     natoms_trx=read_first_x(oenv,&status,opt2fn("-f",NFILE,fnm),&t,&x,box);
453     if (natoms_trx != top.atoms.nr) 
454         fprintf(stderr,
455                 "\nWARNING: topology has %d atoms, whereas trajectory has %d\n",
456                 top.atoms.nr,natoms_trx);
457     natoms = min(top.atoms.nr,natoms_trx);
458     if (bMat || bBond || bPrev) {
459         snew(mat_x,NFRAME);
460
461         if (bPrev)
462             /* With -prev we use all atoms for simplicity */
463             n_ind_m = natoms;
464         else {
465             /* Check which atoms we need (fit/rms) */
466             snew(bInMat,natoms);
467             for(i=0; i<ifit; i++)
468                 bInMat[ind_fit[i]] = TRUE;
469             n_ind_m=ifit;
470             for(i=0; i<irms[0]; i++)
471                 if (!bInMat[ind_rms[0][i]]) {
472                     bInMat[ind_rms[0][i]] = TRUE;
473                     n_ind_m++;
474                 }
475         }
476         /* Make an index of needed atoms */
477         snew(ind_m,n_ind_m);
478         snew(rev_ind_m,natoms);
479         j = 0;
480         for(i=0; i<natoms; i++)
481             if (bPrev || bInMat[i]) {
482                 ind_m[j] = i;
483                 rev_ind_m[i] = j;
484                 j++;
485             }
486         snew(w_rls_m,n_ind_m);
487         snew(ind_rms_m,irms[0]);
488         snew(w_rms_m,n_ind_m);
489         for(i=0; i<ifit; i++)
490             w_rls_m[rev_ind_m[ind_fit[i]]] = w_rls[ind_fit[i]];
491         for(i=0; i<irms[0]; i++) {
492             ind_rms_m[i] = rev_ind_m[ind_rms[0][i]];
493             w_rms_m[ind_rms_m[i]] = w_rms[ind_rms[0][i]];
494         }
495         sfree(bInMat);
496     }
497
498     if (bBond) {
499         ncons = 0;
500         for(k=0; k<F_NRE; k++)
501             if (IS_CHEMBOND(k)) {
502                 iatom  = top.idef.il[k].iatoms;
503                 ncons += top.idef.il[k].nr/3;
504             }
505         fprintf(stderr,"Found %d bonds in topology\n",ncons);
506         snew(ind_bond1,ncons);
507         snew(ind_bond2,ncons);
508         ibond=0;
509         for(k=0; k<F_NRE; k++)
510             if (IS_CHEMBOND(k)) {
511                 iatom = top.idef.il[k].iatoms;
512                 ncons = top.idef.il[k].nr/3;
513                 for (i=0; i<ncons; i++) {
514                     bA1=FALSE; 
515                     bA2=FALSE;
516                     for (j=0; j<irms[0]; j++) {
517                         if (iatom[3*i+1] == ind_rms[0][j]) bA1=TRUE; 
518                         if (iatom[3*i+2] == ind_rms[0][j]) bA2=TRUE;
519                     }
520                     if (bA1 && bA2) {
521                         ind_bond1[ibond] = rev_ind_m[iatom[3*i+1]];
522                         ind_bond2[ibond] = rev_ind_m[iatom[3*i+2]];
523                         ibond++;
524                     }
525                 }
526             }
527         fprintf(stderr,"Using %d bonds for bond angle matrix\n",ibond);
528         if (ibond==0)
529             gmx_fatal(FARGS,"0 bonds found");
530     }
531
532     /* start looping over frames: */
533     tel_mat = 0;
534     teller = 0;
535     do {
536         if (bPBC) 
537           gmx_rmpbc(gpbc,natoms,box,x);
538
539         if (bReset)
540             reset_x(ifit,ind_fit,natoms,NULL,x,w_rls);
541         if (ewhat==ewRhoSc)
542             norm_princ(&top.atoms, ifit, ind_fit, natoms, x);
543
544         if (bFit)
545             /*do the least squares fit to original structure*/
546             do_fit(natoms,w_rls,xp,x);
547
548         if (teller % freq == 0) {
549             /* keep frame for matrix calculation */
550             if (bMat || bBond || bPrev) {
551                 if (tel_mat >= NFRAME) 
552                     srenew(mat_x,tel_mat+1);
553                 snew(mat_x[tel_mat],n_ind_m);
554                 for (i=0;i<n_ind_m;i++)
555                     copy_rvec(x[ind_m[i]],mat_x[tel_mat][i]);
556             }
557             tel_mat++;
558         }
559
560         /*calculate energy of root_least_squares*/
561         if (bPrev) {
562             j=tel_mat-prev-1;
563             if (j<0)
564                 j=0;
565             for (i=0;i<n_ind_m;i++)
566                 copy_rvec(mat_x[j][i],xp[ind_m[i]]);
567             if (bReset)
568                 reset_x(ifit,ind_fit,natoms,NULL,xp,w_rls);
569             if (bFit)
570                 do_fit(natoms,w_rls,x,xp);
571         }    
572         for(j=0; (j<nrms); j++) 
573             rls[j][teller] = 
574                 calc_similar_ind(ewhat!=ewRMSD,irms[j],ind_rms[j],w_rms,x,xp);
575         if (bNorm) {
576             for(j=0; (j<irms[0]); j++)
577                 rlsnorm[j] += 
578                     calc_similar_ind(ewhat!=ewRMSD,1,&(ind_rms[0][j]),w_rms,x,xp);
579         } 
580
581         if (bMirror) {
582             if (bFit)
583                 /*do the least squares fit to mirror of original structure*/
584                 do_fit(natoms,w_rls,xm,x);
585
586             for(j=0; j<nrms; j++)
587                 rlsm[j][teller] = 
588                     calc_similar_ind(ewhat!=ewRMSD,irms[j],ind_rms[j],w_rms,x,xm);
589         }
590         time[teller]=output_env_conv_time(oenv,t);
591
592         teller++;
593         if (teller >= maxframe) {
594             maxframe +=NFRAME;
595             srenew(time,maxframe);
596             for(j=0; (j<nrms); j++) 
597                 srenew(rls[j],maxframe);
598             if (bMirror)
599                 for(j=0; (j<nrms); j++) 
600                     srenew(rlsm[j],maxframe);
601         }
602     } while (read_next_x(oenv,status,&t,natoms_trx,x,box));
603     close_trj(status);
604
605     if (bFile2) {
606         snew(time2,maxframe2);
607
608         fprintf(stderr,"\nWill read second trajectory file\n");
609         snew(mat_x2,NFRAME);
610         natoms_trx2 =
611           read_first_x(oenv,&status,opt2fn("-f2",NFILE,fnm),&t,&x,box);
612         if ( natoms_trx2 != natoms_trx )
613             gmx_fatal(FARGS,
614                       "Second trajectory (%d atoms) does not match the first one"
615                       " (%d atoms)", natoms_trx2, natoms_trx);
616         tel_mat2 = 0;
617         teller2 = 0;
618         do {
619             if (bPBC) 
620               gmx_rmpbc(gpbc,natoms,box,x);
621
622             if (bReset)
623                 reset_x(ifit,ind_fit,natoms,NULL,x,w_rls);
624             if (ewhat==ewRhoSc)
625                 norm_princ(&top.atoms, ifit, ind_fit, natoms, x);
626
627             if (bFit)
628                 /*do the least squares fit to original structure*/
629                 do_fit(natoms,w_rls,xp,x);
630
631             if (teller2 % freq2 == 0) {
632                 /* keep frame for matrix calculation */
633                 if (bMat) {
634                     if (tel_mat2 >= NFRAME) 
635                         srenew(mat_x2,tel_mat2+1);
636                     snew(mat_x2[tel_mat2],n_ind_m);
637                     for (i=0;i<n_ind_m;i++)
638                         copy_rvec(x[ind_m[i]],mat_x2[tel_mat2][i]);
639                 }
640                 tel_mat2++;
641             }
642
643             time2[teller2]=output_env_conv_time(oenv,t);
644
645             teller2++;
646             if (teller2 >= maxframe2) {
647                 maxframe2 +=NFRAME;
648                 srenew(time2,maxframe2);
649             }
650         } while (read_next_x(oenv,status,&t,natoms_trx2,x,box));
651         close_trj(status);
652     } else {
653         mat_x2=mat_x;
654         time2=time;
655         tel_mat2=tel_mat;
656         freq2=freq;
657     }
658     gmx_rmpbc_done(gpbc);
659
660     if (bMat || bBond) {
661         /* calculate RMS matrix */
662         fprintf(stderr,"\n");
663         if (bMat) {
664             fprintf(stderr,"Building %s matrix, %dx%d elements\n",
665                     whatname[ewhat],tel_mat,tel_mat2);
666             snew(rmsd_mat,tel_mat);
667         }
668         if (bBond) {
669             fprintf(stderr,"Building bond angle matrix, %dx%d elements\n",
670                     tel_mat,tel_mat2);
671             snew(bond_mat,tel_mat);
672         }
673         snew(axis,tel_mat);
674         snew(axis2,tel_mat2);
675         rmsd_max=0;
676         if (bFile2)
677             rmsd_min=1e10;
678         else
679             rmsd_min=0;
680         rmsd_avg=0;
681         bond_max=0;
682         bond_min=1e10;
683         for(j=0; j<tel_mat2; j++)
684             axis2[j]=time2[freq2*j];
685         if (bDelta) {
686             if (bDeltaLog) {
687                 delta_scalex=8.0/log(2.0);
688                 delta_xsize=(int)(log(tel_mat/2)*delta_scalex+0.5)+1;
689             }
690             else {
691                 delta_xsize=tel_mat/2;
692             }
693             delta_scaley=1.0/delta_maxy;
694             snew(delta,delta_xsize);
695             for(j=0; j<delta_xsize; j++)
696                 snew(delta[j],del_lev+1);
697             if (avl > 0) {
698                 snew(rmsdav_mat,tel_mat);
699                 for(j=0; j<tel_mat; j++)
700                     snew(rmsdav_mat[j],tel_mat);
701             }
702         }
703
704         if (bFitAll)
705             snew(mat_x2_j,natoms);
706         for(i=0; i<tel_mat; i++) {
707             axis[i]=time[freq*i];
708             fprintf(stderr,"\r element %5d; time %5.2f  ",i,axis[i]);
709             if (bMat) snew(rmsd_mat[i],tel_mat2);
710             if (bBond) snew(bond_mat[i],tel_mat2); 
711             for(j=0; j<tel_mat2; j++) {
712                 if (bFitAll) {
713                     for (k=0;k<n_ind_m;k++)
714                         copy_rvec(mat_x2[j][k],mat_x2_j[k]);
715                     do_fit(n_ind_m,w_rls_m,mat_x[i],mat_x2_j);
716                 } else
717                     mat_x2_j=mat_x2[j];
718                 if (bMat) {
719                     if (bFile2 || (i<j)) {
720                         rmsd_mat[i][j] =
721                             calc_similar_ind(ewhat!=ewRMSD,irms[0],ind_rms_m,
722                                              w_rms_m,mat_x[i],mat_x2_j);
723                         if (rmsd_mat[i][j] > rmsd_max) rmsd_max=rmsd_mat[i][j];
724                         if (rmsd_mat[i][j] < rmsd_min) rmsd_min=rmsd_mat[i][j];
725                         rmsd_avg += rmsd_mat[i][j];
726                     } else
727                         rmsd_mat[i][j]=rmsd_mat[j][i];
728                 }
729                 if (bBond) {
730                     if (bFile2 || (i<=j)) {
731                         ang=0.0;
732                         for(m=0;m<ibond;m++) {
733                             rvec_sub(mat_x[i][ind_bond1[m]],mat_x[i][ind_bond2[m]],vec1);
734                             rvec_sub(mat_x2_j[ind_bond1[m]],mat_x2_j[ind_bond2[m]],vec2);
735                             ang += acos(cos_angle(vec1,vec2));
736                         }
737                         bond_mat[i][j]=ang*180.0/(M_PI*ibond);
738                         if (bond_mat[i][j] > bond_max) bond_max=bond_mat[i][j];
739                         if (bond_mat[i][j] < bond_min) bond_min=bond_mat[i][j];
740                     } 
741                     else
742                         bond_mat[i][j]=bond_mat[j][i];
743                 }
744             }
745         }
746         if (bFile2)
747             rmsd_avg /= tel_mat*tel_mat2;
748         else
749             rmsd_avg /= tel_mat*(tel_mat - 1)/2;
750         if (bMat && (avl > 0)) {
751             rmsd_max=0.0;
752             rmsd_min=0.0;
753             rmsd_avg=0.0;
754             for(j=0; j<tel_mat-1; j++) {
755                 for(i=j+1; i<tel_mat; i++) {
756                     av_tot=0;
757                     weight_tot=0;
758                     for (my=-avl; my<=avl; my++) {
759                         if ((j+my>=0) && (j+my<tel_mat)) {
760                             abs_my = abs(my);
761                             for (mx=-avl; mx<=avl; mx++) {
762                                 if ((i+mx>=0) && (i+mx<tel_mat)) {
763                                     weight = (real)(avl+1-max(abs(mx),abs_my));
764                                     av_tot += weight*rmsd_mat[i+mx][j+my];
765                                     weight_tot+=weight;
766                                 }
767                             }
768                         }
769                     }
770                     rmsdav_mat[i][j] = av_tot/weight_tot;
771                     rmsdav_mat[j][i] = rmsdav_mat[i][j];
772                     if (rmsdav_mat[i][j] > rmsd_max) rmsd_max=rmsdav_mat[i][j];
773                 }
774             }
775             rmsd_mat=rmsdav_mat;
776         }
777
778         if (bMat) {
779             fprintf(stderr,"\n%s: Min %f, Max %f, Avg %f\n",
780                     whatname[ewhat],rmsd_min,rmsd_max,rmsd_avg);
781             rlo.r = 1; rlo.g = 1; rlo.b = 1;
782             rhi.r = 0; rhi.g = 0; rhi.b = 0;
783             if (rmsd_user_max != -1) rmsd_max=rmsd_user_max;
784             if (rmsd_user_min != -1) rmsd_min=rmsd_user_min;
785             if ((rmsd_user_max !=  -1) || (rmsd_user_min != -1))
786                 fprintf(stderr,"Min and Max value set to resp. %f and %f\n",
787                         rmsd_min,rmsd_max);
788             sprintf(buf,"%s %s matrix",gn_rms[0],whatname[ewhat]);
789             write_xpm(opt2FILE("-m",NFILE,fnm,"w"),0,buf,whatlabel[ewhat],
790                       output_env_get_time_label(oenv),output_env_get_time_label(oenv),tel_mat,tel_mat2,
791                       axis,axis2, rmsd_mat,rmsd_min,rmsd_max,rlo,rhi,&nlevels);
792             /* Print the distribution of RMSD values */
793             if (opt2bSet("-dist",NFILE,fnm)) 
794                 low_rmsd_dist(opt2fn("-dist",NFILE,fnm),rmsd_max,tel_mat,rmsd_mat,oenv);
795
796             if (bDelta) {
797                 snew(delta_tot,delta_xsize);
798                 for(j=0; j<tel_mat-1; j++) {
799                     for(i=j+1; i<tel_mat; i++) {
800                         mx=i-j ;
801                         if (mx < tel_mat/2) {
802                             if (bDeltaLog) 
803                                 mx=(int)(log(mx)*delta_scalex+0.5);
804                             my=(int)(rmsd_mat[i][j]*delta_scaley*del_lev+0.5);
805                             delta_tot[mx] += 1.0;
806                             if ((rmsd_mat[i][j]>=0) && (rmsd_mat[i][j]<=delta_maxy))
807                                 delta[mx][my] += 1.0;
808                         }
809                     }
810                 }
811                 delta_max=0;
812                 for(i=0; i<delta_xsize; i++) {
813                     if (delta_tot[i] > 0.0) {
814                         delta_tot[i]=1.0/delta_tot[i];
815                         for(j=0; j<=del_lev; j++) {
816                             delta[i][j] *= delta_tot[i];
817                             if (delta[i][j] > delta_max)
818                                 delta_max=delta[i][j];
819                         }
820                     }
821                 }
822                 fprintf(stderr,"Maximum in delta matrix: %f\n",delta_max);
823                 snew(del_xaxis,delta_xsize);
824                 snew(del_yaxis,del_lev+1);
825                 for (i=0; i<delta_xsize; i++)
826                     del_xaxis[i]=axis[i]-axis[0];
827                 for (i=0; i<del_lev+1; i++)
828                     del_yaxis[i]=delta_maxy*i/del_lev;
829                 sprintf(buf,"%s %s vs. delta t",gn_rms[0],whatname[ewhat]);
830                 fp = ffopen("delta.xpm","w");
831                 write_xpm(fp,0,buf,"density",output_env_get_time_label(oenv),whatlabel[ewhat],
832                           delta_xsize,del_lev+1,del_xaxis,del_yaxis,
833                           delta,0.0,delta_max,rlo,rhi,&nlevels);
834                 ffclose(fp);
835             }
836             if (opt2bSet("-bin",NFILE,fnm)) {
837                 /* NB: File must be binary if we use fwrite */
838                 fp=ftp2FILE(efDAT,NFILE,fnm,"wb");
839                 for(i=0;i<tel_mat;i++) 
840                     if(fwrite(rmsd_mat[i],sizeof(**rmsd_mat),tel_mat2,fp) != tel_mat2)
841                     {
842                         gmx_fatal(FARGS,"Error writing to output file");
843                     }
844                 ffclose(fp);
845             }
846         }
847         if (bBond) {
848             fprintf(stderr,"\nMin. angle: %f, Max. angle: %f\n",bond_min,bond_max);
849             if (bond_user_max != -1) bond_max=bond_user_max;
850             if (bond_user_min != -1) bond_min=bond_user_min;
851             if ((bond_user_max !=  -1) || (bond_user_min != -1))
852                 fprintf(stderr,"Bond angle Min and Max set to:\n"
853                         "Min. angle: %f, Max. angle: %f\n",bond_min,bond_max);
854             rlo.r = 1; rlo.g = 1; rlo.b = 1;
855             rhi.r = 0; rhi.g = 0; rhi.b = 0;
856             sprintf(buf,"%s av. bond angle deviation",gn_rms[0]);
857             write_xpm(opt2FILE("-bm",NFILE,fnm,"w"),0,buf,"degrees",
858                       output_env_get_time_label(oenv),output_env_get_time_label(oenv),tel_mat,tel_mat2,
859                       axis,axis2, bond_mat,bond_min,bond_max,rlo,rhi,&nlevels);
860         }
861     }
862
863     bAv=opt2bSet("-a",NFILE,fnm);
864
865     /* Write the RMSD's to file */
866     if (!bPrev)
867         sprintf(buf,"%s",whatxvgname[ewhat]);
868     else
869         sprintf(buf,"%s with frame %g %s ago",whatxvgname[ewhat],
870                 time[prev*freq]-time[0], output_env_get_time_label(oenv));
871     fp=xvgropen(opt2fn("-o",NFILE,fnm),buf,output_env_get_xvgr_tlabel(oenv),
872                 whatxvglabel[ewhat], oenv);
873     if (output_env_get_print_xvgr_codes(oenv))
874         fprintf(fp,"@ subtitle \"%s%s after %s%s%s\"\n",
875                 (nrms==1)?"":"of "    , gn_rms[0], fitgraphlabel[efit],
876                     bFit     ?" to ":""   , bFit?gn_fit:"");
877     if (nrms != 1)
878         xvgr_legend(fp,nrms,(const char**)gn_rms,oenv);
879     for(i=0; (i<teller); i++) {
880         if ( bSplit && i>0 && 
881             abs(time[bPrev ? freq*i : i]/output_env_get_time_factor(oenv))<1e-5 ) 
882         {
883             fprintf(fp,"&\n");
884         }
885         fprintf(fp,"%12.7f",time[bPrev ? freq*i : i]);
886         for(j=0; (j<nrms); j++) {
887             fprintf(fp," %12.7f",rls[j][i]);
888             if (bAv)
889                 rlstot+=rls[j][i];
890         }
891         fprintf(fp,"\n");
892     }
893     ffclose(fp);
894     
895     if (bMirror) {
896         /* Write the mirror RMSD's to file */
897         sprintf(buf,"%s with Mirror",whatxvgname[ewhat]);
898         sprintf(buf2,"Mirror %s",whatxvglabel[ewhat]);
899         fp=xvgropen(opt2fn("-mir",NFILE,fnm), buf, output_env_get_xvgr_tlabel(oenv), 
900                     buf2,oenv);
901         if (nrms == 1) {
902             if (output_env_get_print_xvgr_codes(oenv))
903                 fprintf(fp,"@ subtitle \"of %s after lsq fit to mirror of %s\"\n",
904                         gn_rms[0],gn_fit);
905         }
906         else {
907             if (output_env_get_print_xvgr_codes(oenv))
908                 fprintf(fp,"@ subtitle \"after lsq fit to mirror %s\"\n",gn_fit);
909             xvgr_legend(fp,nrms,(const char**)gn_rms,oenv);
910         }
911         for(i=0; (i<teller); i++) {
912             if ( bSplit && i>0 && abs(time[i])<1e-5 ) 
913                 fprintf(fp,"&\n");
914             fprintf(fp,"%12.7f",time[i]);
915             for(j=0; (j<nrms); j++)
916                 fprintf(fp," %12.7f",rlsm[j][i]);
917             fprintf(fp,"\n");
918         }
919         ffclose(fp);
920     }
921
922     if (bAv) {
923         sprintf(buf,"Average %s",whatxvgname[ewhat]);
924         sprintf(buf2,"Average %s",whatxvglabel[ewhat]);
925         fp = xvgropen(opt2fn("-a",NFILE,fnm), buf, "Residue", buf2,oenv);
926         for(j=0; (j<nrms); j++)
927             fprintf(fp,"%10d  %10g\n",j,rlstot/teller);
928         ffclose(fp);
929     }
930
931     if (bNorm) {
932         fp = xvgropen("aver.xvg",gn_rms[0],"Residue",whatxvglabel[ewhat],oenv);
933         for(j=0; (j<irms[0]); j++)
934             fprintf(fp,"%10d  %10g\n",j,rlsnorm[j]/teller);
935         ffclose(fp);
936     }
937     do_view(oenv,opt2fn_null("-a",NFILE,fnm),"-graphtype bar");
938     do_view(oenv,opt2fn("-o",NFILE,fnm),NULL);
939     do_view(oenv,opt2fn_null("-mir",NFILE,fnm),NULL);
940     do_view(oenv,opt2fn_null("-m",NFILE,fnm),NULL);
941     do_view(oenv,opt2fn_null("-bm",NFILE,fnm),NULL);
942     do_view(oenv,opt2fn_null("-dist",NFILE,fnm),NULL);
943
944     thanx(stderr);
945
946     return 0;
947 }