Skip to content
Snippets Groups Projects
meldata.cc 26.3 KiB
Newer Older
Mark Jenkinson's avatar
Mark Jenkinson committed
/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
              independent components
    
    meldata.cc - data handler / container class

    Christian F. Beckmann, FMRIB Image Analysis Group
    
Christian Beckmann's avatar
Christian Beckmann committed
    Copyright (C) 1999-2004 University of Oxford */
Mark Jenkinson's avatar
Mark Jenkinson committed

/*  CCOPYRIGHT  */

#include "newimage/newimageall.h"
Mark Jenkinson's avatar
Mark Jenkinson committed
#include "meloptions.h"
#include "meldata.h"
#include "melodic.h"
#include "utils/log.h"
#include <time.h>
#include "miscmaths/miscprob.h"
#include <sstream>
Mark Jenkinson's avatar
Mark Jenkinson committed

using namespace Utilities;
using namespace NEWIMAGE;

namespace Melodic{

  void MelodicData::setup()
  {
    {
      volume4D<float> RawData;
      message("Reading data file " << opts.inputfname.value() << "  ... ");
      read_volume4D(RawData,opts.inputfname.value(),tempInfo);
      message(" done" << endl);
      for(int ctr=1; ctr<=opts.dummy.value(); ctr++){
	RawData.deletevolume(ctr);
      }    
    
      // calculate a Mean image and save it
      Mean = meanvol(RawData);
      tmpnam(Mean_fname); // generate a tmp name
      save_volume(Mean,Mean_fname);
      create_mask(RawData, Mask);
      if(Mask.xsize()==RawData.xsize() &&
	 Mask.ysize()==RawData.ysize() &&
	 Mask.zsize()==RawData.zsize())
	 Data = RawData.matrix(Mask);
      else{
	cerr << "ERROR:: mask and data have different dimensions  \n\n";
	exit(2);
      }
	
Christian Beckmann's avatar
Christian Beckmann committed
      // Do we need to clean up FEAT results?
      if(opts.glmcleanupmode)
	GLMcleanup_preproc();

     
Mark Jenkinson's avatar
Mark Jenkinson committed
      // clean /tmp
      ostringstream osc;
      osc  << "rm " << string(Mean_fname) <<"*  ";
      system(osc.str().c_str());
Mark Jenkinson's avatar
Mark Jenkinson committed
         
      //mask out constant voxels
      message("Excluding voxels with constant value " << endl);
      Matrix DStDev=stdev(Data);
      volume4D<float> tmpMask;
      tmpMask.setmatrix(DStDev,Mask);
      
      float tMmax;
      volume<float> tmpMask2;
      tmpMask2 = tmpMask[0];
      tMmax = tmpMask2.max();
      double st_mean = DStDev.Sum()/DStDev.Ncols();
      double st_std  = stdev(DStDev.t()).AsScalar();
      
      Mask = binarise(tmpMask2,(float) max((float) st_mean-3*st_std,
					   (float) 0.01*st_mean),tMmax);
      Data = RawData.matrix(Mask);
    }

    message("Data size : " << Data.Nrows() << " x " << Data.Ncols() <<endl);

    {// remove mean volume
      //    if((opts.remove_meanvol.value()||opts.varnorm.value())){
      message(string("Removing mean image ... "));
      meanR=mean(Data);
      Data=remmean(Data); 
      message("done" << endl);
      //}else{
      // meanR=zeros(1,Data.Ncols());
      //}
    }
    {// remove mean time course
      meanC=mean(Data,2);
      Data=remmean(Data,2); 
    }

    {//switch dimension in case temporal ICA is required
      if(opts.temporal.value()){
	message(string("Switching dimensions for temporal ICA") << endl);
	Data = Data.t();
	Matrix tmp;
	tmp = meanC;
	meanC = meanR.t();
	meanR = tmp.t();
	message("Data size : " << Data.Nrows() << " x " << Data.Ncols() <<endl);
      }
    }


Mark Jenkinson's avatar
Mark Jenkinson committed
    {// variance-normalize the data
      DiagonalMatrix tmpD;Matrix tmpE;
      message(string("Estimating data covariance ... "));
      SymmetricMatrix Corr;
      Corr = cov(Data.t());
      EigenValues(Corr,tmpD,tmpE);
      
      Matrix RE; DiagonalMatrix RD;
      //RE = tmpE.Columns(2,Corr.Ncols());
      RE = tmpE;
      //RD << abs(tmpD.SymSubMatrix(2,Corr.Ncols()));    
      RD << abs(tmpD);
      Matrix tmpWhite;Matrix tmpDeWhite;
      tmpWhite = sqrt(abs(RD.i()))*RE.t();
      tmpDeWhite = RE*sqrt(RD);
      message("done"<<endl);
      if(opts.varnorm.value())
	message(string("Perform variance-normalisation ... "));
      Matrix WS;
      WS = tmpWhite * Data;
      for(int ctr1 =1; ctr1<=WS.Nrows(); ctr1++){
	for(int ctr2 =1; ctr2<=WS.Ncols(); ctr2++){
	  if(abs(WS(ctr1,ctr2))<3.1)
	    WS(ctr1,ctr2)=0.0;
	}
      }
      
      stdDev = stdev(Data - tmpDeWhite*WS);   
      stdDevi = pow(stdDev,-1);   
Mark Jenkinson's avatar
Mark Jenkinson committed
      Data = Data + meanC*ones(1,Data.Ncols());
    }
    
    DataVN = SP(Data,ones(Data.Nrows(),1)*stdDevi);

    if(opts.output_all.value()){
      volume4D<float> tempVol; 
      tempVol.setmatrix(stdDevi,Mask);
      save_volume4D(tempVol,logger.appendDir(opts.outputfname.value() 
					     + "_vn_stdev"),tempInfo);
      tempVol.setmatrix(DataVN,Mask);
      save_volume4D(tempVol,logger.appendDir(opts.outputfname.value() 
					     + "_vn"),tempInfo);
    }

Mark Jenkinson's avatar
Mark Jenkinson committed
    if(opts.varnorm.value()){
      Data = DataVN;
      message("done"<<endl);
    }
    {//remove row mean
      if(opts.temporal.value()){
	message(string("Removing mean image ... "));
Mark Jenkinson's avatar
Mark Jenkinson committed
      }else{
	message(string("Removing mean time course ... "));
      }
      meanC=mean(Data,2);
      Data=remmean(Data,2); 
      message("done"<<endl);
Mark Jenkinson's avatar
Mark Jenkinson committed
    }
    
    if(opts.segment.value().length()>0){
       create_RXweight();
    }
 
    //save the mask
    save_volume(Mask,logger.appendDir("mask"));

    //seed the random number generator
    double tmptime = time(NULL);
    // cerr << tmptime << endl << endl;;
    srand((unsigned int) tmptime);
Mark Jenkinson's avatar
Mark Jenkinson committed
  } // void setup()

