diff --git a/pvmfit.cc b/pvmfit.cc
index 36153000218c7fcf6fd6684280025c7eaa001e6a..cc255aca05132413bd30b99053bf984901070d17 100644
--- a/pvmfit.cc
+++ b/pvmfit.cc
@@ -69,13 +69,14 @@ int main(int argc, char** argv)
   cout<<minx<<" "<<maxx<<" "<<miny<<" "<<maxy<<" "<<minz<<" "<<maxz<<endl;
 
   if(opts.verbose.value()) cout<<"setting up vols"<<endl;
-  volume<float> S0(maxx-minx,maxy-miny,maxz-minz);
+  volume<float> S0(maxx-minx,maxy-miny,maxz-minz), BIC, f0;
   volume<float> dvol(maxx-minx,maxy-miny,maxz-minz);
   volume<float> tmpvol(maxx-minx,maxy-miny,maxz-minz);
   volume4D<float> tmpvol4D(maxx-minx,maxy-miny,maxz-minz,3);
-  
-  vector< volume<float> > fvol,thvol,phvol;
+
+  vector< volume<float> > fvol,thvol,phvol,k1vol,k2vol, psivol;
   vector< volume4D<float> > dyads;
+  vector< volume4D<float> > fanning_vecs; 
 
   if(opts.verbose.value()) cout<<"copying input properties to output volumes"<<endl;
   copybasicproperties(data[0],S0);
@@ -83,7 +84,6 @@ int main(int argc, char** argv)
   copybasicproperties(data[0],tmpvol);
   copybasicproperties(data[0],tmpvol4D);
 
-
   tmpvol = 0;
   tmpvol4D = 0;
   for(int i=0;i<opts.nfibres.value();i++){
@@ -91,25 +91,33 @@ int main(int argc, char** argv)
     thvol.push_back(tmpvol);
     phvol.push_back(tmpvol);
     dyads.push_back(tmpvol4D);
+    if (opts.cnonlinear_Fanning.value() || opts.modelnum.value()==4)
+      fanning_vecs.push_back(tmpvol4D);
+    if (opts.modelnum.value()==3)
+      k1vol.push_back(tmpvol);
+    if (opts.modelnum.value()==4){
+      k1vol.push_back(tmpvol);
+      k2vol.push_back(tmpvol);
+      psivol.push_back(tmpvol);
+    }
   }
 
   if(opts.verbose.value()) cout<<"zeroing output volumes"<<endl;
   S0=0;dvol=0;
-  volume<float> dvol_std, f0vol;
+  volume<float> dvol_std;
   if(opts.modelnum.value()==2){
     dvol_std.reinitialize(maxx-minx,maxy-miny,maxz-minz);
     dvol_std=0;
   }
-
-  if(opts.include_f0.value()){
-    f0vol.reinitialize(maxx-minx,maxy-miny,maxz-minz);
-    f0vol=0;
-  }
+  BIC.reinitialize(maxx-minx,maxy-miny,maxz-minz);
+  BIC=0;
+  f0.reinitialize(maxx-minx,maxy-miny,maxz-minz);
+  f0=0;
+  
   
 
   if(opts.verbose.value()) cout<<"ok"<<endl;
 
