Tidy: modernize-use-nullptr
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_cluster.cpp
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,2015,2016,2017, 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 #include "gmxpre.h"
38
39 #include <cmath>
40 #include <cstdlib>
41 #include <cstring>
42
43 #include <algorithm>
44
45 #include "gromacs/commandline/pargs.h"
46 #include "gromacs/commandline/viewit.h"
47 #include "gromacs/fileio/confio.h"
48 #include "gromacs/fileio/matio.h"
49 #include "gromacs/fileio/trxio.h"
50 #include "gromacs/fileio/xvgr.h"
51 #include "gromacs/gmxana/cmat.h"
52 #include "gromacs/gmxana/gmx_ana.h"
53 #include "gromacs/linearalgebra/eigensolver.h"
54 #include "gromacs/math/do_fit.h"
55 #include "gromacs/math/vec.h"
56 #include "gromacs/pbcutil/pbc.h"
57 #include "gromacs/pbcutil/rmpbc.h"
58 #include "gromacs/random/threefry.h"
59 #include "gromacs/random/uniformintdistribution.h"
60 #include "gromacs/random/uniformrealdistribution.h"
61 #include "gromacs/topology/index.h"
62 #include "gromacs/topology/topology.h"
63 #include "gromacs/utility/arraysize.h"
64 #include "gromacs/utility/cstringutil.h"
65 #include "gromacs/utility/fatalerror.h"
66 #include "gromacs/utility/futil.h"
67 #include "gromacs/utility/smalloc.h"
68
69 /* print to two file pointers at once (i.e. stderr and log) */
70 static gmx_inline
71 void lo_ffprintf(FILE *fp1, FILE *fp2, const char *buf)
72 {
73     fprintf(fp1, "%s", buf);
74     fprintf(fp2, "%s", buf);
75 }
76
77 /* just print a prepared buffer to fp1 and fp2 */
78 static gmx_inline
79 void ffprintf(FILE *fp1, FILE *fp2, const char *buf)
80 {
81     lo_ffprintf(fp1, fp2, buf);
82 }
83
84 /* prepare buffer with one argument, then print to fp1 and fp2 */
85 static gmx_inline
86 void ffprintf_d(FILE *fp1, FILE *fp2, char *buf, const char *fmt, int arg)
87 {
88     sprintf(buf, fmt, arg);
89     lo_ffprintf(fp1, fp2, buf);
90 }
91
92 /* prepare buffer with one argument, then print to fp1 and fp2 */
93 static gmx_inline
94 void ffprintf_g(FILE *fp1, FILE *fp2, char *buf, const char *fmt, real arg)
95 {
96     sprintf(buf, fmt, arg);
97     lo_ffprintf(fp1, fp2, buf);
98 }
99
100 /* prepare buffer with one argument, then print to fp1 and fp2 */
101 static gmx_inline
102 void ffprintf_s(FILE *fp1, FILE *fp2, char *buf, const char *fmt, const char *arg)
103 {
104     sprintf(buf, fmt, arg);
105     lo_ffprintf(fp1, fp2, buf);
106 }
107
108 /* prepare buffer with two arguments, then print to fp1 and fp2 */
109 static gmx_inline
110 void ffprintf_dd(FILE *fp1, FILE *fp2, char *buf, const char *fmt, int arg1, int arg2)
111 {
112     sprintf(buf, fmt, arg1, arg2);
113     lo_ffprintf(fp1, fp2, buf);
114 }
115
116 /* prepare buffer with two arguments, then print to fp1 and fp2 */
117 static gmx_inline
118 void ffprintf_gg(FILE *fp1, FILE *fp2, char *buf, const char *fmt, real arg1, real arg2)
119 {
120     sprintf(buf, fmt, arg1, arg2);
121     lo_ffprintf(fp1, fp2, buf);
122 }
123
124 /* prepare buffer with two arguments, then print to fp1 and fp2 */
125 static gmx_inline
126 void ffprintf_ss(FILE *fp1, FILE *fp2, char *buf, const char *fmt, const char *arg1, const char *arg2)
127 {
128     sprintf(buf, fmt, arg1, arg2);
129     lo_ffprintf(fp1, fp2, buf);
130 }
131
132 typedef struct {
133     int  ncl;
134     int *cl;
135 } t_clusters;
136
137 typedef struct {
138     int  nr;
139     int *nb;
140 } t_nnb;
141
142 void cp_index(int nn, int from[], int to[])
143 {
144     int i;
145
146     for (i = 0; (i < nn); i++)
147     {
148         to[i] = from[i];
149     }
150 }
151
152 void mc_optimize(FILE *log, t_mat *m, real *time,
153                  int maxiter, int nrandom,
154                  int seed, real kT,
155                  const char *conv, gmx_output_env_t *oenv)
156 {
157     FILE      *fp = nullptr;
158     real       ecur, enext, emin, prob, enorm;
159     int        i, j, iswap, jswap, nn, nuphill = 0;
160     t_mat     *minimum;
161
162     if (seed == 0)
163     {
164         seed = static_cast<int>(gmx::makeRandomSeed());
165     }
166     gmx::DefaultRandomEngine rng(seed);
167
168     if (m->n1 != m->nn)
169     {
170         fprintf(stderr, "Can not do Monte Carlo optimization with a non-square matrix.\n");
171         return;
172     }
173     printf("\nDoing Monte Carlo optimization to find the smoothest trajectory\n");
174     printf("by reordering the frames to minimize the path between the two structures\n");
175     printf("that have the largest pairwise RMSD.\n");
176     printf("Using random seed %d.\n", seed);
177
178     iswap = jswap = -1;
179     enorm = m->mat[0][0];
180     for (i = 0; (i < m->n1); i++)
181     {
182         for (j = 0; (j < m->nn); j++)
183         {
184             if (m->mat[i][j] > enorm)
185             {
186                 enorm   = m->mat[i][j];
187                 iswap   = i;
188                 jswap   = j;
189             }
190         }
191     }
192     if ((iswap == -1) || (jswap == -1))
193     {
194         fprintf(stderr, "Matrix contains identical values in all fields\n");
195         return;
196     }
197     swap_rows(m, 0, iswap);
198     swap_rows(m, m->n1-1, jswap);
199     emin = ecur = mat_energy(m);
200     printf("Largest distance %g between %d and %d. Energy: %g.\n",
201            enorm, iswap, jswap, emin);
202
203     nn  = m->nn;
204
205     /* Initiate and store global minimum */
206     minimum     = init_mat(nn, m->b1D);
207     minimum->nn = nn;
208     copy_t_mat(minimum, m);
209
210     if (nullptr != conv)
211     {
212         fp = xvgropen(conv, "Convergence of the MC optimization",
213                       "Energy", "Step", oenv);
214     }
215
216     gmx::UniformIntDistribution<int>     intDistNN(1, nn-2); // [1,nn-2]
217     gmx::UniformRealDistribution<real>   realDistOne;        // [0,1)
218
219     for (i = 0; (i < maxiter); i++)
220     {
221         /* Generate new swapping candidates */
222         do
223         {
224             iswap = intDistNN(rng);
225             jswap = intDistNN(rng);
226         }
227         while ((iswap == jswap) || (iswap >= nn-1) || (jswap >= nn-1));
228
229         /* Apply swap and compute energy */
230         swap_rows(m, iswap, jswap);
231         enext = mat_energy(m);
232
233         /* Compute probability */
234         prob = 0;
235         if ((enext < ecur) || (i < nrandom))
236         {
237             prob = 1;
238             if (enext < emin)
239             {
240                 /* Store global minimum */
241                 copy_t_mat(minimum, m);
242                 emin = enext;
243             }
244         }
245         else if (kT > 0)
246         {
247             /* Try Monte Carlo step */
248             prob = std::exp(-(enext-ecur)/(enorm*kT));
249         }
250
251         if (prob == 1 || realDistOne(rng) < prob)
252         {
253             if (enext > ecur)
254             {
255                 nuphill++;
256             }
257
258             fprintf(log, "Iter: %d Swapped %4d and %4d (energy: %g prob: %g)\n",
259                     i, iswap, jswap, enext, prob);
260             if (nullptr != fp)
261             {
262                 fprintf(fp, "%6d  %10g\n", i, enext);
263             }
264             ecur = enext;
265         }
266         else
267         {
268             swap_rows(m, jswap, iswap);
269         }
270     }
271     fprintf(log, "%d uphill steps were taken during optimization\n",
272             nuphill);
273
274     /* Now swap the matrix to get it into global minimum mode */
275     copy_t_mat(m, minimum);
276
277     fprintf(log, "Global minimum energy %g\n", mat_energy(minimum));
278     fprintf(log, "Global minimum energy %g\n", mat_energy(m));
279     fprintf(log, "Swapped time and frame indices and RMSD to next neighbor:\n");
280     for (i = 0; (i < m->nn); i++)
281     {
282         fprintf(log, "%10g  %5d  %10g\n",
283                 time[m->m_ind[i]],
284                 m->m_ind[i],
285                 (i < m->nn-1) ? m->mat[m->m_ind[i]][m->m_ind[i+1]] : 0);
286     }
287
288     if (nullptr != fp)
289     {
290         xvgrclose(fp);
291     }
292 }
293
294 static void calc_dist(int nind, rvec x[], real **d)
295 {
296     int      i, j;
297     real    *xi;
298     rvec     dx;
299
300     for (i = 0; (i < nind-1); i++)
301     {
302         xi = x[i];
303         for (j = i+1; (j < nind); j++)
304         {
305             /* Should use pbc_dx when analysing multiple molecueles,
306              * but the box is not stored for every frame.
307              */
308             rvec_sub(xi, x[j], dx);
309             d[i][j] = norm(dx);
310         }
311     }
312 }
313
314 static real rms_dist(int isize, real **d, real **d_r)
315 {
316     int  i, j;
317     real r, r2;
318
319     r2 = 0.0;
320     for (i = 0; (i < isize-1); i++)
321     {
322         for (j = i+1; (j < isize); j++)
323         {
324             r   = d[i][j]-d_r[i][j];
325             r2 += r*r;
326         }
327     }
328     r2 /= (isize*(isize-1))/2;
329
330     return std::sqrt(r2);
331 }
332
333 static bool rms_dist_comp(const t_dist &a, const t_dist &b)
334 {
335     return a.dist < b.dist;
336 }
337
338 static bool clust_id_comp(const t_clustid &a, const t_clustid &b)
339 {
340     return a.clust < b.clust;
341 }
342
343 static bool nrnb_comp(const t_nnb &a, const t_nnb &b)
344 {
345     /* return b<a, we want highest first */
346     return b.nr < a.nr;
347 }
348
349 void gather(t_mat *m, real cutoff, t_clusters *clust)
350 {
351     t_clustid *c;
352     t_dist    *d;
353     int        i, j, k, nn, cid, n1, diff;
354     gmx_bool   bChange;
355
356     /* First we sort the entries in the RMSD matrix */
357     n1 = m->nn;
358     nn = ((n1-1)*n1)/2;
359     snew(d, nn);
360     for (i = k = 0; (i < n1); i++)
361     {
362         for (j = i+1; (j < n1); j++, k++)
363         {
364             d[k].i    = i;
365             d[k].j    = j;
366             d[k].dist = m->mat[i][j];
367         }
368     }
369     if (k != nn)
370     {
371         gmx_incons("gather algortihm");
372     }
373     std::sort(d, d+nn, rms_dist_comp);
374
375     /* Now we make a cluster index for all of the conformations */
376     c = new_clustid(n1);
377
378     /* Now we check the closest structures, and equalize their cluster numbers */
379     fprintf(stderr, "Linking structures ");
380     do
381     {
382         fprintf(stderr, "*");
383         bChange = FALSE;
384         for (k = 0; (k < nn) && (d[k].dist < cutoff); k++)
385         {
386             diff = c[d[k].j].clust - c[d[k].i].clust;
387             if (diff)
388             {
389                 bChange = TRUE;
390                 if (diff > 0)
391                 {
392                     c[d[k].j].clust = c[d[k].i].clust;
393                 }
394                 else
395                 {
396                     c[d[k].i].clust = c[d[k].j].clust;
397                 }
398             }
399         }
400     }
401     while (bChange);
402     fprintf(stderr, "\nSorting and renumbering clusters\n");
403     /* Sort on cluster number */
404     std::sort(c, c+n1, clust_id_comp);
405
406     /* Renumber clusters */
407     cid = 1;
408     for (k = 1; k < n1; k++)
409     {
410         if (c[k].clust != c[k-1].clust)
411         {
412             c[k-1].clust = cid;
413             cid++;
414         }
415         else
416         {
417             c[k-1].clust = cid;
418         }
419     }
420     c[k-1].clust = cid;
421     if (debug)
422     {
423         for (k = 0; (k < n1); k++)
424         {
425             fprintf(debug, "Cluster index for conformation %d: %d\n",
426                     c[k].conf, c[k].clust);
427         }
428     }
429     clust->ncl = cid;
430     for (k = 0; k < n1; k++)
431     {
432         clust->cl[c[k].conf] = c[k].clust;
433     }
434
435     sfree(c);
436     sfree(d);
437 }
438
439 gmx_bool jp_same(int **nnb, int i, int j, int P)
440 {
441     gmx_bool bIn;
442     int      k, ii, jj, pp;
443
444     bIn = FALSE;
445     for (k = 0; nnb[i][k] >= 0; k++)
446     {
447         bIn = bIn || (nnb[i][k] == j);
448     }
449     if (!bIn)
450     {
451         return FALSE;
452     }
453
454     bIn = FALSE;
455     for (k = 0; nnb[j][k] >= 0; k++)
456     {
457         bIn = bIn || (nnb[j][k] == i);
458     }
459     if (!bIn)
460     {
461         return FALSE;
462     }
463
464     pp = 0;
465     for (ii = 0; nnb[i][ii] >= 0; ii++)
466     {
467         for (jj = 0; nnb[j][jj] >= 0; jj++)
468         {
469             if ((nnb[i][ii] == nnb[j][jj]) && (nnb[i][ii] != -1))
470             {
471                 pp++;
472             }
473         }
474     }
475
476     return (pp >= P);
477 }
478
479 static void jarvis_patrick(int n1, real **mat, int M, int P,
480                            real rmsdcut, t_clusters *clust)
481 {
482     t_dist     *row;
483     t_clustid  *c;
484     int       **nnb;
485     int         i, j, k, cid, diff, maxval;
486     gmx_bool    bChange;
487     real      **mcpy = nullptr;
488
489     if (rmsdcut < 0)
490     {
491         rmsdcut = 10000;
492     }
493
494     /* First we sort the entries in the RMSD matrix row by row.
495      * This gives us the nearest neighbor list.
496      */
497     snew(nnb, n1);
498     snew(row, n1);
499     for (i = 0; (i < n1); i++)
500     {
501         for (j = 0; (j < n1); j++)
502         {
503             row[j].j    = j;
504             row[j].dist = mat[i][j];
505         }
506         std::sort(row, row+n1, rms_dist_comp);
507         if (M > 0)
508         {
509             /* Put the M nearest neighbors in the list */
510             snew(nnb[i], M+1);
511             for (j = k = 0; (k < M) && (j < n1) && (mat[i][row[j].j] < rmsdcut); j++)
512             {
513                 if (row[j].j  != i)
514                 {
515                     nnb[i][k]  = row[j].j;
516                     k++;
517                 }
518             }
519             nnb[i][k] = -1;
520         }
521         else
522         {
523             /* Put all neighbors nearer than rmsdcut in the list */
524             maxval = 0;
525             k      = 0;
526             for (j = 0; (j < n1) && (mat[i][row[j].j] < rmsdcut); j++)
527             {
528                 if (row[j].j != i)
529                 {
530                     if (k >= maxval)
531                     {
532                         maxval += 10;
533                         srenew(nnb[i], maxval);
534                     }
535                     nnb[i][k] = row[j].j;
536                     k++;
537                 }
538             }
539             if (k == maxval)
540             {
541                 srenew(nnb[i], maxval+1);
542             }
543             nnb[i][k] = -1;
544         }
545     }
546     sfree(row);
547     if (debug)
548     {
549         fprintf(debug, "Nearest neighborlist. M = %d, P = %d\n", M, P);
550         for (i = 0; (i < n1); i++)
551         {
552             fprintf(debug, "i:%5d nbs:", i);
553             for (j = 0; nnb[i][j] >= 0; j++)
554             {
555                 fprintf(debug, "%5d[%5.3f]", nnb[i][j], mat[i][nnb[i][j]]);
556             }
557             fprintf(debug, "\n");
558         }
559     }
560
561     c = new_clustid(n1);
562     fprintf(stderr, "Linking structures ");
563     /* Use mcpy for temporary storage of booleans */
564     mcpy = mk_matrix(n1, n1, FALSE);
565     for (i = 0; i < n1; i++)
566     {
567         for (j = i+1; j < n1; j++)
568         {
569             mcpy[i][j] = jp_same(nnb, i, j, P);
570         }
571     }
572     do
573     {
574         fprintf(stderr, "*");
575         bChange = FALSE;
576         for (i = 0; i < n1; i++)
577         {
578             for (j = i+1; j < n1; j++)
579             {
580                 if (mcpy[i][j])
581                 {
582                     diff = c[j].clust - c[i].clust;
583                     if (diff)
584                     {
585                         bChange = TRUE;
586                         if (diff > 0)
587                         {
588                             c[j].clust = c[i].clust;
589                         }
590                         else
591                         {
592                             c[i].clust = c[j].clust;
593                         }
594                     }
595                 }
596             }
597         }
598     }
599     while (bChange);
600
601     fprintf(stderr, "\nSorting and renumbering clusters\n");
602     /* Sort on cluster number */
603     std::sort(c, c+n1, clust_id_comp);
604
605     /* Renumber clusters */
606     cid = 1;
607     for (k = 1; k < n1; k++)
608     {
609         if (c[k].clust != c[k-1].clust)
610         {
611             c[k-1].clust = cid;
612             cid++;
613         }
614         else
615         {
616             c[k-1].clust = cid;
617         }
618     }
619     c[k-1].clust = cid;
620     clust->ncl   = cid;
621     for (k = 0; k < n1; k++)
622     {
623         clust->cl[c[k].conf] = c[k].clust;
624     }
625     if (debug)
626     {
627         for (k = 0; (k < n1); k++)
628         {
629             fprintf(debug, "Cluster index for conformation %d: %d\n",
630                     c[k].conf, c[k].clust);
631         }
632     }
633
634     done_matrix(n1, &mcpy);
635
636     sfree(c);
637     for (i = 0; (i < n1); i++)
638     {
639         sfree(nnb[i]);
640     }
641     sfree(nnb);
642 }
643
644 static void dump_nnb (FILE *fp, const char *title, int n1, t_nnb *nnb)
645 {
646     int i, j;
647
648     /* dump neighbor list */
649     fprintf(fp, "%s", title);
650     for (i = 0; (i < n1); i++)
651     {
652         fprintf(fp, "i:%5d #:%5d nbs:", i, nnb[i].nr);
653         for (j = 0; j < nnb[i].nr; j++)
654         {
655             fprintf(fp, "%5d", nnb[i].nb[j]);
656         }
657         fprintf(fp, "\n");
658     }
659 }
660
661 static void gromos(int n1, real **mat, real rmsdcut, t_clusters *clust)
662 {
663     t_dist *row;
664     t_nnb  *nnb;
665     int     i, j, k, j1, maxval;
666
667     /* Put all neighbors nearer than rmsdcut in the list */
668     fprintf(stderr, "Making list of neighbors within cutoff ");
669     snew(nnb, n1);
670     snew(row, n1);
671     for (i = 0; (i < n1); i++)
672     {
673         maxval = 0;
674         k      = 0;
675         /* put all neighbors within cut-off in list */
676         for (j = 0; j < n1; j++)
677         {
678             if (mat[i][j] < rmsdcut)
679             {
680                 if (k >= maxval)
681                 {
682                     maxval += 10;
683                     srenew(nnb[i].nb, maxval);
684                 }
685                 nnb[i].nb[k] = j;
686                 k++;
687             }
688         }
689         /* store nr of neighbors, we'll need that */
690         nnb[i].nr = k;
691         if (i%(1+n1/100) == 0)
692         {
693             fprintf(stderr, "%3d%%\b\b\b\b", (i*100+1)/n1);
694         }
695     }
696     fprintf(stderr, "%3d%%\n", 100);
697     sfree(row);
698
699     /* sort neighbor list on number of neighbors, largest first */
700     std::sort(nnb, nnb+n1, nrnb_comp);
701
702     if (debug)
703     {
704         dump_nnb(debug, "Nearest neighborlist after sort.\n", n1, nnb);
705     }
706
707     /* turn first structure with all its neighbors (largest) into cluster
708        remove them from pool of structures and repeat for all remaining */
709     fprintf(stderr, "Finding clusters %4d", 0);
710     /* cluster id's start at 1: */
711     k = 1;
712     while (nnb[0].nr)
713     {
714         /* set cluster id (k) for first item in neighborlist */
715         for (j = 0; j < nnb[0].nr; j++)
716         {
717             clust->cl[nnb[0].nb[j]] = k;
718         }
719         /* mark as done */
720         nnb[0].nr = 0;
721         sfree(nnb[0].nb);
722
723         /* adjust number of neighbors for others, taking removals into account: */
724         for (i = 1; i < n1 && nnb[i].nr; i++)
725         {
726             j1 = 0;
727             for (j = 0; j < nnb[i].nr; j++)
728             {
729                 /* if this neighbor wasn't removed */
730                 if (clust->cl[nnb[i].nb[j]] == 0)
731                 {
732                     /* shift the rest (j1<=j) */
733                     nnb[i].nb[j1] = nnb[i].nb[j];
734                     /* next */
735                     j1++;
736                 }
737             }
738             /* now j1 is the new number of neighbors */
739             nnb[i].nr = j1;
740         }
741         /* sort again on nnb[].nr, because we have new # neighbors: */
742         /* but we only need to sort upto i, i.e. when nnb[].nr>0 */
743         std::sort(nnb, nnb+i, nrnb_comp);
744
745         fprintf(stderr, "\b\b\b\b%4d", k);
746         /* new cluster id */
747         k++;
748     }
749     fprintf(stderr, "\n");
750     sfree(nnb);
751     if (debug)
752     {
753         fprintf(debug, "Clusters (%d):\n", k);
754         for (i = 0; i < n1; i++)
755         {
756             fprintf(debug, " %3d", clust->cl[i]);
757         }
758         fprintf(debug, "\n");
759     }
760
761     clust->ncl = k-1;
762 }
763
764 rvec **read_whole_trj(const char *fn, int isize, int index[], int skip,
765                       int *nframe, real **time, const gmx_output_env_t *oenv, gmx_bool bPBC, gmx_rmpbc_t gpbc)
766 {
767     rvec       **xx, *x;
768     matrix       box;
769     real         t;
770     int          i, i0, j, max_nf;
771     int          natom;
772     t_trxstatus *status;
773
774
775     max_nf = 0;
776     xx     = nullptr;
777     *time  = nullptr;
778     natom  = read_first_x(oenv, &status, fn, &t, &x, box);
779     i      = 0;
780     i0     = 0;
781     do
782     {
783         if (bPBC)
784         {
785             gmx_rmpbc(gpbc, natom, box, x);
786         }
787         if (i0 >= max_nf)
788         {
789             max_nf += 10;
790             srenew(xx, max_nf);
791             srenew(*time, max_nf);
792         }
793         if ((i % skip) == 0)
794         {
795             snew(xx[i0], isize);
796             /* Store only the interesting atoms */
797             for (j = 0; (j < isize); j++)
798             {
799                 copy_rvec(x[index[j]], xx[i0][j]);
800             }
801             (*time)[i0] = t;
802             i0++;
803         }
804         i++;
805     }
806     while (read_next_x(oenv, status, &t, x, box));
807     fprintf(stderr, "Allocated %lu bytes for frames\n",
808             (unsigned long) (max_nf*isize*sizeof(**xx)));
809     fprintf(stderr, "Read %d frames from trajectory %s\n", i0, fn);
810     *nframe = i0;
811     sfree(x);
812
813     return xx;
814 }
815
816 static int plot_clusters(int nf, real **mat, t_clusters *clust,
817                          int minstruct)
818 {
819     int  i, j, ncluster, ci;
820     int *cl_id, *nstruct, *strind;
821
822     snew(cl_id, nf);
823     snew(nstruct, nf);
824     snew(strind, nf);
825     for (i = 0; i < nf; i++)
826     {
827         strind[i] = 0;
828         cl_id[i]  = clust->cl[i];
829         nstruct[cl_id[i]]++;
830     }
831     ncluster = 0;
832     for (i = 0; i < nf; i++)
833     {
834         if (nstruct[i] >= minstruct)
835         {
836             ncluster++;
837             for (j = 0; (j < nf); j++)
838             {
839                 if (cl_id[j] == i)
840                 {
841                     strind[j] = ncluster;
842                 }
843             }
844         }
845     }
846     ncluster++;
847     fprintf(stderr, "There are %d clusters with at least %d conformations\n",
848             ncluster, minstruct);
849
850     for (i = 0; (i < nf); i++)
851     {
852         ci = cl_id[i];
853         for (j = 0; j < i; j++)
854         {
855             if ((ci == cl_id[j]) && (nstruct[ci] >= minstruct))
856             {
857                 /* color different clusters with different colors, as long as
858                    we don't run out of colors */
859                 mat[i][j] = strind[i];
860             }
861             else
862             {
863                 mat[i][j] = 0;
864             }
865         }
866     }
867     sfree(strind);
868     sfree(nstruct);
869     sfree(cl_id);
870
871     return ncluster;
872 }
873
874 static void mark_clusters(int nf, real **mat, real val, t_clusters *clust)
875 {
876     int i, j;
877
878     for (i = 0; i < nf; i++)
879     {
880         for (j = 0; j < i; j++)
881         {
882             if (clust->cl[i] == clust->cl[j])
883             {
884                 mat[i][j] = val;
885             }
886             else
887             {
888                 mat[i][j] = 0;
889             }
890         }
891     }
892 }
893
894 static char *parse_filename(const char *fn, int maxnr)
895 {
896     int         i;
897     char       *fnout;
898     const char *ext;
899     char        buf[STRLEN];
900
901     if (std::strchr(fn, '%'))
902     {
903         gmx_fatal(FARGS, "will not number filename %s containing '%c'", fn, '%');
904     }
905     /* number of digits needed in numbering */
906     i = static_cast<int>((std::log(static_cast<real>(maxnr))/std::log(10.0)) + 1);
907     /* split fn and ext */
908     ext = std::strrchr(fn, '.');
909     if (!ext)
910     {
911         gmx_fatal(FARGS, "cannot separate extension in filename %s", fn);
912     }
913     ext++;
914     /* insert e.g. '%03d' between fn and ext */
915     sprintf(buf, "%s%%0%dd.%s", fn, i, ext);
916     snew(fnout, std::strlen(buf)+1);
917     std::strcpy(fnout, buf);
918
919     return fnout;
920 }
921
922 static void ana_trans(t_clusters *clust, int nf,
923                       const char *transfn, const char *ntransfn, FILE *log,
924                       t_rgb rlo, t_rgb rhi, const gmx_output_env_t *oenv)
925 {
926     FILE  *fp;
927     real **trans, *axis;
928     int   *ntrans;
929     int    i, ntranst, maxtrans;
930     char   buf[STRLEN];
931
932     snew(ntrans, clust->ncl);
933     snew(trans, clust->ncl);
934     snew(axis, clust->ncl);
935     for (i = 0; i < clust->ncl; i++)
936     {
937         axis[i] = i+1;
938         snew(trans[i], clust->ncl);
939     }
940     ntranst  = 0;
941     maxtrans = 0;
942     for (i = 1; i < nf; i++)
943     {
944         if (clust->cl[i] != clust->cl[i-1])
945         {
946             ntranst++;
947             ntrans[clust->cl[i-1]-1]++;
948             ntrans[clust->cl[i]-1]++;
949             trans[clust->cl[i-1]-1][clust->cl[i]-1]++;
950             maxtrans = static_cast<int>(std::max(static_cast<real>(maxtrans), trans[clust->cl[i]-1][clust->cl[i-1]-1]));
951         }
952     }
953     ffprintf_dd(stderr, log, buf, "Counted %d transitions in total, "
954                 "max %d between two specific clusters\n", ntranst, maxtrans);
955     if (transfn)
956     {
957         fp = gmx_ffopen(transfn, "w");
958         i  = std::min(maxtrans+1, 80);
959         write_xpm(fp, 0, "Cluster Transitions", "# transitions",
960                   "from cluster", "to cluster",
961                   clust->ncl, clust->ncl, axis, axis, trans,
962                   0, maxtrans, rlo, rhi, &i);
963         gmx_ffclose(fp);
964     }
965     if (ntransfn)
966     {
967         fp = xvgropen(ntransfn, "Cluster Transitions", "Cluster #", "# transitions",
968                       oenv);
969         for (i = 0; i < clust->ncl; i++)
970         {
971             fprintf(fp, "%5d %5d\n", i+1, ntrans[i]);
972         }
973         xvgrclose(fp);
974     }
975     sfree(ntrans);
976     for (i = 0; i < clust->ncl; i++)
977     {
978         sfree(trans[i]);
979     }
980     sfree(trans);
981     sfree(axis);
982 }
983
984 static void analyze_clusters(int nf, t_clusters *clust, real **rmsd,
985                              int natom, t_atoms *atoms, rvec *xtps,
986                              real *mass, rvec **xx, real *time,
987                              int ifsize, int *fitidx,
988                              int iosize, int *outidx,
989                              const char *trxfn, const char *sizefn,
990                              const char *transfn, const char *ntransfn,
991                              const char *clustidfn, gmx_bool bAverage,
992                              int write_ncl, int write_nst, real rmsmin,
993                              gmx_bool bFit, FILE *log, t_rgb rlo, t_rgb rhi,
994                              const gmx_output_env_t *oenv)
995 {
996     FILE        *size_fp = nullptr;
997     char         buf[STRLEN], buf1[40], buf2[40], buf3[40], *trxsfn;
998     t_trxstatus *trxout  = nullptr;
999     t_trxstatus *trxsout = nullptr;
1000     int          i, i1, cl, nstr, *structure, first = 0, midstr;
1001     gmx_bool    *bWrite = nullptr;
1002     real         r, clrmsd, midrmsd;
1003     rvec        *xav = nullptr;
1004     matrix       zerobox;
1005
1006     clear_mat(zerobox);
1007
1008     ffprintf_d(stderr, log, buf, "\nFound %d clusters\n\n", clust->ncl);
1009     trxsfn = nullptr;
1010     if (trxfn)
1011     {
1012         /* do we write all structures? */
1013         if (write_ncl)
1014         {
1015             trxsfn = parse_filename(trxfn, std::max(write_ncl, clust->ncl));
1016             snew(bWrite, nf);
1017         }
1018         ffprintf_ss(stderr, log, buf, "Writing %s structure for each cluster to %s\n",
1019                     bAverage ? "average" : "middle", trxfn);
1020         if (write_ncl)
1021         {
1022             /* find out what we want to tell the user:
1023                Writing [all structures|structures with rmsd > %g] for
1024                {all|first %d} clusters {with more than %d structures} to %s     */
1025             if (rmsmin > 0.0)
1026             {
1027                 sprintf(buf1, "structures with rmsd > %g", rmsmin);
1028             }
1029             else
1030             {
1031                 sprintf(buf1, "all structures");
1032             }
1033             buf2[0] = buf3[0] = '\0';
1034             if (write_ncl >= clust->ncl)
1035             {
1036                 if (write_nst == 0)
1037                 {
1038                     sprintf(buf2, "all ");
1039                 }
1040             }
1041             else
1042             {
1043                 sprintf(buf2, "the first %d ", write_ncl);
1044             }
1045             if (write_nst)
1046             {
1047                 sprintf(buf3, " with more than %d structures", write_nst);
1048             }
1049             sprintf(buf, "Writing %s for %sclusters%s to %s\n", buf1, buf2, buf3, trxsfn);
1050             ffprintf(stderr, log, buf);
1051         }
1052
1053         /* Prepare a reference structure for the orientation of the clusters  */
1054         if (bFit)
1055         {
1056             reset_x(ifsize, fitidx, natom, nullptr, xtps, mass);
1057         }
1058         trxout = open_trx(trxfn, "w");
1059         /* Calculate the average structure in each cluster,               *
1060          * all structures are fitted to the first struture of the cluster */
1061         snew(xav, natom);
1062     }
1063
1064     if (transfn || ntransfn)
1065     {
1066         ana_trans(clust, nf, transfn, ntransfn, log, rlo, rhi, oenv);
1067     }
1068
1069     if (clustidfn)
1070     {
1071         FILE *fp = xvgropen(clustidfn, "Clusters", output_env_get_xvgr_tlabel(oenv), "Cluster #", oenv);
1072         if (output_env_get_print_xvgr_codes(oenv))
1073         {
1074             fprintf(fp, "@    s0 symbol 2\n");
1075             fprintf(fp, "@    s0 symbol size 0.2\n");
1076             fprintf(fp, "@    s0 linestyle 0\n");
1077         }
1078         for (i = 0; i < nf; i++)
1079         {
1080             fprintf(fp, "%8g %8d\n", time[i], clust->cl[i]);
1081         }
1082         xvgrclose(fp);
1083     }
1084     if (sizefn)
1085     {
1086         size_fp = xvgropen(sizefn, "Cluster Sizes", "Cluster #", "# Structures", oenv);
1087         if (output_env_get_print_xvgr_codes(oenv))
1088         {
1089             fprintf(size_fp, "@g%d type %s\n", 0, "bar");
1090         }
1091     }
1092     snew(structure, nf);
1093     fprintf(log, "\n%3s | %3s  %4s | %6s %4s | cluster members\n",
1094             "cl.", "#st", "rmsd", "middle", "rmsd");
1095     for (cl = 1; cl <= clust->ncl; cl++)
1096     {
1097         /* prepare structures (fit, middle, average) */
1098         if (xav)
1099         {
1100             for (i = 0; i < natom; i++)
1101             {
1102                 clear_rvec(xav[i]);
1103             }
1104         }
1105         nstr = 0;
1106         for (i1 = 0; i1 < nf; i1++)
1107         {
1108             if (clust->cl[i1] == cl)
1109             {
1110                 structure[nstr] = i1;
1111                 nstr++;
1112                 if (trxfn && (bAverage || write_ncl) )
1113                 {
1114                     if (bFit)
1115                     {
1116                         reset_x(ifsize, fitidx, natom, nullptr, xx[i1], mass);
1117                     }
1118                     if (nstr == 1)
1119                     {
1120                         first = i1;
1121                     }
1122                     else if (bFit)
1123                     {
1124                         do_fit(natom, mass, xx[first], xx[i1]);
1125                     }
1126                     if (xav)
1127                     {
1128                         for (i = 0; i < natom; i++)
1129                         {
1130                             rvec_inc(xav[i], xx[i1][i]);
1131                         }
1132                     }
1133                 }
1134             }
1135         }
1136         if (sizefn)
1137         {
1138             fprintf(size_fp, "%8d %8d\n", cl, nstr);
1139         }
1140         clrmsd  = 0;
1141         midstr  = 0;
1142         midrmsd = 10000;
1143         for (i1 = 0; i1 < nstr; i1++)
1144         {
1145             r = 0;
1146             if (nstr > 1)
1147             {
1148                 for (i = 0; i < nstr; i++)
1149                 {
1150                     if (i < i1)
1151                     {
1152                         r += rmsd[structure[i]][structure[i1]];
1153                     }
1154                     else
1155                     {
1156                         r += rmsd[structure[i1]][structure[i]];
1157                     }
1158                 }
1159                 r /= (nstr - 1);
1160             }
1161             if (r < midrmsd)
1162             {
1163                 midstr  = structure[i1];
1164                 midrmsd = r;
1165             }
1166             clrmsd += r;
1167         }
1168         clrmsd /= nstr;
1169
1170         /* dump cluster info to logfile */
1171         if (nstr > 1)
1172         {
1173             sprintf(buf1, "%6.3f", clrmsd);
1174             if (buf1[0] == '0')
1175             {
1176                 buf1[0] = ' ';
1177             }
1178             sprintf(buf2, "%5.3f", midrmsd);
1179             if (buf2[0] == '0')
1180             {
1181                 buf2[0] = ' ';
1182             }
1183         }
1184         else
1185         {
1186             sprintf(buf1, "%5s", "");
1187             sprintf(buf2, "%5s", "");
1188         }
1189         fprintf(log, "%3d | %3d %s | %6g%s |", cl, nstr, buf1, time[midstr], buf2);
1190         for (i = 0; i < nstr; i++)
1191         {
1192             if ((i % 7 == 0) && i)
1193             {
1194                 sprintf(buf, "\n%3s | %3s  %4s | %6s %4s |", "", "", "", "", "");
1195             }
1196             else
1197             {
1198                 buf[0] = '\0';
1199             }
1200             i1 = structure[i];
1201             fprintf(log, "%s %6g", buf, time[i1]);
1202         }
1203         fprintf(log, "\n");
1204
1205         /* write structures to trajectory file(s) */
1206         if (trxfn)
1207         {
1208             if (write_ncl)
1209             {
1210                 for (i = 0; i < nstr; i++)
1211                 {
1212                     bWrite[i] = FALSE;
1213                 }
1214             }
1215             if (cl < write_ncl+1 && nstr > write_nst)
1216             {
1217                 /* Dump all structures for this cluster */
1218                 /* generate numbered filename (there is a %d in trxfn!) */
1219                 sprintf(buf, trxsfn, cl);
1220                 trxsout = open_trx(buf, "w");
1221                 for (i = 0; i < nstr; i++)
1222                 {
1223                     bWrite[i] = TRUE;
1224                     if (rmsmin > 0.0)
1225                     {
1226                         for (i1 = 0; i1 < i && bWrite[i]; i1++)
1227                         {
1228                             if (bWrite[i1])
1229                             {
1230                                 bWrite[i] = rmsd[structure[i1]][structure[i]] > rmsmin;
1231                             }
1232                         }
1233                     }
1234                     if (bWrite[i])
1235                     {
1236                         write_trx(trxsout, iosize, outidx, atoms, i, time[structure[i]], zerobox,
1237                                   xx[structure[i]], nullptr, nullptr);
1238                     }
1239                 }
1240                 close_trx(trxsout);
1241             }
1242             /* Dump the average structure for this cluster */
1243             if (bAverage)
1244             {
1245                 for (i = 0; i < natom; i++)
1246                 {
1247                     svmul(1.0/nstr, xav[i], xav[i]);
1248                 }
1249             }
1250             else
1251             {
1252                 for (i = 0; i < natom; i++)
1253                 {
1254                     copy_rvec(xx[midstr][i], xav[i]);
1255                 }
1256                 if (bFit)
1257                 {
1258                     reset_x(ifsize, fitidx, natom, nullptr, xav, mass);
1259                 }
1260             }
1261             if (bFit)
1262             {
1263                 do_fit(natom, mass, xtps, xav);
1264             }
1265             write_trx(trxout, iosize, outidx, atoms, cl, time[midstr], zerobox, xav, nullptr, nullptr);
1266         }
1267     }
1268     /* clean up */
1269     if (trxfn)
1270     {
1271         close_trx(trxout);
1272         sfree(xav);
1273         if (write_ncl)
1274         {
1275             sfree(bWrite);
1276         }
1277     }
1278     sfree(structure);
1279     if (trxsfn)
1280     {
1281         sfree(trxsfn);
1282     }
1283
1284     if (size_fp)
1285     {
1286         xvgrclose(size_fp);
1287     }
1288 }
1289
1290 static void convert_mat(t_matrix *mat, t_mat *rms)
1291 {
1292     int i, j;
1293
1294     rms->n1 = mat->nx;
1295     matrix2real(mat, rms->mat);
1296     /* free input xpm matrix data */
1297     for (i = 0; i < mat->nx; i++)
1298     {
1299         sfree(mat->matrix[i]);
1300     }
1301     sfree(mat->matrix);
1302
1303     for (i = 0; i < mat->nx; i++)
1304     {
1305         for (j = i; j < mat->nx; j++)
1306         {
1307             rms->sumrms += rms->mat[i][j];
1308             rms->maxrms  = std::max(rms->maxrms, rms->mat[i][j]);
1309             if (j != i)
1310             {
1311                 rms->minrms = std::min(rms->minrms, rms->mat[i][j]);
1312             }
1313         }
1314     }
1315     rms->nn = mat->nx;
1316 }
1317
1318 int gmx_cluster(int argc, char *argv[])
1319 {
1320     const char        *desc[] = {
1321         "[THISMODULE] can cluster structures using several different methods.",
1322         "Distances between structures can be determined from a trajectory",
1323         "or read from an [REF].xpm[ref] matrix file with the [TT]-dm[tt] option.",
1324         "RMS deviation after fitting or RMS deviation of atom-pair distances",
1325         "can be used to define the distance between structures.[PAR]",
1326
1327         "single linkage: add a structure to a cluster when its distance to any",
1328         "element of the cluster is less than [TT]cutoff[tt].[PAR]",
1329
1330         "Jarvis Patrick: add a structure to a cluster when this structure",
1331         "and a structure in the cluster have each other as neighbors and",
1332         "they have a least [TT]P[tt] neighbors in common. The neighbors",
1333         "of a structure are the M closest structures or all structures within",
1334         "[TT]cutoff[tt].[PAR]",
1335
1336         "Monte Carlo: reorder the RMSD matrix using Monte Carlo such that",
1337         "the order of the frames is using the smallest possible increments.",
1338         "With this it is possible to make a smooth animation going from one",
1339         "structure to another with the largest possible (e.g.) RMSD between",
1340         "them, however the intermediate steps should be as small as possible.",
1341         "Applications could be to visualize a potential of mean force",
1342         "ensemble of simulations or a pulling simulation. Obviously the user",
1343         "has to prepare the trajectory well (e.g. by not superimposing frames).",
1344         "The final result can be inspect visually by looking at the matrix",
1345         "[REF].xpm[ref] file, which should vary smoothly from bottom to top.[PAR]",
1346
1347         "diagonalization: diagonalize the RMSD matrix.[PAR]",
1348
1349         "gromos: use algorithm as described in Daura [IT]et al.[it]",
1350         "([IT]Angew. Chem. Int. Ed.[it] [BB]1999[bb], [IT]38[it], pp 236-240).",
1351         "Count number of neighbors using cut-off, take structure with",
1352         "largest number of neighbors with all its neighbors as cluster",
1353         "and eliminate it from the pool of clusters. Repeat for remaining",
1354         "structures in pool.[PAR]",
1355
1356         "When the clustering algorithm assigns each structure to exactly one",
1357         "cluster (single linkage, Jarvis Patrick and gromos) and a trajectory",
1358         "file is supplied, the structure with",
1359         "the smallest average distance to the others or the average structure",
1360         "or all structures for each cluster will be written to a trajectory",
1361         "file. When writing all structures, separate numbered files are made",
1362         "for each cluster.[PAR]",
1363
1364         "Two output files are always written:",
1365         "",
1366         " * [TT]-o[tt] writes the RMSD values in the upper left half of the matrix",
1367         "   and a graphical depiction of the clusters in the lower right half",
1368         "   When [TT]-minstruct[tt] = 1 the graphical depiction is black",
1369         "   when two structures are in the same cluster.",
1370         "   When [TT]-minstruct[tt] > 1 different colors will be used for each",
1371         "   cluster.",
1372         " * [TT]-g[tt] writes information on the options used and a detailed list",
1373         "   of all clusters and their members.",
1374         "",
1375
1376         "Additionally, a number of optional output files can be written:",
1377         "",
1378         " * [TT]-dist[tt] writes the RMSD distribution.",
1379         " * [TT]-ev[tt] writes the eigenvectors of the RMSD matrix",
1380         "   diagonalization.",
1381         " * [TT]-sz[tt] writes the cluster sizes.",
1382         " * [TT]-tr[tt] writes a matrix of the number transitions between",
1383         "   cluster pairs.",
1384         " * [TT]-ntr[tt] writes the total number of transitions to or from",
1385         "   each cluster.",
1386         " * [TT]-clid[tt] writes the cluster number as a function of time.",
1387         " * [TT]-cl[tt] writes average (with option [TT]-av[tt]) or central",
1388         "   structure of each cluster or writes numbered files with cluster members",
1389         "   for a selected set of clusters (with option [TT]-wcl[tt], depends on",
1390         "   [TT]-nst[tt] and [TT]-rmsmin[tt]). The center of a cluster is the",
1391         "   structure with the smallest average RMSD from all other structures",
1392         "   of the cluster.",
1393     };
1394
1395     FILE              *fp, *log;
1396     int                nf, i, i1, i2, j;
1397     gmx_int64_t        nrms = 0;
1398
1399     matrix             box;
1400     rvec              *xtps, *usextps, *x1, **xx = nullptr;
1401     const char        *fn, *trx_out_fn;
1402     t_clusters         clust;
1403     t_mat             *rms, *orig = nullptr;
1404     real              *eigenvalues;
1405     t_topology         top;
1406     int                ePBC;
1407     t_atoms            useatoms;
1408     t_matrix          *readmat = nullptr;
1409     real              *eigenvectors;
1410
1411     int                isize = 0, ifsize = 0, iosize = 0;
1412     int               *index = nullptr, *fitidx = nullptr, *outidx = nullptr;
1413     char              *grpname;
1414     real               rmsd, **d1, **d2, *time = nullptr, time_invfac, *mass = nullptr;
1415     char               buf[STRLEN], buf1[80], title[STRLEN];
1416     gmx_bool           bAnalyze, bUseRmsdCut, bJP_RMSD = FALSE, bReadMat, bReadTraj, bPBC = TRUE;
1417
1418     int                method, ncluster = 0;
1419     static const char *methodname[] = {
1420         nullptr, "linkage", "jarvis-patrick", "monte-carlo",
1421         "diagonalization", "gromos", nullptr
1422     };
1423     enum {
1424         m_null, m_linkage, m_jarvis_patrick,
1425         m_monte_carlo, m_diagonalize, m_gromos, m_nr
1426     };
1427     /* Set colors for plotting: white = zero RMS, black = maximum */
1428     static t_rgb      rlo_top  = { 1.0, 1.0, 1.0 };
1429     static t_rgb      rhi_top  = { 0.0, 0.0, 0.0 };
1430     static t_rgb      rlo_bot  = { 1.0, 1.0, 1.0 };
1431     static t_rgb      rhi_bot  = { 0.0, 0.0, 1.0 };
1432     static int        nlevels  = 40, skip = 1;
1433     static real       scalemax = -1.0, rmsdcut = 0.1, rmsmin = 0.0;
1434     gmx_bool          bRMSdist = FALSE, bBinary = FALSE, bAverage = FALSE, bFit = TRUE;
1435     static int        niter    = 10000, nrandom = 0, seed = 0, write_ncl = 0, write_nst = 1, minstruct = 1;
1436     static real       kT       = 1e-3;
1437     static int        M        = 10, P = 3;
1438     gmx_output_env_t *oenv;
1439     gmx_rmpbc_t       gpbc = nullptr;
1440
1441     t_pargs           pa[] = {
1442         { "-dista", FALSE, etBOOL, {&bRMSdist},
1443           "Use RMSD of distances instead of RMS deviation" },
1444         { "-nlevels", FALSE, etINT,  {&nlevels},
1445           "Discretize RMSD matrix in this number of levels" },
1446         { "-cutoff", FALSE, etREAL, {&rmsdcut},
1447           "RMSD cut-off (nm) for two structures to be neighbor" },
1448         { "-fit",   FALSE, etBOOL, {&bFit},
1449           "Use least squares fitting before RMSD calculation" },
1450         { "-max",   FALSE, etREAL, {&scalemax},
1451           "Maximum level in RMSD matrix" },
1452         { "-skip",  FALSE, etINT,  {&skip},
1453           "Only analyze every nr-th frame" },
1454         { "-av",    FALSE, etBOOL, {&bAverage},
1455           "Write average iso middle structure for each cluster" },
1456         { "-wcl",   FALSE, etINT,  {&write_ncl},
1457           "Write the structures for this number of clusters to numbered files" },
1458         { "-nst",   FALSE, etINT,  {&write_nst},
1459           "Only write all structures if more than this number of structures per cluster" },
1460         { "-rmsmin", FALSE, etREAL, {&rmsmin},
1461           "minimum rms difference with rest of cluster for writing structures" },
1462         { "-method", FALSE, etENUM, {methodname},
1463           "Method for cluster determination" },
1464         { "-minstruct", FALSE, etINT, {&minstruct},
1465           "Minimum number of structures in cluster for coloring in the [REF].xpm[ref] file" },
1466         { "-binary", FALSE, etBOOL, {&bBinary},
1467           "Treat the RMSD matrix as consisting of 0 and 1, where the cut-off "
1468           "is given by [TT]-cutoff[tt]" },
1469         { "-M",     FALSE, etINT,  {&M},
1470           "Number of nearest neighbors considered for Jarvis-Patrick algorithm, "
1471           "0 is use cutoff" },
1472         { "-P",     FALSE, etINT,  {&P},
1473           "Number of identical nearest neighbors required to form a cluster" },
1474         { "-seed",  FALSE, etINT,  {&seed},
1475           "Random number seed for Monte Carlo clustering algorithm (0 means generate)" },
1476         { "-niter", FALSE, etINT,  {&niter},
1477           "Number of iterations for MC" },
1478         { "-nrandom", FALSE, etINT,  {&nrandom},
1479           "The first iterations for MC may be done complete random, to shuffle the frames" },
1480         { "-kT",    FALSE, etREAL, {&kT},
1481           "Boltzmann weighting factor for Monte Carlo optimization "
1482           "(zero turns off uphill steps)" },
1483         { "-pbc", FALSE, etBOOL,
1484           { &bPBC }, "PBC check" }
1485     };
1486     t_filenm          fnm[] = {
1487         { efTRX, "-f",     nullptr,        ffOPTRD },
1488         { efTPS, "-s",     nullptr,        ffOPTRD },
1489         { efNDX, nullptr,     nullptr,        ffOPTRD },
1490         { efXPM, "-dm",   "rmsd",       ffOPTRD },
1491         { efXPM, "-om",   "rmsd-raw",   ffWRITE },
1492         { efXPM, "-o",    "rmsd-clust", ffWRITE },
1493         { efLOG, "-g",    "cluster",    ffWRITE },
1494         { efXVG, "-dist", "rmsd-dist",  ffOPTWR },
1495         { efXVG, "-ev",   "rmsd-eig",   ffOPTWR },
1496         { efXVG, "-conv", "mc-conv",    ffOPTWR },
1497         { efXVG, "-sz",   "clust-size", ffOPTWR},
1498         { efXPM, "-tr",   "clust-trans", ffOPTWR},
1499         { efXVG, "-ntr",  "clust-trans", ffOPTWR},
1500         { efXVG, "-clid", "clust-id",   ffOPTWR},
1501         { efTRX, "-cl",   "clusters.pdb", ffOPTWR }
1502     };
1503 #define NFILE asize(fnm)
1504
1505     if (!parse_common_args(&argc, argv,
1506                            PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT,
1507                            NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr,
1508                            &oenv))
1509     {
1510         return 0;
1511     }
1512
1513     /* parse options */
1514     bReadMat   = opt2bSet("-dm", NFILE, fnm);
1515     bReadTraj  = opt2bSet("-f", NFILE, fnm) || !bReadMat;
1516     if (opt2parg_bSet("-av", asize(pa), pa) ||
1517         opt2parg_bSet("-wcl", asize(pa), pa) ||
1518         opt2parg_bSet("-nst", asize(pa), pa) ||
1519         opt2parg_bSet("-rmsmin", asize(pa), pa) ||
1520         opt2bSet("-cl", NFILE, fnm) )
1521     {
1522         trx_out_fn = opt2fn("-cl", NFILE, fnm);
1523     }
1524     else
1525     {
1526         trx_out_fn = nullptr;
1527     }
1528     if (bReadMat && output_env_get_time_factor(oenv) != 1)
1529     {
1530         fprintf(stderr,
1531                 "\nWarning: assuming the time unit in %s is %s\n",
1532                 opt2fn("-dm", NFILE, fnm), output_env_get_time_unit(oenv));
1533     }
1534     if (trx_out_fn && !bReadTraj)
1535     {
1536         fprintf(stderr, "\nWarning: "
1537                 "cannot write cluster structures without reading trajectory\n"
1538                 "         ignoring option -cl %s\n", trx_out_fn);
1539     }
1540
1541     method = 1;
1542     while (method < m_nr && gmx_strcasecmp(methodname[0], methodname[method]) != 0)
1543     {
1544         method++;
1545     }
1546     if (method == m_nr)
1547     {
1548         gmx_fatal(FARGS, "Invalid method");
1549     }
1550
1551     bAnalyze = (method == m_linkage || method == m_jarvis_patrick ||
1552                 method == m_gromos );
1553
1554     /* Open log file */
1555     log = ftp2FILE(efLOG, NFILE, fnm, "w");
1556
1557     fprintf(stderr, "Using %s method for clustering\n", methodname[0]);
1558     fprintf(log, "Using %s method for clustering\n", methodname[0]);
1559
1560     /* check input and write parameters to log file */
1561     bUseRmsdCut = FALSE;
1562     if (method == m_jarvis_patrick)
1563     {
1564         bJP_RMSD = (M == 0) || opt2parg_bSet("-cutoff", asize(pa), pa);
1565         if ((M < 0) || (M == 1))
1566         {
1567             gmx_fatal(FARGS, "M (%d) must be 0 or larger than 1", M);
1568         }
1569         if (M < 2)
1570         {
1571             sprintf(buf1, "Will use P=%d and RMSD cutoff (%g)", P, rmsdcut);
1572             bUseRmsdCut = TRUE;
1573         }
1574         else
1575         {
1576             if (P >= M)
1577             {
1578                 gmx_fatal(FARGS, "Number of neighbors required (P) must be less than M");
1579             }
1580             if (bJP_RMSD)
1581             {
1582                 sprintf(buf1, "Will use P=%d, M=%d and RMSD cutoff (%g)", P, M, rmsdcut);
1583                 bUseRmsdCut = TRUE;
1584             }
1585             else
1586             {
1587                 sprintf(buf1, "Will use P=%d, M=%d", P, M);
1588             }
1589         }
1590         ffprintf_s(stderr, log, buf, "%s for determining the neighbors\n\n", buf1);
1591     }
1592     else /* method != m_jarvis */
1593     {
1594         bUseRmsdCut = ( bBinary || method == m_linkage || method == m_gromos );
1595     }
1596     if (bUseRmsdCut && method != m_jarvis_patrick)
1597     {
1598         fprintf(log, "Using RMSD cutoff %g nm\n", rmsdcut);
1599     }
1600     if (method == m_monte_carlo)
1601     {
1602         fprintf(log, "Using %d iterations\n", niter);
1603     }
1604
1605     if (skip < 1)
1606     {
1607         gmx_fatal(FARGS, "skip (%d) should be >= 1", skip);
1608     }
1609
1610     /* get input */
1611     if (bReadTraj)
1612     {
1613         /* don't read mass-database as masses (and top) are not used */
1614         read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &ePBC, &xtps, nullptr, box,
1615                       TRUE);
1616         if (bPBC)
1617         {
1618             gpbc = gmx_rmpbc_init(&top.idef, ePBC, top.atoms.nr);
1619         }
1620
1621         fprintf(stderr, "\nSelect group for least squares fit%s:\n",
1622                 bReadMat ? "" : " and RMSD calculation");
1623         get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm),
1624                   1, &ifsize, &fitidx, &grpname);
1625         if (trx_out_fn)
1626         {
1627             fprintf(stderr, "\nSelect group for output:\n");
1628             get_index(&(top.atoms), ftp2fn_null(efNDX, NFILE, fnm),
1629                       1, &iosize, &outidx, &grpname);
1630             /* merge and convert both index groups: */
1631             /* first copy outidx to index. let outidx refer to elements in index */
1632             snew(index, iosize);
1633             isize = iosize;
1634             for (i = 0; i < iosize; i++)
1635             {
1636                 index[i]  = outidx[i];
1637                 outidx[i] = i;
1638             }
1639             /* now lookup elements from fitidx in index, add them if necessary
1640                and also let fitidx refer to elements in index */
1641             for (i = 0; i < ifsize; i++)
1642             {
1643                 j = 0;
1644                 while (j < isize && index[j] != fitidx[i])
1645                 {
1646                     j++;
1647                 }
1648                 if (j >= isize)
1649                 {
1650                     /* slow this way, but doesn't matter much */
1651                     isize++;
1652                     srenew(index, isize);
1653                 }
1654                 index[j]  = fitidx[i];
1655                 fitidx[i] = j;
1656             }
1657         }
1658         else /* !trx_out_fn */
1659         {
1660             isize = ifsize;
1661             snew(index, isize);
1662             for (i = 0; i < ifsize; i++)
1663             {
1664                 index[i]  = fitidx[i];
1665                 fitidx[i] = i;
1666             }
1667         }
1668     }
1669
1670     if (bReadTraj)
1671     {
1672         /* Loop over first coordinate file */
1673         fn = opt2fn("-f", NFILE, fnm);
1674
1675         xx = read_whole_trj(fn, isize, index, skip, &nf, &time, oenv, bPBC, gpbc);
1676         output_env_conv_times(oenv, nf, time);
1677         if (!bRMSdist || bAnalyze)
1678         {
1679             /* Center all frames on zero */
1680             snew(mass, isize);
1681             for (i = 0; i < ifsize; i++)
1682             {
1683                 mass[fitidx[i]] = top.atoms.atom[index[fitidx[i]]].m;
1684             }
1685             if (bFit)
1686             {
1687                 for (i = 0; i < nf; i++)
1688                 {
1689                     reset_x(ifsize, fitidx, isize, nullptr, xx[i], mass);
1690                 }
1691             }
1692         }
1693         if (bPBC)
1694         {
1695             gmx_rmpbc_done(gpbc);
1696         }
1697     }
1698
1699     if (bReadMat)
1700     {
1701         fprintf(stderr, "Reading rms distance matrix ");
1702         read_xpm_matrix(opt2fn("-dm", NFILE, fnm), &readmat);
1703         fprintf(stderr, "\n");
1704         if (readmat[0].nx != readmat[0].ny)
1705         {
1706             gmx_fatal(FARGS, "Matrix (%dx%d) is not square",
1707                       readmat[0].nx, readmat[0].ny);
1708         }
1709         if (bReadTraj && bAnalyze && (readmat[0].nx != nf))
1710         {
1711             gmx_fatal(FARGS, "Matrix size (%dx%d) does not match the number of "
1712                       "frames (%d)", readmat[0].nx, readmat[0].ny, nf);
1713         }
1714
1715         nf = readmat[0].nx;
1716         sfree(time);
1717         time        = readmat[0].axis_x;
1718         time_invfac = output_env_get_time_invfactor(oenv);
1719         for (i = 0; i < nf; i++)
1720         {
1721             time[i] *= time_invfac;
1722         }
1723
1724         rms = init_mat(readmat[0].nx, method == m_diagonalize);
1725         convert_mat(&(readmat[0]), rms);
1726
1727         nlevels = readmat[0].nmap;
1728     }
1729     else   /* !bReadMat */
1730     {
1731         rms  = init_mat(nf, method == m_diagonalize);
1732         nrms = (static_cast<gmx_int64_t>(nf)*static_cast<gmx_int64_t>(nf-1))/2;
1733         if (!bRMSdist)
1734         {
1735             fprintf(stderr, "Computing %dx%d RMS deviation matrix\n", nf, nf);
1736             /* Initialize work array */
1737             snew(x1, isize);
1738             for (i1 = 0; i1 < nf; i1++)
1739             {
1740                 for (i2 = i1+1; i2 < nf; i2++)
1741                 {
1742                     for (i = 0; i < isize; i++)
1743                     {
1744                         copy_rvec(xx[i1][i], x1[i]);
1745                     }
1746                     if (bFit)
1747                     {
1748                         do_fit(isize, mass, xx[i2], x1);
1749                     }
1750                     rmsd = rmsdev(isize, mass, xx[i2], x1);
1751                     set_mat_entry(rms, i1, i2, rmsd);
1752                 }
1753                 nrms -= nf-i1-1;
1754                 fprintf(stderr, "\r# RMSD calculations left: " "%" GMX_PRId64 "   ", nrms);
1755                 fflush(stderr);
1756             }
1757             sfree(x1);
1758         }
1759         else /* bRMSdist */
1760         {
1761             fprintf(stderr, "Computing %dx%d RMS distance deviation matrix\n", nf, nf);
1762
1763             /* Initiate work arrays */
1764             snew(d1, isize);
1765             snew(d2, isize);
1766             for (i = 0; (i < isize); i++)
1767             {
1768                 snew(d1[i], isize);
1769                 snew(d2[i], isize);
1770             }
1771             for (i1 = 0; i1 < nf; i1++)
1772             {
1773                 calc_dist(isize, xx[i1], d1);
1774                 for (i2 = i1+1; (i2 < nf); i2++)
1775                 {
1776                     calc_dist(isize, xx[i2], d2);
1777                     set_mat_entry(rms, i1, i2, rms_dist(isize, d1, d2));
1778                 }
1779                 nrms -= nf-i1-1;
1780                 fprintf(stderr, "\r# RMSD calculations left: " "%" GMX_PRId64 "   ", nrms);
1781                 fflush(stderr);
1782             }
1783             /* Clean up work arrays */
1784             for (i = 0; (i < isize); i++)
1785             {
1786                 sfree(d1[i]);
1787                 sfree(d2[i]);
1788             }
1789             sfree(d1);
1790             sfree(d2);
1791         }
1792         fprintf(stderr, "\n\n");
1793     }
1794     ffprintf_gg(stderr, log, buf, "The RMSD ranges from %g to %g nm\n",
1795                 rms->minrms, rms->maxrms);
1796     ffprintf_g(stderr, log, buf, "Average RMSD is %g\n", 2*rms->sumrms/(nf*(nf-1)));
1797     ffprintf_d(stderr, log, buf, "Number of structures for matrix %d\n", nf);
1798     ffprintf_g(stderr, log, buf, "Energy of the matrix is %g.\n", mat_energy(rms));
1799     if (bUseRmsdCut && (rmsdcut < rms->minrms || rmsdcut > rms->maxrms) )
1800     {
1801         fprintf(stderr, "WARNING: rmsd cutoff %g is outside range of rmsd values "
1802                 "%g to %g\n", rmsdcut, rms->minrms, rms->maxrms);
1803     }
1804     if (bAnalyze && (rmsmin < rms->minrms) )
1805     {
1806         fprintf(stderr, "WARNING: rmsd minimum %g is below lowest rmsd value %g\n",
1807                 rmsmin, rms->minrms);
1808     }
1809     if (bAnalyze && (rmsmin > rmsdcut) )
1810     {
1811         fprintf(stderr, "WARNING: rmsd minimum %g is above rmsd cutoff %g\n",
1812                 rmsmin, rmsdcut);
1813     }
1814
1815     /* Plot the rmsd distribution */
1816     rmsd_distribution(opt2fn("-dist", NFILE, fnm), rms, oenv);
1817
1818     if (bBinary)
1819     {
1820         for (i1 = 0; (i1 < nf); i1++)
1821         {
1822             for (i2 = 0; (i2 < nf); i2++)
1823             {
1824                 if (rms->mat[i1][i2] < rmsdcut)
1825                 {
1826                     rms->mat[i1][i2] = 0;
1827                 }
1828                 else
1829                 {
1830                     rms->mat[i1][i2] = 1;
1831                 }
1832             }
1833         }
1834     }
1835
1836     snew(clust.cl, nf);
1837     switch (method)
1838     {
1839         case m_linkage:
1840             /* Now sort the matrix and write it out again */
1841             gather(rms, rmsdcut, &clust);
1842             break;
1843         case m_diagonalize:
1844             /* Do a diagonalization */
1845             snew(eigenvalues, nf);
1846             snew(eigenvectors, nf*nf);
1847             std::memcpy(eigenvectors, rms->mat[0], nf*nf*sizeof(real));
1848             eigensolver(eigenvectors, nf, 0, nf, eigenvalues, rms->mat[0]);
1849             sfree(eigenvectors);
1850
1851             fp = xvgropen(opt2fn("-ev", NFILE, fnm), "RMSD matrix Eigenvalues",
1852                           "Eigenvector index", "Eigenvalues (nm\\S2\\N)", oenv);
1853             for (i = 0; (i < nf); i++)
1854             {
1855                 fprintf(fp, "%10d  %10g\n", i, eigenvalues[i]);
1856             }
1857             xvgrclose(fp);
1858             break;
1859         case m_monte_carlo:
1860             orig     = init_mat(rms->nn, FALSE);
1861             orig->nn = rms->nn;
1862             copy_t_mat(orig, rms);
1863             mc_optimize(log, rms, time, niter, nrandom, seed, kT,
1864                         opt2fn_null("-conv", NFILE, fnm), oenv);
1865             break;
1866         case m_jarvis_patrick:
1867             jarvis_patrick(rms->nn, rms->mat, M, P, bJP_RMSD ? rmsdcut : -1, &clust);
1868             break;
1869         case m_gromos:
1870             gromos(rms->nn, rms->mat, rmsdcut, &clust);
1871             break;
1872         default:
1873             gmx_fatal(FARGS, "DEATH HORROR unknown method \"%s\"", methodname[0]);
1874     }
1875
1876     if (method == m_monte_carlo || method == m_diagonalize)
1877     {
1878         fprintf(stderr, "Energy of the matrix after clustering is %g.\n",
1879                 mat_energy(rms));
1880     }
1881
1882     if (bAnalyze)
1883     {
1884         if (minstruct > 1)
1885         {
1886             ncluster = plot_clusters(nf, rms->mat, &clust, minstruct);
1887         }
1888         else
1889         {
1890             mark_clusters(nf, rms->mat, rms->maxrms, &clust);
1891         }
1892         init_t_atoms(&useatoms, isize, FALSE);
1893         snew(usextps, isize);
1894         useatoms.resinfo = top.atoms.resinfo;
1895         for (i = 0; i < isize; i++)
1896         {
1897             useatoms.atomname[i]    = top.atoms.atomname[index[i]];
1898             useatoms.atom[i].resind = top.atoms.atom[index[i]].resind;
1899             useatoms.nres           = std::max(useatoms.nres, useatoms.atom[i].resind+1);
1900             copy_rvec(xtps[index[i]], usextps[i]);
1901         }
1902         useatoms.nr = isize;
1903         analyze_clusters(nf, &clust, rms->mat, isize, &useatoms, usextps, mass, xx, time,
1904                          ifsize, fitidx, iosize, outidx,
1905                          bReadTraj ? trx_out_fn : nullptr,
1906                          opt2fn_null("-sz", NFILE, fnm),
1907                          opt2fn_null("-tr", NFILE, fnm),
1908                          opt2fn_null("-ntr", NFILE, fnm),
1909                          opt2fn_null("-clid", NFILE, fnm),
1910                          bAverage, write_ncl, write_nst, rmsmin, bFit, log,
1911                          rlo_bot, rhi_bot, oenv);
1912     }
1913     gmx_ffclose(log);
1914
1915     if (bBinary && !bAnalyze)
1916     {
1917         /* Make the clustering visible */
1918         for (i2 = 0; (i2 < nf); i2++)
1919         {
1920             for (i1 = i2+1; (i1 < nf); i1++)
1921             {
1922                 if (rms->mat[i1][i2])
1923                 {
1924                     rms->mat[i1][i2] = rms->maxrms;
1925                 }
1926             }
1927         }
1928     }
1929
1930     fp = opt2FILE("-o", NFILE, fnm, "w");
1931     fprintf(stderr, "Writing rms distance/clustering matrix ");
1932     if (bReadMat)
1933     {
1934         write_xpm(fp, 0, readmat[0].title, readmat[0].legend, readmat[0].label_x,
1935                   readmat[0].label_y, nf, nf, readmat[0].axis_x, readmat[0].axis_y,
1936                   rms->mat, 0.0, rms->maxrms, rlo_top, rhi_top, &nlevels);
1937     }
1938     else
1939     {
1940         sprintf(buf, "Time (%s)", output_env_get_time_unit(oenv));
1941         sprintf(title, "RMS%sDeviation / Cluster Index",
1942                 bRMSdist ? " Distance " : " ");
1943         if (minstruct > 1)
1944         {
1945             write_xpm_split(fp, 0, title, "RMSD (nm)", buf, buf,
1946                             nf, nf, time, time, rms->mat, 0.0, rms->maxrms, &nlevels,
1947                             rlo_top, rhi_top, 0.0, ncluster,
1948                             &ncluster, TRUE, rlo_bot, rhi_bot);
1949         }
1950         else
1951         {
1952             write_xpm(fp, 0, title, "RMSD (nm)", buf, buf,
1953                       nf, nf, time, time, rms->mat, 0.0, rms->maxrms,
1954                       rlo_top, rhi_top, &nlevels);
1955         }
1956     }
1957     fprintf(stderr, "\n");
1958     gmx_ffclose(fp);
1959     if (nullptr != orig)
1960     {
1961         fp = opt2FILE("-om", NFILE, fnm, "w");
1962         sprintf(buf, "Time (%s)", output_env_get_time_unit(oenv));
1963         sprintf(title, "RMS%sDeviation", bRMSdist ? " Distance " : " ");
1964         write_xpm(fp, 0, title, "RMSD (nm)", buf, buf,
1965                   nf, nf, time, time, orig->mat, 0.0, orig->maxrms,
1966                   rlo_top, rhi_top, &nlevels);
1967         gmx_ffclose(fp);
1968         done_mat(&orig);
1969         sfree(orig);
1970     }
1971     /* now show what we've done */
1972     do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
1973     do_view(oenv, opt2fn_null("-sz", NFILE, fnm), "-nxy");
1974     if (method == m_diagonalize)
1975     {
1976         do_view(oenv, opt2fn_null("-ev", NFILE, fnm), "-nxy");
1977     }
1978     do_view(oenv, opt2fn("-dist", NFILE, fnm), "-nxy");
1979     if (bAnalyze)
1980     {
1981         do_view(oenv, opt2fn_null("-tr", NFILE, fnm), "-nxy");
1982         do_view(oenv, opt2fn_null("-ntr", NFILE, fnm), "-nxy");
1983         do_view(oenv, opt2fn_null("-clid", NFILE, fnm), "-nxy");
1984     }
1985     do_view(oenv, opt2fn_null("-conv", NFILE, fnm), nullptr);
1986
1987     return 0;
1988 }