Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_cluster.c
index d4e4af2bb27828474bdf7867e8840dca438888b9..e93a10f95ea4a38949ee8805dfa02ffdc8961d53 100644 (file)
@@ -1,68 +1,70 @@
 /*
+ * This file is part of the GROMACS molecular simulation package.
  *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2004, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
+ * Copyright (c) 2001-2004, The GROMACS development team.
+ * Copyright (c) 2013,2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
  * of the License, or (at your option) any later version.
  *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
  *
- * For more info, check our website at http://www.gromacs.org
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
  *
- * And Hey:
- * Green Red Orange Magenta Azure Cyan Skyblue
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
  */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "gmxpre.h"
+
 #include <math.h>
+#include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
-#include "macros.h"
-#include "smalloc.h"
-#include "typedefs.h"
-#include "statutil.h"
-#include "tpxio.h"
-#include "string2.h"
-#include "vec.h"
-#include "macros.h"
-#include "index.h"
-#include "random.h"
-#include "pbc.h"
-#include "rmpbc.h"
-#include "xvgr.h"
-#include "futil.h"
-#include "matio.h"
-#include "cmat.h"
-#include "do_fit.h"
-#include "trnio.h"
-#include "viewit.h"
-#include "gmx_ana.h"
 
+#include "gromacs/commandline/pargs.h"
+#include "gromacs/fileio/matio.h"
+#include "gromacs/fileio/tpxio.h"
+#include "gromacs/fileio/trnio.h"
+#include "gromacs/fileio/trxio.h"
+#include "gromacs/fileio/xvgr.h"
+#include "gromacs/gmxana/cmat.h"
+#include "gromacs/gmxana/gmx_ana.h"
+#include "gromacs/legacyheaders/macros.h"
+#include "gromacs/legacyheaders/typedefs.h"
+#include "gromacs/legacyheaders/viewit.h"
 #include "gromacs/linearalgebra/eigensolver.h"
+#include "gromacs/math/do_fit.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/pbcutil/rmpbc.h"
+#include "gromacs/random/random.h"
+#include "gromacs/topology/index.h"
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/futil.h"
+#include "gromacs/utility/smalloc.h"
 
 /* print to two file pointers at once (i.e. stderr and log) */
-static inline
+static gmx_inline
 void lo_ffprintf(FILE *fp1, FILE *fp2, const char *buf)
 {
     fprintf(fp1, "%s", buf);
@@ -70,14 +72,14 @@ void lo_ffprintf(FILE *fp1, FILE *fp2, const char *buf)
 }
 
 /* just print a prepared buffer to fp1 and fp2 */
-static inline
+static gmx_inline
 void ffprintf(FILE *fp1, FILE *fp2, const char *buf)
 {
     lo_ffprintf(fp1, fp2, buf);
 }
 
 /* prepare buffer with one argument, then print to fp1 and fp2 */
-static inline
+static gmx_inline
 void ffprintf_d(FILE *fp1, FILE *fp2, char *buf, const char *fmt, int arg)
 {
     sprintf(buf, fmt, arg);
@@ -85,7 +87,7 @@ void ffprintf_d(FILE *fp1, FILE *fp2, char *buf, const char *fmt, int arg)
 }
 
 /* prepare buffer with one argument, then print to fp1 and fp2 */
-static inline
+static gmx_inline
 void ffprintf_g(FILE *fp1, FILE *fp2, char *buf, const char *fmt, real arg)
 {
     sprintf(buf, fmt, arg);
@@ -93,7 +95,7 @@ void ffprintf_g(FILE *fp1, FILE *fp2, char *buf, const char *fmt, real arg)
 }
 
 /* prepare buffer with one argument, then print to fp1 and fp2 */