-  //int counter=0;
   ColumnVector S(bvals.Ncols());
   if(opts.verbose.value()) cout<<"starting the fits"<<endl;
   for(int k = minz; k < maxz; k++){
@@ -117,32 +125,52 @@ int main(int argc, char** argv)
     for(int j=miny; j < maxy; j++){
       for(int i =minx; i< maxx; i++){
 	if(mask(i,j,k)==0)continue;
+
 	for(int t=0;t < data.tsize();t++)
 	  S(t+1)=data(i,j,k,t);
-
+	///////////////////////////////////////////////////
+	//Fit Ball & sticks with "nfibres" compartments
+	///////////////////////////////////////////////////
 	if(opts.modelnum.value()==1){
-	  if (opts.cnonlinear.value()){
-	    PVM_single_c pvm(S,bvecs,bvals,opts.nfibres.value(),opts.include_f0.value());
+	  if (opts.cnonlinear.value()){  //Use pseudo-constrained optimization
+	    PVM_single_c pvm(S,bvecs,bvals,opts.nfibres.value(),opts.saveBIC.value(),opts.use_f0.value());
 	    pvm.fit();
 	  
 	    S0(i-minx,j-miny,k-minz)   = pvm.get_s0();
 	    dvol(i-minx,j-miny,k-minz) = pvm.get_d();
-	    if (opts.include_f0.value())
-	      f0vol(i-minx,j-miny,k-minz)   = pvm.get_f0();
+	    BIC(i-minx,j-miny,k-minz) = pvm.get_BIC();
+	    f0(i-minx,j-miny,k-minz) = pvm.get_f0();
 	    for(int f=0;f<opts.nfibres.value();f++){
 	      fvol[f](i-minx,j-miny,k-minz)  = pvm.get_f(f+1);
 	      thvol[f](i-minx,j-miny,k-minz) = pvm.get_th(f+1);
 	      phvol[f](i-minx,j-miny,k-minz) = pvm.get_ph(f+1);
 	    }
 	  }
-	  else{
-	    PVM_single pvm(S,bvecs,bvals,opts.nfibres.value(),opts.include_f0.value());
+	  else if (opts.cnonlinear_Fanning.value()){  //Use pseudo-constrained optimization and return fanning angle estimates using the Hessian of the cost function
+	    PVM_single_c pvm(S,bvecs,bvals,opts.nfibres.value(),opts.saveBIC.value(),opts.use_f0.value(),true);
 	    pvm.fit();
 	  
 	    S0(i-minx,j-miny,k-minz)   = pvm.get_s0();
 	    dvol(i-minx,j-miny,k-minz) = pvm.get_d();
-	    if (opts.include_f0.value())
-	      f0vol(i-minx,j-miny,k-minz)   = pvm.get_f0();
+	    BIC(i-minx,j-miny,k-minz) = pvm.get_BIC();
+	    f0(i-minx,j-miny,k-minz) = pvm.get_f0();
+	    for(int f=0;f<opts.nfibres.value();f++){
+	      fvol[f](i-minx,j-miny,k-minz)  = pvm.get_f(f+1);
+	      thvol[f](i-minx,j-miny,k-minz) = pvm.get_th(f+1);
+	      phvol[f](i-minx,j-miny,k-minz) = pvm.get_ph(f+1);
+	      ColumnVector tmp_vec= pvm.get_invHes_e1(f+1);
+	      fanning_vecs[f](i-minx,j-miny,k-minz,0)=tmp_vec(1);
+	      fanning_vecs[f](i-minx,j-miny,k-minz,1)=tmp_vec(2);
+	      fanning_vecs[f](i-minx,j-miny,k-minz,2)=tmp_vec(3);
+	    }
+	  }
+	  else{  //Use original optimization
+	    PVM_single pvm(S,bvecs,bvals,opts.nfibres.value(), opts.use_f0.value());
+	    pvm.fit();
+	  
+	    S0(i-minx,j-miny,k-minz)   = pvm.get_s0();
+	    dvol(i-minx,j-miny,k-minz) = pvm.get_d();
+	    f0(i-minx,j-miny,k-minz) = pvm.get_f0();
 	    for(int f=0;f<opts.nfibres.value();f++){
 	      fvol[f](i-minx,j-miny,k-minz)  = pvm.get_f(f+1);
 	      thvol[f](i-minx,j-miny,k-minz) = pvm.get_th(f+1);
@@ -150,32 +178,127 @@ int main(int argc, char** argv)
 	    }
 	  }
 	}
-	else{
-	  PVM_multi pvm(S,bvecs,bvals,opts.nfibres.value(),opts.include_f0.value());
+	/////////////////////////////////////////////////////////
+	//Fit Ball & sticks (model 2) with "nfibres" compartments
+	/////////////////////////////////////////////////////////
+	else if (opts.modelnum.value()==2){ 
+	  PVM_multi pvm(S,bvecs,bvals,opts.nfibres.value());
 	  pvm.fit();
-	  
+
 	  S0(i-minx,j-miny,k-minz)   = pvm.get_s0();
 	  dvol(i-minx,j-miny,k-minz) = pvm.get_d();
 	  dvol_std(i-minx,j-miny,k-minz) = pvm.get_d_std();
-	  if (opts.include_f0.value())
-	      f0vol(i-minx,j-miny,k-minz)   = pvm.get_f0();
 	  for(int f=0;f<opts.nfibres.value();f++){
 	    fvol[f](i-minx,j-miny,k-minz)  = pvm.get_f(f+1);
 	    thvol[f](i-minx,j-miny,k-minz) = pvm.get_th(f+1);
 	    phvol[f](i-minx,j-miny,k-minz) = pvm.get_ph(f+1);
 	  }
 	}
-	
-	for(int f=0;f<opts.nfibres.value();f++){
-	  dyads[f](i-minx,j-miny,k-minz,0) = sin(thvol[f](i-minx,j-miny,k-minz)) * cos(phvol[f](i-minx,j-miny,k-minz));
-	  dyads[f](i-minx,j-miny,k-minz,1) = sin(thvol[f](i-minx,j-miny,k-minz)) * sin(phvol[f](i-minx,j-miny,k-minz));
-	  dyads[f](i-minx,j-miny,k-minz,2) = cos(thvol[f](i-minx,j-miny,k-minz));
+
+	///////////////////////////////////////////////////
+	//Fit Ball & Watsons with "nfibres" compartments
+	///////////////////////////////////////////////////
+	else if (opts.modelnum.value()==3){ 
+	  cout<<i<<" "<<j<<" "<<k<<endl;
+	  if (!opts.all.value()){
+	    PVM_Ball_Watsons pvm(S,bvecs,bvals,opts.nfibres.value(),opts.saveBIC.value(),opts.use_f0.value(),opts.gridsearch.value());
+	    pvm.fit();
+	    
+	    S0(i-minx,j-miny,k-minz)   = pvm.get_s0();
+	    dvol(i-minx,j-miny,k-minz) = pvm.get_d();
+	    BIC(i-minx,j-miny,k-minz) = pvm.get_BIC();
+	    for (int f=0;f<opts.nfibres.value();f++){
+	      fvol[f](i-minx,j-miny,k-minz)  = pvm.get_f(f+1);
+	      thvol[f](i-minx,j-miny,k-minz) = pvm.get_th(f+1);
+	      phvol[f](i-minx,j-miny,k-minz) = pvm.get_ph(f+1);
+	      k1vol[f](i-minx,j-miny,k-minz) = pvm.get_k(f+1);
+	    } 
+	  }
+	  else{  //Fit all Ball & Watsons with up to "nfibres" compartments and choose the best using BIC
+	    float bestBIC=1.0e20;
+	    for (int n=1; n<=opts.nfibres.value(); n++){
+	      PVM_Ball_Watsons pvmn(S,bvecs,bvals,n,true,opts.use_f0.value(),opts.gridsearch.value());
+	      pvmn.fit();	    
+	      if (pvmn.get_BIC()<bestBIC){ //Keep the model with the smallest BIC
+		bestBIC=pvmn.get_BIC();
+		S0(i-minx,j-miny,k-minz)   = pvmn.get_s0();
+		dvol(i-minx,j-miny,k-minz) = pvmn.get_d();
+		BIC(i-minx,j-miny,k-minz) = pvmn.get_BIC();
+		for (int f=0;f<n;f++){   //compartments are not sorted here! 
+		  fvol[f](i-minx,j-miny,k-minz)  = pvmn.get_f(f+1);
+		  thvol[f](i-minx,j-miny,k-minz) = pvmn.get_th(f+1);
+		  phvol[f](i-minx,j-miny,k-minz) = pvmn.get_ph(f+1);
+		  k1vol[f](i-minx,j-miny,k-minz) = pvmn.get_k(f+1);
+		}
+	      }
+	    }
+	  }
 	}
+
+	///////////////////////////////////////////////////
+	//Fit Ball & Binghams with "nfibres" compartments
+	///////////////////////////////////////////////////
+	else if (opts.modelnum.value()==4){ 
+	  cout<<i<<" "<<j<<" "<<k<<endl;
+	  
+	  if (!opts.all.value()){
+	    PVM_Ball_Binghams pvm(S,bvecs,bvals,opts.nfibres.value(),opts.saveBIC.value(),opts.use_f0.value(),opts.gridsearch.value());
+	    pvm.fit();
+	    S0(i-minx,j-miny,k-minz)   = pvm.get_s0();
+	    dvol(i-minx,j-miny,k-minz) = pvm.get_d();
+	    BIC(i-minx,j-miny,k-minz) = pvm.get_BIC();
+	    f0(i-minx,j-miny,k-minz) = pvm.get_f0();
+	    for (int f=0;f<opts.nfibres.value();f++){
+	      fvol[f](i-minx,j-miny,k-minz)  = pvm.get_f(f+1);
+	      thvol[f](i-minx,j-miny,k-minz) = pvm.get_th(f+1);
+	      phvol[f](i-minx,j-miny,k-minz) = pvm.get_ph(f+1);
+	      k1vol[f](i-minx,j-miny,k-minz) = pvm.get_k1(f+1);
+	      k2vol[f](i-minx,j-miny,k-minz) = pvm.get_k2(f+1);
+	      psivol[f](i-minx,j-miny,k-minz) = pvm.get_psi(f+1);
+	      ColumnVector tmp_vec= pvm.get_fanning_vector(f+1);
+	      fanning_vecs[f](i-minx,j-miny,k-minz,0)=tmp_vec(1);
+	      fanning_vecs[f](i-minx,j-miny,k-minz,1)=tmp_vec(2);
+	      fanning_vecs[f](i-minx,j-miny,k-minz,2)=tmp_vec(3);
+	    } 
+	  }
+	  else{	//Fit all Ball & Binghams with up to "nfibres" compartments and choose the best using BIC
+	    float bestBIC=1.0e20;
+	    for (int n=1; n<=opts.nfibres.value(); n++){
+	      PVM_Ball_Binghams pvmn(S,bvecs,bvals,n,true,opts.use_f0.value(),opts.gridsearch.value());
+	      pvmn.fit();
+	      if (pvmn.get_BIC()<bestBIC){ //Keep the model with the smallest BIC
+		bestBIC=pvmn.get_BIC();
+		S0(i-minx,j-miny,k-minz)   = pvmn.get_s0();
+		dvol(i-minx,j-miny,k-minz) = pvmn.get_d();
+		BIC(i-minx,j-miny,k-minz) = pvmn.get_BIC();
+		f0(i-minx,j-miny,k-minz) = pvmn.get_f0();
+		for (int f=0;f<n;f++){   //compartments are not sorted here! 
+		  fvol[f](i-minx,j-miny,k-minz)  = pvmn.get_f(f+1);
+		  thvol[f](i-minx,j-miny,k-minz) = pvmn.get_th(f+1);
+		  phvol[f](i-minx,j-miny,k-minz) = pvmn.get_ph(f+1);
+		  k1vol[f](i-minx,j-miny,k-minz) = pvmn.get_k1(f+1);
+		  k2vol[f](i-minx,j-miny,k-minz) = pvmn.get_k2(f+1);
+		  psivol[f](i-minx,j-miny,k-minz) = pvmn.get_psi(f+1);
+		  ColumnVector tmp_vec= pvmn.get_fanning_vector(f+1);
+		  fanning_vecs[f](i-minx,j-miny,k-minz,0)=tmp_vec(1);
+		  fanning_vecs[f](i-minx,j-miny,k-minz,1)=tmp_vec(2);
+		  fanning_vecs[f](i-minx,j-miny,k-minz,2)=tmp_vec(3);
+		}
+	      }
+	    }
+	  }
+	}
+
+	for(int f=0;f<opts.nfibres.value();f++)
+	  if (fvol[f](i-minx,j-miny,k-minz)!=0){
+	    dyads[f](i-minx,j-miny,k-minz,0) = sin(thvol[f](i-minx,j-miny,k-minz))*cos(phvol[f](i-minx,j-miny,k-minz));
+	    dyads[f](i-minx,j-miny,k-minz,1) = sin(thvol[f](i-minx,j-miny,k-minz))*sin(phvol[f](i-minx,j-miny,k-minz));
+	    dyads[f](i-minx,j-miny,k-minz,2) = cos(thvol[f](i-minx,j-miny,k-minz));
+	  }
       }
     }
   }
-  
-  
+
   if(opts.verbose.value())
     cout << "saving results" << endl;
 
@@ -183,15 +306,21 @@ int main(int argc, char** argv)
   save_volume(S0,opts.ofile.value()+"_S0");
 
   dvol.setDisplayMaximumMinimum(dvol.max(),0);
-  save_volume(dvol,opts.ofile.value()+"_D");
+  save_volume(dvol,opts.ofile.value()+"_d");
 
   if(opts.modelnum.value()==2){
     dvol_std.setDisplayMaximumMinimum(dvol_std.max(),0);
-    save_volume(dvol_std,opts.ofile.value()+"_D_STD");
+    save_volume(dvol_std,opts.ofile.value()+"_d_std");
   }
-  if (opts.include_f0.value()){
-    f0vol.setDisplayMaximumMinimum(1,0);
-    save_volume(f0vol,opts.ofile.value()+"_f0");
+
+  if(opts.saveBIC.value()){
+    BIC.setDisplayMaximumMinimum(BIC.max(),BIC.min());
+    save_volume(BIC,opts.ofile.value()+"_BIC");
+  }
+
+  if(opts.use_f0.value()){
+    f0.setDisplayMaximumMinimum(1,0);
+    save_volume(f0,opts.ofile.value()+"_f0");
   }
 
   for(int f=1;f<=opts.nfibres.value();f++){
@@ -201,10 +330,39 @@ int main(int argc, char** argv)
     save_volume(thvol[f-1],opts.ofile.value()+"_th"+num2str(f));
     phvol[f-1].setDisplayMaximumMinimum(phvol[f-1].max(),phvol[f-1].min());
     save_volume(phvol[f-1],opts.ofile.value()+"_ph"+num2str(f));
-    dyads[f-1].setDisplayMaximumMinimum(-1,1);
+    dyads[f-1].setDisplayMaximumMinimum(1,-1);
     save_volume4D(dyads[f-1],opts.ofile.value()+"_dyads"+num2str(f));
-
+    if (opts.cnonlinear_Fanning.value()){
+      fanning_vecs[f-1].setDisplayMaximumMinimum(1,-1);
+      save_volume4D(fanning_vecs[f-1],opts.ofile.value()+"_fans"+num2str(f));
+    }
+    if (opts.modelnum.value()==3){
+      k1vol[f-1].setDisplayMaximumMinimum(k1vol[f-1].max(),k1vol[f-1].min());
+      save_volume(k1vol[f-1],opts.ofile.value()+"_k1_"+num2str(f));
+    }
+    if (opts.modelnum.value()==4){
+      k1vol[f-1].setDisplayMaximumMinimum(k1vol[f-1].max(),k1vol[f-1].min());
+      save_volume(k1vol[f-1],opts.ofile.value()+"_k1_"+num2str(f));
+      k2vol[f-1].setDisplayMaximumMinimum(k2vol[f-1].max(),k2vol[f-1].min());
+      save_volume(k2vol[f-1],opts.ofile.value()+"_k2_"+num2str(f));
+      psivol[f-1].setDisplayMaximumMinimum(psivol[f-1].max(),psivol[f-1].min());
+      save_volume(psivol[f-1],opts.ofile.value()+"_psi_"+num2str(f));
+      fanning_vecs[f-1].setDisplayMaximumMinimum(1,-1);
+      save_volume4D(fanning_vecs[f-1],opts.ofile.value()+"_fans"+num2str(f));
+    }
   }
-
-  return 0;
+ return 0;
 }
+
+
+
+
+
+
+
+
+
+
+
+
+