  void MelodicData::save()
  {   

    //check for temporal ICA
    if(opts.temporal.value()){
      message(string("temporal ICA: transform back the data ... "));
Mark Jenkinson's avatar
Mark Jenkinson committed
      Matrix tmpIC = mixMatrix.t();
      mixMatrix=IC.t();
      IC=tmpIC;

      unmixMatrix=pinv(mixMatrix);
      Data = Data.t();
      tmpIC = meanC;
      meanC = meanR.t();
      meanR = tmpIC.t();
      //  whiteMatrix = whiteMatrix.t;
      //  dewhiteMatrix = dewhiteMatrix.t();
      message(string("done") << endl);
      opts.temporal.set_T(false); // Do not switch again!
Mark Jenkinson's avatar
Mark Jenkinson committed
    }
 
    message("Writing results to : " << endl);

    //Output IC	
Christian Beckmann's avatar
Christian Beckmann committed
    if((IC.Storage()>0)&&(opts.output_origIC.value())&&(after_mm==false)){
Mark Jenkinson's avatar
Mark Jenkinson committed
      volume4D<float> tempVol; 
      tempVol.setmatrix(IC,Mask);
      //strncpy(tempInfo.header.hist.aux_file,"render3",24);
      save_volume4D(tempVol,logger.appendDir(opts.outputfname.value() 
Christian Beckmann's avatar
Christian Beckmann committed
					     + "_oIC"),tempInfo);
Mark Jenkinson's avatar
Mark Jenkinson committed
      message("  " << logger.appendDir(opts.outputfname.value() + "_oIC") <<endl);
    }

    //Output IC -- adjusted for noise	
      if(IC.Storage()>0){
      volume4D<float> tempVol;	
	//      volumeinfo tempInfo;
	//  read_volume4D(tempVol,opts.inputfname.value(),tempInfo); 

      //Matrix ICadjust = IC;
Mark Jenkinson's avatar
Mark Jenkinson committed
      Matrix ICadjust;
Christian Beckmann's avatar
Christian Beckmann committed
      if(after_mm)
	ICadjust = IC;
      else{
	stdNoisei = pow(stdev(Data - mixMatrix * IC)*std::sqrt((float)(Data.Nrows()-1))/
			std::sqrt((float)(Data.Nrows()-IC.Nrows())),-1);

	ColumnVector diagvals;
	diagvals=pow(diag(unmixMatrix*unmixMatrix.t()),-0.5);
	ICadjust = SP(IC,diagvals*stdNoisei);
      }
Mark Jenkinson's avatar
Mark Jenkinson committed
      tempVol.setmatrix(ICadjust,Mask);
      //strncpy(tempInfo.header.hist.aux_file,"render3",24);
      save_volume4D(tempVol,logger.appendDir(opts.outputfname.value() 
					     + "_IC"),tempInfo);
      message("  " << logger.appendDir(opts.outputfname.value() + "_IC") <<endl);

      if(opts.output_origIC.value()){
	tempVol.setmatrix(stdNoisei,Mask);
	save_volume4D(tempVol,logger.appendDir(string("Noise_stddev_inv")),tempInfo);
	message("  " << logger.appendDir(string("Noise_stddev_inv")) <<endl);
      }
      
Mark Jenkinson's avatar
Mark Jenkinson committed
    }

    //Output mixMatrix
    if(mixMatrix.Storage()>0){
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_mix"),
			 mixMatrix); 
      mixFFT=calc_FFT(mixMatrix);
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_FTmix"),
			 mixFFT);      
      message("  "<<
	      logger.appendDir(opts.outputfname.value() + "_mix") <<endl);
      message("  "<<
	      logger.appendDir(opts.outputfname.value() + "_FTmix") <<endl);
    }

    //Output ICstats
    if(ICstats.Storage()>0){
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_ICstats"),
			 ICstats); 
      message("  "<<
	      logger.appendDir(opts.outputfname.value() + "_ICstats") <<endl);
    }

