Пример #1
0
CLUSTER *
MRISclusterKMeans(MRI_SURFACE *mris, MRI *mri_profiles, int k, char *start_fname, MRI_SURFACE *mris_ico) {
  int    i, nsamples, iter, done, nchanged ;
  char   fname[STRLEN] ;
  CLUSTER *ct ;

  nsamples = mri_profiles->nframes ;
  ct = calloc(k, sizeof(CLUSTER)) ;
  for (i = 0 ; i < k ; i++) {
    ct[i].v_mean = VectorAlloc(nsamples, MATRIX_REAL) ;
    ct[i].m_cov = MatrixIdentity(nsamples, NULL) ;
    ct[i].npoints = 0 ;
  }

  initialize_kmeans_centers(mris, mri_profiles, ct, k) ;

  done = iter = 0 ;
  do {
    nchanged = mark_clusters(mris, mri_profiles, ct, k) ;
    if (nchanged == 0)
      done = 1 ;
    compute_cluster_statistics(mris, mri_profiles, ct, k) ;
    sprintf(fname, "%s.clusters%6.6d.annot",
            mris->hemisphere == LEFT_HEMISPHERE ? "lh" : "rh", iter) ;
    printf("%6.6d: writing %s\n", iter, fname) ;
    MRISwriteAnnotation(mris, fname) ;
    sprintf(fname, "./%s.clusters%6.6d.indices",
            mris->hemisphere == LEFT_HEMISPHERE ? "lh" : "rh", iter) ;
    MRISwriteCurvature(mris, fname) ;
    if (iter++ > max_iterations)
      done = 1 ;
  } while (!done) ;

  return(ct) ;
}
Пример #2
0
void class1(graph_t * g)
{
    node_t *n, *t, *h;
    edge_t *e, *rep;

    mark_clusters(g);
    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
	for (e = agfstout(g, n); e; e = agnxtout(g, e)) {

	    /* skip edges already processed */
	    if (ED_to_virt(e))
		continue;

	    /* skip edges that we want to ignore in this phase */
	    if (nonconstraint_edge(e))
		continue;

	    t = UF_find(agtail(e));
	    h = UF_find(aghead(e));

	    /* skip self, flat, and intra-cluster edges */
	    if (t == h)
		continue;


	    /* inter-cluster edges require special treatment */
	    if (ND_clust(t) || ND_clust(h)) {
		interclust1(g, agtail(e), aghead(e), e);
		continue;
	    }

	    if ((rep = find_fast_edge(t, h)))
		merge_oneway(e, rep);
	    else
		virtual_edge(t, h, e);

#ifdef NOTDEF
	    if ((t == agtail(e)) && (h == aghead(e))) {
		if (rep = find_fast_edge(t, h))
		    merge_oneway(e, rep);
		else
		    virtual_edge(t, h, e);
	    } else {
		f = agfindedge(g, t, h);
		if (f && (ED_to_virt(f) == NULL))
		    rep = virtual_edge(t, h, f);
		else
		    rep = find_fast_edge(t, h);
		if (rep)
		    merge_oneway(e, rep);
		else
		    virtual_edge(t, h, e);
	    }
#endif
	}
    }
}
Пример #3
0
void class2(graph_t* g)
{
	int		c;
	node_t	*n,*t,*h;
	edge_t	*e,*prev,*opp;

	g->u.nlist = NULL;

	g->u.n_nodes = 0;	/* new */

	mark_clusters(g);
	for (c = 1; c <= g->u.n_cluster; c++)
		build_skeleton(g,g->u.clust[c]);
	for (n = agfstnode(g); n; n = agnxtnode(g,n))
		for (e = agfstout(g,n); e; e = agnxtout(g,e)) {
			if (e->head->u.weight_class <= 2) e->head->u.weight_class++;
			if (e->tail->u.weight_class <= 2) e->tail->u.weight_class++;
	}

	for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
		if ((n->u.clust == NULL) && (n == UF_find(n))) {fast_node(g,n); g->u.n_nodes++;}
		prev = NULL;
		for (e = agfstout(g,n); e; e = agnxtout(g,e)) {

				/* already processed */
			if (e->u.to_virt) continue;

				/* edges involving sub-clusters of g */
			if (is_cluster_edge(e)) {
				/* following is new cluster multi-edge code */
				if (mergeable(prev,e)) {
					if (prev->u.to_virt) { 
						merge_chain(g,e,prev->u.to_virt,FALSE);
						other_edge(e);
					}
					else if (e->tail->u.rank == e->head->u.rank) {
						merge_oneway(e,prev);
						other_edge(e);
					}
					/* else is an intra-cluster edge */
					continue;
				}
				interclrep(g,e);
				prev = e;
				continue;
			}
				/* merge multi-edges */
			if (prev && (e->tail == prev->tail) && (e->head == prev->head)) {
				if (e->tail->u.rank == e->head->u.rank) {
					merge_oneway(e,prev);
					other_edge(e);
					continue;
				}
				if ((e->u.label == NULL) && (prev->u.label == NULL) && ports_eq(e,prev)) {
					if (Concentrate) 
						e->u.edge_type = IGNORED;
					else{
					merge_chain(g,e,prev->u.to_virt,TRUE);
					other_edge(e);
					}
					continue;
				}
				/* parallel edges with different labels fall through here */
			}

				/* self edges */
			if (e->tail == e->head) {
				other_edge(e);
				prev = e;
				continue;
			}

			t = UF_find(e->tail);
			h = UF_find(e->head);

				/* non-leader leaf nodes */
			if ((e->tail != t) || (e->head != h)) {
					/* ### need to merge stuff */
				continue;	
			}


				/* flat edges */
			if (e->tail->u.rank == e->head->u.rank) {
				flat_edge(g,e);
				prev = e;
				continue;
			}

				/* forward edges */
			if (e->head->u.rank > e->tail->u.rank) {
				make_chain(g,e->tail,e->head,e);
				prev = e;
				continue;
			}

				/* backward edges */
			else {
				/*other_edge(e);*/
				if ((opp = agfindedge(g,e->head,e->tail))) {
					/* shadows a forward edge */
					if (opp->u.to_virt == NULL)
						make_chain(g,opp->tail,opp->head,opp);
					if ((e->u.label == NULL) && (opp->u.label == NULL) && ports_eq(e,opp)) {
						if (Concentrate) {
							e->u.edge_type = IGNORED;
							opp->u.conc_opp_flag = TRUE;
						}
						else{	/* see above.  this is getting out of hand */
						other_edge(e);
						merge_chain(g,e,opp->u.to_virt,TRUE);
						}
						continue;
					}
				}
				make_chain(g,e->head,e->tail,e);
				prev = e;
			}
		}
	}
	/* since decompose() is not called on subgraphs */
	if (g != g->root) {
		g->u.comp.list = ALLOC(1,g->u.comp.list,node_t*);
		g->u.comp.list[0] = g->u.nlist;
	}
