diff --git a/ccops.cc b/ccops.cc
index a9419c9e9757a1a72250092d41a90c5d7dd17ded..e59a9eaf3612a6c5f2dd62ff647a1671a65da786 100644
--- a/ccops.cc
+++ b/ccops.cc
@@ -92,23 +92,48 @@ void do_kmeans(const Matrix& data,ColumnVector& y,const int 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++;
+  
+  // // 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);
+
+
+// initialise with far-away trick
+// start with a random class centre. then each new class centre is
+  // as far as possible from the cog of the previous classes
+  means.Column(1) = data.Row(round(rand()/float(RAND_MAX)*float(n-1))+1).t();
+  ColumnVector cog(d);
+  for(int cl=2;cl<=k;cl++){
+    cog = sum(means.SubMatrix(1,d,1,cl-1),2);
+    
+    int maxi=1;float dist=0,maxdist=0;
+    for(int i=1;i<=n;i++){
+      float cdist=0,mindist=-1;int minc=1;
+      for(int prevcl=cl-1;prevcl>=1;prevcl--){
+	cdist = (means.Column(prevcl)-data.Row(i).t()).SumSquare();
+	if(mindist==-1 || cdist<mindist){mindist=cdist;minc=prevcl;}
+      }
+      dist = mindist;
+      if(dist>=maxdist){maxdist=dist;maxi=i;}
     }
+    means.Column(cl)=data.Row(maxi).t();
   }
-  for(int m=1;m<=k;m++)
-    means.Column(m) /= nmeans(m);
+
+
   
   // iterate
   for(int iter=0;iter<numiter;iter++){
@@ -144,6 +169,9 @@ void do_kmeans(const Matrix& data,ColumnVector& y,const int k){
   
 }
 
+
+
+
 void kmeans_reord(const Matrix& A,ColumnVector& r,ColumnVector& y,const int k){
   do_kmeans(A,y,k);
  
@@ -165,6 +193,120 @@ void kmeans_reord(const Matrix& A,ColumnVector& r,ColumnVector& y,const int k){
   } 
 }
 
+void do_fuzzy(const Matrix& data,Matrix& u,const int k){
+  int numiter     = 200;
+  float fuzziness = 2;
+
+  int n = data.Nrows();
+  int d = data.Ncols();
+  Matrix means(d,k),newmeans(d,k);
+  ColumnVector nmeans(k);
+  means=0;
+  nmeans=0;
+  
+  // initialise with far-away trick
+  // start with a random class centre. then each new class centre is
+  // as far as possible from the cog of the previous classes
+  means.Column(1) = data.Row(round(rand()/float(RAND_MAX)*float(n-1))+1).t();
+  ColumnVector cog(d);
+  for(int cl=2;cl<=k;cl++){
+    cog = sum(means.SubMatrix(1,d,1,cl-1),2);    
+    int maxi=1;float dist=0,maxdist=0;
+    for(int i=1;i<=n;i++){
+      float cdist=0,mindist=-1;int minc=1;
+      for(int prevcl=cl-1;prevcl>=1;prevcl--){
+	cdist = (means.Column(prevcl)-data.Row(i).t()).SumSquare();
+	if(mindist==-1 || cdist<mindist){mindist=cdist;minc=prevcl;}
+      }
+      dist = mindist;
+      if(dist>=maxdist){maxdist=dist;maxi=i;}
+    }
+    means.Column(cl)=data.Row(maxi).t();
+  }
+
+  // iterate
+  for(int iter=0;iter<numiter;iter++){
+    // loop over datapoints and attribute z for closest mean
+    newmeans=0.0;
+    nmeans=0;
+    for(int i=1;i<=n;i++){
+      float mindist=-1,dist=0;
+      int mm=1;
+      for(int m=1;m<=k;m++){
+	dist = (means.Column(m)-data.Row(i).t()).SumSquare();
+	if( mindist==-1 || 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)
+	newmeans.Column(m) /= nmeans(m);
+      means.Column(m) = newmeans.Column(m);
+    }
+  }
+
+  // now use this to calculate u
+  u.ReSize(n,k);
+  u=0.0;
+  for(int i=1;i<=n;i++){
+    for(int j=1;j<=k;j++){
+      float xi_cj = (data.Row(i) - means.Column(j).t()).SumSquare();
+      if(xi_cj==0){u.Row(i)=0.01/float(k-1);u(i,j)=0.99;break;}
+      float xi_cl;
+      for(int l=1;l<=k;l++){
+	xi_cl = (data.Row(i) - means.Column(l).t()).SumSquare();
+	u(i,j) += std::exp(std::log(xi_cj/xi_cl)/(fuzziness-1));
+      }
+      u(i,j) = 1/u(i,j);
+    }
+  }
+  
+
+}
+
+
+void fuzzy_reord(const Matrix& A,Matrix& u,ColumnVector& r,ColumnVector& y,const int k){
+  do_fuzzy(A,u,k);
+  OUT(u);
+
+  float junk;
+  int index;
+  y.ReSize(A.Nrows());
+  r.ReSize(A.Nrows());
+  for(int i=1;i<=A.Nrows();i++){
+    junk = u.Row(i).Maximum1(index);
+    y(i) = index;
+  }
+ 
+  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)
 {
  
@@ -403,6 +545,7 @@ int main ( int argc, char **argv ){
   make_basename(ip);
   
   ColumnVector y1,r1,y2,r2;
+  Matrix U;
   volume<int> myOM;
   volume<int> coordvol;
   volume<int> tractcoordvol;
@@ -571,6 +714,8 @@ int main ( int argc, char **argv ){
       spect_reord(CtCt,r1,y1);
     else if(opts.scheme.value()=="kmeans")
       kmeans_reord(CtCt,r1,y1,opts.nclusters.value());
+    else if(opts.scheme.value()=="fuzzy")
+      fuzzy_reord(CtCt,U,r1,y1,opts.nclusters.value());
     else{
       cerr << "unkown reordering scheme" << endl;
       return(-1);
@@ -597,14 +742,14 @@ int main ( int argc, char **argv ){
 	outcoords(i,2,0)=(int)newcoordmat(int(r1(i+1)),3);
       } 
     }
-    cout<<"done."<<endl;
+    cout<<"Saving results"<<endl;
     write_ascii_matrix(r1,opts.directory.value()+"/"+base+"r1");
     write_ascii_matrix(y1,opts.directory.value()+"/"+base+"y1");
     save_volume(outCCvol,opts.directory.value()+"/reord_CC_"+base);
     save_volume(outcoords,opts.directory.value()+"/coords_for_reord_"+base);
 
     // save clustering if kmeans used
-    if(opts.scheme.value() == "kmeans"){
+    if(opts.scheme.value() == "kmeans" || opts.scheme.value()=="fuzzy"){
       volume<int> mask;
       if(opts.mask.value() == "")
 	read_volume(mask,opts.directory.value()+"/fdt_paths");
@@ -616,30 +761,28 @@ int main ( int argc, char **argv ){
 	     outcoords(i,1,0),
 	     outcoords(i,2,0)) = (int)y1(i+1);
       }
+      mask.setDisplayMaximumMinimum(y1.Maximum(),0);
       save_volume(mask,opts.directory.value()+"/reord_mask_"+base);
       
-      // // save tractspace clustering if specified
-//       volume<int> outmask,tractmask;
-//       read_volume(tractmask,opts.directory.value()+"/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,opts.directory.value()+"/tract_clustering_"+base);
+      // save memberships if fuzzy clustering used
+      if(opts.scheme.value() == "fuzzy"){
+	volume<float> umask;
+	umask.reinitialize(mask.xsize(),mask.ysize(),mask.zsize());
+	OUT(U);
+	for(int cl=1;cl<=opts.nclusters.value();cl++){
+	  umask=0;
+	  for(int i=0;i<outcoords.xsize();i++){
+	    //if((int)y1(i+1) == cl){
+	      umask(outcoords(i,0,0),
+		    outcoords(i,1,0),
+		    outcoords(i,2,0)) = U(r1(i+1),cl);
+	      //}
+	  }
+	  umask.setDisplayMaximumMinimum(1,0);
+	  save_volume(umask,opts.directory.value()+"/reord_membership_class"+num2str(cl)+"_"+base);
+	}
 	
+      }
 	
     }
     
@@ -685,6 +828,8 @@ int main ( int argc, char **argv ){
     save_volume(outvol,opts.directory.value()+"/reord_"+base);
     save_volume(outtractcoords,opts.directory.value()+"/tract_space_coords_for_reord_"+base);
   }
+
+  cout << "Done." << endl;
   return 0;
 }
  
diff --git a/ccopsOptions.h b/ccopsOptions.h
index 2b96345d456780ca53fe1887f199b2f95506bc3b..d74955851fe86f8bc96ae6e607129f5e6e70271a 100644
--- a/ccopsOptions.h
+++ b/ccopsOptions.h
@@ -72,7 +72,7 @@ class ccopsOptions {
 	       string("Tractography Results Directory"),
 	       false, requires_argument),
    excl_mask(string("-x"), string(""),
-	     string("exclusion mask (in tract space johannes)"),
+	     string("exclusion mask (in tract space)"),
 	     false, requires_argument),  
    reord1(string("--r1"), bool(false),
 	     string("do seedspace reordering (default no)"),
@@ -90,13 +90,13 @@ class ccopsOptions {
 	 string("power to raise the correlation matrix to (default 1)"), 
 	 false, requires_argument),
    mask(string("-m,--mask"), "", 
-	 string("brain mask used to output the clustered roi mask"), 
+	 string("brain mask used to output the clustered roi mask (not necessary if --dir set)"), 
 	 false, requires_argument),
    scheme(string("-s,--scheme"), "spectral", 
-	 string("Reordering algorithm. Can be either spectral (default) or kmeans"), 
+	 string("Reordering algorithm. Can be either spectral (default) or kmeans or fuzzy"), 
 	 false, requires_argument),
    nclusters(string("-k,--nclusters"), 2, 
-	  string("Number of clusters to be used in kmeans"), 
+	  string("Number of clusters to be used in kmeans or fuzzy"), 
 	  false, requires_argument),
    options("ccops","")
    {