Mark Jenkinson's avatar
Mark Jenkinson committed
    //Output unmixMatrix
    if(opts.output_unmix.value() && unmixMatrix.Storage()>0){
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_unmix"),unmixMatrix);
Mark Jenkinson's avatar
Mark Jenkinson committed
      message("  "<<
	  logger.appendDir(opts.outputfname.value() + "_unmix") <<endl);
    }

    //Output Mask
    message("  "<< logger.appendDir("mask") <<endl);

    //Output mean
    if(opts.output_mean.value() && meanC.Storage()>0 && meanR.Storage()>0){
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_meanR"),
			 meanR);
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_meanC"),
			 meanC);
      message("  "<<
	  logger.appendDir(opts.outputfname.value() + "_meanR") <<endl);
      message("  "<<
	  logger.appendDir(opts.outputfname.value() + "_meanC") <<endl);
    }

    //Output white
    if(opts.output_white.value() && whiteMatrix.Storage()>0&&
       dewhiteMatrix.Storage()>0){
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_white"),
			 whiteMatrix);
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_dewhite"),dewhiteMatrix);
      Matrix tmp;
      tmp=calc_FFT(dewhiteMatrix);
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_FTdewhite"),tmp);
      message("  "<<
	  logger.appendDir(opts.outputfname.value() + "_white") <<endl);
      message("  "<<
	  logger.appendDir(opts.outputfname.value() + "_dewhite") <<endl);
    }

    //Output PCA
    if(opts.output_pca.value() && pcaD.Storage()>0&&pcaE.Storage()>0){
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_pcaE"),
			 pcaE);
      message("  "<<
	      logger.appendDir(opts.outputfname.value() + "_pcaE") <<endl);