Пример #4
0
int gmx_cluster(int argc,char *argv[])
{
  static char *desc[] = {
    "g_cluster can cluster structures with several different methods.",
    "Distances between structures can be determined from a trajectory",
    "or read from an XPM matrix file with the [TT]-dm[tt] option.",
    "RMS deviation after fitting or RMS deviation of atom-pair distances",
    "can be used to define the distance between structures.[PAR]",
    
    "single linkage: add a structure to a cluster when its distance to any",
    "element of the cluster is less than [TT]cutoff[tt].[PAR]",
    
    "Jarvis Patrick: add a structure to a cluster when this structure",
    "and a structure in the cluster have each other as neighbors and",
    "they have a least [TT]P[tt] neighbors in common. The neighbors",
    "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]",
    
    "diagonalization: diagonalize the RMSD matrix.[PAR]"
    
    "gromos: use algorithm as described in Daura [IT]et al.[it]",
    "([IT]Angew. Chem. Int. Ed.[it] [BB]1999[bb], [IT]38[it], pp 236-240).",
    "Count number of neighbors using cut-off, take structure with",
    "largest number of neighbors with all its neighbors as cluster",
    "and eleminate it from the pool of clusters. Repeat for remaining",
    "structures in pool.[PAR]",
    
    "When the clustering algorithm assigns each structure to exactly one",
    "cluster (single linkage, Jarvis Patrick and gromos) and a trajectory",
    "file is supplied, the structure with",
    "the smallest average distance to the others or the average structure",
    "or all structures for each cluster will be written to a trajectory",
    "file. When writing all structures, separate numbered files are made",
    "for each cluster.[PAR]"
    
    "Two output files are always written:[BR]",
    "[TT]-o[tt] writes the RMSD values in the upper left half of the matrix",
    "and a graphical depiction of the clusters in the lower right half",
    "When [TT]-minstruct[tt] = 1 the graphical depiction is black",
    "when two structures are in the same cluster.",
    "When [TT]-minstruct[tt] > 1 different colors will be used for each",
    "cluster.[BR]",
    "[TT]-g[tt] writes information on the options used and a detailed list",
    "of all clusters and their members.[PAR]",
    
    "Additionally, a number of optional output files can be written:[BR]",
    "[TT]-dist[tt] writes the RMSD distribution.[BR]",
    "[TT]-ev[tt] writes the eigenvectors of the RMSD matrix",
    "diagonalization.[BR]",
    "[TT]-sz[tt] writes the cluster sizes.[BR]",
    "[TT]-tr[tt] writes a matrix of the number transitions between",
    "cluster pairs.[BR]",
    "[TT]-ntr[tt] writes the total number of transitions to or from",
    "each cluster.[BR]",
    "[TT]-clid[tt] writes the cluster number as a function of time.[BR]",
    "[TT]-cl[tt] writes average (with option [TT]-av[tt]) or central",
    "structure of each cluster or writes numbered files with cluster members",
    "for a selected set of clusters (with option [TT]-wcl[tt], depends on",
    "[TT]-nst[tt] and [TT]-rmsmin[tt]).[BR]",
  };
  
  FILE         *fp,*log;
  int          i,i1,i2,j,nf,nrms;

  matrix       box;
  rvec         *xtps,*usextps,*x1,**xx=NULL;
  char         *fn,*trx_out_fn;
  t_clusters   clust;
  t_mat        *rms;
  real         *eigval;
  t_topology   top;
  int          ePBC;
  t_atoms      useatoms;
  t_matrix     *readmat;
  real         *tmp;
  
  int      isize=0,ifsize=0,iosize=0;
  atom_id  *index=NULL, *fitidx, *outidx;
  char     *grpname;
  real     rmsd,**d1,**d2,*time,time_invfac,*mass=NULL;
  char     buf[STRLEN],buf1[80],title[STRLEN];
  bool     bAnalyze,bUseRmsdCut,bJP_RMSD=FALSE,bReadMat,bReadTraj;

  int method,ncluster=0;  
  static char *methodname[] = { 
    NULL, "linkage", "jarvis-patrick","monte-carlo", 
    "diagonalization", "gromos", NULL
  };
  enum { m_null, m_linkage, m_jarvis_patrick, 
	 m_monte_carlo, m_diagonalize, m_gromos, m_nr };
  /* Set colors for plotting: white = zero RMS, black = maximum */
  static t_rgb rlo_top = { 1.0, 1.0, 1.0 };
  static t_rgb rhi_top = { 0.0, 0.0, 0.0 };
  static t_rgb rlo_bot = { 1.0, 1.0, 1.0 };
  static t_rgb rhi_bot = { 0.0, 0.0, 1.0 };
  static int  nlevels=40,skip=1;
  static real scalemax=-1.0,rmsdcut=0.1,rmsmin=0.0;
  static bool bRMSdist=FALSE,bBinary=FALSE,bAverage=FALSE,bFit=TRUE;
  static int  niter=10000,seed=1993,write_ncl=0,write_nst=1,minstruct=1;
  static real kT=1e-3;
  static int  M=10,P=3;
  t_pargs pa[] = {
    { "-dista", FALSE, etBOOL, {&bRMSdist},
      "Use RMSD of distances instead of RMS deviation" },
    { "-nlevels",FALSE,etINT,  {&nlevels},
      "Discretize RMSD matrix in # levels" },
    { "-cutoff",FALSE, etREAL, {&rmsdcut},
      "RMSD cut-off (nm) for two structures to be neighbor" },
    { "-fit",   FALSE, etBOOL, {&bFit},
      "Use least squares fitting before RMSD calculation" },
    { "-max",   FALSE, etREAL, {&scalemax},
      "Maximum level in RMSD matrix" },
    { "-skip",  FALSE, etINT,  {&skip},
      "Only analyze every nr-th frame" },
    { "-av",    FALSE, etBOOL, {&bAverage},
      "Write average iso middle structure for each cluster" },
    { "-wcl",   FALSE, etINT,  {&write_ncl},
      "Write all structures for first # clusters to numbered files" },
    { "-nst",   FALSE, etINT,  {&write_nst},
      "Only write all structures if more than # per cluster" },
    { "-rmsmin",FALSE, etREAL, {&rmsmin},
      "minimum rms difference with rest of cluster for writing structures" },
    { "-method",FALSE, etENUM, {methodname},
      "Method for cluster determination" },
    { "-minstruct", FALSE, etINT, {&minstruct},
      "Minimum number of structures in cluster for coloring in the xpm file" },
    { "-binary",FALSE, etBOOL, {&bBinary},
      "Treat the RMSD matrix as consisting of 0 and 1, where the cut-off "
      "is given by -cutoff" },
    { "-M",     FALSE, etINT,  {&M},
      "Number of nearest neighbors considered for Jarvis-Patrick algorithm, "
      "0 is use cutoff" },
    { "-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" },
    { "-niter", FALSE, etINT,  {&niter},
      "Number of iterations for MC" },
    { "-kT",    FALSE, etREAL, {&kT},
      "Boltzmann weighting factor for Monte Carlo optimization "
      "(zero turns off uphill steps)" }
  };
  t_filenm fnm[] = {
    { efTRX, "-f",     NULL,        ffOPTRD },
    { efTPS, "-s",     NULL,        ffOPTRD },
    { efNDX, NULL,     NULL,        ffOPTRD },
    { efXPM, "-dm",   "rmsd",       ffOPTRD },     
    { efXPM, "-o",    "rmsd-clust", ffWRITE },
    { efLOG, "-g",    "cluster",    ffWRITE },
    { efXVG, "-dist", "rmsd-dist",  ffOPTWR },
    { efXVG, "-ev",   "rmsd-eig",   ffOPTWR },
    { efXVG, "-sz",   "clust-size", ffOPTWR},
    { efXPM, "-tr",   "clust-trans",ffOPTWR},
    { efXVG, "-ntr",  "clust-trans",ffOPTWR},
    { efXVG, "-clid", "clust-id.xvg",ffOPTWR},
    { efTRX, "-cl",   "clusters.pdb", ffOPTWR }
  };
#define NFILE asize(fnm)
  
  CopyRight(stderr,argv[0]);
  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);

  /* parse options */
  bReadMat   = opt2bSet("-dm",NFILE,fnm);
  bReadTraj  = opt2bSet("-f",NFILE,fnm) || !bReadMat;
  if ( opt2parg_bSet("-av",asize(pa),pa) ||
       opt2parg_bSet("-wcl",asize(pa),pa) ||
       opt2parg_bSet("-nst",asize(pa),pa) ||
       opt2parg_bSet("-rmsmin",asize(pa),pa) ||
       opt2bSet("-cl",NFILE,fnm) )
    trx_out_fn = opt2fn("-cl",NFILE,fnm);
  else
    trx_out_fn = NULL;
  if (bReadMat && time_factor()!=1) {
    fprintf(stderr,
	    "\nWarning: assuming the time unit in %s is %s\n",
	    opt2fn("-dm",NFILE,fnm),time_unit());
  }
  if (trx_out_fn && !bReadTraj)
    fprintf(stderr,"\nWarning: "
	    "cannot write cluster structures without reading trajectory\n"
	    "         ignoring option -cl %s\n", trx_out_fn);

  method=1;
  while ( method < m_nr && strcasecmp(methodname[0], methodname[method])!=0 )
    method++;
  if (method == m_nr)
    gmx_fatal(FARGS,"Invalid method");
  
  bAnalyze = (method == m_linkage || method == m_jarvis_patrick ||
	      method == m_gromos );
  
  /* Open log file */
  log = ftp2FILE(efLOG,NFILE,fnm,"w");

  fprintf(stderr,"Using %s method for clustering\n",methodname[0]);
  fprintf(log,"Using %s method for clustering\n",methodname[0]);

  /* check input and write parameters to log file */
  bUseRmsdCut = FALSE;
  if (method == m_jarvis_patrick) {
    bJP_RMSD = (M == 0) || opt2parg_bSet("-cutoff",asize(pa),pa);
    if ((M<0) || (M == 1))
      gmx_fatal(FARGS,"M (%d) must be 0 or larger than 1",M);
    if (M < 2) {
      sprintf(buf1,"Will use P=%d and RMSD cutoff (%g)",P,rmsdcut);
      bUseRmsdCut = TRUE;
    } else {
      if (P >= M)
	gmx_fatal(FARGS,"Number of neighbors required (P) must be less than M");
      if (bJP_RMSD) {
	sprintf(buf1,"Will use P=%d, M=%d and RMSD cutoff (%g)",P,M,rmsdcut);
	bUseRmsdCut = TRUE;
      } else
	sprintf(buf1,"Will use P=%d, M=%d",P,M);
    }
    ffprintf1(stderr,log,buf,"%s for determining the neighbors\n\n",buf1);
  } else /* method != m_jarvis */
    bUseRmsdCut = ( bBinary || method == m_linkage || method == m_gromos );
  if (bUseRmsdCut && method != m_jarvis_patrick)
    fprintf(log,"Using RMSD cutoff %g nm\n",rmsdcut);
  if ( method==m_monte_carlo )
    fprintf(log,"Using %d iterations\n",niter);
  
  if (skip < 1)
    gmx_fatal(FARGS,"skip (%d) should be >= 1",skip);

  /* get input */
  if (bReadTraj) {
    /* don't read mass-database as masses (and top) are not used */
    read_tps_conf(ftp2fn(efTPS,NFILE,fnm),buf,&top,&ePBC,&xtps,NULL,box,
		  bAnalyze);
    
    fprintf(stderr,"\nSelect group for least squares fit%s:\n",
	    bReadMat?"":" and RMSD calculation");
    get_index(&(top.atoms),ftp2fn_null(efNDX,NFILE,fnm),
	      1,&ifsize,&fitidx,&grpname);
    if (trx_out_fn) {
      fprintf(stderr,"\nSelect group for output:\n");
      get_index(&(top.atoms),ftp2fn_null(efNDX,NFILE,fnm),
		1,&iosize,&outidx,&grpname);
      /* merge and convert both index groups: */
      /* first copy outidx to index. let outidx refer to elements in index */
      snew(index,iosize);
      isize = iosize;
      for(i=0; i<iosize; i++) {
	index[i]=outidx[i];
	outidx[i]=i;
      }
      /* now lookup elements from fitidx in index, add them if necessary
	 and also let fitidx refer to elements in index */
      for(i=0; i<ifsize; i++) {
	j=0;
	while (j<isize && index[j]!=fitidx[i])
	  j++;
	if (j>=isize) {
	  /* slow this way, but doesn't matter much */
	  isize++;
	  srenew(index,isize);
	}
	index[j]=fitidx[i];
	fitidx[i]=j;
      }
    } else { /* !trx_out_fn */
      isize = ifsize;
      snew(index, isize);
      for(i=0; i<ifsize; i++) {
	index[i]=fitidx[i];
	fitidx[i]=i;
      }
    }
  }
  /* Initiate arrays */
  snew(d1,isize);
  snew(d2,isize);
  for(i=0; (i<isize); i++) {
    snew(d1[i],isize);
    snew(d2[i],isize);
  }

  if (bReadTraj) {
    /* Loop over first coordinate file */
    fn = opt2fn("-f",NFILE,fnm);
    
    xx = read_whole_trj(fn,isize,index,skip,&nf,&time);
    convert_times(nf, time);
    if (!bRMSdist || bAnalyze) {
      /* Center all frames on zero */
      snew(mass,isize);
      for(i=0; i<ifsize; i++)
	mass[fitidx[i]] = top.atoms.atom[index[fitidx[i]]].m;
      if (bFit)
      for(i=0; i<nf; i++)
	reset_x(ifsize,fitidx,isize,NULL,xx[i],mass);
    }
  }
  if (bReadMat) {
    fprintf(stderr,"Reading rms distance matrix ");
    read_xpm_matrix(opt2fn("-dm",NFILE,fnm),&readmat);
    fprintf(stderr,"\n");
    if (readmat[0].nx != readmat[0].ny)
      gmx_fatal(FARGS,"Matrix (%dx%d) is not square",
		  readmat[0].nx,readmat[0].ny);
    if (bReadTraj && bAnalyze && (readmat[0].nx != nf))
      gmx_fatal(FARGS,"Matrix size (%dx%d) does not match the number of "
		  "frames (%d)",readmat[0].nx,readmat[0].ny,nf);

    nf = readmat[0].nx;
    sfree(time);
    time = readmat[0].axis_x;
    time_invfac = time_invfactor();
    for(i=0; i<nf; i++)
      time[i] *= time_invfac;

    rms = init_mat(readmat[0].nx,method == m_diagonalize);
    convert_mat(&(readmat[0]),rms);
    
    nlevels = readmat[0].nmap;
  } else { /* !bReadMat */
    rms = init_mat(nf,method == m_diagonalize);
    nrms = (nf*(nf-1))/2;
    if (!bRMSdist) {
      fprintf(stderr,"Computing %dx%d RMS deviation matrix\n",nf,nf);
      snew(x1,isize);
      for(i1=0; (i1<nf); i1++) {
	for(i2=i1+1; (i2<nf); i2++) {
	  for(i=0; i<isize; i++)
	    copy_rvec(xx[i1][i],x1[i]);
	  if (bFit)
	    do_fit(isize,mass,xx[i2],x1);
	  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);
      }
    } else { /* bRMSdist */
      fprintf(stderr,"Computing %dx%d RMS distance deviation matrix\n",nf,nf);
      for(i1=0; (i1<nf); i1++) {
	calc_dist(isize,xx[i1],d1);
	for(i2=i1+1; (i2<nf); i2++) {
	  calc_dist(isize,xx[i2],d2);
	  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,"\n\n");
  }
  ffprintf2(stderr,log,buf,"The RMSD ranges from %g to %g nm\n",
	    rms->minrms,rms->maxrms);
  ffprintf1(stderr,log,buf,"Average RMSD is %g\n",2*rms->sumrms/(nf*(nf-1)));
  ffprintf1(stderr,log,buf,"Number of structures for matrix %d\n",nf);
  ffprintf1(stderr,log,buf,"Energy of the matrix is %g nm\n",mat_energy(rms));
  if (bUseRmsdCut && (rmsdcut < rms->minrms || rmsdcut > rms->maxrms) )
    fprintf(stderr,"WARNING: rmsd cutoff %g is outside range of rmsd values "
	    "%g to %g\n",rmsdcut,rms->minrms,rms->maxrms);
  if (bAnalyze && (rmsmin < rms->minrms) )
    fprintf(stderr,"WARNING: rmsd minimum %g is below lowest rmsd value %g\n",
	    rmsmin,rms->minrms);
  if (bAnalyze && (rmsmin > rmsdcut) )
    fprintf(stderr,"WARNING: rmsd minimum %g is above rmsd cutoff %g\n",
	    rmsmin,rmsdcut);
  
  /* Plot the rmsd distribution */
  rmsd_distribution(opt2fn("-dist",NFILE,fnm),rms);
  
  if (bBinary) {
    for(i1=0; (i1 < nf); i1++) 
      for(i2=0; (i2 < nf); i2++)
	if (rms->mat[i1][i2] < rmsdcut)
	  rms->mat[i1][i2] = 0;
	else
	  rms->mat[i1][i2] = 1;
  }

  snew(clust.cl,nf);
  switch (method) {
  case m_linkage: 
    /* Now sort the matrix and write it out again */
    gather(rms,rmsdcut,&clust);
    break;
  case m_diagonalize:
    /* Do a diagonalization */
      snew(eigval,nf);
      snew(tmp,nf*nf);
      memcpy(tmp,rms->mat[0],nf*nf*sizeof(real));
      eigensolver(tmp,nf,0,nf,eigval,rms->mat[0]);
      sfree(tmp);
      
      fp = xvgropen(opt2fn("-ev",NFILE,fnm),"RMSD matrix Eigenvalues",
                    "Eigenvector index","Eigenvalues (nm\\S2\\N)");
      for(i=0; (i<nf); i++)
          fprintf(fp,"%10d  %10g\n",i,eigval[i]);
          ffclose(fp);
      break;
  case m_monte_carlo:
    mc_optimize(log,rms,niter,&seed,kT);
    swap_mat(rms);
    reset_index(rms);
    break;
  case m_jarvis_patrick:
    jarvis_patrick(rms->nn,rms->mat,M,P,bJP_RMSD ? rmsdcut : -1,&clust);
    break;
  case m_gromos:
    gromos(rms->nn,rms->mat,rmsdcut,&clust);
    break;
  default:
    gmx_fatal(FARGS,"DEATH HORROR unknown method \"%s\"",methodname[0]);
  }
  
  if (method == m_monte_carlo || method == m_diagonalize)
    fprintf(stderr,"Energy of the matrix after clustering is %g nm\n",
	    mat_energy(rms));
  
  if (bAnalyze) {
    if (minstruct > 1) {
      ncluster = plot_clusters(nf,rms->mat,&clust,nlevels,minstruct);
    } else {
      mark_clusters(nf,rms->mat,rms->maxrms,&clust);
    }
    init_t_atoms(&useatoms,isize,FALSE);
    snew(usextps, isize);
    useatoms.resname=top.atoms.resname;
    for(i=0; i<isize; i++) {
      useatoms.atomname[i]=top.atoms.atomname[index[i]];
      useatoms.atom[i].resnr=top.atoms.atom[index[i]].resnr;
      useatoms.nres=max(useatoms.nres,useatoms.atom[i].resnr+1);
      copy_rvec(xtps[index[i]],usextps[i]);
    }
    useatoms.nr=isize;
    analyze_clusters(nf,&clust,rms->mat,isize,&useatoms,usextps,mass,xx,time,
		     ifsize,fitidx,iosize,outidx,
		     bReadTraj?trx_out_fn:NULL,
		     opt2fn_null("-sz",NFILE,fnm),
		     opt2fn_null("-tr",NFILE,fnm),
		     opt2fn_null("-ntr",NFILE,fnm),
		     opt2fn_null("-clid",NFILE,fnm),
		     bAverage, write_ncl, write_nst, rmsmin, bFit, log,
		     rlo_bot,rhi_bot);
  }
  ffclose(log);
  
  if (bBinary && !bAnalyze)
    /* Make the clustering visible */
    for(i2=0; (i2 < nf); i2++)
       for(i1=i2+1; (i1 < nf); i1++)
	 if (rms->mat[i1][i2])
	   rms->mat[i1][i2] = rms->maxrms;

  fp = opt2FILE("-o",NFILE,fnm,"w");
  fprintf(stderr,"Writing rms distance/clustering matrix ");
  if (bReadMat) {
    write_xpm(fp,0,readmat[0].title,readmat[0].legend,readmat[0].label_x,
	      readmat[0].label_y,nf,nf,readmat[0].axis_x,readmat[0].axis_y,
	      rms->mat,0.0,rms->maxrms,rlo_top,rhi_top,&nlevels);
  } 
  else {
    sprintf(buf,"Time (%s)",time_unit());
    sprintf(title,"RMS%sDeviation / Cluster Index",
 	    bRMSdist ? " Distance " : " ");
    if (minstruct > 1) {
      write_xpm_split(fp,0,title,"RMSD (nm)",buf,buf,
		      nf,nf,time,time,rms->mat,0.0,rms->maxrms,&nlevels,
		      rlo_top,rhi_top,0.0,(real) ncluster,
		      &ncluster,TRUE,rlo_bot,rhi_bot);
    } else {
      write_xpm(fp,0,title,"RMSD (nm)",buf,buf,
		nf,nf,time,time,rms->mat,0.0,rms->maxrms,
		rlo_top,rhi_top,&nlevels);
    }
  }
  fprintf(stderr,"\n");
  ffclose(fp);
  
  /* now show what we've done */
  do_view(opt2fn("-o",NFILE,fnm),"-nxy");
  do_view(opt2fn_null("-sz",NFILE,fnm),"-nxy");
  if (method == m_diagonalize)
    do_view(opt2fn_null("-ev",NFILE,fnm),"-nxy");
  do_view(opt2fn("-dist",NFILE,fnm),"-nxy");
  if (bAnalyze) {
    do_view(opt2fn_null("-tr",NFILE,fnm),"-nxy");
    do_view(opt2fn_null("-ntr",NFILE,fnm),"-nxy");
    do_view(opt2fn_null("-clid",NFILE,fnm),"-nxy");
  }
  
  /* Thank the user for her patience */  
  thanx(stderr);
  
  return 0;
}