diff --git a/meldata.cc b/meldata.cc index ec8538187966d91ed0ce0992bb08f6c7aabdcd8e..a735d8b0b539a1b03ac78501f61527790d3aa41b 100644 --- a/meldata.cc +++ b/meldata.cc @@ -48,7 +48,11 @@ namespace Melodic{ exit(2); } - + // Do we need to clean up FEAT results? + if(opts.glmcleanupmode) + GLMcleanup_preproc(); + + // clean /tmp ostringstream osc; osc << "rm " << string(Mean_fname) <<"* "; @@ -565,6 +569,159 @@ namespace Melodic{ } //void status() + + void MelodicData::GLMcleanup_preproc() + { + if(fsl_imageexists(opts.glmcleanup.value() + "/stats/res4d")){ + volume4D<float> RawData; + message("File res4d exists " << endl); + message(" Reading data file " << opts.glmcleanup.value() + "/stats/res4d" << " ... "); + read_volume4D(RawData,string(opts.glmcleanup.value() + "/stats/res4d"),tempInfo); + Data = RawData.matrix(Mask); + } + else{ + // res4d does not exist, regress out the PE's instead + //meanR=mean(Data); + //Data=remmean(Data); + message("File res4d does not exists " << endl); + message("Re-generating this from the PEs " << endl); + Matrix PEs, pemat; + volume4D<float> tmppe; + int pe_ctr=2; + read_volume4D(tmppe,opts.glmcleanup.value() + "/stats/pe1"); + PEs = tmppe.matrix(Mask); + while (fsl_imageexists(opts.glmcleanup.value() + "/stats/pe" + num2str(pe_ctr))){ + read_volume4D(tmppe,opts.glmcleanup.value() + "/stats/pe" + num2str(pe_ctr)); + pemat = tmppe.matrix(Mask); + PEs = PEs & pemat; + pe_ctr++; + } + outMsize(" ... reading PEs :",PEs); + Data = remmean(Data).t(); + PEs = PEs.t(); + Matrix tcs, tmpinv; + tmpinv = pinv(PEs.t()*PEs); + tcs = tmpinv * (PEs.t() * Data); + tcs = tcs.t(); + outMsize(" ... created time courses :",tcs); + write_ascii_matrix(opts.glmcleanup.value() + "/stats/timecourses_ICAcleanup",tcs); + Data = Data - PEs * tcs.t(); + Data = Data.t(); + + //save Data as res4d_new + tmppe.setmatrix(Data,Mask); + save_volume4D(tmppe,opts.glmcleanup.value() + "/stats/res4d_new"); + } + } + + void MelodicData::GLMcleanup_postproc() + { + message("Staring GLM cleanup " << endl << endl); + message("Creating new PEs, DOF and sigmasquareds ... " << endl); + // First, save all the old files + volume4D<float> tmpvol, old_dof; + Matrix pemaps; + volumeinfo tmpvolinfo; + int pe_ctr = 1; + while(fsl_imageexists(opts.glmcleanup.value() + "/stats/pe" + num2str(pe_ctr))) + { + read_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/pe" + num2str(pe_ctr),tmpvolinfo); + save_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/old_pe" + num2str(pe_ctr),tmpvolinfo); + if (pemaps.Storage()==0) pemaps = tmpvol.matrix(Mask); + else pemaps = pemaps & tmpvol.matrix(Mask); + pe_ctr++; + } + read_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/sigmasquareds",tmpvolinfo); + save_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/old_sigmasquareds",tmpvolinfo); + if(fsl_imageexists(opts.glmcleanup.value() + "/stats/dof")) + { + read_volume4D(old_dof,opts.glmcleanup.value() + "/stats/dof",tmpvolinfo); + save_volume4D(old_dof,opts.glmcleanup.value() + "/stats/old_dof",tmpvolinfo); + } + else + { + read_volume4D(old_dof,opts.glmcleanup.value() + "/stats/sigmasquareds"); + Matrix tmpmat; + tmpmat = read_ascii_matrix(opts.glmcleanup.value() + "/stats/dof"); + char callRMstr[1000]; + ostrstream osc(callRMstr,1000); + osc << "mv " << opts.glmcleanup.value() << "/stats/dof " << opts.glmcleanup.value() << "/stats/old_dof " <<'\0'; + system(callRMstr); + old_dof = old_dof * 0 + tmpmat(1,1); + } + + // Read in thresholded maps + Matrix threshmaps; + int ic_ctr = 2; + message(" Reading in thresholded IC maps ..."); + read_volume4D(tmpvol,logger.appendDir("stats/thresh_zstat1")); + threshmaps = tmpvol.matrix(Mask); + while(fsl_imageexists(logger.appendDir("stats/thresh_zstat" + num2str(ic_ctr)))) + { + read_volume4D(tmpvol,logger.appendDir("stats/thresh_zstat" + num2str(ic_ctr))); + threshmaps = threshmaps & tmpvol.matrix(Mask); + ic_ctr++; + } + message(" ... done " << endl); + outMsize(" threshmaps ",threshmaps); + outMsize(" pemaps ",pemaps); + + //read in data + message(" Reading in " << opts.inputfname.value() << " ... "); + Matrix orig_data; + read_volume4D(tmpvol,opts.inputfname.value(),tempInfo); + orig_data = tmpvol.matrix(Mask); + orig_data = remmean(orig_data); + message(" ... done " << endl); + + //re-regress PE maps and thresholded maps against data + message(" Calculating new OLS results ..." << endl); + Matrix allmaps, alltcs, resi; + + allmaps = pemaps & threshmaps; + + outMsize(" allmaps ",allmaps); + outMsize(" orig_data ",orig_data); + + allmaps = pemaps & threshmaps; + alltcs = ( orig_data * allmaps.t() ) * pinv (allmaps * allmaps.t() ); + + outMsize(" alltcs",alltcs); + resi = orig_data - alltcs * allmaps; + pemaps = pemaps - pemaps * threshmaps.t() * pinv (threshmaps * threshmaps.t() ) * threshmaps; + outMsize(" ... new PEs :",pemaps); + + Matrix R; + R = Identity(orig_data.Nrows()) - alltcs * pinv(alltcs.t() * alltcs) * alltcs.t(); + Matrix sigsq; + sigsq = sum(SP(resi,resi)) / R.Trace(); + outMsize(" ... new sigmasquareds :",sigsq); + + Matrix new_dof; + new_dof = old_dof.matrix(Mask); + for(int j_ctr=1;j_ctr<=threshmaps.Ncols();j_ctr++) + for(int i_ctr=1;i_ctr<=threshmaps.Nrows();i_ctr++) + if(abs(threshmaps(i_ctr,j_ctr)) > 0) + new_dof(1,j_ctr)--; + outMsize(" ... new DOFs :", new_dof); + message(" ... done " << endl); + + //save out new GLM results + message(" Saving results ... "); + tmpvol.setmatrix(sigsq,Mask); + save_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/sigmasquareds"); + + for(int tmp_ctr=1;tmp_ctr<=pemaps.Nrows(); tmp_ctr++){ + tmpvol.setmatrix(pemaps.Row(tmp_ctr),Mask); + save_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/pe" + num2str(tmp_ctr)); + } + tmpvol.setmatrix(new_dof,Mask); + save_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/dof"); + message(" ... done " << endl); + message(endl << " finished GLM cleanup ! " << endl << endl); + + } + Matrix MelodicData::calc_FFT(const Matrix& Mat) { Matrix res; diff --git a/meldata.h b/meldata.h index fdb693e7a748d1571e81489c67f8752ae81009d0..a01b2535f48a4d97f46c7eb9c375544622fbe4d9 100644 --- a/meldata.h +++ b/meldata.h @@ -33,6 +33,13 @@ namespace Melodic{ { after_mm = false; } + + //destructor + ~MelodicData() + { + if(opts.glmcleanupmode) + GLMcleanup_postproc(); + } void save(); @@ -185,9 +192,14 @@ namespace Melodic{ char Mean_fname[1000]; + int glm_pes; + void create_mask(volume4D<float> &theData, volume<float> &theMask); // void remove_comp(Matrix& Mat, const int numIC); void create_RXweight(); + + void GLMcleanup_preproc(); + void GLMcleanup_postproc(); }; } diff --git a/melodic.cc b/melodic.cc index b960a7a555fdd1a0fd95f7a9320f78624509f24d..1a0a3403b6e93a5a336a142ac46c24d907545733 100644 --- a/melodic.cc +++ b/melodic.cc @@ -162,8 +162,6 @@ int main(int argc, char *argv[]) } } - - if( bool(opts.genreport.value()) ){ report.analysistxt(); report.PPCA_rep(); diff --git a/melodic.h b/melodic.h index 039bb815722f11b08eeb64fcb2942af30e0af34d..fd4841120de95af942556dfe08c3d4883fa2bb14 100644 --- a/melodic.h +++ b/melodic.h @@ -11,6 +11,7 @@ #ifndef __MELODIC_h #define __MELODIC_h +//#include "fslio/fslio.h" #include<sstream> @@ -32,7 +33,7 @@ namespace Melodic{ -const string version = "ln(12) beta"; +const string version = "2.7.1"; } diff --git a/meloptions.cc b/meloptions.cc index eb9eb401fc0cef52f512782a8798754898fdcd44..2ef911c8445e532b59cbbe61b4db249e02104c81 100644 --- a/meloptions.cc +++ b/meloptions.cc @@ -28,10 +28,11 @@ MelodicOptions* MelodicOptions::gopt = NULL; void MelodicOptions::parse_command_line(int argc, char** argv, Log& logger, const string &p_version) { //set version number and some other stuff - version = p_version; - filtermode = false; - explicitnums = false; - logfname = string("melodic.log"); + version = p_version; + glmcleanupmode = false; + filtermode = false; + explicitnums = false; + logfname = string("melodic.log"); // work out the path to the $FSLDIR/bin directory if(getenv("FSLDIR")!=0){ @@ -115,7 +116,7 @@ MelodicOptions* MelodicOptions::gopt = NULL; } if (filter.value().length()>0){ if (filtermix.value().length()<0){ - cerr << "ERROR:: no mixing matrix for filtering (use --mix='filename') \n\n"; + cerr << "ERROR:: no mixing matrix for filtering specified (use --mix='filename') \n\n"; print_usage(argc,argv); exit(2); } else { @@ -123,6 +124,24 @@ MelodicOptions* MelodicOptions::gopt = NULL; varnorm.set_T(false); } } + if (glmcleanup.value().length()>0){ + glmcleanupmode = true; + output_MMstats.set_T(true); + perf_mm.set_T(true); + maskfname.set_T(glmcleanup.value() + "/mask"); + // varnorm.set_T(false); + logdir.set_T(glmcleanup.value() + "/GLM_cleanup.ica"); + if (!fsl_imageexists(inputfname.value()) || + !fsl_imageexists(glmcleanup.value() + "/stats/cope1")){ + cerr << "ERROR:: one or more file in the specified feat directory does not exist \n\n"; + exit(2); + } + // if (FslFileExists(string(glmcleanup.value() + "/stats/res4d").c_str())){ + // message("\n Warning:: res4d exists - using this as input file\n\n"); + + // inputfname.set_T(string(glmcleanup.value() + "/stats/res4d")); + //} + } if (threshold.value()<=0){ use_mask.set_T(false); } diff --git a/meloptions.h b/meloptions.h index a51566d89eeeebf84c6ef8f77887712f2b457d96..a2e8c6a44798b174ef70d40b5efe283af5b54931 100644 --- a/meloptions.h +++ b/meloptions.h @@ -38,6 +38,7 @@ class MelodicOptions { string binpath; string logfname; bool filtermode; + bool glmcleanupmode; bool explicitnums; Option<string> logdir; @@ -68,6 +69,7 @@ class MelodicOptions { Option<string> ICsfname; Option<string> filtermix; Option<string> filter; + Option<string> glmcleanup; Option<bool> genreport; Option<float> tr; @@ -199,6 +201,9 @@ class MelodicOptions { filter(string("-f,--filter"), string(""), string("component numbers to remove\n "), false, requires_argument), + glmcleanup(string("--cleanup"), string(""), + string("<feat dir>\n "), + false, requires_argument), genreport(string("--report"), false, string("generate Melodic web report"), false, no_argument), @@ -314,6 +319,7 @@ class MelodicOptions { options.add(ICsfname); options.add(filtermix); options.add(filter); + options.add(glmcleanup); options.add(genreport); options.add(tr); options.add(logPower);