Mark Jenkinson's avatar
Mark Jenkinson committed
      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_pcaD"),
			 (Matrix) diag(pcaD));
      message("  "<<
	      logger.appendDir(opts.outputfname.value() + "_pcaD") <<endl);
      
Mark Jenkinson's avatar
Mark Jenkinson committed
      volume4D<float> tempVol;	

      Matrix PCAmaps;

      if(whiteMatrix.Ncols()==Data.Ncols()){
	PCAmaps = dewhiteMatrix.t();
      }else
	PCAmaps = whiteMatrix * Data;
     
Mark Jenkinson's avatar
Mark Jenkinson committed

      tempVol.setmatrix(PCAmaps,Mask);
      //strncpy(tempInfo.header.hist.aux_file,"render3",24);
      save_volume4D(tempVol,logger.appendDir(opts.outputfname.value() 
					     + "_pca"),tempInfo);
      message("  " << 
	  logger.appendDir(opts.outputfname.value() + "_pca") <<endl);
Mark Jenkinson's avatar
Mark Jenkinson committed
  } //void save()
  
  int MelodicData::remove_components()
  {  
    message("Reading " << opts.filtermix.value() << endl) 
    mixMatrix = read_ascii_matrix(opts.filtermix.value());
    if (mixMatrix.Storage()<=0) {
      cerr <<" Please specify the mixing matrix correctly" << endl;
      exit(2);
    }
    
    unmixMatrix = pinv(mixMatrix);
    IC = unmixMatrix * Data;

    string tmpstr;
    tmpstr = opts.filter.value();

    Matrix noiseMix;
    Matrix noiseIC;

    int ctr=0;    
    char *p;
    char t[1024];
    const char *discard = ", [];{(})abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*_-=+|\':><./?";
    
    message("Filtering the data...");
    strcpy(t, tmpstr.c_str());
    p=strtok(t,discard);
    ctr = atoi(p);
    if(ctr>0 && ctr<=mixMatrix.Ncols()){
      message(" "<< ctr );
      noiseMix = mixMatrix.Column(ctr);
      noiseIC  = IC.Row(ctr).t();    
    }else{
      cerr << endl<< "component number "<<ctr<<" does not exist" << endl;
    }
    
    do{
      p=strtok(NULL,discard);
      if(p){
	ctr = atoi(p);
	
        if(ctr>0 && ctr<=mixMatrix.Ncols()){
	  message(" "<<ctr);
	  noiseMix |= mixMatrix.Column(ctr);
	  noiseIC  |= IC.Row(ctr).t();
	}
	else{
	  cerr << endl<< "component number "<<ctr<<" does not exist" << endl;
	}
      }
    }while(p);
    message(endl);
    Matrix newData;
    newData = Data - noiseMix * noiseIC.t();

    //cerr << newData.Nrows() << " x " << newData.Ncols() << endl;
    //cerr << meanC.Nrows() << " x " << meanC.Ncols() << endl;
    //cerr << meanR.Nrows() << " x " << meanR.Ncols() << endl;
    newData = newData + meanC*ones(1,newData.Ncols());
    newData = newData + ones(newData.Nrows(),1)*meanR;
    
    volume4D<float> tmp;
    read_volume4D(tmp,opts.inputfname.value()); 
    tmp.setmatrix(newData,Mask);
    save_volume4D(tmp,logger.appendDir(opts.outputfname.value() + "_ICAfiltered")); 
   
    return 0;
  } // int remove_components()

  void MelodicData::create_RXweight()
  {
    message("Reading the weights for the covariance R_X from file "<< opts.segment.value() << endl);
  
    volume4D<float> tmpRX;
    read_volume4D(tmpRX,opts.segment.value());
    RXweight = tmpRX.matrix(Mask);
  } 
 
  void MelodicData::create_mask(volume4D<float> &theData, 
				volume<float> &theMask)
  {
    if(opts.use_mask.value() && opts.maskfname.value().size()>0){   // mask provided 
      read_volume(theMask,opts.maskfname.value());
      message("Mask provided : " << opts.maskfname.value()<<endl);
    }
    else{
      if(opts.perf_bet.value() && opts.use_mask.value()){ //use BET
	message("Create mask ... ");
	// set up all strings
	string BET_outputfname = string(Mean_fname)+"_brain";

	string BET_path = opts.binpath + "bet";
	string BET_optarg = "-m -f 0.4"; // see man bet
Stephen Smith's avatar
Stephen Smith committed
	string Mask_fname = BET_outputfname+"_mask";
Mark Jenkinson's avatar
Mark Jenkinson committed

	// Setup external call to BET:

	ostringstream osc;
Mark Jenkinson's avatar
Mark Jenkinson committed
	osc  << BET_path << " " << Mean_fname << " " 
	     << BET_outputfname << " " << BET_optarg << " > /dev/null ";
Mark Jenkinson's avatar
Mark Jenkinson committed
	
        message("  Calling BET: " << osc.str() << endl);
	system(osc.str().c_str());
Mark Jenkinson's avatar
Mark Jenkinson committed
	
	// read back the Mask file   
	read_volume(theMask,Mask_fname);

	message("done" << endl);
      }  
      else{
	if(opts.use_mask.value()){   //just threshold the Mean
	  message("Create mask ... ");
	  float Mmin, Mmax, Mtmp;
	  Mmin = Mean.min(); Mmax = Mean.max();
	  theMask = binarise(Mean,Mmin + opts.threshold.value()* (Mmax-Mmin),Mmax);
          Mtmp = Mmin + opts.threshold.value()* (Mmax-Mmin);
	  message("done" << endl);
	}
	else{ //well, don't threshold then
	  theMask = Mean;
	  theMask = 1.0;
	}
      }
    }
    if(opts.remove_endslices.value()){ 
      // just in case mc introduced something nasty
      message("  Deleting end slices" << endl);
      for(int ctr1=theMask.miny(); ctr1<=theMask.maxy(); ctr1++){
	for(int ctr2=theMask.minx(); ctr2<=theMask.maxx(); ctr2++){   
	  theMask(ctr2,ctr1,Mask.minz()) = 0.0;
	  theMask(ctr2,ctr1,Mask.maxz()) = 0.0;
	}
      }
    }
  } //void create_mask()

  void MelodicData::sort()
  {
    int numComp = mixMatrix.Ncols(), numVox = IC.Ncols(), 
        numTime = mixMatrix.Nrows(), i,j;

    for(int ctr_i = 1; ctr_i <= numComp; ctr_i++){
      if(IC.Row(ctr_i).Sum()>0){
	flipres(ctr_i); };}
    //    cerr << "HERE2" << endl << endl;


    // re-order wrt standard deviation of IC maps
    message("  sorting IC maps" << endl << endl);  
    Matrix tmpscales, tmpICrow, tmpMIXcol;
    tmpscales = stdev(IC,2);
    ICstats = tmpscales;

    //cerr << "SCLAES2 " << tmpscales << endl;

    double max_val, min_val = tmpscales.Minimum()-1;

    for(int ctr_i = 1; ctr_i <= numComp; ctr_i++){

      max_val = tmpscales.Maximum2(i,j);
      ICstats(ctr_i,1)=max_val;

      //cerr << endl << "scales: " << tmpscales << " ctr_i " << ctr_i << 
      //	" i " << i << " j " << j << " max " << max_val << endl << endl;

  
      tmpICrow = IC.Row(ctr_i);
      tmpMIXcol = mixMatrix.Column(ctr_i);
      
      IC.SubMatrix(ctr_i,ctr_i,1,numVox) = IC.SubMatrix(i,i,1,numVox);
      mixMatrix.SubMatrix(1,numTime,ctr_i,ctr_i) = 
	mixMatrix.SubMatrix(1,numTime,i,i);
  
      IC.SubMatrix(i,i,1,numVox) = tmpICrow.SubMatrix(1,1,1,numVox);
      mixMatrix.SubMatrix(1,numTime,i,i) = tmpMIXcol.SubMatrix(1,numTime,1,1);
  
      tmpscales(i,1)=tmpscales(ctr_i,1);
      tmpscales(ctr_i,1)=min_val;
      }

    //cerr << " ICstats " << ICstats << endl << endl;

    ICstats /= ICstats.Column(1).Sum();
    ICstats *= 100;


    //cerr << " ICstats " << ICstats << endl << endl;
    
    if(EVP.Storage()>0){
      tmpscales = ICstats.Column(1).AsMatrix(ICstats.Nrows(),1) * EVP(1,numComp);
      ICstats |= tmpscales;
    }

    if(DataVN.Storage()>0&&stdDev.Storage()>0){
      //cerr << " ICstats " << ICstats << endl << endl;

      Matrix copeP(tmpscales), copeN(tmpscales);
      Matrix max_ICs(tmpscales), min_ICs(tmpscales);

      for(int ctr_i = 1; ctr_i <= numComp; ctr_i++){
	int i,j;
	max_ICs(ctr_i,1) = IC.Row(ctr_i).Maximum2(i,j);
	//cerr << " ICstats " << ICstats << endl << endl;

	//cerr << endl <<(pinv(mixMatrix)*DataVN.Column(j)) << endl;
	copeP(ctr_i,1) = std::abs((pinv(mixMatrix)*DataVN.Column(j)).Row(ctr_i).AsScalar()*stdDev(1,j)*100*(mixMatrix.Column(ctr_i).Maximum()-mixMatrix.Column(ctr_i).Minimum())/meanR(1,j));

	min_ICs(ctr_i,1) = IC.Row(ctr_i).Minimum2(i,j);
	copeN(ctr_i,1) = -1.0*std::abs((pinv(mixMatrix)*DataVN.Column(j)).Row(ctr_i).AsScalar()*stdDev(1,j)*100*(mixMatrix.Column(ctr_i).Maximum()-mixMatrix.Column(ctr_i).Minimum())/meanR(1,j));

      }
      ICstats |= copeP;
      ICstats |= copeN;
    }
    
    mixFFT=calc_FFT(mixMatrix);
    unmixMatrix = pinv(mixMatrix);

    //if(ICstats.Storage()>0){cout << "ICstats: " << ICstats.Nrows() <<"x" << ICstats.Ncols() << endl;}else{cout << "ICstats empty " <<endl;}
  }

