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