diff --git a/ccops.cc b/ccops.cc
index 810f9f0290df8b1a441ca12be292223052c42087..255bb9574b92cf6cd46fa46a437c3b40b4d7e386 100644
--- a/ccops.cc
+++ b/ccops.cc
@@ -70,6 +70,100 @@ using namespace CCOPS;
       
   } 
 
+bool compare(const pair<float,int> &r1,const pair<float,int> &r2){
+  return (r1.first<r2.first);
+}
+void randomise(vector< pair<float,int> >& r){
+  for(unsigned int i=1;i<=r.size();i++){
+    pair<float,int> p(rand()/float(RAND_MAX),i);
+    r[i-1]=p;
+  }
+  sort(r.begin(),r.end(),compare);
+  
+}
+void do_kmeans(const Matrix& data,ColumnVector& y,const int k){
+  int numiter=200;
+  if(data.Nrows() != (int)y.Nrows()){
+    y.ReSize(data.Nrows());
+  }
+  int n = data.Nrows();
+  int d = data.Ncols();
+  Matrix means(d,k),newmeans(d,k);
+  ColumnVector nmeans(k);
+  means=0;
+  nmeans=0;
+  // initialise random
+  vector< pair<float,int> > rindex(n);
+  randomise(rindex);
+  vector<pair<float,int> >::iterator riter;
+  int nn=0,cl=1,nperclass=(int)(float(n)/float(k));
+  for(riter=rindex.begin();riter!=rindex.end();++riter){
+    means.Column(cl) += data.Row((*riter).second).t();
+    nmeans(cl) += 1;
+    y((*riter).second)=cl;
+    nn++;
+    if(nn>=nperclass && cl<k){
+      nn=0;
+      cl++;
+    }
+  }
+  for(int m=1;m<=k;m++)
+    means.Column(m) /= nmeans(m);
+  
+  // iterate
+  for(int iter=0;iter<numiter;iter++){
+    // loop over datapoints and attribute z for closest mean
+    newmeans=0;
+    nmeans=0;
+    for(int i=1;i<=n;i++){
+      float mindist=1E20,dist=0;
+      int mm=1;
+      for(int m=1;m<=k;m++){
+	dist = (means.Column(m)-data.Row(i).t()).SumSquare();
+	if( dist<mindist){
+	  mindist=dist;
+	  mm = m;
+	}
+      }
+      y(i) = mm;
+      newmeans.Column(mm) += data.Row(i).t();
+      nmeans(mm) += 1;
+    }
+    
+    // compute means
+    for(int m=1;m<=k;m++){
+      if(nmeans(m)==0){
+	cout << "Only found " << k-1 << " clusters!!!" << endl;
+	do_kmeans(data,y,k-1);
+	return;
+      }
+      newmeans.Column(m) /= nmeans(m);
+    }
+    means = newmeans;
+  }
+  
+}
+
+void kmeans_reord(const Matrix& A,ColumnVector& r,ColumnVector& y,const int k){
+  do_kmeans(A,y,k);
+ 
+  vector< pair<float,int> > myvec2;
+  for(int i=1;i<=A.Nrows();i++){
+    pair<int,int> mypair;
+    mypair.first=y(i);
+    mypair.second=i;
+    myvec2.push_back(mypair);
+  }  
+  
+  sort(myvec2.begin(),myvec2.end());
+  r.ReSize(A.Nrows());
+  y.ReSize(A.Nrows());
+  
+  for(int i=1;i<=A.Nrows();i++){
+    y(i)=myvec2[i-1].first;
+    r(i)=myvec2[i-1].second;
+  } 
+}
 
 void rem_zrowcol(const Matrix& myOMmat,const Matrix& coordmat,const Matrix& tractcoordmat,const bool coordbool,const bool tractcoordbool,Matrix& newOMmat,Matrix& newcoordmat, Matrix& newtractcoordmat)
 {
@@ -80,7 +174,7 @@ void rem_zrowcol(const Matrix& myOMmat,const Matrix& coordmat,const Matrix& trac
 
 
 
- cerr<< "Checking for all zero rows"<<endl;
+ cout<< "Checking for all zero rows"<<endl;
  for(int i=1;i<=myOMmat.Nrows();i++){
    dimsum=0;
    for(int j=1;j<=myOMmat.Ncols();j++){
@@ -91,7 +185,7 @@ void rem_zrowcol(const Matrix& myOMmat,const Matrix& coordmat,const Matrix& trac
 
 
 
- cerr<< "Checking for all zero cols"<<endl;
+ cout<< "Checking for all zero cols"<<endl;
  for(int j=1;j<=myOMmat.Ncols();j++){
    dimsum=0;
    for(int i=1;i<=myOMmat.Nrows();i++){
@@ -110,7 +204,7 @@ void rem_zrowcol(const Matrix& myOMmat,const Matrix& coordmat,const Matrix& trac
  }
 
  int zrowcounter=0,zcolcounter=0,nzrowcounter=1,nzcolcounter=1;
- cerr<<"Forming New Matrix"<<endl;
+ cout<<"Forming New Matrix"<<endl;
  for(int j=1;j<=myOMmat.Ncols();j++){
    zrowcounter=0;
    nzrowcounter=1;
@@ -150,7 +244,7 @@ void rem_zrowcol(const Matrix& myOMmat,const Matrix& coordmat,const Matrix& trac
 
 
  if(coordbool){
-   cerr<<"Updating Seed Coordinates"<<endl;
+   cout<<"Updating Seed Coordinates"<<endl;
    zrowcounter=0;nzrowcounter=1;
    if(zerorows.size()>0){//Are there any zero rows?
      for(int i=1;i<=coordmat.Nrows();i++){
@@ -169,7 +263,7 @@ void rem_zrowcol(const Matrix& myOMmat,const Matrix& coordmat,const Matrix& trac
 }
 
  if(tractcoordbool){
-   cerr<<"Updating Tract Coordinates"<<endl;
+   cout<<"Updating Tract Coordinates"<<endl;
    zcolcounter=0;nzcolcounter=1;
    if(zerocols.size()>0){//Are there any zero cols?
      for(int i=1;i<=tractcoordmat.Nrows();i++){
@@ -344,7 +438,7 @@ int main ( int argc, char **argv ){
     }
   }
   else{
-    cerr<<"Seed Space Coordinate File Not present - Ignoring"<<endl;
+    cout<<"Seed Space Coordinate File Not present - Ignoring"<<endl;
   }
 
   //Checking For and Loading Up Tract coordinates
@@ -360,7 +454,7 @@ int main ( int argc, char **argv ){
     }
   }
   else{
-    cerr<<"Tract Space Coordinate File Not present - Ignoring"<<endl;
+    cout<<"Tract Space Coordinate File Not present - Ignoring"<<endl;
   }
  
 
@@ -426,14 +520,14 @@ int main ( int argc, char **argv ){
 
 
 
-  cerr<<"Computing correlation"<<endl;
+  cout<<"Computing correlation"<<endl;
   SymmetricMatrix CtCt;
   CtCt << corrcoef(newOMmat.t());
   CtCt << CtCt+1;
 
   // adding connexity constraint
   if(!coordbool){
-    cerr<<"WARNING !! No coordinates provided. I cannot apply any connexity constraint."<<endl;
+    cout<<"WARNING !! No coordinates provided. I cannot apply any connexity constraint."<<endl;
   }
   else{
     add_connexity(CtCt,newcoordmat,opts.connexity.value());
@@ -466,11 +560,18 @@ int main ( int argc, char **argv ){
 
   }
   else{
-    cerr<<"Starting First Reordering"<<endl;
-    spect_reord(CtCt,r1,y1);
-   
+    cout<<"Starting First Reordering"<<endl;
+
+    if(opts.scheme.value()=="spectral")
+      spect_reord(CtCt,r1,y1);
+    else if(opts.scheme.value()=="kmeans")
+      kmeans_reord(CtCt,r1,y1,opts.nclusters.value());
+    else{
+      cerr << "unkown reordering scheme" << endl;
+      return(-1);
+    }
    
-    cerr<<"Permuting seed CC matrix"<<endl;
+    cout<<"Permuting seed CC matrix"<<endl;
     for(int j=0;j<outCCvol.ysize();j++){
       for(int i=0;i<outCCvol.xsize();i++){
 	outCCvol(i,j,0)=CtCt((int)r1(i+1),(int)r1(j+1));
@@ -479,7 +580,7 @@ int main ( int argc, char **argv ){
    
    
     if(coordbool){
-      cerr<<"Permuting Seed Coordinates"<<endl;
+      cout<<"Permuting Seed Coordinates"<<endl;
       for(int i=0;i<outcoords.xsize();i++){
 	outcoords(i,0,0)=(int)newcoordmat(int(r1(i+1)),1);
 	outcoords(i,1,0)=(int)newcoordmat(int(r1(i+1)),2);
@@ -491,15 +592,60 @@ int main ( int argc, char **argv ){
     write_ascii_matrix(y1,base+"y1");
     save_volume(outCCvol,"reord_CC_"+base);
     save_volume(outcoords,"coords_for_reord_"+base);
+
+    // save clustering if kmeans used
+    if(opts.scheme.value() == "kmeans"){
+      volume<int> mask;
+      read_volume(mask,opts.mask.value());
+      mask = 0;
+      for(int i=0;i<outcoords.xsize();i++){
+	mask(outcoords(i,0,0),
+	     outcoords(i,1,0),
+	     outcoords(i,2,0)) = (int)y1(i+1) + 1;
+      }
+      save_volume(mask,"reord_mask_"+base);
+
+      // save tractspace clustering if specified
+	volume<int> outmask,tractmask;
+	read_volume(tractmask,"lookup_tractspace_fdt_matrix2");
+	outmask=tractmask;
+	copybasicproperties(tractmask,outmask);
+	
+	outmask=0;
+	for(int z=0;z<tractmask.zsize();z++)
+	  for(int y=0;y<tractmask.ysize();y++)
+	    for(int x=0;x<tractmask.xsize();x++){
+	      int j=tractmask(x,y,z);
+	      ColumnVector vals(myOM.xsize());
+	      for(int i=0;i<myOM.xsize();i++){
+		vals(i+1) = myOM(i,j,0);
+	      }
+	      if(vals.MaximumAbsoluteValue()==0)continue;
+	      int index;
+	      vals.Maximum1(index);
+	      outmask(x,y,z) = (int)y1(index);
+	    }
+	save_volume(outmask,"tract_clustering_"+base);
+	
+
+    }
  
   }
 
   if(opts.reord2.value()){
-    cerr<<"Starting Second Reordering"<<endl;
+    cout<<"Starting Second Reordering"<<endl;
     SymmetricMatrix CC;
     CC << corrcoef(newOMmat);
     CC<<CC+1;
-    spect_reord(CC,r2,y2);
+
+    if(opts.scheme.value()=="spectral")
+      spect_reord(CC,r2,y2);
+    else if(opts.scheme.value()=="kmeans")
+      kmeans_reord(CC,r2,y2,opts.nclusters.value());
+    else{
+      cerr << "unkown reordering scheme" << endl;
+      return(-1);
+    }
  
     write_ascii_matrix(r2,base+"r2");
     write_ascii_matrix(y2,base+"y2");
@@ -508,7 +654,7 @@ int main ( int argc, char **argv ){
     volume<int> outtractcoords(newtractcoordmat.Nrows(),3,1);
 
 
-    cerr<<"Permuting Matrix"<<endl;
+    cout<<"Permuting Matrix"<<endl;
     for(int j=0;j<outvol.ysize();j++){
       for(int i=0;i<outvol.xsize();i++){
 	outvol(i,j,0)=(int)newOMmat((int)r1(i+1),(int)r2(j+1));
@@ -516,7 +662,7 @@ int main ( int argc, char **argv ){
     }
 
     if(tractcoordbool){
-      cerr<<"Permuting Tract Coordinates"<<endl;
+      cout<<"Permuting Tract Coordinates"<<endl;
       for(int i=0;i<outtractcoords.xsize();i++){
 	outtractcoords(i,0,0)=(int)newtractcoordmat(int(r2(i+1)),1);
 	outtractcoords(i,1,0)=(int)newtractcoordmat(int(r2(i+1)),2);
diff --git a/ccopsOptions.h b/ccopsOptions.h
index 24478b1f1233d309bb4f1ad23fe7fb667114b900..c0038b39310795e67115f45f5d672c9da3bb8bc2 100644
--- a/ccopsOptions.h
+++ b/ccopsOptions.h
@@ -35,7 +35,7 @@ class ccopsOptions {
   Option<float> power;
   Option<string> mask;
   Option<string> scheme;
-  Option<int>    kmeans;
+  Option<int>    nclusters;
   bool parse_command_line(int argc, char** argv);
   
  private:
@@ -88,9 +88,9 @@ class ccopsOptions {
 	 string("brain mask used to output the clustered roi mask"), 
 	 false, requires_argument),
    scheme(string("-s,--scheme"), "spectral", 
-	 string("Reordering algorithm. Can be either spectral (default) or dpm or kmeans"), 
+	 string("Reordering algorithm. Can be either spectral (default) or kmeans"), 
 	 false, requires_argument),
-   kmeans(string("-K"), 2, 
+   nclusters(string("-k,--nclusters"), 2, 
 	  string("Number of clusters to be used in kmeans"), 
 	  false, requires_argument),
    options("ccops","")
@@ -109,7 +109,7 @@ class ccopsOptions {
        options.add(power);
        options.add(mask);
        options.add(scheme);
-       options.add(kmeans);
+       options.add(nclusters);
        
      }
      catch(X_OptionError& e) {