Mark Jenkinson's avatar
Mark Jenkinson committed

  void MelodicData::status(const string &txt)
  {
    cout << "MelodicData Object " << txt << endl;
    if(Data.Storage()>0){cout << "Data: " << Data.Nrows() <<"x" << Data.Ncols() << endl;}else{cout << "Data empty " <<endl;}
    if(pcaE.Storage()>0){cout << "pcaE: " << pcaE.Nrows() <<"x" << pcaE.Ncols() << endl;}else{cout << "pcaE empty " <<endl;}
    if(pcaD.Storage()>0){cout << "pcaD: " << pcaD.Nrows() <<"x" << pcaD.Ncols() << endl;}else{cout << "pcaD empty " <<endl;}
    if(whiteMatrix.Storage()>0){cout << "white: " << whiteMatrix.Nrows() <<"x" << whiteMatrix.Ncols() << endl;}else{cout << "white empty " <<endl;}
    if(dewhiteMatrix.Storage()>0){cout << "dewhite: " << dewhiteMatrix.Nrows() <<"x" << dewhiteMatrix.Ncols() << endl;}else{cout << "dewhite empty " <<endl;}
    if(mixMatrix.Storage()>0){cout << "mix: " << mixMatrix.Nrows() <<"x" << mixMatrix.Ncols() << endl;}else{cout << "mix empty " <<endl;}
    if(unmixMatrix.Storage()>0){cout << "unmix: " << unmixMatrix.Nrows() <<"x" << unmixMatrix.Ncols() << endl;}else{cout << "unmix empty " <<endl;}
    if(IC.Storage()>0){cout << "IC: " << IC.Nrows() <<"x" << IC.Ncols() << endl;}else{cout << "IC empty " <<endl;}
   
  } //void status()

