Skip to content
Snippets Groups Projects
pvmfit.cc 13.03 KiB
/*  Copyright (C) 2009 University of Oxford  */



/*  CCOPYRIGHT  */

#include <iostream>
#include <cmath>
#include "miscmaths/miscmaths.h"
#include "miscmaths/nonlin.h"
#include "newmat.h"
#include "pvmfitOptions.h"
#include "newimage/newimageall.h"
#include "diffmodels.h"

using namespace std;
using namespace NEWMAT;
using namespace MISCMATHS;
using namespace PVMFIT;
using namespace NEWIMAGE;




int main(int argc, char** argv)
{
  //parse command line
  pvmfitOptions& opts = pvmfitOptions::getInstance();
  int success=opts.parse_command_line(argc,argv);
  if(!success) return 1;
   if(opts.verbose.value()){
    cout<<"data file "<<opts.datafile.value()<<endl;
    cout<<"mask file "<<opts.maskfile.value()<<endl;
    cout<<"bvecs     "<<opts.bvecsfile.value()<<endl;
    cout<<"bvals     "<<opts.bvalsfile.value()<<endl;
  }
  
  // Set random seed:
  Matrix bvecs = read_ascii_matrix(opts.bvecsfile.value());
  if(bvecs.Nrows()>3) bvecs=bvecs.t();
  for(int i=1;i<=bvecs.Ncols();i++){
    float tmpsum=sqrt(bvecs(1,i)*bvecs(1,i)+bvecs(2,i)*bvecs(2,i)+bvecs(3,i)*bvecs(3,i));
    if(tmpsum!=0){
      bvecs(1,i)=bvecs(1,i)/tmpsum;
      bvecs(2,i)=bvecs(2,i)/tmpsum;
      bvecs(3,i)=bvecs(3,i)/tmpsum;
    }  
  }
  Matrix bvals = read_ascii_matrix(opts.bvalsfile.value());
  if(bvals.Nrows()>1) bvals=bvals.t();


  volume4D<float> data;
  volume<int> mask;

  if(opts.verbose.value()) cout<<"reading data"<<endl;
  read_volume4D(data,opts.datafile.value());

  if(opts.verbose.value()) cout<<"reading mask"<<endl;
  read_volume(mask,opts.maskfile.value());

  if(opts.verbose.value()) cout<<"ok"<<endl;
  int minx=0;
  int maxx=mask.xsize();
  int miny=0;
  int maxy=mask.ysize();
  int minz=0;
  int maxz=mask.zsize();
  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), 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,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);
  copybasicproperties(data[0],dvol);
  copybasicproperties(data[0],tmpvol);
  copybasicproperties(data[0],tmpvol4D);

  tmpvol = 0;
  tmpvol4D = 0;
  for(int i=0;i<opts.nfibres.value();i++){
    fvol.push_back(tmpvol);
    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;
  if(opts.modelnum.value()==2){
    dvol_std.reinitialize(maxx-minx,maxy-miny,maxz-minz);
    dvol_std=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;

  ColumnVector S(bvals.Ncols());
  if(opts.verbose.value()) cout<<"starting the fits"<<endl;
  for(int k = minz; k < maxz; k++){
    cout<<k<<" slices processed"<<endl;
    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()){  //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();
	    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 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();
	    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);
	      phvol[f](i-minx,j-miny,k-minz) = pvm.get_ph(f+1);
	    }
	  }
	}
	/////////////////////////////////////////////////////////
	//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();
	  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);
	  }
	}

	///////////////////////////////////////////////////
	//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;

  S0.setDisplayMaximumMinimum(S0.max(),0);
  save_volume(S0,opts.ofile.value()+"_S0");

  dvol.setDisplayMaximumMinimum(dvol.max(),0);
  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");
  }

  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++){
    fvol[f-1].setDisplayMaximumMinimum(1,0);
    save_volume(fvol[f-1],opts.ofile.value()+"_f"+num2str(f));
    thvol[f-1].setDisplayMaximumMinimum(thvol[f-1].max(),thvol[f-1].min());
    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);
    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;
}