From 00cee88887e65a317c49df1e653c9299c328e3a7 Mon Sep 17 00:00:00 2001 From: Saad Jbabdi <saad@fmrib.ox.ac.uk> Date: Wed, 25 Nov 2009 12:32:32 +0000 Subject: [PATCH] *** empty log message *** --- pvmfit.cc | 510 +++++------------------------------------------- pvmfitOptions.h | 5 + 2 files changed, 51 insertions(+), 464 deletions(-) diff --git a/pvmfit.cc b/pvmfit.cc index dc92a23..a8e6157 100644 --- a/pvmfit.cc +++ b/pvmfit.cc @@ -11,8 +11,7 @@ #include "newmat.h" #include "pvmfitOptions.h" #include "newimage/newimageall.h" - -const float two_pi=0.636619772; +#include "diffmodels.h" using namespace std; using namespace NEWMAT; @@ -20,356 +19,6 @@ using namespace MISCMATHS; using namespace PVMFIT; using namespace NEWIMAGE; -inline SymmetricMatrix vec2tens(ColumnVector& Vec){ - SymmetricMatrix tens(3); - tens(1,1)=Vec(1); - tens(2,1)=Vec(2); - tens(3,1)=Vec(3); - tens(2,2)=Vec(4); - tens(3,2)=Vec(5); - tens(3,3)=Vec(6); - return tens; -} -Matrix form_Amat(const Matrix& r,const Matrix& b) -{ - Matrix A(r.Ncols(),7); - Matrix tmpvec(3,1), tmpmat; - - for( int i = 1; i <= r.Ncols(); i++){ - tmpvec << r(1,i) << r(2,i) << r(3,i); - tmpmat = tmpvec*tmpvec.t()*b(1,i); - A(i,1) = tmpmat(1,1); - A(i,2) = 2*tmpmat(1,2); - A(i,3) = 2*tmpmat(1,3); - A(i,4) = tmpmat(2,2); - A(i,5) = 2*tmpmat(2,3); - A(i,6) = tmpmat(3,3); - A(i,7) = 1; - } - return A; -} -// dtifit -class DTI { -public: - - DTI(const ColumnVector& iY, - const Matrix& iAmat):Y(iY),pinvAmat(iAmat){ - - npts = Y.Nrows(); - v1.ReSize(3); - v2.ReSize(3); - v3.ReSize(3); - - } - ~DTI(){} - void fit(); - float get_fa()const{return fa;} - float get_md()const{return md;} - float get_s0()const{return s0;} - float get_mo()const{return mo;} - ColumnVector get_v1()const{return v1;} - ColumnVector get_v2()const{return v2;} - ColumnVector get_v3()const{return v3;} - ColumnVector get_v(const int& i)const{if(i==1)return v1;else if(i==2)return v2;else return v3;} - void print(); - -private: - const ColumnVector& Y; - const Matrix& pinvAmat; - int npts; - ColumnVector v1,v2,v3; - float l1,l2,l3; - float fa,s0,md,mo; - -}; -void DTI::fit(){ - ColumnVector logS(npts); - ColumnVector Dvec(7); - SymmetricMatrix tens; - Matrix Vd; - DiagonalMatrix Dd(3); - - for (int i=1;i<=npts; i++){ - if(Y(i)>0) - logS(i)=log(Y(i)); - else - logS(i)=0; - } - - Dvec = -pinvAmat*logS; - - if(Dvec(7)>-23) - s0=exp(-Dvec(7)); - else - s0=Y.MaximumAbsoluteValue(); - - for (int i=1;i<=Y.Nrows();i++){ - if(s0<Y.Sum()/Y.Nrows()){ s0=Y.MaximumAbsoluteValue(); } - logS(i)=(Y(i)/s0)>0.01 ? log(Y(i)):log(0.01*s0); - } - Dvec = -pinvAmat*logS; - s0=exp(-Dvec(7)); - - if(s0<Y.Sum()/Y.Nrows()){ s0=Y.Sum()/Y.Nrows(); } - tens = vec2tens(Dvec); - - EigenValues(tens,Dd,Vd); - - md = Dd.Sum()/Dd.Nrows(); - - l1 = Dd(3,3); - l2 = Dd(2,2); - l3 = Dd(1,1); - v1 = Vd.Column(3); - v2 = Vd.Column(2); - v3 = Vd.Column(1); - - float e1=l1-md, e2=l2-md, e3=l3-md; - float n = (e1 + e2 - 2*e3)*(2*e1 - e2 - e3)*(e1 - 2*e2 + e3); - float d = (e1*e1 + e2*e2 + e3*e3 - e1*e2 - e2*e3 - e1*e3); - d = sqrt(MAX(0, d)); - d = 2*d*d*d; - mo = MIN(MAX(d ? n/d : 0.0, -1),1); - - float numer=1.5*((l1-md)*(l1-md)+(l2-md)*(l2-md)+(l3-md)*(l3-md)); - float denom=(l1*l1+l2*l2+l3*l3); - if(denom>0) fa=numer/denom; - else fa=0; - if(fa>0){fa=sqrt(fa);} - else{fa=0;} - - -} -void DTI::print(){ - cout << "DTI FIT RESULTS " << endl; - cout << "S0 :" << s0 << endl; - cout << "MD :" << md << endl; - cout << "FA :" << fa << endl;; - cout << "MO :" << mo << endl;; -} - -// nonlinear optimisation - -// nonlinear class for despot1_hifi -class PVMNonlinCF : public NonlinCF { -public: - PVMNonlinCF(const ColumnVector& iY, - const ColumnVector& ibvals, - const ColumnVector& isina,const ColumnVector& icosa,const ColumnVector& ibeta, - const int& nfibres):Y(iY),bvals(ibvals),sinalpha(isina),cosalpha(icosa),beta(ibeta){ - - npts = Y.Nrows(); - nparams = nfibres*3 + 2; - nfib = nfibres; - - // OUT(Y.t()); -// OUT(npts); -// OUT(nparams); -// OUT(bvals.t()); -// OUT(sinalpha.t()); -// OUT(beta.t()); - - } - ~PVMNonlinCF(){} - - NEWMAT::ReturnMatrix grad(const NEWMAT::ColumnVector& p)const; - boost::shared_ptr<BFMatrix> hess(const NEWMAT::ColumnVector&p,boost::shared_ptr<BFMatrix> iptr)const; - double cf(const NEWMAT::ColumnVector& p)const; - NEWMAT::ReturnMatrix forwardModel(const NEWMAT::ColumnVector& p)const; - -private: - const ColumnVector& Y; - const ColumnVector& bvals; - const ColumnVector& sinalpha; - const ColumnVector& cosalpha; - const ColumnVector& beta; - - float npts; - int nparams; - int nfib; -}; -NEWMAT::ReturnMatrix PVMNonlinCF::forwardModel(const NEWMAT::ColumnVector& p)const{ - ColumnVector ret(npts); - - double val; - float angtmp; - ColumnVector f(nfib); - - float sumf=0; - for(int i=3,j=1;i<=p.Nrows();i+=3,j++){ - f(j) = abs(two_pi*atan(p(i))); - sumf += f(j); - } - for(int i=1;i<=Y.Nrows();i++){ - val = 0.0; - for(int k=3;k<=p.Nrows();k+=3){ - angtmp = cos(p(k+2)-beta(i))*sinalpha(i)*sin(p(k+1)) + cosalpha(i)*cos(p(k+1)); - - val += f(k/3)*exp(-bvals(i)*p(2)*angtmp*angtmp); - } - ret(i) = (p(1)*((1-sumf)*exp(-bvals(i)*p(2))+val)); - - } - - ret.Release(); - return(ret); -} - -double PVMNonlinCF::cf(const NEWMAT::ColumnVector& p)const{ - // p(1) = S0 - // p(2) = d - // p(3) = f1 - // p(4) = th1 - // p(5) = ph1 - // etc. - - //cout << "CF" << endl; - //OUT(p.t()); - - double cfv = 0.0; - double err; - float angtmp; - ColumnVector f(nfib); - - float sumf=0; - for(int i=3,j=1;i<=p.Nrows();i+=3,j++){ - f(j) = abs(two_pi*atan(p(i))); - sumf += f(j); - } - - for(int i=1;i<=Y.Nrows();i++){ - err = 0.0; - for(int k=3;k<=p.Nrows();k+=3){ - angtmp = cos(p(k+2)-beta(i))*sinalpha(i)*sin(p(k+1)) + cosalpha(i)*cos(p(k+1)); - //err += p(k)*exp(-bvals(i)*p(2)*angtmp*angtmp); - err += f(k/3)*exp(-bvals(i)*p(2)*angtmp*angtmp); - } - err = (p(1)*((1-sumf)*exp(-bvals(i)*p(2))+err) - Y(i)); - - cfv += err*err; - } - //OUT(cfv); - return(cfv); -} -NEWMAT::ReturnMatrix PVMNonlinCF::grad(const NEWMAT::ColumnVector& p)const{ - //cout << "gradv" << endl; - //OUT(p.t()); - - NEWMAT::ColumnVector gradv(p.Nrows()); - gradv = 0.0; - double dval1; - double dval2; - float angtmp,tmpval; - ColumnVector f(nfib); - - float sumf=0; - for(int i=3,j=1;i<=p.Nrows();i+=3,j++){ - f(j) = abs(two_pi*atan(p(i))); - sumf += f(j); - } - - for(int i=1;i<=Y.Nrows();i++){ - // calculate difference between signal and data - dval1 = 0.0; - dval2 = 0.0; - for(int k=3;k<=p.Nrows();k+=3){ - angtmp = cos(p(k+2)-beta(i))*sinalpha(i)*sin(p(k+1)) + cosalpha(i)*cos(p(k+1)); - angtmp *= angtmp; - // tmpval = p(k)*exp(-bvals(i)*p(2)*angtmp); - tmpval = f(k/3)*exp(-bvals(i)*p(2)*angtmp); - dval1 += tmpval; - dval2 += -bvals(i)*angtmp*tmpval; - } - dval1 = (p(1)*((1-sumf)*exp(-bvals(i)*p(2))+dval1) - Y(i)); - dval2 = (p(1)*(-bvals(i)*(1-sumf)*exp(-bvals(i)*p(2))+dval2)); - - gradv(1) += 2 * dval1 * (dval1+Y(i))/p(1); - gradv(2) += 2 * dval1 * dval2; - - for(int k=3;k<=p.Nrows();k+=3){ - angtmp = cos(p(k+2)-beta(i))*sinalpha(i)*sin(p(k+1)) + cosalpha(i)*cos(p(k+1)); - tmpval = f(k/3)*exp(-bvals(i)*p(2)*angtmp*angtmp); - - gradv(k) += 2 * dval1 * p(1) * (-exp(-bvals(i)*p(2)) + tmpval) / f(k/3) * sign(p(k)) / (1+p(k)*p(k)); - gradv(k+1) += 2 * dval1 * p(1) * tmpval * (-bvals(i)*p(2)*2*angtmp*(cos(p(k+2)-beta(i))*sinalpha(i)*cos(p(k+1)) - cosalpha(i)*sin(p(k+1)))); - gradv(k+2) += 2 * dval1 * p(1) * tmpval * (bvals(i)*p(2)*2*angtmp*(sin(p(k+2)-beta(i))*sinalpha(i)*sin(p(k+1)))); - - } - } - - //OUT(gradv.t()); - - gradv.Release(); - return(gradv); -} -// this uses Gauss-Newton approximation -boost::shared_ptr<BFMatrix> PVMNonlinCF::hess(const NEWMAT::ColumnVector& p,boost::shared_ptr<BFMatrix> iptr)const{ - //cout << "hessian" << endl; - //OUT(p.t()); - - boost::shared_ptr<BFMatrix> hessm; - - if (iptr && iptr->Nrows()==(unsigned int)p.Nrows() && iptr->Ncols()==(unsigned int)p.Nrows()) hessm = iptr; - else hessm = boost::shared_ptr<BFMatrix>(new FullBFMatrix(p.Nrows(),p.Nrows())); - - double dval1; - double dval2; - float angtmp,tmpval; - ColumnVector f(nfib); - float sumf=0; - for(int i=3,j=1;i<=p.Nrows();i+=3,j++){ - f(j) = abs(two_pi*atan(p(i))); - sumf += f(j); - } - - Matrix J(Y.Nrows(),nparams); - for(int i=1;i<=Y.Nrows();i++){ - - dval1 = 0.0; - dval2 = 0.0; - for(int k=3;k<=p.Nrows();k+=3){ - angtmp = cos(p(k+2)-beta(i))*sinalpha(i)*sin(p(k+1)) + cosalpha(i)*cos(p(k+1)); - angtmp *= angtmp; - // tmpval = p(k)*exp(-bvals(i)*p(2)*angtmp); - tmpval = f(k/3)*exp(-bvals(i)*p(2)*angtmp); - dval1 += tmpval; - dval2 += -bvals(i)*angtmp*tmpval; - } - dval1 = (p(1)*((1-sumf)*exp(-bvals(i)*p(2))+dval1) - Y(i)); - dval2 = (p(1)*(-bvals(i)*(1-sumf)*exp(-bvals(i)*p(2))+dval2)); - - J(i,1) = (dval1+Y(i))/p(1); - J(i,2) = dval2; - - for(int k=3;k<=p.Nrows();k+=3){ - angtmp = cos(p(k+2)-beta(i))*sinalpha(i)*sin(p(k+1)) + cosalpha(i)*cos(p(k+1)); - tmpval = f(k/3)*exp(-bvals(i)*p(2)*angtmp*angtmp); - - J(i,k) = p(1) * (-exp(-bvals(i)*p(2)) + tmpval)/ f(k/3) * sign(p(k)) / (1+p(k)*p(k));; - J(i,k+1) = p(1) * tmpval * (-bvals(i)*p(2)*2*angtmp*(cos(p(k+2)-beta(i))*sinalpha(i)*cos(p(k+1)) - cosalpha(i)*sin(p(k+1)))); - J(i,k+2) = p(1) * tmpval * (bvals(i)*p(2)*2*angtmp*(sin(p(k+2)-beta(i))*sinalpha(i)*sin(p(k+1)))); - } - } - - for (int i=1; i<=p.Nrows(); i++){ - for (int j=i; j<=p.Nrows(); j++){ - dval1 = 0.0; - for(int k=1;k<=J.Nrows();k++) - dval1 += J(k,i)*J(k,j); - hessm->Set(i,j,dval1); - } - } - - for (int j=1; j<=p.Nrows(); j++) { - for (int i=j+1; i<=p.Nrows(); i++) { - hessm->Set(i,j,hessm->Peek(j,i)); - } - } - - //hessm->Print(); - - return(hessm); -} @@ -387,35 +36,19 @@ int main(int argc, char** argv) } // Set random seed: - Matrix r = read_ascii_matrix(opts.bvecsfile.value()); - if(r.Nrows()>3) r=r.t(); - for(int i=1;i<=r.Ncols();i++){ - float tmpsum=sqrt(r(1,i)*r(1,i)+r(2,i)*r(2,i)+r(3,i)*r(3,i)); + 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){ - r(1,i)=r(1,i)/tmpsum; - r(2,i)=r(2,i)/tmpsum; - r(3,i)=r(3,i)/tmpsum; + bvecs(1,i)=bvecs(1,i)/tmpsum; + bvecs(2,i)=bvecs(2,i)/tmpsum; + bvecs(3,i)=bvecs(3,i)/tmpsum; } } - Matrix b = read_ascii_matrix(opts.bvalsfile.value()); - if(b.Nrows()>1) b=b.t(); - - ColumnVector alpha,beta,sinalpha,cosalpha; - ColumnVector bvals; - - bvals = b.Row(1).t(); - cart2sph(r,alpha,beta); - sinalpha.ReSize(alpha.Nrows()); - cosalpha.ReSize(alpha.Nrows()); - for(int i=1;i<=alpha.Nrows();i++){ - sinalpha(i) = sin(alpha(i)); - cosalpha(i) = cos(alpha(i)); - } + Matrix bvals = read_ascii_matrix(opts.bvalsfile.value()); + if(bvals.Nrows()>1) bvals=bvals.t(); - // for dti - Matrix Amat; - Amat = form_Amat(r,b); - Amat = pinv(Amat); volume4D<float> data; volume<int> mask; @@ -447,6 +80,9 @@ int main(int argc, char** argv) 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; @@ -459,116 +95,57 @@ int main(int argc, char** argv) 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; + } + if(opts.verbose.value()) cout<<"ok"<<endl; //int counter=0; - ColumnVector S(bvals.Nrows()); + 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; - - //counter++; - //OUT(counter); - //if(counter<1443)continue; - for(int t=0;t < data.tsize();t++) S(t+1)=data(i,j,k,t); - - // initialisation /////////////////////////////////// - DTI dti(S,Amat); - dti.fit(); - - //dti.print(); - - float th,ph; - cart2sph(dti.get_v1(),th,ph); - ColumnVector start(2+3*opts.nfibres.value()); - start(1) = dti.get_s0(); - start(2) = (dti.get_md()>0?dti.get_md():0.001); - start(3) = tan(dti.get_fa())/two_pi; - start(4) = th; - start(5) = ph; - float sumf=abs(two_pi*atan(start(3))); - float tmpsumf = sumf; - for(int ff=2;ff<=opts.nfibres.value();ff++){ - float denom=2; - do{ - start(ff*3) = tan(abs(two_pi*atan(start(3))/(denom)))/two_pi; - denom *= 2; - tmpsumf = sumf + abs(two_pi*atan(start(ff*3))); - }while(tmpsumf>1); - sumf += abs(two_pi*atan(start(ff*3))); - cart2sph(dti.get_v(ff),th,ph); - start(ff*3+1) = th; - start(ff*3+2) = ph; - } - ////////////////////////////////////////////////////// - - PVMNonlinCF pvm_cf(S,bvals,sinalpha,cosalpha,beta,opts.nfibres.value()); - ColumnVector final_par; - - //cout << i << " " << j << " " << k << endl; - //OUT(start.t()); - if(dti.get_fa()<1 & dti.get_md()>0){ - NonlinParam lmpar(start.Nrows(),NL_LM,start); // Levenberg-Marquardt - lmpar.SetGaussNewtonType(LM_L); // Levenberg - lmpar.SetStartingEstimate(start); - - NonlinOut status = nonlin(lmpar,pvm_cf); - final_par = lmpar.Par(); + if(opts.modelnum.value()==1){ + PVM_single 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(); + 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{ - final_par = start; - } - - //OUT(final_par.t()); - - -// OUT(pvm_cf.forwardModel(final_par).t()); - - S0(i-minx,j-miny,k-minz)=final_par(1); - dvol(i-minx,j-miny,k-minz)=final_par(2); - - for(int f=0;f<opts.nfibres.value();f++){ - fvol[f](i-minx,j-miny,k-minz) = abs(2.0/M_PI*atan(final_par(3*(1+f)))); - thvol[f](i-minx,j-miny,k-minz) = final_par(3*(1+f)+1); - phvol[f](i-minx,j-miny,k-minz) = final_par(3*(1+f)+2); - } - - // where we reorder the PVFs - if(opts.nfibres.value()>1){ - vector< pair<float,int> > fpairs; - vector< pair<float,float> > apairs; - pair<float,int> mypair; - pair<float,float> mypair2; + 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++){ - mypair.first = fvol[f](i-minx,j-miny,k-minz); - mypair.second = f; - fpairs.push_back(mypair); - mypair2.first = thvol[f](i-minx,j-miny,k-minz); - mypair2.second = phvol[f](i-minx,j-miny,k-minz); - apairs.push_back(mypair2); - } - sort(fpairs.begin(),fpairs.end()); - for(int f=0,ff=opts.nfibres.value()-1;f<opts.nfibres.value();f++,ff--){ - fvol[ff](i-minx,j-miny,k-minz) = fpairs[f].first; - thvol[ff](i-minx,j-miny,k-minz) = apairs[fpairs[f].second].first; - phvol[ff](i-minx,j-miny,k-minz) = apairs[fpairs[f].second].second; + 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); } } - - // create dyads? + 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)); } - } } } @@ -583,6 +160,11 @@ int main(int argc, char** argv) 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"); + } + 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)); diff --git a/pvmfitOptions.h b/pvmfitOptions.h index b9c9d4a..bf7c7b2 100644 --- a/pvmfitOptions.h +++ b/pvmfitOptions.h @@ -35,6 +35,7 @@ class pvmfitOptions { Option<string> bvecsfile; Option<string> bvalsfile; Option<int> nfibres; + Option<int> modelnum; bool parse_command_line(int argc, char** argv); private: @@ -80,6 +81,9 @@ class pvmfitOptions { nfibres(string("-n,--nfibres"), 1, string("number of fibres to fit - default=1"), false, requires_argument), + modelnum(string("--model"), 1, + string("1:monoexponential;2:non mono-exponential"), + false, requires_argument), options("pvmfit", "pvmfit -k <datafile> -m <maskfile> -r <bvecsfile> -b <bvalsfile> [-n 2]\n") { @@ -93,6 +97,7 @@ class pvmfitOptions { options.add(bvecsfile); options.add(bvalsfile); options.add(nfibres); + options.add(modelnum); } catch(X_OptionError& e) { options.usage(); -- GitLab