Christian Beckmann's avatar
Christian Beckmann committed

  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, old_ssq;
Christian Beckmann's avatar
Christian Beckmann committed
    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++;
      }
Christian Beckmann's avatar
Christian Beckmann committed
    read_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/sigmasquareds",tmpvolinfo);
    save_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/old_sigmasquareds",tmpvolinfo);
    old_ssq = tmpvol.matrix(Mask);

Christian Beckmann's avatar
Christian Beckmann committed
    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");
	
        ostringstream osc;
        osc  << "mv " << opts.glmcleanup.value() << "/stats/dof " <<  opts.glmcleanup.value() << "/stats/old_dof ";
        system(osc.str().c_str());
Christian Beckmann's avatar
Christian Beckmann committed
	old_dof = old_dof * 0 + tmpmat(1,1);
      }

    // Read in thresholded maps
    Matrix threshmaps;
Christian Beckmann's avatar
Christian Beckmann committed
    int ic_ctr = 1;
Christian Beckmann's avatar
Christian Beckmann committed
    message(" Reading in thresholded IC maps ...");
Christian Beckmann's avatar
Christian Beckmann committed
    //    read_volume4D(tmpvol,logger.appendDir("stats/thresh_zstat1"));
    //    threshmaps = tmpvol.matrix(Mask);
