/*
+ * 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 "copyrite.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 "gromacs/legacyheaders/macros.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/legacyheaders/typedefs.h"
+#include "gromacs/commandline/pargs.h"
+#include "gromacs/fileio/tpxio.h"
+#include "gromacs/fileio/trxio.h"
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/legacyheaders/macros.h"
+#include "gromacs/topology/index.h"
+#include "gromacs/random/random.h"
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/pbcutil/rmpbc.h"
+#include "gromacs/fileio/xvgr.h"
+#include "gromacs/utility/futil.h"
+#include "gromacs/fileio/matio.h"
#include "cmat.h"
-#include "do_fit.h"
-#include "trnio.h"
-#include "viewit.h"
+#include "gromacs/fileio/trnio.h"
+#include "gromacs/legacyheaders/viewit.h"
#include "gmx_ana.h"
#include "gromacs/linearalgebra/eigensolver.h"
+#include "gromacs/math/do_fit.h"
+#include "gromacs/utility/fatalerror.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);
}
/* 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);
}
/* 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);
}
/* 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);
}
/* 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);
}
/* 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);
}
/* 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);
}
}
-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)
}
i++;
}
- while (read_next_x(oenv, status, &t, natom, x, box));
+ while (read_next_x(oenv, status, &t, x, box));
fprintf(stderr, "Allocated %lu bytes for frames\n",
(unsigned long) (max_nf*isize*sizeof(**xx)));
fprintf(stderr, "Read %d frames from trajectory %s\n", i0, fn);
}
static int plot_clusters(int nf, real **mat, t_clusters *clust,
- int nlevels, int minstruct)
+ int minstruct)
{
int i, j, ncluster, ci;
int *cl_id, *nstruct, *strind;
"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)
{
{
fprintf(fp, "%5d %5d\n", i+1, ntrans[i]);
}
- ffclose(fp);
+ gmx_ffclose(fp);
}
sfree(ntrans);
for (i = 0; i < clust->ncl; i++)
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",
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",
"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]",
};
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;
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;
{ "-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)" },
{ 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);
TRUE);
if (bPBC)
{
- gpbc = gmx_rmpbc_init(&top.idef, ePBC, top.atoms.nr, box);
+ gpbc = gmx_rmpbc_init(&top.idef, ePBC, top.atoms.nr);
}
fprintf(stderr, "\nSelect group for least squares fit%s:\n",
}
}
}
- /* Initiate arrays */
- snew(d1, isize);
- snew(d2, isize);
- for (i = 0; (i < isize); i++)
- {
- snew(d1[i], isize);
- snew(d2[i], isize);
- }
if (bReadTraj)
{
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++)
{
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++)
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");
}
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 "
{
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);
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));
}
{
if (minstruct > 1)
{
- ncluster = plot_clusters(nf, rms->mat, &clust, nlevels, minstruct);
+ ncluster = plot_clusters(nf, rms->mat, &clust, minstruct);
}
else
{
bAverage, write_ncl, write_nst, rmsmin, bFit, log,
rlo_bot, rhi_bot, oenv);
}
- ffclose(log);
+ gmx_ffclose(log);
if (bBinary && !bAnalyze)
{
}
}
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");
do_view(oenv, opt2fn_null("-ntr", NFILE, fnm), "-nxy");
do_view(oenv, opt2fn_null("-clid", NFILE, fnm), "-nxy");
}
-
- /* Thank the user for her patience */
- thanx(stderr);
+ do_view(oenv, opt2fn_null("-conv", NFILE, fnm), NULL);
return 0;
}