-static inline
+static gmx_inline
 void ffprintf_s(FILE *fp1, FILE *fp2, char *buf, const char *fmt, const char *arg)
 {
     sprintf(buf, fmt, arg);
@@ -101,7 +103,7 @@ void ffprintf_s(FILE *fp1, FILE *fp2, char *buf, const char *fmt, const char *ar
 }
 
 /* prepare buffer with two arguments, then print to fp1 and fp2 */
-static inline
+static gmx_inline
 void ffprintf_dd(FILE *fp1, FILE *fp2, char *buf, const char *fmt, int arg1, int arg2)
 {
     sprintf(buf, fmt, arg1, arg2);
@@ -109,7 +111,7 @@ void ffprintf_dd(FILE *fp1, FILE *fp2, char *buf, const char *fmt, int arg1, int
 }
 
 /* prepare buffer with two arguments, then print to fp1 and fp2 */
-static inline
+static gmx_inline
 void ffprintf_gg(FILE *fp1, FILE *fp2, char *buf, const char *fmt, real arg1, real arg2)
 {
     sprintf(buf, fmt, arg1, arg2);
@@ -117,7 +119,7 @@ void ffprintf_gg(FILE *fp1, FILE *fp2, char *buf, const char *fmt, real arg1, re
 }
 
 /* prepare buffer with two arguments, then print to fp1 and fp2 */
-static inline
+static gmx_inline
 void ffprintf_ss(FILE *fp1, FILE *fp2, char *buf, const char *fmt, const char *arg1, const char *arg2)
 {
     sprintf(buf, fmt, arg1, arg2);
@@ -149,81 +151,137 @@ void cp_index(int nn, int from[], int to[])
     }
 }
 
-void mc_optimize(FILE *log, t_mat *m, int maxiter, int *seed, real kT)
+void mc_optimize(FILE *log, t_mat *m, real *time,
+                 int maxiter, int nrandom,
+                 int seed, real kT,
+                 const char *conv, output_env_t oenv)
 {
-    real  e[2], ei, ej, efac;
-    int  *low_index;
-    int   cur = 0;
-#define next (1-cur)
-    int   i, isw, jsw, iisw, jjsw, nn;
-
-    fprintf(stderr, "\nDoing Monte Carlo clustering\n");
-    nn = m->nn;
-    snew(low_index, nn);
-    cp_index(nn, m->m_ind, low_index);
-    if (getenv("TESTMC"))
-    {
-        e[cur] = mat_energy(m);
-        pr_energy(log, e[cur]);
-        fprintf(log, "Doing 1000 random swaps\n");
-        for (i = 0; (i < 1000); i++)
-        {
-            do
+    FILE      *fp = NULL;
+    real       ecur, enext, emin, prob, enorm;
+    int        i, j, iswap, jswap, nn, nuphill = 0;
+    gmx_rng_t  rng;
+    t_mat     *minimum;
+
+    if (m->n1 != m->nn)
+    {
+        fprintf(stderr, "Can not do Monte Carlo optimization with a non-square matrix.\n");
+        return;
+    }
+    printf("\nDoing Monte Carlo optimization to find the smoothest trajectory\n");
+    printf("by reordering the frames to minimize the path between the two structures\n");
+    printf("that have the largest pairwise RMSD.\n");
+
+    iswap = jswap = -1;
+    enorm = m->mat[0][0];
+    for (i = 0; (i < m->n1); i++)
+    {
+        for (j = 0; (j < m->nn); j++)
+        {
+            if (m->mat[i][j] > enorm)
             {
-                isw = nn*rando(seed);
-                jsw = nn*rando(seed);
+                enorm   = m->mat[i][j];
+                iswap   = i;
+                jswap   = j;
             }
-            while ((isw == jsw) || (isw >= nn) || (jsw >= nn));
-            iisw          = m->m_ind[isw];
-            jjsw          = m->m_ind[jsw];
-            m->m_ind[isw] = jjsw;
-            m->m_ind[jsw] = iisw;
         }
     }
-    e[cur] = mat_energy(m);
-    pr_energy(log, e[cur]);
+    if ((iswap == -1) || (jswap == -1))
+    {
+        fprintf(stderr, "Matrix contains identical values in all fields\n");
+        return;
+    }
+    swap_rows(m, 0, iswap);
+    swap_rows(m, m->n1-1, jswap);
+    emin = ecur = mat_energy(m);
+    printf("Largest distance %g between %d and %d. Energy: %g.\n",
+           enorm, iswap, jswap, emin);
+
+    rng = gmx_rng_init(seed);
+    nn  = m->nn;
+
+    /* Initiate and store global minimum */
+    minimum     = init_mat(nn, m->b1D);
+    minimum->nn = nn;
+    copy_t_mat(minimum, m);
+
+    if (NULL != conv)
+    {
+        fp = xvgropen(conv, "Convergence of the MC optimization",
+                      "Energy", "Step", oenv);
+    }
     for (i = 0; (i < maxiter); i++)
     {
+        /* Generate new swapping candidates */
         do
         {
-            isw = nn*rando(seed);
-            jsw = nn*rando(seed);
+            iswap = 1+(nn-2)*gmx_rng_uniform_real(rng);
+            jswap = 1+(nn-2)*gmx_rng_uniform_real(rng);
         }
-        while ((isw == jsw) || (isw >= nn) || (jsw >= nn));
+        while ((iswap == jswap) || (iswap >= nn-1) || (jswap >= nn-1));
 
-        iisw = m->m_ind[isw];
-        jjsw = m->m_ind[jsw];
-        ei   = row_energy(nn, iisw, m->mat[jsw]);
-        ej   = row_energy(nn, jjsw, m->mat[isw]);
+        /* Apply swap and compute energy */
+        swap_rows(m, iswap, jswap);
+        enext = mat_energy(m);
 
-        e[next] = e[cur] + (ei+ej-EROW(m, isw)-EROW(m, jsw))/nn;
-
-        efac = kT ? exp((e[next]-e[cur])/kT) : -1;
-        if ((e[next] > e[cur]) || (efac > rando(seed)))
+        /* Compute probability */
+        prob = 0;
+        if ((enext < ecur) || (i < nrandom))
         {
-
-            if (e[next] > e[cur])
+            prob = 1;
+            if (enext < emin)
             {
-                cp_index(nn, m->m_ind, low_index);
+                /* Store global minimum */
+                copy_t_mat(minimum, m);
+                emin = enext;
             }
-            else
+        }
+        else if (kT > 0)
+        {
+            /* Try Monte Carlo step */
+            prob = exp(-(enext-ecur)/(enorm*kT));
+        }
+
+        if ((prob == 1) || (gmx_rng_uniform_real(rng) < prob))
+        {
+            if (enext > ecur)
             {
-                fprintf(log, "Taking uphill step\n");
+                nuphill++;
             }
 
-            /* Now swapping rows */
-            m->m_ind[isw]  = jjsw;
-            m->m_ind[jsw]  = iisw;
-            EROW(m, isw)   = ei;
-            EROW(m, jsw)   = ej;
-            cur            = next;
-            fprintf(log, "Iter: %d Swapped %4d and %4d (now %g)",
-                    i, isw, jsw, mat_energy(m));
-            pr_energy(log, e[cur]);
+            fprintf(log, "Iter: %d Swapped %4d and %4d (energy: %g prob: %g)\n",
+                    i, iswap, jswap, enext, prob);
+            if (NULL != fp)
+            {
+                fprintf(fp, "%6d  %10g\n", i, enext);
+            }
+            ecur = enext;
+        }
+        else
+        {
+            swap_rows(m, jswap, iswap);
         }
     }
-    /* Now restore the highest energy index */
-    cp_index(nn, low_index, m->m_ind);
+    fprintf(log, "%d uphill steps were taken during optimization\n",
+            nuphill);
+
+    /* Now swap the matrix to get it into global minimum mode */
+    copy_t_mat(m, minimum);
+
+    fprintf(log, "Global minimum energy %g\n", mat_energy(minimum));
+    fprintf(log, "Global minimum energy %g\n", mat_energy(m));
+    fprintf(log, "Swapped time and frame indices and RMSD to next neighbor:\n");
+    for (i = 0; (i < m->nn); i++)
+    {
+        fprintf(log, "%10g  %5d  %10g\n",
+                time[m->m_ind[i]],
+                m->m_ind[i],
+                (i < m->nn-1) ? m->mat[m->m_ind[i]][m->m_ind[i+1]] : 0);
+    }
+
+    if (NULL != fp)
+    {
+        fclose(fp);
+    }
 }
 
 static void calc_dist(int nind, rvec x[], real **d)
@@ -921,13 +979,13 @@ static void ana_trans(t_clusters *clust, int nf,
                 "max %d between two specific clusters\n", ntranst, maxtrans);
     if (transfn)
     {
-        fp = ffopen(transfn, "w");
+        fp = gmx_ffopen(transfn, "w");
         i  = min(maxtrans+1, 80);
         write_xpm(fp, 0, "Cluster Transitions", "# transitions",
                   "from cluster", "to cluster",
                   clust->ncl, clust->ncl, axis, axis, trans,
                   0, maxtrans, rlo, rhi, &i);
-        ffclose(fp);
+        gmx_ffclose(fp);
     }
     if (ntransfn)
     {
@@ -937,7 +995,7 @@ static void ana_trans(t_clusters *clust, int nf,
         {
             fprintf(fp, "%5d %5d\n", i+1, ntrans[i]);
         }
-        ffclose(fp);
+        gmx_ffclose(fp);
     }
     sfree(ntrans);
     for (i = 0; i < clust->ncl; i++)
@@ -1036,19 +1094,25 @@ static void analyze_clusters(int nf, t_clusters *clust, real **rmsd,
     if (clustidfn)
     {
         fp = xvgropen(clustidfn, "Clusters", output_env_get_xvgr_tlabel(oenv), "Cluster #", oenv);
-        fprintf(fp, "@    s0 symbol 2\n");
-        fprintf(fp, "@    s0 symbol size 0.2\n");
-        fprintf(fp, "@    s0 linestyle 0\n");
+        if (output_env_get_print_xvgr_codes(oenv))
+        {
+            fprintf(fp, "@    s0 symbol 2\n");
+            fprintf(fp, "@    s0 symbol size 0.2\n");
+            fprintf(fp, "@    s0 linestyle 0\n");
+        }
         for (i = 0; i < nf; i++)
         {
             fprintf(fp, "%8g %8d\n", time[i], clust->cl[i]);
         }
-        ffclose(fp);
+        gmx_ffclose(fp);
     }
     if (sizefn)
     {
         fp = xvgropen(sizefn, "Cluster Sizes", "Cluster #", "# Structures", oenv);
-        fprintf(fp, "@g%d type %s\n", 0, "bar");
+        if (output_env_get_print_xvgr_codes(oenv))
+        {
+            fprintf(fp, "@g%d type %s\n", 0, "bar");
+        }
     }
     snew(structure, nf);
     fprintf(log, "\n%3s | %3s  %4s | %6s %4s | cluster members\n",
@@ -1275,7 +1339,7 @@ static void convert_mat(t_matrix *mat, t_mat *rms)
 int gmx_cluster(int argc, char *argv[])
 {
     const char        *desc[] = {
-        "[TT]g_cluster[tt] can cluster structures using several different methods.",
+        "[THISMODULE] can cluster structures using several different methods.",
         "Distances between structures can be determined from a trajectory",
         "or read from an [TT].xpm[tt] matrix file with the [TT]-dm[tt] option.",
         "RMS deviation after fitting or RMS deviation of atom-pair distances",
@@ -1290,7 +1354,16 @@ int gmx_cluster(int argc, char *argv[])
         "of a structure are the M closest structures or all structures within",
         "[TT]cutoff[tt].[PAR]",
 
-        "Monte Carlo: reorder the RMSD matrix using Monte Carlo.[PAR]",
+        "Monte Carlo: reorder the RMSD matrix using Monte Carlo such that",
+        "the order of the frames is using the smallest possible increments.",
+        "With this it is possible to make a smooth animation going from one",
+        "structure to another with the largest possible (e.g.) RMSD between",
+        "them, however the intermediate steps should be as small as possible.",
+        "Applications could be to visualize a potential of mean force",
+        "ensemble of simulations or a pulling simulation. Obviously the user",
+        "has to prepare the trajectory well (e.g. by not superimposing frames).",
+        "The final result can be inspect visually by looking at the matrix",
+        "[TT].xpm[tt] file, which should vary smoothly from bottom to top.[PAR]",
 
         "diagonalization: diagonalize the RMSD matrix.[PAR]",
 
@@ -1338,13 +1411,14 @@ int gmx_cluster(int argc, char *argv[])
     };
 
     FILE              *fp, *log;
-    int                i, i1, i2, j, nf, nrms;
+    int                nf, i, i1, i2, j;
+    gmx_int64_t        nrms = 0;
 
     matrix             box;
     rvec              *xtps, *usextps, *x1, **xx = NULL;
     const char        *fn, *trx_out_fn;
     t_clusters         clust;
-    t_mat             *rms;
+    t_mat             *rms, *orig = NULL;
     real              *eigenvalues;
     t_topology         top;
     int                ePBC;
@@ -1376,7 +1450,7 @@ int gmx_cluster(int argc, char *argv[])
     static int   nlevels  = 40, skip = 1;
     static real  scalemax = -1.0, rmsdcut = 0.1, rmsmin = 0.0;
     gmx_bool     bRMSdist = FALSE, bBinary = FALSE, bAverage = FALSE, bFit = TRUE;
-    static int   niter    = 10000, seed = 1993, write_ncl = 0, write_nst = 1, minstruct = 1;
+    static int   niter    = 10000, nrandom = 0, seed = 1993, write_ncl = 0, write_nst = 1, minstruct = 1;
     static real  kT       = 1e-3;
     static int   M        = 10, P = 3;
     output_env_t oenv;
@@ -1416,9 +1490,11 @@ int gmx_cluster(int argc, char *argv[])
         { "-P",     FALSE, etINT,  {&P},
           "Number of identical nearest neighbors required to form a cluster" },
         { "-seed",  FALSE, etINT,  {&seed},
-          "Random number seed for Monte Carlo clustering algorithm" },
+          "Random number seed for Monte Carlo clustering algorithm: <= 0 means generate" },
         { "-niter", FALSE, etINT,  {&niter},
           "Number of iterations for MC" },
+        { "-nrandom", FALSE, etINT,  {&nrandom},
+          "The first iterations for MC may be done complete random, to shuffle the frames" },
         { "-kT",    FALSE, etREAL, {&kT},
           "Boltzmann weighting factor for Monte Carlo optimization "
           "(zero turns off uphill steps)" },
@@ -1430,22 +1506,27 @@ int gmx_cluster(int argc, char *argv[])
         { efTPS, "-s",     NULL,        ffOPTRD },
         { efNDX, NULL,     NULL,        ffOPTRD },
         { efXPM, "-dm",   "rmsd",       ffOPTRD },
+        { efXPM, "-om",   "rmsd-raw",   ffWRITE },
         { efXPM, "-o",    "rmsd-clust", ffWRITE },
         { efLOG, "-g",    "cluster",    ffWRITE },
         { efXVG, "-dist", "rmsd-dist",  ffOPTWR },
         { efXVG, "-ev",   "rmsd-eig",   ffOPTWR },
+        { efXVG, "-conv", "mc-conv",    ffOPTWR },
         { efXVG, "-sz",   "clust-size", ffOPTWR},
         { efXPM, "-tr",   "clust-trans", ffOPTWR},
         { efXVG, "-ntr",  "clust-trans", ffOPTWR},
-        { efXVG, "-clid", "clust-id.xvg", ffOPTWR},
+        { efXVG, "-clid", "clust-id",   ffOPTWR},
         { efTRX, "-cl",   "clusters.pdb", ffOPTWR }
     };
 #define NFILE asize(fnm)
 
-    parse_common_args(&argc, argv,
-                      PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT | PCA_BE_NICE,
-                      NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL,
-                      &oenv);
+    if (!parse_common_args(&argc, argv,
+                           PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT,
+                           NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL,
+                           &oenv))
+    {
+        return 0;
+    }
 
     /* parse options */
     bReadMat   = opt2bSet("-dm", NFILE, fnm);
@@ -1603,14 +1684,6 @@ int gmx_cluster(int argc, char *argv[])
             }
         }
     }
-    /* Initiate arrays */
-    snew(d1, isize);
-    snew(d2, isize);
-    for (i = 0; (i < isize); i++)
-    {
-        snew(d1[i], isize);
-        snew(d2[i], isize);
-    }
 
     if (bReadTraj)
     {
@@ -1674,14 +1747,15 @@ int gmx_cluster(int argc, char *argv[])
     else   /* !bReadMat */
     {
         rms  = init_mat(nf, method == m_diagonalize);
-        nrms = (nf*(nf-1))/2;
+        nrms = ((gmx_int64_t)nf*((gmx_int64_t)nf-1))/2;
         if (!bRMSdist)
         {
             fprintf(stderr, "Computing %dx%d RMS deviation matrix\n", nf, nf);
+            /* Initialize work array */
             snew(x1, isize);
-            for (i1 = 0; (i1 < nf); i1++)
+            for (i1 = 0; i1 < nf; i1++)
             {
-                for (i2 = i1+1; (i2 < nf); i2++)
+                for (i2 = i1+1; i2 < nf; i2++)
                 {
                     for (i = 0; i < isize; i++)
                     {
@@ -1694,14 +1768,24 @@ int gmx_cluster(int argc, char *argv[])
                     rmsd = rmsdev(isize, mass, xx[i2], x1);
                     set_mat_entry(rms, i1, i2, rmsd);
                 }
-                nrms -= (nf-i1-1);
-                fprintf(stderr, "\r# RMSD calculations left: %d   ", nrms);
+                nrms -= (gmx_int64_t) (nf-i1-1);
+                fprintf(stderr, "\r# RMSD calculations left: " "%"GMX_PRId64 "   ", nrms);
             }
+            sfree(x1);
         }
         else /* bRMSdist */
         {
             fprintf(stderr, "Computing %dx%d RMS distance deviation matrix\n", nf, nf);
-            for (i1 = 0; (i1 < nf); i1++)
+
+            /* Initiate work arrays */
+            snew(d1, isize);
+            snew(d2, isize);
+            for (i = 0; (i < isize); i++)
+            {
+                snew(d1[i], isize);
+                snew(d2[i], isize);
+            }
+            for (i1 = 0; i1 < nf; i1++)
             {
                 calc_dist(isize, xx[i1], d1);
                 for (i2 = i1+1; (i2 < nf); i2++)
@@ -1710,8 +1794,16 @@ int gmx_cluster(int argc, char *argv[])
                     set_mat_entry(rms, i1, i2, rms_dist(isize, d1, d2));
                 }
                 nrms -= (nf-i1-1);
-                fprintf(stderr, "\r# RMSD calculations left: %d   ", nrms);
+                fprintf(stderr, "\r# RMSD calculations left: " "%"GMX_PRId64 "   ", nrms);
+            }
+            /* Clean up work arrays */
+            for (i = 0; (i < isize); i++)
+            {
+                sfree(d1[i]);
+                sfree(d2[i]);
             }
+            sfree(d1);
+            sfree(d2);
         }
         fprintf(stderr, "\n\n");
     }
@@ -1719,7 +1811,7 @@ int gmx_cluster(int argc, char *argv[])
                 rms->minrms, rms->maxrms);
     ffprintf_g(stderr, log, buf, "Average RMSD is %g\n", 2*rms->sumrms/(nf*(nf-1)));
     ffprintf_d(stderr, log, buf, "Number of structures for matrix %d\n", nf);
-    ffprintf_g(stderr, log, buf, "Energy of the matrix is %g nm\n", mat_energy(rms));
+    ffprintf_g(stderr, log, buf, "Energy of the matrix is %g.\n", mat_energy(rms));
     if (bUseRmsdCut && (rmsdcut < rms->minrms || rmsdcut > rms->maxrms) )
     {
         fprintf(stderr, "WARNING: rmsd cutoff %g is outside range of rmsd values "
@@ -1778,12 +1870,14 @@ int gmx_cluster(int argc, char *argv[])
             {
                 fprintf(fp, "%10d  %10g\n", i, eigenvalues[i]);
             }
-            ffclose(fp);
+            gmx_ffclose(fp);
             break;
         case m_monte_carlo:
-            mc_optimize(log, rms, niter, &seed, kT);
-            swap_mat(rms);
-            reset_index(rms);
+            orig     = init_mat(rms->nn, FALSE);
+            orig->nn = rms->nn;
+            copy_t_mat(orig, rms);
+            mc_optimize(log, rms, time, niter, nrandom, seed, kT,
+                        opt2fn_null("-conv", NFILE, fnm), oenv);
             break;
         case m_jarvis_patrick:
             jarvis_patrick(rms->nn, rms->mat, M, P, bJP_RMSD ? rmsdcut : -1, &clust);
@@ -1797,7 +1891,7 @@ int gmx_cluster(int argc, char *argv[])
 
     if (method == m_monte_carlo || method == m_diagonalize)
     {
-        fprintf(stderr, "Energy of the matrix after clustering is %g nm\n",
+        fprintf(stderr, "Energy of the matrix after clustering is %g.\n",
                 mat_energy(rms));
     }
 
@@ -1832,7 +1926,7 @@ int gmx_cluster(int argc, char *argv[])
                          bAverage, write_ncl, write_nst, rmsmin, bFit, log,
                          rlo_bot, rhi_bot, oenv);
     }
-    ffclose(log);
+    gmx_ffclose(log);
 
     if (bBinary && !bAnalyze)
     {
@@ -1877,8 +1971,19 @@ int gmx_cluster(int argc, char *argv[])
         }
     }
     fprintf(stderr, "\n");
-    ffclose(fp);
-
+    gmx_ffclose(fp);
+    if (NULL != orig)
+    {
+        fp = opt2FILE("-om", NFILE, fnm, "w");
+        sprintf(buf, "Time (%s)", output_env_get_time_unit(oenv));
+        sprintf(title, "RMS%sDeviation", bRMSdist ? " Distance " : " ");
+        write_xpm(fp, 0, title, "RMSD (nm)", buf, buf,
+                  nf, nf, time, time, orig->mat, 0.0, orig->maxrms,
+                  rlo_top, rhi_top, &nlevels);
+        gmx_ffclose(fp);
+        done_mat(&orig);
+        sfree(orig);
+    }
     /* now show what we've done */
     do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
     do_view(oenv, opt2fn_null("-sz", NFILE, fnm), "-nxy");
@@ -1893,6 +1998,7 @@ int gmx_cluster(int argc, char *argv[])
         do_view(oenv, opt2fn_null("-ntr", NFILE, fnm), "-nxy");
         do_view(oenv, opt2fn_null("-clid", NFILE, fnm), "-nxy");
     }
+    do_view(oenv, opt2fn_null("-conv", NFILE, fnm), NULL);
 
     return 0;
 }