Christian Beckmann's avatar
Christian Beckmann committed
    while(fsl_imageexists(logger.appendDir("stats/thresh_zstat" + num2str(ic_ctr))))
      {
	read_volume4D(tmpvol,logger.appendDir("stats/thresh_zstat" + num2str(ic_ctr)));
Christian Beckmann's avatar
Christian Beckmann committed
	
	Matrix newmap;
	newmap = tmpvol.matrix(Mask);
	Matrix corrcf;
	corrcf = pemaps.t() | newmap.t();
	corrcf = corrcoef(corrcf);
	corrcf = corrcf.SubMatrix(corrcf.Nrows(),corrcf.Nrows(),1,pemaps.Nrows());    
	message("IC map " << ic_ctr << ":  " << corrcf);
	if(opts.glmPEreg.value()==0.0 || opts.glmPEreg.value() > max(abs(corrcf)).AsScalar()){
	  message("        removing IC map " << endl);
	  if(threshmaps.Storage() == 0)
	    threshmaps = newmap;
	  else
	    threshmaps = threshmaps & newmap;
	}
	else
	  message("        not removing IC map " << endl);
Christian Beckmann's avatar
Christian Beckmann committed
	ic_ctr++;
      }
    message(" ... done " << endl); 
Christian Beckmann's avatar
Christian Beckmann committed
    //  outMsize("    threshmaps ",threshmaps);
    //outMsize("    pemaps ",pemaps);
Christian Beckmann's avatar
Christian Beckmann committed
 
    //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(" size of pes and thresholded maps: ",allmaps);
Christian Beckmann's avatar
Christian Beckmann committed
    //outMsize("    orig_data ",orig_data);
Christian Beckmann's avatar
Christian Beckmann committed

    alltcs = ( orig_data * allmaps.t() ) * pinv (allmaps * allmaps.t() ); 
    
Christian Beckmann's avatar
Christian Beckmann committed
    //outMsize("    alltcs",alltcs);
Christian Beckmann's avatar
Christian Beckmann committed
    resi = orig_data - alltcs * allmaps;
    pemaps = pemaps - pemaps * threshmaps.t() * pinv (threshmaps * threshmaps.t() ) * threshmaps;
Christian Beckmann's avatar
Christian Beckmann committed
    //outMsize("  ... new PEs :",pemaps);
Christian Beckmann's avatar
Christian Beckmann committed

    Matrix R;
    R = Identity(orig_data.Nrows()) - alltcs * pinv(alltcs.t() * alltcs) * alltcs.t();
    Matrix sigsq;
    sigsq = sum(SP(resi,resi)) / R.Trace(); 
Christian Beckmann's avatar
Christian Beckmann committed
    //outMsize("  ... new sigmasquareds :",sigsq);
    Matrix new_dof, new_dof2;
    new_dof  = old_dof.matrix(Mask);
    new_dof2 = old_dof.matrix(Mask);

    // Calculate new_dof
Christian Beckmann's avatar
Christian Beckmann committed
    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)--;
Christian Beckmann's avatar
Christian Beckmann committed
    //outMsize("  ... new DOFs :", new_dof);
Christian Beckmann's avatar
Christian Beckmann committed
    message(" ... done " << endl); 
    

    // Calculate new_dof2
    //    for(int j_ctr=1;j_ctr<=threshmaps.Ncols();j_ctr++)
    //  for(int i_ctr=1;i_ctr<=threshmaps.Nrows();i_ctr++)
    new_dof2 = SP(new_dof2,SP(sigsq,pow(old_ssq,-1)));

Christian Beckmann's avatar
Christian Beckmann committed
    //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));
Christian Beckmann's avatar
Christian Beckmann committed
    }
    tmpvol.setmatrix(new_dof,Mask);
    save_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/dof");
   
    tmpvol.setmatrix(new_dof2,Mask);
    save_volume4D(tmpvol,opts.glmcleanup.value() + "/stats/dof2");
   
Christian Beckmann's avatar
Christian Beckmann committed
    message(" ... done " << endl);
    message(endl << " finished GLM cleanup ! " << endl << endl);
  }

Mark Jenkinson's avatar
Mark Jenkinson committed
  Matrix MelodicData::calc_FFT(const Matrix& Mat)
  {
    Matrix res;
    for(int ctr=1; ctr <= Mat.Ncols(); ctr++)
      {
	ColumnVector tmpCol;
	tmpCol=Mat.Column(ctr);
	ColumnVector FtmpCol_real;
	ColumnVector FtmpCol_imag;
	ColumnVector tmpPow;
	if(tmpCol.Nrows()%2 != 0){
	  Matrix empty(1,1); empty=0;
	  tmpCol &= empty;}
	RealFFT(tmpCol,FtmpCol_real,FtmpCol_imag);
	tmpPow = pow(FtmpCol_real,2)+pow(FtmpCol_imag,2);
	tmpPow = tmpPow.Rows(2,tmpPow.Nrows());
	if(opts.logPower.value()) tmpPow = log(tmpPow);
	if(res.Storage()==0){res= tmpPow;}else{res|=tmpPow;}
      }
    return res;
  } //Matrix calc_FFT()

  Matrix MelodicData::smoothColumns(const Matrix &inp)
  {
    Matrix temp(inp);
    int ctr1 = temp.Nrows();
    Matrix temp2(temp);
    temp2=0;
    
    temp = temp.Row(4) & temp.Row(3) & temp.Row(2) & temp & temp.Row(ctr1-1) 
      & temp.Row(ctr1-2) &temp.Row(ctr1-3);
    
    double kern[] ={0.0045 , 0.055, 0.25, 0.4, 0.25, 0.055, 0.0045};
    double fac = 0.9090909;

    //  Matrix FFTinp;
    //FFTinp = calc_FFT(inp);
    //write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_FT"),
    //			 FFTinp);    FFTinp = calc_FFT(inp);
  //write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_Sinp"),
    //		 inp);   
    
    for(int cc=1;cc<=temp2.Ncols();cc++){
      //  double all = FFTinp.Column(cc).Rows(1,30).SumAbsoluteValue() / FFTinp.Column(cc).SumAbsoluteValue();
      // if( all > 0.5){
      for(int cr=1;cr<=temp2.Nrows();cr++){
	temp2(cr,cc) = fac*( kern[0] * temp(cr,cc) + kern[1] * temp(cr+1,cc) + 
			     kern[2] * temp(cr+2,cc) + kern[3] * temp(cr+3,cc) + 
			     kern[4] * temp(cr+4,cc) + kern[5] * temp(cr+5,cc) + 
			     kern[6] * temp(cr+6,cc));
      }//}
      //else{
      //	for(int cr=1;cr<=temp2.Nrows();cr++){
      //	  temp2(cr,cc) = temp(cr+3,cc);
      //	}
      //}
    }
//write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_Sout"),
//		 temp2);   
    return temp2;
  }
}