diff --git a/meldata.cc b/meldata.cc
new file mode 100644
index 0000000000000000000000000000000000000000..01da5935cd6776a05525911fcd4aae8489c07aa0
--- /dev/null
+++ b/meldata.cc
@@ -0,0 +1,500 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    meldata.cc - data handler / container class
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT  */
+
+#include "newimageall.h"
+#include "meloptions.h"
+#include "meldata.h"
+#include "melodic.h"
+#include "log.h"
+#include <time.h>
+
+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);
+      }
+	
+           
+      // clean /tmp
+      char callRMstr[1000];
+      ostrstream osc(callRMstr,1000);
+      osc  << "rm " << string(Mean_fname) <<"*  " << '\0';
+      system(callRMstr);
+         
+      //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());
+      //}
+    }
+    {//switch dimension in case temporal ICA is required
+      // if(opts.temporal.value()){
+      //       if(opts.remove_meanvol.value()){  
+      // 	message(string("Remove mean time course for temporal ICA ... "));
+      // 	meanC=meanR;
+      // 	meanR=mean(Data);
+      // 	Data=remmean(Data,2); 
+      // 	message("done"<<endl); 
+      //       }
+      //       Data = Data.t();
+      //     }
+    }
+    {// remove mean time course
+      meanC=mean(Data,2);
+      Data=remmean(Data,2); 
+    }
+    {// 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;
+	}
+      }
+      
+      stdDevi = pow(stdev(Data - tmpDeWhite*WS),-1);    
+      Data = Data + meanC*ones(1,Data.Ncols());
+    }
+    
+    DataVN = SP(Data,ones(Data.Nrows(),1)*stdDevi);
+    if(opts.varnorm.value()){
+      Data = DataVN;
+      message("done"<<endl);
+    }
+    {//remove row mean
+      if(opts.temporal.value()){
+	Data=remmean(Data,2);
+      }else{
+	message(string("Removing mean time course ... "));
+	meanC=mean(Data,2);
+	Data=remmean(Data,2); 
+	message("done"<<endl);
+      }
+    }
+    
+    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);
+    srand((unsigned int) tmptime/Data.Ncols()*Data.Nrows());
+   
+  } // void setup()
+
+  void MelodicData::save()
+  {   
+
+    //check for temporal ICA
+    if(opts.temporal.value()){
+      Matrix tmpIC = mixMatrix.t();
+      mixMatrix=IC.t();
+      IC=tmpIC;
+    }
+ 
+    message("Writing results to : " << endl);
+
+    //Output IC	
+    if((IC.Storage()>0)&&(opts.output_origIC.value()) ){
+      volume4D<float> tempVol; 
+      tempVol.setmatrix(IC,Mask);
+      //strncpy(tempInfo.header.hist.aux_file,"render3",24);
+      save_volume4D(tempVol,logger.appendDir(opts.outputfname.value() 
+					     + "_origIC"),tempInfo);
+      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;
+      if(opts.temporal.value()){
+	Data=Data.t();
+      }
+    
+      Matrix ICadjust;
+      stdNoisei = pow(stdev(Data - mixMatrix * IC),-1);
+      ICadjust = SP(IC,ones(IC.Nrows(),1)*stdNoisei);
+      
+      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);
+    }
+
+    //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 unmixMatrix
+    if(opts.output_unmix.value() && unmixMatrix.Storage()>0){
+      write_ascii_matrix(opts.outputfname.value() + "_unmix",unmixMatrix);
+      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);
+      write_ascii_matrix(logger.appendDir(opts.outputfname.value() + "_pcaD"),
+			 (Matrix) diag(pcaD));
+      volume4D<float> tempVol;	
+      //volumeinfo tempInfo;
+      //read_volume4D(tempVol,opts.inputfname.value(),tempInfo); 
+
+      Matrix ICadjust = IC;
+      if(opts.temporal.value()){
+	Data=Data.t();
+      }
+    
+      Matrix PCAmaps;
+      PCAmaps = whiteMatrix * Data;
+
+      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);
+      message("  "<<
+	  logger.appendDir(opts.outputfname.value() + "_pcaE") <<endl);
+      message("  "<<
+	  logger.appendDir(opts.outputfname.value() + "_pcaD") <<endl);
+    }
+  } //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
+	string Mask_fname = BET_outputfname+"_mask.hdr";
+
+	// Setup external call to BET:
+
+	char callBETstr[1000];
+	ostrstream osc(callBETstr,1000);
+	osc  << BET_path << " " << Mean_fname << " " 
+	     << BET_outputfname << " " << BET_optarg << " > /dev/null " << '\0';
+	
+        message("  Calling BET: " << callBETstr << endl);
+	system(callBETstr);
+	
+	// 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::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()
+
+  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;
+  }
+}
+
diff --git a/meldata.h b/meldata.h
new file mode 100644
index 0000000000000000000000000000000000000000..8eadddf3d3ecadedfc5ad4216bbda6152631beb7
--- /dev/null
+++ b/meldata.h
@@ -0,0 +1,172 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    meldata.h - data container class
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT */
+
+
+#ifndef __MELODICDATA_h
+#define __MELODICDATA_h
+
+#include "newimageall.h"
+#include "log.h"
+#include "meloptions.h"
+
+using namespace Utilities;
+using namespace NEWIMAGE;
+
+namespace Melodic{
+  
+  class MelodicData
+    {
+    public:
+
+      //constructor
+      MelodicData(MelodicOptions &popts, Log &plogger):  
+	opts(popts),
+	logger(plogger)
+	{		
+	}  
+ 
+      void save();
+
+      inline void save4D(Matrix what, string fname){
+	 volume4D<float> tempVol;
+	 tempVol.setmatrix(what,Mask);
+	 save_volume4D(tempVol,logger.appendDir(fname),tempInfo);
+      }
+      
+      inline void saveascii(Matrix what, string fname){
+	 write_ascii_matrix(logger.appendDir(fname),what);      }
+
+      int  remove_components();
+      void setup();
+      void status(const string &txt);
+
+      inline Matrix& get_pcaE() {return pcaE;}
+      inline void set_pcaE(Matrix& Arg) {pcaE = Arg;}
+
+      inline DiagonalMatrix& get_pcaD() {return pcaD;}
+      inline void set_pcaD(DiagonalMatrix& Arg) {pcaD = Arg;}
+
+      inline Matrix& get_data() {return Data;}
+      inline void set_data(Matrix& Arg) {Data = Arg;}
+
+      inline Matrix& get_IC() {return IC;}
+      inline void set_IC(Matrix& Arg) {IC = Arg;}
+      
+      inline Matrix& get_white() {return whiteMatrix;}
+      inline void set_white(Matrix& Arg) {whiteMatrix = Arg;}
+      
+      inline Matrix& get_dewhite() {return dewhiteMatrix;}
+      inline void set_dewhite(Matrix& Arg) {dewhiteMatrix = Arg;}
+      
+      inline Matrix& get_meanC() {return meanC;}
+      inline Matrix& get_meanR() {return meanR;}
+
+      inline Matrix& get_stdDevi() {return stdDevi;}
+      inline void set_stdDevi(Matrix& Arg) {stdDevi = Arg;}
+  
+      inline Matrix& get_mix() {return mixMatrix;}
+      inline void set_mix(Matrix& Arg) {mixMatrix = Arg;}
+   
+      inline Matrix& get_fmix() {return mixFFT;}
+      inline void set_fmix(Matrix& Arg) {mixFFT = Arg;}
+
+      inline Matrix& get_unmix() {return unmixMatrix;}
+      inline void set_unmix(Matrix& Arg) {unmixMatrix = Arg;}
+
+      inline volume<float>& get_mask() {return Mask;}
+      inline void set_mask(volume<float>& Arg) {Mask = Arg;}
+  
+      inline volume<float>& get_mean() {return Mean;}
+      inline void set_mean(volume<float>& Arg) {Mean = Arg;}
+   
+      inline Matrix& get_Data() {return Data;}
+      inline void set_Data(Matrix& Arg) {Data = Arg;}
+    
+      inline Matrix& get_DataVN() {return DataVN;}
+      inline void set_DataVN(Matrix& Arg) {DataVN = Arg;}
+
+      inline Matrix& get_RXweight() {return RXweight;}
+      inline void set_RXweight(Matrix& Arg) {RXweight = Arg;}
+ 
+      inline Matrix& get_EVP() {return EVP;}
+      inline void set_EVP(Matrix& Arg) {EVP = Arg;}
+      
+      inline Matrix& get_EV() {return EV;}
+      inline void set_EV(Matrix& Arg) {EV = Arg;}
+
+      inline Matrix& get_PPCA() {return PPCA;}
+      inline void set_PPCA(Matrix& Arg) {PPCA = Arg;}
+
+      inline Matrix& get_stdNoisei() {return stdNoisei;}
+      inline void set_stdNoisei(Matrix& Arg) {stdNoisei = Arg;}
+
+      inline int data_dim() {return Data.Nrows();}
+      inline int data_samples() {return Data.Ncols();}
+     
+      inline float get_resels() {return Resels;}
+      inline void set_resels(float& Arg) {Resels = Arg;}
+
+      Matrix smoothColumns(const Matrix &inp);
+
+      inline void flipres(int num){
+	IC.Row(num) = -IC.Row(num);
+	mixMatrix.Column(num) = -mixMatrix.Column(num);
+	mixFFT=calc_FFT(mixMatrix);
+	unmixMatrix = pinv(mixMatrix);
+      }
+
+      
+      inline void varnorm(){
+	Data = SP(Data,ones(Data.Nrows(),1)*stdDevi);
+      }
+
+      volumeinfo tempInfo;
+      
+      Matrix calc_FFT(const Matrix& Mat);
+
+    private:
+      MelodicOptions &opts;     
+      Log &logger;       
+      //      static MelodicData* melodat;
+
+      Matrix pcaE;
+      DiagonalMatrix pcaD;
+      Matrix whiteMatrix;
+      Matrix dewhiteMatrix;
+      Matrix meanC;
+      Matrix meanR;
+      Matrix stdDevi;
+      Matrix RXweight;
+      Matrix mixMatrix;
+      Matrix unmixMatrix;
+      Matrix mixFFT;
+      Matrix IC;
+      Matrix EVP;
+      Matrix EV;
+      Matrix stdNoisei;
+      volume<float> Mask;
+      volume<float> Mean;
+      Matrix Data;
+      Matrix DataVN;
+      Matrix PPCA;
+      
+      float Resels;
+
+      char Mean_fname[1000];
+
+      void create_mask(volume4D<float> &theData, volume<float> &theMask);
+      //      void remove_comp(Matrix& Mat, const int numIC);
+      void create_RXweight();
+         
+    };
+}
+
+#endif
diff --git a/melgmix.h b/melgmix.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b4755e2a5665ca58011550db6b7a325f751927e
--- /dev/null
+++ b/melgmix.h
@@ -0,0 +1,195 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    melgmix.h - class for Gaussian/Gamma Mixture Model
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT */
+
+#ifndef __MELGMIX_h
+#define __MELGMIX_h
+
+#include "newimageall.h"
+#include "log.h"
+#include "melodic.h"
+#include "options.h"
+#include "meloptions.h"
+//#include "melreport.h"
+
+using namespace Utilities;
+using namespace NEWIMAGE;
+
+namespace Melodic{
+  
+  class MelGMix
+    {
+    public:
+
+      //constructor
+     /*  MelGMix(MelodicOptions &popts, Log &plogger):   */
+/* 	opts(popts), */
+/* 	logger(plogger), */
+/* 	mainhtml() */
+/* 	{ */
+/* 	}   */
+ 
+      MelGMix(MelodicOptions &popts, Log &plogger):
+	opts(popts),
+	logger(plogger)
+	{
+	}
+
+      ~MelGMix() { 
+	//mainhtml << endl << "<hr></CENTER></BODY></HTML>" << endl;
+	  }
+
+      void save();
+
+      void setup(const RowVector& dat, volumeinfo inf, const string dirname,
+		 int here, volume<float> themask, 
+		 volume<float> themean, int num_mix = 3, 
+		 float eps = 0.0, bool fixdim = false);
+      
+
+      void gmmfit();
+      void ggmfit();
+
+      inline void fit(string mtype = string("GGM"))
+	{
+	  mmtype = mtype;
+	  if(mmtype==string("GGM")) 
+	    this->ggmfit(); 
+	  else 
+	    this->gmmfit();
+	}
+
+      inline Matrix threshold(string levels)
+	{return this->threshold(data, levels);}
+      inline Matrix threshold(RowVector& levels) 
+	{return this->threshold(data, levels);}
+      Matrix threshold(const RowVector& dat, Matrix& levels);
+      Matrix threshold(const RowVector& dat, string levels);
+
+      void status(const string &txt);
+ 
+      inline RowVector& get_means() {return means;}
+      inline void set_means(RowVector& Arg) {means = Arg;}
+    
+      inline RowVector& get_vars() {return vars;}
+      inline void set_vars(RowVector& Arg) {vars = Arg;}
+      
+      inline RowVector& get_pi() {return props;}
+      inline void set_pi(RowVector& Arg) {props = Arg;}
+      
+      inline RowVector& get_data() {return data;}
+      inline void set_data(RowVector& Arg) {data = Arg;}
+
+      inline RowVector& get_prob() {return probmap;}
+
+      inline float get_eps() {return epsilon;}
+      inline void set_eps(float Arg) {epsilon = Arg;}
+
+      inline Matrix& get_threshmaps() {return threshmaps;}
+      inline void set_threshmaps(Matrix& Arg) {threshmaps = Arg;}
+
+      inline bool isfitted(){return fitted;}
+
+      inline int mixtures(){return nummix;}
+     
+      inline string get_type() { return mmtype;}
+      inline void set_type(string Arg) { mmtype = Arg;}
+      
+      inline string get_prefix() { return prefix;}
+      inline void  set_prefix(string Arg) { prefix = Arg;}
+
+      inline RowVector get_probmap() {return probmap;}
+
+      inline float get_offset() {return offset;}
+      inline void set_offset(float Arg) {offset = Arg;}
+
+      inline void flipres(int num){
+	means = -means;
+	data = -data;
+	threshmaps = -threshmaps;
+	if(mmtype=="GGM"){
+	  float tmp;
+	  tmp= means(2);means(2)= means(3);means(3)=tmp;
+	  tmp=vars(2);vars(2)=vars(3);vars(3)=tmp;
+	  tmp=props(2);props(2)=props(3);props(3)=tmp;
+	}
+      }      
+
+      void create_rep();
+
+      inline void add_infstr(string what){
+	threshinfo.push_back(what);
+      }
+
+      inline string get_infstr(int num){
+	if((threshinfo.size()<(unsigned int)(num-1))||(num<1))
+	  return string("");
+	else
+	  return threshinfo[num-1];
+      }
+
+      inline int size_infstr(){
+      return threshinfo.size();
+      }
+
+      inline void clear_infstr(){
+	threshinfo.clear();
+      }
+
+    private:
+      MelodicOptions &opts;     
+      Log &logger; //global log file
+
+      //Log mainhtml;
+
+      void gmmupdate();
+      float gmmevidence();
+      void gmmreducemm();
+      void add_params(Matrix& mu, Matrix& sig, Matrix& pi, 
+		      float logLH, float MDL, float Evi, bool advance = false);
+      void get_params(int index, Matrix& mu, Matrix& sig, Matrix& pi, 
+		      float logLH, float MDL, float Evi);
+
+      Matrix Params;
+      Matrix threshmaps;
+
+      RowVector means;
+      RowVector vars;
+      RowVector props;
+      RowVector data;
+      RowVector probmap;
+
+      volume<float> Mean;
+      volume<float> Mask;
+
+      float epsilon;
+      float logprobY;
+      float MDL;
+      float Evi;
+      float offset;
+
+      int nummix;
+      int numdata;
+      int cnumber;
+
+      bool fitted;
+      bool fixdim;
+
+      string prefix;
+      string mmtype;
+      string dirname;
+
+      volumeinfo bginfo;
+      vector<string> threshinfo;
+
+    };
+}
+
+#endif
diff --git a/melica.cc b/melica.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1f355fb3dbeb0f91400cb6d3751e474d7a54b3e2
--- /dev/null
+++ b/melica.cc
@@ -0,0 +1,408 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    melica.cc - ICA estimation 
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT  */
+
+#include <stdlib.h>
+#include "newimageall.h"
+#include "log.h"
+#include "meloptions.h"
+#include "meldata.h"
+#include "melodic.h"
+#include "newmatap.h"
+#include "newmatio.h"
+#include "melica.h"
+#include "melpca.h"
+#include "miscprob.h"
+
+using namespace Utilities;
+using namespace NEWIMAGE;
+
+namespace Melodic{
+    
+  void MelodicICA::ica_fastica_symm(const Matrix &Data)
+  {
+    // based on Aapo Hyvärinen's fastica method
+    // see www.cis.hut.fi/projects/ica/fastica/
+    
+    //initialize matrices
+    Matrix redUMM_old;
+    Matrix tmpU;    
+    
+     //srand((unsigned int)timer(NULL));
+    
+    redUMM = melodat.get_white()*
+       unifrnd(melodat.get_white().Ncols(),dim); // got to start somewhere
+    
+    if(opts.guessfname.value().size()>1){
+      message("  Use columns in " << opts.guessfname.value() 
+	      << " as initial values for the mixing matrix " <<endl);
+      Matrix guess ;
+      guess  = melodat.get_white()*read_ascii_matrix(opts.guessfname.value());
+      redUMM.Columns(1,guess.Ncols()) = guess;
+    }
+    
+    symm_orth(redUMM);
+
+    int itt_ctr=1; 
+    double minAbsSin = 1.0;
+    do{ // da loop!!!
+
+      redUMM_old = redUMM;
+      
+      //calculate IC estimates
+      tmpU = Data.t() * redUMM;
+      
+      //update redUMM depending on nonlinearity
+      if(opts.nonlinearity.value()=="pow4"){
+	redUMM = (Data * pow(tmpU,3.0)) / samples - 3 * redUMM;
+	}
+      if(opts.nonlinearity.value()=="pow3"){
+        tmpU /= opts.nlconst1.value();
+	redUMM = 3 * (Data * pow(tmpU,2.0)) / samples  - 
+	  (SP(ones(dim,1)*sum(tmpU,1),redUMM))/ samples;
+      }
+      if(opts.nonlinearity.value()=="tanh"){
+	Matrix hyptanh;
+	hyptanh = tanh(opts.nlconst1.value()*tmpU);
+	redUMM = (Data * hyptanh - opts.nlconst1.value()*SP(ones(dim,1)*
+							    sum(1-pow(hyptanh,2),1),redUMM))/samples;
+      }
+      if(opts.nonlinearity.value()=="gauss"){
+	Matrix tmpUsq;
+	Matrix tmpU2;
+	Matrix gauss;
+	Matrix dgauss;
+	tmpUsq = pow(tmpU,2);
+	tmpU2 = exp(-(opts.nlconst2.value()/2) * tmpUsq);
+	gauss = SP(tmpU,tmpU2);
+	dgauss = SP(1-opts.nlconst2.value()*tmpUsq,tmpU2);
+	redUMM = (Data * gauss - SP(ones(dim,1)*
+				     sum(dgauss,1),redUMM))/samples;
+      }
+      
+      // orthogonalize the unmixing-matrix 
+      symm_orth(redUMM);
+
+      //termination condition : angle between old and new < epsilon
+      minAbsSin = 1 - diag(abs(redUMM.t()*redUMM_old)).Minimum();
+      message("  Step no. " << itt_ctr << " change : " << minAbsSin << endl);
+      if(abs(minAbsSin) < opts.epsilon.value()){ break;}
+      
+      itt_ctr++;
+    } while(itt_ctr < opts.maxNumItt.value());
+    
+    if(itt_ctr>=opts.maxNumItt.value()){
+      cerr << "  No convergence after " << itt_ctr <<" steps "<<endl;
+    } else {
+      message("  Convergence after " << itt_ctr <<" steps " << endl << endl);
+      no_convergence = false;
+      {Matrix temp(melodat.get_dewhite() * redUMM);
+       melodat.set_mix(temp);}
+      {Matrix temp(redUMM.t()*melodat.get_white());
+      melodat.set_unmix(temp);}
+    } 
+  }
+  
+
+   void MelodicICA::ica_fastica_defl(const Matrix &Data)
+   {
+     if(!opts.explicitnums || opts.numICs.value()>dim){
+      opts.numICs.set_T(dim); 
+      message("  Using numICs:" << opts.numICs.value() << endl);
+     }
+     
+     //redUMM = zeros(dim); // got to start somewhere
+     redUMM = melodat.get_white()*
+       unifrnd(melodat.get_white().Ncols(),opts.numICs.value());
+     int guesses=0;
+     if(opts.guessfname.value().size()>1){
+       message("  Use columns in " << opts.guessfname.value() << " as initial values for the mixing matrix " <<endl);
+       Matrix guess;
+       guess  = melodat.get_white()*read_ascii_matrix(opts.guessfname.value());
+       guesses = guess.Ncols();
+       redUMM.Columns(1,guesses) = guess;
+     }
+
+     int ctrIC = 1;
+     int numRestart = 0;
+     
+     while(ctrIC<=opts.numICs.value()){
+       
+       message("  Extracting IC " << ctrIC << "  ... ");
+       ColumnVector w;
+       ColumnVector w_old;   
+       ColumnVector tmpU;
+       if(ctrIC <= guesses){
+	 w = redUMM.Column(ctrIC);}
+       else{
+	 w = unifrnd(dim,1);}
+       
+       w = w - redUMM * redUMM.t() * w;
+       w = w / norm2(w);  
+       int itt_ctr = 1; 
+
+       do{
+	 w_old = w;
+ 
+	 tmpU = Data.t() * w;
+	 
+	if(opts.nonlinearity.value()=="pow4"){
+	  w =  (Data * pow(tmpU,3.0)) / samples - 3 * w;
+	}
+	if(opts.nonlinearity.value()=="tanh"){
+	  ColumnVector hyptanh;
+          hyptanh = tanh(opts.nlconst1.value()*tmpU);
+ 	  w = (Data * hyptanh - opts.nlconst1.value()*SP(ones(dim,1)*
+                  sum(1-pow(hyptanh,2),1),w))/samples;
+	} 
+	if(opts.nonlinearity.value()=="pow3"){
+	  tmpU /= opts.nlconst1.value();
+ 	  w = 3*(Data * pow(tmpU,2.0)) / samples - 2*(SP(ones(dim,1)*
+                  sum(tmpU,1),w))/samples;
+	} 
+	if(opts.nonlinearity.value()=="gauss"){
+	  ColumnVector tmpUsq;
+	  ColumnVector tmpU2;
+	  ColumnVector gauss;
+	  ColumnVector dgauss;
+	  tmpUsq = pow(tmpU,2);
+	  tmpU2 = exp(-(opts.nlconst2.value()/2) * tmpUsq);
+	  gauss = SP(tmpU,tmpU2);
+	  dgauss = SP(1-opts.nlconst2.value()*tmpUsq,tmpU2);
+          w = (Data * gauss - SP(ones(dim,1)*
+				 sum(dgauss,1),w))/samples;
+	}
+ 
+	// orthogonalize w
+	w = w - redUMM * redUMM.t() * w;
+	w = w / norm2(w);  
+
+	//termination condition : angle between old and new < epsilon
+	if(norm2(w-w_old) < opts.epsilon.value() || 
+	   norm2(w+w_old) < opts.epsilon.value()){break;}
+        //cout << norm2(w-w_old) << "   " << norm2(w+w_old) << endl;
+	itt_ctr++;
+      } while(itt_ctr <= opts.maxNumItt.value());
+
+      if(itt_ctr<opts.maxNumItt.value()){
+	redUMM.Column(ctrIC) = w;
+        message(" estimated using " << itt_ctr << " iterations " << endl);
+        ctrIC++; 
+        numRestart = 0;
+      } 
+      else{
+        if(numRestart > opts.maxRestart.value()){
+	  message(endl << "  Estimation failed after " 
+		  << numRestart << " attempts " 
+		  << " giving up " << endl);
+	  break;
+	}
+	else{
+          numRestart++;
+	  message(endl <<"  Estimation failed - restart " 
+		  << numRestart << endl);
+	}
+      }
+     }
+     if(numRestart < opts.maxRestart.value()){
+       no_convergence = false;
+       {Matrix temp(melodat.get_dewhite() * redUMM);
+       melodat.set_mix(temp);}
+       {Matrix temp(redUMM.t()*melodat.get_white());
+       melodat.set_unmix(temp);}
+     }
+   }
+
+
+  void MelodicICA::ica_maxent(const Matrix &Data)
+  {
+    cerr << "  Not fully implemented yet " << endl;
+    //     cout << "maxent" <<endl;
+  }
+
+
+  void MelodicICA::ica_jade(const Matrix &Data)
+  { 
+    int dim_sym = (int) (dim*(dim+1))/2;  
+    int num_CM = dim_sym;
+    Matrix CM;
+    Matrix R; R = Identity(dim);
+    Matrix Qij; Qij = zeros(dim);
+    Matrix Xim;
+    Matrix Xjm;
+    Matrix scale; scale = ones(dim,1)/samples;
+
+    for (int im =1; im <= dim; im++){
+      Xim = Data.Row(im);
+write_ascii_matrix("Xim",Data.Row(1));
+      //Qij = SP((scale * pow(Xim,2)),Data) * Data.t();//- R - 2*R.Column(im)*R.Column(im).t();
+      Qij = (pow(Xim,2)) * Data.t();//- R - 2*R.Column(im)*R.Column(im).t();
+      if(im==1){CM = Qij; write_ascii_matrix("CM",CM);exit(2);}else{CM |= Qij;}
+      for (int jm = 1; jm < im; jm++){
+	Xjm = Data.Row(jm);
+	Qij = (SP((scale * SP(Xim,Xjm)),Data) * Data.t() - R.Column(im)*R.Column(jm).t() 
+	       - R.Column(jm)*R.Column(im).t());
+	Qij *= sqrt(2);
+	CM  |= Qij;
+      }
+    }
+
+    write_ascii_matrix("CM",CM);
+
+    Matrix redUMM; redUMM = Identity(dim);
+  
+    bool exitloop = false;
+    int ctr_itt = 0;
+    int ctr_updates = 0;
+    Matrix Givens; Givens = zeros(2,num_CM);
+    Matrix Givens_ip; Givens_ip = zeros(2);
+    Matrix Givens_ro; Givens_ro = zeros(2);
+    double det_on, det_off;
+    double cos_theta, sin_theta, theta;
+
+    while(!exitloop && ctr_itt <= opts.maxNumItt.value()){
+      ctr_itt++;
+      cout << "loop" <<endl;
+      for(int ctr_p = 1; ctr_p < dim; ctr_p++){
+	for(int ctr_q = ctr_p+1; ctr_q <= dim; ctr_q++){
+
+	  for(int ctr_i = 0; ctr_i < num_CM; ctr_i++){
+	    int Ip = ctr_p + ctr_i * dim;
+	    int Iq = ctr_q + ctr_i * dim;
+	    Givens(1,ctr_i + 1) = CM(ctr_p,Ip) - CM(ctr_q,Iq);
+	    Givens(2,ctr_i + 1) = CM(ctr_p,Iq) - CM(ctr_q,Ip);
+	  }
+	  
+	  Givens_ip = Givens * Givens.t();
+	  det_on = Givens_ip(1,1) - Givens_ip(2,2);
+	  det_off = Givens_ip(1,2) + Givens_ip(2,1);
+	  theta = 0.5 * atan2(det_off, det_on + sqrt(det_on*det_on + det_off*det_off));
+
+	  cout << theta << endl;
+
+	  if(abs(theta) > opts.epsilon.value()){
+	    ctr_updates++;
+	    message("  Step No. "<< ctr_itt << " change : " << theta << endl);
+
+	    //create Givens rotation matrix
+	    cos_theta = cos(theta);
+	    sin_theta = sin(theta);
+	    Givens_ro(1,1) = cos_theta;
+	    Givens_ro(1,2) = -sin_theta;
+	    Givens_ro(2,1) = sin_theta;
+	    Givens_ro(2,2) = cos_theta;
+
+	    //update 2 entries of redUMM
+	    {Matrix tmp_redUMM;
+	    tmp_redUMM = redUMM.Column(ctr_p);
+	    tmp_redUMM |= redUMM.Column(ctr_q);
+	    tmp_redUMM *= Givens_ro;
+	    redUMM.Column(ctr_p) = tmp_redUMM.Column(1);
+	    redUMM.Column(ctr_q) = tmp_redUMM.Column(2);}
+
+	    //update Cumulant matrix
+	    {Matrix tmp_CM;
+	    tmp_CM = CM.Row(ctr_p);
+	    tmp_CM &= CM.Row(ctr_q);
+	    tmp_CM = Givens_ro.t() * tmp_CM;
+	    CM.Row(ctr_p) = tmp_CM.Row(1);
+	    CM.Row(ctr_q) = tmp_CM.Row(2);}
+
+	    //update Cumulant matrices
+	    for(int ctr_i = 0; ctr_i < num_CM; ctr_i++){
+	      int Ip = ctr_p + ctr_i * dim;
+	      int Iq = ctr_q + ctr_i * dim;
+	      CM.Column(Ip) = cos_theta*CM.Column(Ip)+sin_theta*CM.Column(Iq);
+	      CM.Column(Iq) = cos_theta*CM.Column(Iq)-sin_theta*CM.Column(Ip);
+	    }
+	  }
+	  else{
+	    exitloop = true;
+	  }
+	}
+      }
+    }//while loop
+    if(ctr_itt > opts.maxNumItt.value()){
+       cerr << "  No convergence after " << ctr_itt <<" steps "<<endl;
+     } else {
+       message("  Convergence after " << ctr_itt <<" steps " << endl << endl);
+       no_convergence = false;
+       {Matrix temp(melodat.get_dewhite() * redUMM);
+       melodat.set_mix(temp);}
+       {Matrix temp(redUMM.t()*melodat.get_white());
+       melodat.set_unmix(temp);
+       }
+     }
+  }
+
+  Matrix MelodicICA::sign(const Matrix &Inp)
+  {
+    Matrix Res = Inp;
+    Res = 1;
+    for(int ctr_i = 1; ctr_i <= Inp.Ncols(); ctr_i++){
+      for(int ctr_j = 1; ctr_j <= Inp.Nrows(); ctr_j++){
+	if(Inp(ctr_j,ctr_i)<0){Res(ctr_j,ctr_i)=-1;}
+      }
+    } 
+    return Res;
+  }
+
+  void MelodicICA::sort()
+  {
+    int numComp = melodat.get_mix().Ncols();
+
+    Matrix tmpIC = melodat.get_IC();
+    Matrix tmpA  = melodat.get_mix();
+
+    for(int ctr_i = 1; ctr_i <= numComp; ctr_i++){
+      if(tmpIC.Row(ctr_i).Sum()>0){
+	tmpIC.Row(ctr_i) = -tmpIC.Row(ctr_i);
+	tmpA.Column(ctr_i) = -tmpA.Column(ctr_i);
+      };
+
+    }
+    melodat.set_mix(tmpA);
+    melodat.set_IC(tmpIC);
+    Matrix tmpW = pinv(tmpA);
+    melodat.set_unmix(tmpW);
+  }
+
+  void MelodicICA::perf_ica(const Matrix &Data)
+  { 
+    message("Starting ICA estimation using " << opts.approach.value() 
+	    << endl << endl);
+    dim = Data.Nrows();
+    samples = Data.Ncols();
+    
+    no_convergence = true;
+    //switch to the chosen method
+    
+    //      cout << endl << "Dim = " << dim << endl << "Samples = " << samples << endl;
+    if(opts.approach.value()==string("symm")){
+      ica_fastica_symm(Data);}
+    if(opts.approach.value()==string("defl")){
+      ica_fastica_defl(Data);}
+    if(opts.approach.value()==string("jade")){
+      ica_jade(Data);}
+    if(opts.approach.value()==string("maxent")){
+      ica_maxent(Data);}
+    
+    if(!no_convergence){//calculate the IC
+      Matrix temp(melodat.get_unmix()*melodat.get_Data());
+      //  Add the mean time course again  
+      temp += melodat.get_unmix()*melodat.get_meanC()*ones(1,temp.Ncols());
+
+      melodat.set_IC(temp);
+      sort();
+    }
+  }
+}
+
+
diff --git a/melica.h b/melica.h
new file mode 100644
index 0000000000000000000000000000000000000000..8cbce7669968416c2e9afb195fe05e510264feba
--- /dev/null
+++ b/melica.h
@@ -0,0 +1,65 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    melica.h - ICA estimation
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT */
+
+#ifndef __MELODICICA_h
+#define __MELODICICA_h
+#include "newimageall.h"
+#include "log.h"
+#include "melpca.h"
+#include "meloptions.h"
+#include "meldata.h"
+#include "melodic.h"
+#include "newmatap.h"
+#include "newmatio.h"
+#include "melreport.h"
+
+using namespace Utilities;
+using namespace NEWIMAGE;
+
+namespace Melodic{
+  
+  class MelodicICA
+    {
+    public:
+      MelodicICA(MelodicData &pmelodat, MelodicOptions &popts, Log &plogger, MelodicReport &preport):  
+	melodat(pmelodat),
+	opts(popts),
+	logger(plogger),
+	report(preport)
+	{		
+	} 
+      
+      void perf_ica(const Matrix &Data);
+      
+      bool no_convergence;
+
+    private:
+      MelodicData &melodat;
+      MelodicOptions &opts;
+      Log &logger;
+      MelodicReport &report;
+
+      int dim;
+      int samples; 
+      Matrix redUMM;
+
+      void ica_fastica_symm(const Matrix &Data);
+      void ica_fastica_defl(const Matrix &Data);
+      void ica_maxent(const Matrix &Data);
+      void ica_jade(const Matrix &Data);
+      Matrix randm(const int dim1, const int dim2);
+      void sort();
+      Matrix sign(const Matrix &Inp);
+
+    };   
+}
+
+#endif
diff --git a/melodic.cc b/melodic.cc
new file mode 100644
index 0000000000000000000000000000000000000000..13e6a1a3d0376b0aa31a80a9badd25565a9c2e62
--- /dev/null
+++ b/melodic.cc
@@ -0,0 +1,426 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    melodic.cc - main program file
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT  */
+
+#include <iostream>
+#include "newmatap.h"
+#include "newmatio.h"
+#include "newimageall.h"
+#include "miscmaths.h"
+#include "miscprob.h"
+#include <string>
+#include <math.h>
+#include "options.h"
+#include "log.h"
+#include "meloptions.h"
+#include "meldata.h"
+#include "melpca.h"
+#include "melica.h"
+#include "melodic.h"
+#include "melreport.h"
+#include "melgmix.h"
+
+using namespace Utilities;
+using namespace NEWMAT;
+using namespace NEWIMAGE;
+using namespace Melodic;
+using namespace MISCPLOT;
+
+string myfloat2str(float f, int width, int prec, bool scientif)
+  {
+    ostrstream os;
+    int redw = int(std::abs(std::log10(std::abs(f))))+1;
+    if(width>0)
+      os.width(width);
+    if(scientif)
+      os.setf(ios::scientific);
+    os.precision(redw+std::abs(prec));
+    os.setf(ios::internal, ios::adjustfield);
+    os << f << '\0';
+    return os.str();
+  }
+
+Matrix mmall(Log& logger, MelodicOptions& opts,
+	     MelodicData& melodat, MelodicReport& report, Matrix& probs);
+void repall(Log& logger, MelodicOptions& opts, MelodicData& melodat, 
+	    MelodicReport& report, Matrix mmres, Matrix probs);
+void mmonly(Log& logger, MelodicOptions& opts,
+	    MelodicData& melodat, MelodicReport& report);
+
+int main(int argc, char *argv[])
+{
+
+  try{
+    // Setup logging:
+    Log& logger  =   LogSingleton::getInstance();
+ 
+    // parse command line - will output arguments to logfile
+    MelodicOptions& opts = MelodicOptions::getInstance();
+    opts.parse_command_line(argc, argv, logger, Melodic::version); 
+
+    //set up data object
+    MelodicData melodat(opts,logger);
+      
+    MelodicReport report(melodat,opts,logger);
+   
+    if (opts.filtermode || opts.filtermix.value().length()>0){
+      if(opts.filtermode){ // just filter out some noise from a previous run
+	melodat.setup();
+	melodat.remove_components();
+      }
+      else
+	mmonly(logger,opts,melodat,report);
+    } 
+    else
+    {  // standard PICA now
+      int retry = 0;
+      bool no_conv;
+      bool leaveloop = false;
+
+      melodat.setup();
+
+      do{
+	//do PCA pre-processing
+	MelodicPCA pcaobj(melodat,opts,logger,report);
+	pcaobj.perf_pca(melodat.get_DataVN());
+	pcaobj.perf_white(melodat.get_Data());
+
+	//do ICA
+	MelodicICA icaobj(melodat,opts,logger,report);
+	icaobj.perf_ica(melodat.get_white()*melodat.get_Data());
+    
+	no_conv = icaobj.no_convergence;
+
+	opts.maxNumItt.set_T(500);
+	if((opts.approach.value()=="symm")&&(retry > std::min(opts.retrystep,3))){
+	  if(no_conv){
+	    retry++;
+	    opts.approach.set_T("defl");
+	    message(endl << "Restarting MELODIC using deflation approach" 
+		    << endl << endl);
+	  }
+	  else{
+	    leaveloop = true;
+	  }
+	}
+	else{
+	  if(no_conv){
+	    retry++;
+	    if(opts.pca_dim.value()-retry*opts.retrystep > 
+	       0.1*melodat.data_dim()){
+	      opts.pca_dim.set_T(opts.pca_dim.value()-retry*opts.retrystep);
+	    }
+	    else{
+	      if(opts.pca_dim.value()-retry*opts.retrystep <  melodat.data_dim()){
+		opts.pca_dim.set_T(opts.pca_dim.value()+retry*opts.retrystep);
+	      }else{
+		leaveloop = true; //stupid, but break does not compile 
+		                  //on all platforms
+	      }
+	    }
+	    if(!leaveloop){
+	      message(endl << "Restarting MELODIC using -d " 
+		      << opts.pca_dim.value() 
+		      << endl << endl);
+	    }
+	  }
+	}
+      } while (no_conv && retry<opts.maxRestart.value() && !leaveloop);	
+     
+      if(!no_conv){
+	//first save raw IC results
+	melodat.save();
+
+	Matrix pmaps;//(melodat.get_IC());
+	Matrix mmres;
+
+	if(opts.perf_mm.value())
+	  mmres = mmall(logger,opts,melodat,report,pmaps);
+	else{
+	  if( bool(opts.genreport.value()) ){
+	    message(endl 
+		    << "Creating web report in " << report.getDir() 
+		    << " " << endl);
+	    for(int ctr=1; ctr<= melodat.get_IC().Nrows(); ctr++){
+	      string prefix = "IC_"+num2str(ctr);
+	      message("  " << ctr);
+	      report.IC_simplerep(prefix,ctr,melodat.get_IC().Nrows());
+	    }
+
+	    
+	    
+	    message(endl << endl <<
+		    " To view the output report point your web browser at " <<
+		    report.getDir() + "/00index.html" << endl<< endl); 
+	  }
+	}		 
+
+	if( bool(opts.genreport.value()) ){
+	  report.analysistxt();
+	  report.PPCA_rep();
+	}
+	//cerr << mmres.Nrows() << " x " << mmres.Ncols() << endl;
+
+	//  if(opts.genreport.value())
+	//  repall(logger,opts,melodat,report,mmres,pmaps,threshmaps);
+
+	message("finished!" << endl << endl);
+      } else { 
+	message(endl <<"No convergence -- giving up " << endl <<
+		"please contact fsl@fmrib.ox.ac.uk " << endl);
+      }	     
+    }
+  }
+  catch(Exception e) 
+    {
+      cerr << endl << e.what() << endl;
+    }
+  catch(X_OptionError& e) 
+    {
+      cerr << endl << e.what() << endl;
+    }
+
+  return 0;
+}
+
+void mmonly(Log& logger, MelodicOptions& opts,
+	   MelodicData& melodat, MelodicReport& report){
+
+  Matrix ICs;
+  Matrix mixMatrix;
+  Matrix fmixMatrix;
+  volumeinfo ICvolInfo;
+  volume<float> Mask;
+  volume<float> Mean;
+  
+  {
+    volume4D<float> RawData;
+    message("Reading data file " << opts.inputfname.value() << "  ... ");
+    read_volume4D(RawData,opts.inputfname.value(),ICvolInfo);
+    message(" done" << endl);
+    Mean = meanvol(RawData);
+  }
+
+  {
+    volume4D<float> RawIC;
+    message("Reading components " << opts.ICsfname.value() << "  ... ");
+    read_volume4D(RawIC,opts.ICsfname.value());
+    message(" done" << endl);
+
+    message("Creating mask   ... ");
+    Mask = binarise(RawIC[0],float(RawIC[0].min()),float(RawIC[0].max()));
+
+    ICs = RawIC.matrix(Mask);
+    if(ICs.Nrows()>1){
+      Matrix DStDev=stdev(ICs);
+      
+      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);  
+      ICs = RawIC.matrix(Mask);
+    }
+    else{
+      Mask = binarise(RawIC[0],float(0.001),float(RawIC[0].max())) 
+	+ binarise(RawIC[0],float(RawIC[0].min()),float(-0.001));
+      ICs = RawIC.matrix(Mask);
+    }
+
+    //cerr << "ICs : " << ICs.Ncols() << ICs.Nrows() << endl;
+    message(" done" << endl);
+  }
+
+  message("Reading mixing matrix " << opts.filtermix.value());
+  mixMatrix = read_ascii_matrix(opts.filtermix.value());
+  if (mixMatrix.Storage()<=0) {
+    cerr <<" Please specify the mixing matrix correctly" << endl;
+    exit(2);
+  }
+  message(" done" << endl);
+
+  melodat.tempInfo = ICvolInfo;
+  melodat.set_mask(Mask);
+  melodat.set_mean(Mean);
+  melodat.set_IC(ICs);
+  melodat.set_mix(mixMatrix);
+  fmixMatrix = melodat.calc_FFT(mixMatrix);
+  melodat.set_fmix(fmixMatrix);
+  fmixMatrix = pinv(mixMatrix);
+  melodat.set_unmix(fmixMatrix);
+
+  //  write_ascii_matrix("ICs",ICs);
+  
+  Matrix mmres;
+  Matrix pmaps;//(ICs);
+  if(opts.perf_mm.value())
+    mmres = mmall(logger,opts,melodat,report,pmaps);
+}
+
+void repall(Log& logger, MelodicOptions& opts, MelodicData& melodat, 
+	    MelodicReport& report, Matrix& mmpars, Matrix& probs)
+{
+  if( bool(opts.genreport.value()) ){
+
+    message(endl 
+	    << "Creating report in " << report.getDir() 
+	    << endl);
+
+    for(int ctr=1; ctr<=probs.Nrows(); ctr++){
+      message("  " << ctr);
+      MelGMix mixmod(opts, logger);
+      
+      //load MelGMix
+      
+      //report.IC_rep(mixmod,ctr,melodat.get_IC().Nrows());
+  
+    }  
+  }
+}
+
+Matrix mmall(Log& logger, MelodicOptions& opts,
+	   MelodicData& melodat, MelodicReport& report, Matrix& pmaps)
+{
+  
+  Matrix mmpars(5*melodat.get_IC().Nrows(),5);
+  mmpars = 0;
+  //Matrix pmaps(melodat.get_IC());
+  
+  Log stats;
+  
+  if(opts.output_MMstats.value()){  
+    stats.makeDir(logger.appendDir("stats"),"stats.log");
+  }
+
+  message(endl 
+	  << "Running Mixture Modelling on Z-transformed IC maps ..." 
+	  << endl);
+
+  for(int ctr=1; ctr <= melodat.get_IC().Nrows(); ctr++){
+    MelGMix mixmod(opts, logger);
+    
+    message("  IC map " << ctr << " ... "<< endl;);
+    
+    Matrix ICmap;
+
+    if(melodat.get_stdNoisei().Storage()>0)
+      ICmap = SP(melodat.get_IC().Row(ctr),melodat.get_stdNoisei());
+    else
+      ICmap = melodat.get_IC().Row(ctr);
+
+    string wherelog;
+    if(opts.genreport.value())
+      wherelog = report.getDir();
+    else
+      wherelog = logger.getDir();
+
+    mixmod.setup( ICmap, melodat.tempInfo,
+		  wherelog,ctr,
+		  melodat.get_mask(), 
+		  melodat.get_mean(),3);
+    mixmod.fit("GGM");
+
+    if(opts.output_MMstats.value()){
+      melodat.save4D(mixmod.get_probmap(),
+		    string("stats/probmap_")+num2str(ctr));
+    }
+    // save probability map
+    //if((mixmod.get_probmap().Storage()>0)&&
+    //   (mixmod.get_probmap().Ncols() == pmaps.Ncols()))
+    // pmaps.Row(ctr) = mixmod.get_probmap();
+    //else
+    //  pmaps.Row(ctr) = zeros(1,pmaps.Ncols());
+
+    message("   thresholding ... "<< endl);
+    mixmod.threshold(opts.mmthresh.value());  
+
+    //re-orient the data  
+    
+    //message("   done " << endl);
+    Matrix tmp;
+    tmp=(mixmod.get_threshmaps().Row(1));
+    float posint = SP(tmp,gt(tmp,zeros(1,tmp.Ncols()))).Sum();
+    float negint = -SP(tmp,lt(tmp,zeros(1,tmp.Ncols()))).Sum();
+   
+    //cerr << posint << "  " << negint << endl;
+    
+    if((posint<0.01)&&(negint<0.01)){
+      mixmod.clear_infstr();
+      //cerr << "after infstr"<<endl;
+      mixmod.threshold("0.05n "+opts.mmthresh.value());
+      //cerr << " back again" << endl;
+      posint = SP(tmp,gt(tmp,zeros(1,tmp.Ncols()))).Sum();
+      negint = -SP(tmp,lt(tmp,zeros(1,tmp.Ncols()))).Sum();
+    }
+    //cerr << posint << "  " << negint << endl;
+    if(negint>posint){//flip map
+      melodat.flipres(ctr);
+      mixmod.flipres(ctr);
+    }
+
+    //save mixture model stats 
+    if(opts.output_MMstats.value()){
+      stats << " IC " << num2str(ctr) << " " << mixmod.get_type() << endl
+	    << " Means :  " << mixmod.get_means() << endl
+	    << " Vars. :  " << mixmod.get_vars()  << endl
+	    << " Prop. :  " << mixmod.get_pi()    << endl << endl;
+      //  << " Offs. :  " << mixmod.get_offset() << endl << endl;
+      //cerr << mixmod.get_threshmaps().Nrows() << " " << mixmod.get_threshmaps().Ncols()<< endl;
+      melodat.save4D(mixmod.get_threshmaps(),
+		     string("stats/thresh_zstat")+num2str(ctr));
+    }
+
+    //save mmpars
+    // mmpars((ctr-1)*5+1,1) = ctr;
+//     if(mixmod.get_type()=="GGM")
+//       mmpars((ctr-1)*5+1,2) = 1.0;
+//     else
+//       mmpars((ctr-1)*5+1,2) = 0.0;
+//     mmpars((ctr-1)*5+1,2) = mixmod.get_means().Ncols();
+//     tmp =  mixmod.get_means();
+//     for(int ctr2=1;ctr2<=mixmod.get_means().Ncols();ctr2++)
+//       mmpars((ctr-1)*5+2,ctr2) = tmp(1,ctr2);
+//     tmp =  mixmod.get_vars();
+//     for(int ctr2=1;ctr2<=mixmod.get_vars().Ncols();ctr2++)
+//       mmpars((ctr-1)*5+3,ctr2) = tmp(1,ctr2);
+//     tmp =  mixmod.get_pi(); 
+//     for(int ctr2=1;ctr2<=mixmod.get_pi().Ncols();ctr2++)
+//       mmpars((ctr-1)*5+4,ctr2) = tmp(1,ctr2);
+//     mmpars((ctr-1)*5+5,1) = mixmod.get_offset();
+
+ 
+
+    if( bool(opts.genreport.value()) ){
+      message("   creating report page ... ");
+      report.IC_rep(mixmod,ctr,melodat.get_IC().Nrows());	    
+      message("   done" << endl);
+    }
+  }
+  if( bool(opts.genreport.value()) ){
+    message(endl << endl << 
+	    " To view the output report point your web browser at " <<
+	    report.getDir() + "/00index.html" << endl << endl); 
+  }
+  if(!opts.filtermode&&opts.filtermix.value().length()==0){
+    //now safe new data
+    bool what = opts.verbose.value();
+    opts.verbose.set_T(false);
+    melodat.save();
+    opts.verbose.set_T(what);
+  }
+  return mmpars;
+}
diff --git a/melodic.h b/melodic.h
new file mode 100644
index 0000000000000000000000000000000000000000..c18372642341ae7e5d0142c629b2c1d5672ceb9d
--- /dev/null
+++ b/melodic.h
@@ -0,0 +1,34 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+                 independent components
+    
+    melodic.h - main program header
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT */
+
+#ifndef __MELODIC_h
+#define __MELODIC_h
+
+#include<strstream>
+
+// a simple message macro that takes care of cout and log
+#define message(msg) { \
+  MelodicOptions& opt = MelodicOptions::getInstance(); \
+  if(opt.verbose.value()) \
+    { \
+      cout << msg; \
+    } \
+  Log& logger  =   LogSingleton::getInstance(); \
+  logger.str() << msg; \
+}
+
+namespace Melodic{
+
+const string version = "2.0";  
+
+}
+
+#endif
diff --git a/meloptions.cc b/meloptions.cc
new file mode 100644
index 0000000000000000000000000000000000000000..96e29c5ec07a37496225f0cdce54cb08446ef713
--- /dev/null
+++ b/meloptions.cc
@@ -0,0 +1,247 @@
+
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    meloptions.cc - class for command line options
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+     
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT  */
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdio.h>
+#include "log.h"
+#include "meloptions.h"
+#include "newimageall.h"
+
+using namespace Utilities;
+using namespace NEWIMAGE;
+
+namespace Melodic {
+
+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");
+
+  // work out the path to the $FSLDIR/bin directory
+  if(getenv("FSLDIR")!=0){
+    binpath = (string) getenv("FSLDIR") + "/bin/";
+  }
+  else{
+    binpath = argv[0];
+    binpath = binpath.substr(0,binpath.length()-7);
+  }
+
+  // parse once to establish log directory name
+  for(int a = options.parse_command_line(argc, argv); a < argc; a++);
+
+  // act on simple command line arguments
+  if(help.value())
+    {
+      print_usage(argc, argv);
+      exit(0);
+    } 
+  if(vers.value())
+    {
+      print_version();
+      cout << endl;
+      exit(0);
+    } 
+  if(copyright.value())
+    {
+      print_copyright();
+      exit(0);
+    } 
+  if(! options.check_compulsory_arguments())
+    {
+      print_version();
+      cout << endl;
+      cout << "Usage: melodic <options> -i <filename>" << endl <<
+	"Please specify input file name correctly or try melodic --help" 
+	   << endl << endl;
+      exit(2);
+    }     
+
+  // check for invalid values
+  if (inputfname.value().size()<1) {
+    cerr << "ERROR:: Input volume not found\n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (approach.value() != "symm" && approach.value() != "defl"  && 
+      approach.value() != "jade" && approach.value() != "maxent"){
+    cerr << "ERROR:: unknown approach \n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (nonlinearity.value() != "pow3" && nonlinearity.value() != "pow4" && nonlinearity.value() != "tanh" 
+      && nonlinearity.value() != "gauss" ){
+    cerr << "ERROR:: unknown nonlinearity \n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (maxNumItt.value() < 1){
+    cerr << "ERROR:: maxItt too small \n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (epsilon.value() < 0.000000001){
+    cerr << "ERROR:: epsilon too small  \n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (epsilon.value() >= 0.01){
+    cerr << "ERROR:: epsilon too large  \n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (nlconst1.value() <= 0){
+    cerr << "ERROR:: nlconst1 negative  \n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (!remove_meanvol.value()){
+    varnorm.set_T(false);
+  }
+  if (filter.value().length()>0){
+    if (filtermix.value().length()<0){
+      cerr << "ERROR:: no mixing matrix for filtering (use --mix='filename') \n\n"; 
+      print_usage(argc,argv);
+      exit(2);
+    } else {   
+      filtermode = true;
+      varnorm.set_T(false);
+    } 
+  }
+  if (threshold.value()<=0){
+    use_mask.set_T(false);
+  }
+  if (output_pca.value()){
+    output_white.set_T(true);
+  }
+  if(threshold.value()>=1){
+    threshold.set_T(threshold.value()/100);
+    if(threshold.value()>=1){
+      cerr << "ERROR:: threshold level not a percentage value  \n\n";
+      print_usage(argc,argv);
+      exit(2);
+    }
+  }
+  if (nlconst2.value() <= 0){
+    cerr << "ERROR:: nlconst2 negative  \n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (dummy.value() < 0){
+    cerr << "ERROR:: negative dummy value  \n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (repeats.value() < 1){
+    cerr << "ERROR:: repeats < 1 \n\n";
+    print_usage(argc,argv);
+    exit(2);
+  }
+  if (numICs.value() > 0){
+    explicitnums = true;
+  }
+  
+  //transform inputfname to its basename
+  string basename = inputfname.value();
+  make_basename(basename);
+  inputfname.set_T(basename);
+
+  //create melodic directory name
+  if(logdir.value()==string("melodic.log")){
+    logdir.set_T(string(inputfname.value()+".ica"));
+    logger.makeDir(logdir.value(),logfname);
+  }
+  else{
+    // setup logger directory
+    system(("mkdir "+ logdir.value() + " 2>/dev/null").c_str());
+    logger.setDir(logdir.value(),logfname);
+  }
+  message(endl << "Melodic Version " << version << endl << endl);
+
+  // parse again so that options are logged
+  for(int a = 0; a < argc; a++)
+    logger.str() << argv[a] << " ";
+  logger.str() << endl << "---------------------------------------------" << endl << endl;
+
+  message("Melodic results will be in " << logger.getDir() << endl << endl);
+}
+
+void MelodicOptions::print_usage(int argc, char *argv[])
+{
+  print_version();
+  options.usage();
+  /* cout << "Usage: " << argv[0] << " "; 
+
+    Have own usage output here
+  */
+}
+
+void MelodicOptions::print_version()
+{
+  cout << "MELODIC Version " << version;
+}
+
+void MelodicOptions::print_copyright()
+{
+  print_version();
+  cout << endl << "Copyright (C) 1999-2002 University of Oxford " << endl;
+}
+
+void MelodicOptions::status()
+{
+  cout << " version = " << version << endl;
+ 
+  cout << " logdir = "  << logdir.value() << endl;
+  cout << " inputfname = "  << inputfname.value() << endl;
+  cout << " outputfname = "  << outputfname.value() << endl;
+  cout << " guessfname = "  << guessfname.value() << endl;
+  cout << " maskfname = "  << maskfname.value() << endl;
+  cout << " paradigmfname = "  <<  paradigmfname.value() << endl;
+  cout << " nonlinearity = "  << nonlinearity.value() << endl;
+  cout << " approach = "  << approach.value() << endl;
+  
+  cout << " pca_dim = "  << pca_dim.value() << endl;
+  cout << " segment = "  << segment.value() << endl;
+  cout << " numICs = "  << numICs.value() << endl;
+  cout << " maxNumItt = "  << maxNumItt.value() << endl;
+  cout << " maxRestart = "  << maxRestart.value() << endl;
+  cout << " dummy = "  << dummy.value() << endl;
+  cout << " repeats = "  << repeats.value() << endl;
+  cout << " nlconst1 = "  << nlconst1.value() << endl;
+  cout << " nlconst2 = "  << nlconst2.value() << endl;
+  cout << " epsilon = "  << epsilon.value() << endl;
+  cout << " threshold = "  << threshold.value() << endl;
+  
+  cout << " help = "  << help.value() << endl;
+  cout << " verbose = "  << verbose.value() << endl;
+  cout << " vers = "  << vers.value() << endl;
+  cout << " copyright = "  << copyright.value() << endl;
+  cout << " perf_bet = "  << perf_bet.value() << endl;
+  cout << " remove_meanvol = "  << remove_meanvol.value() << endl;
+  cout << " remove_endslices  = " << remove_endslices.value() << endl;
+  cout << " output_pca = "  << output_pca.value() << endl;
+  cout << " output_white = "  << output_white.value() << endl;
+  cout << " output_mean = "  << output_mean.value() << endl;
+  cout << " use_mask = "  << use_mask.value() << endl;
+  cout << " output_unmix = "  << output_unmix.value() << endl;
+  cout << " guess_remderiv = "  << guess_remderiv.value() << endl;
+  cout << " filter  = " << filter.value() << endl;
+  cout << " logPower  = " << logPower.value() << endl;
+}
+
+}
diff --git a/meloptions.h b/meloptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..8242c0db4c58ffd44a83bf0001d76dadbcd79643
--- /dev/null
+++ b/meloptions.h
@@ -0,0 +1,344 @@
+
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    meloptions.h - class for command line options
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT */
+
+
+#ifndef __MELODICOPTIONS_h
+#define __MELODICOPTIONS_h
+
+#include <string>
+#include <strstream>
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdio.h>
+#include "options.h"
+#include "log.h"
+#include "melodic.h"
+
+
+using namespace Utilities;
+
+namespace Melodic {
+
+class MelodicOptions {
+ public:
+  static MelodicOptions& getInstance();
+  ~MelodicOptions() { delete gopt; }
+  
+  string version;
+  string binpath;
+  string logfname;
+  bool   filtermode;
+  bool   explicitnums;
+  
+  Option<string> logdir;
+  Option<string> inputfname;
+
+  Option<string> outputfname;
+
+  Option<string> maskfname;
+  Option<bool>   use_mask;
+  Option<bool>   perf_bet;
+  Option<float>  threshold;
+
+  Option<int>    pca_dim;
+  Option<string> pca_est;
+  Option<int>    numICs;
+  Option<string> approach;
+  Option<string> nonlinearity;
+
+  Option<bool>   varnorm;
+  Option<string> segment;
+  Option<bool>   tsmooth;
+  Option<float>  epsilon;
+  Option<int>    maxNumItt;
+  Option<int>    maxRestart;
+
+  Option<string> mmthresh;
+  Option<bool>   perf_mm;
+  Option<string> ICsfname;
+  Option<string> filtermix; 
+  Option<string> filter; 
+
+  Option<bool>   genreport;
+  Option<float>  tr;
+  Option<bool>   logPower;
+
+  Option<bool>   output_unmix;
+  Option<bool>   output_MMstats;
+  Option<bool>   output_pca;
+  Option<bool>   output_white;
+  Option<bool>   output_origIC;
+  Option<bool>   output_mean;
+
+  Option<bool> verbose;  
+  Option<bool> vers;
+  Option<bool> copyright;
+  Option<bool> help;
+
+  Option<string> guessfname;
+  Option<string> paradigmfname;
+
+  Option<int>  dummy;
+  Option<int>  repeats;
+  Option<float> nlconst1;
+  Option<float> nlconst2;
+
+
+  Option<bool> remove_meanvol;
+  Option<bool> remove_endslices;
+
+  Option<bool> guess_remderiv;
+  Option<bool> temporal;
+
+  int retrystep;
+
+  void parse_command_line(int argc, char** argv, Log& logger,  const string &p_version);
+
+ private:
+  MelodicOptions();  
+  const MelodicOptions& operator=(MelodicOptions&);
+  MelodicOptions(MelodicOptions&);
+
+  OptionParser options; 
+      
+  static MelodicOptions* gopt;
+
+  void print_usage(int argc, char *argv[]);  
+  void print_version(); 
+  void print_copyright();
+  void status();
+};
+
+ inline MelodicOptions& MelodicOptions::getInstance(){
+   if(gopt == NULL)
+     gopt = new MelodicOptions();
+   
+   return *gopt;
+ }
+
+ inline MelodicOptions::MelodicOptions() :
+   logdir(string("-o,--outdir"), string("melodic.log"),
+	  string("output directory name\n"), 
+	  false, requires_argument),
+   inputfname(string("-i,--in"), string(""),
+	      string("input file name"), 
+	      true, requires_argument),
+   outputfname(string("-O,--out"), string("melodic"),
+	   string("output file name"), 
+	   false, requires_argument,false),
+   maskfname(string("-m,--mask"), string(""),
+	   string("file name of mask for thresholding"), 
+	   false, requires_argument),
+   use_mask(string("--nomask"), true,
+	   string("switch off masking"), 
+	   false, no_argument),
+   perf_bet(string("--nobet"), true,
+	   string("\tswitch off BET"), 
+	   false, no_argument),
+   threshold(string("--bgthreshold"),  0.00000001,
+	   string("brain / non-brain threshold (only if --nobet selected)\n"), 
+	   false, requires_argument),
+   pca_dim(string("-d,--dim"), 0,
+	   string("dimensionality reduction into #num dimensions (default: automatic estimation)"), 
+	   false, requires_argument),
+   pca_est(string("--dimest"), string("lap"),
+	   string("use specific dim. estimation technique: lap, bic, mdl, aic, mean (default: lap)"), 
+	   false, requires_argument),
+   numICs(string("-n,--numICs"), -1,
+	   string("numer of IC's to extract (for deflation approach)"), 
+	   false, requires_argument),
+   approach(string("-a,--approach"),  string("symm"),
+	   string("approach for ICA estimation: defl, symm"), 
+	   false, requires_argument),
+   nonlinearity(string("--nl"), string("pow3"),
+	   string("\tnonlinearity: gauss, tanh, pow3, pow4"), 
+	   false, requires_argument),
+   varnorm(string("--vn,--varnorm"), true,
+	   string("switch off variance normalisation"), 
+	   false, no_argument),
+   segment(string("--covarweight"), string(""),
+	   string("voxel-wise weights for the covariance matrix (e.g. segmentation information)"),
+	   false, requires_argument),
+   tsmooth(string("--spca"),  false,
+	   string("smooth the eigenvectors prior to IC decomposition"), 
+	    false, no_argument, false),
+   epsilon(string("--eps,--epsilon"), 0.00005,
+	   string("minimum error change"), 
+	   false, requires_argument),
+   maxNumItt(string("--maxit"),  500,
+	   string("\tmaximum number of iterations before restart"), 
+	   false, requires_argument),
+   maxRestart(string("--maxrestart"),  6,
+	   string("maximum number of restarts\n"), 
+	   false, requires_argument),
+   mmthresh(string("--mmthresh"), string("0.5"),
+	   string("threshold for Mixture Model based inference"), 
+	   false, requires_argument),
+   perf_mm(string("--no_mm"), true,
+	   string("\tswitch off mixture modelling on IC maps\n "), 
+	   false, no_argument),
+   ICsfname(string("--ICs"), string(""),
+	   string("\tfilename of the IC components file for mixture modelling"), 
+	   false, requires_argument),
+   filtermix(string("--mix"),  string(""),
+	   string("\tmixing matrix for mixture modelling / filtering"), 
+	   false, requires_argument),
+   filter(string("-f,--filter"),  string(""),
+	   string("component numbers to remove\n "), 
+	   false, requires_argument),
+   genreport(string("--report"), false,
+	   string("generate Melodic web report"), 
+	   false, no_argument),
+   tr(string("--tr"),  0.0,
+	   string("\tTR in seconds"), 
+	   false, requires_argument),
+   logPower(string("--logPower"),  false,
+	   string("calculate log of power for frequency spectrum\n"), 
+	    false, no_argument),
+   output_unmix(string("--Ounmix"),  false,
+	   string("output unmixing matrix"), 
+	   false, no_argument),
+   output_MMstats(string("--Ostats"),  false,
+	   string("output thresholded maps and probability maps"), 
+	   false, no_argument),
+   output_pca(string("--Opca"),  false,
+	   string("\toutput PCA results"), 
+	   false, no_argument),
+   output_white(string("--Owhite"),  false,
+	   string("output whitening/dewhitening matrices"), 
+	   false, no_argument),
+   output_origIC(string("--Oorig"),  false,
+	   string("\toutput the original ICs"), 
+	   false, no_argument),
+   output_mean(string("--Omean"),  false,
+	   string("\toutput mean volume\n"), 
+	   false, no_argument),
+   verbose(string("-v,--verbose"), false,
+	   string("switch on diagnostic messages"), 
+	   false, no_argument),
+   vers(string("-V,--version"), false,
+	   string("prints version information"), 
+	   false, no_argument),
+   copyright(string("--copyright"), false,
+	   string("prints copyright information"), 
+	   false, no_argument),
+   help(string("-h,--help"),  false,
+	   string("prints this help message"), 
+	   false, no_argument),
+   guessfname(string("-g,--guess"), string(""),
+	   string("file name of guess of mixing matrix"), 
+	   false, requires_argument, false),
+   paradigmfname(string("-p,--paradigm"),  string(""),
+	   string("file name of FEAT paradigm file"), 
+	   false, requires_argument, false),
+   dummy(string("--dummy"),  0,
+	   string("number of dummy volumes"), 
+	   false, requires_argument,false),
+   repeats(string("--repeats"), 1,
+	   string("number of repeats (multistart)"), 
+	   false, requires_argument, false),
+   nlconst1(string("--nl1,--nlconst1"),  1.0,
+	   string("nonlinear constant 1"), 
+	   false, requires_argument, false),
+   nlconst2(string("--nl2,--nlconst2"),  1.0,
+	   string("nonlinear constant 2"), 
+	   false, requires_argument, false),
+   remove_meanvol(string("--keepmeanvol"), true,
+	   string("do not subtract mean volume"), 
+	   false, no_argument, false),
+   remove_endslices(string("--remEndslices"),  false,
+	   string("delete end slices (motion correction artefacts)"), 
+	   false, no_argument,false),
+   guess_remderiv(string("--remderiv"),  false,
+	   string("removes every second entry in paradigm file (EV derivatives)"), 
+	   false, no_argument, false),
+   temporal(string("--temporal"),  false,
+	   string("perform temporal ICA"), 
+	    false, no_argument, false),
+   retrystep(3),
+   options(string(""), 
+	   string(" melodic -i <filename> <options>")+
+	   string("\n \t \t to run melodic")+
+	   string("\n melodic -i <filename> --mix=melodic_mix")+
+	   string(" --filter=\"string of component numbers\"")+
+	   string("\n \t \t to remove estimated ICs from input")+
+	   string("\n melodic -i <filename> --ICs=melodic_IC")+
+	   string(" --mix=melodic_mix <options>")+
+	   string("\n \t \t to run Mixture Model based inference on estimated ICs")+
+	   string("\n melodic --help "))
+   {
+     try {  
+            options.add(logdir);
+	    options.add(inputfname);
+	    options.add(outputfname);
+	    options.add(guessfname);
+	    options.add(maskfname);
+	    options.add(use_mask);
+	    options.add(perf_bet);
+	    options.add(threshold);
+	    options.add(pca_dim);
+	    options.add(pca_est);
+	    options.add(numICs);
+	    options.add(approach);
+	    options.add(nonlinearity);
+	    options.add(varnorm);
+	    options.add(segment);
+	    options.add(tsmooth);
+	    options.add(epsilon);
+	    options.add(maxNumItt);
+	    options.add(maxRestart);
+	    options.add(mmthresh);
+	    options.add(perf_mm);
+	    options.add(ICsfname);
+	    options.add(filtermix);
+	    options.add(filter);
+	    options.add(genreport);
+	    options.add(tr);
+	    options.add(logPower);
+	    options.add(output_unmix);
+	    options.add(output_MMstats);
+	    options.add(output_pca);
+	    options.add(output_white);
+	    options.add(output_origIC);
+	    options.add(output_mean);
+	    options.add(verbose);
+	    options.add(vers);
+	    options.add(copyright);
+	    options.add(help);
+	   
+	    options.add(guessfname);
+	    options.add(paradigmfname); 
+	    options.add(dummy);
+	    options.add(repeats);
+	    options.add(nlconst1);
+	    options.add(nlconst2);
+	    options.add(remove_meanvol);
+	    options.add(remove_endslices);
+	    options.add(guess_remderiv);
+	    options.add(temporal);
+     }
+     catch(X_OptionError& e) {
+       options.usage();
+       cerr << endl << e.what() << endl;
+     } 
+     catch(std::exception &e) {
+       cerr << e.what() << endl;
+     }    
+     
+   }
+}
+
+#endif
+
+
+
diff --git a/melpca.cc b/melpca.cc
new file mode 100644
index 0000000000000000000000000000000000000000..66a5f4277be06707cf9c8bd4bb1b90f284d2f5ef
--- /dev/null
+++ b/melpca.cc
@@ -0,0 +1,586 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    melpca.cc - PCA and whitening 
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-200 University of Oxford */
+
+/*  CCOPYRIGHT  */
+
+#include "newimageall.h"
+#include "log.h"
+#include "meloptions.h"
+#include "meldata.h"
+#include "melodic.h"
+#include "newmatap.h"
+#include "newmatio.h"
+#include "melpca.h"
+#include "libprob.h"
+
+using namespace Utilities;
+using namespace NEWIMAGE;
+
+namespace Melodic{
+
+   void MelodicPCA::perf_pca(const Matrix &Data)
+   {    
+     message("Starting PCA  ... ");
+
+     SymmetricMatrix Corr;
+
+     if(opts.segment.value().length()>0){
+       Matrix Res;
+       Res = ones(Data.Nrows(),1)*melodat.get_RXweight();
+       Res = SP(melodat.get_Data(),Res);
+       Corr = cov(Res.t());
+     }
+     else{
+       Corr = cov(melodat.get_Data().t());
+     }
+
+     Matrix tmpE;
+     DiagonalMatrix tmpD;
+ 
+     EigenValues(Corr,tmpD,tmpE);
+
+     if(opts.tsmooth.value()){
+       message(" temporal smoothing of Eigenvectors " << endl);
+       tmpE=melodat.smoothColumns(tmpE);
+     }
+  
+     melodat.set_pcaE(tmpE);
+     melodat.set_pcaD(tmpD);
+     
+     RowVector AdjEV;
+     AdjEV = tmpD.AsRow().Reverse();
+     SortDescending(AdjEV);
+  
+     RowVector PercEV(AdjEV);     
+     PercEV = cumsum(AdjEV / sum(AdjEV,2).AsScalar());
+     write_ascii_matrix(logger.appendDir("eigenvalues_percent"),PercEV);
+     melodat.set_EVP(PercEV);
+     AdjEV = (AdjEV - min(AdjEV).AsScalar())/(max(AdjEV).AsScalar() - min(AdjEV).AsScalar());
+     melodat.set_EV((AdjEV));
+     message("done" << endl);
+   }
+  
+  void MelodicPCA::perf_white(const Matrix &Data)
+  {
+    Matrix RE;
+    DiagonalMatrix RD;
+    Matrix tmpWhite;
+    Matrix tmpDeWhite;
+
+    int N = melodat.get_pcaE().Ncols();    
+    if(opts.pca_dim.value() > N){
+      message("dimensionality too large - using -dim " << N << 
+              " instead " << endl);
+      opts.pca_dim.set_T(N);
+    }
+    if(opts.pca_dim.value() < 0){
+      if(opts.remove_meanvol.value()){
+	opts.pca_dim.set_T(N-2);
+      }else{
+	opts.pca_dim.set_T(N-1);
+      }
+    }
+    if(opts.pca_dim.value() ==0){
+      opts.pca_dim.set_T(pcadim());
+      if(melodat.get_Data().Nrows()<20){
+	opts.pca_dim.set_T(N-2);
+	message("too few data points for full estimation, using "
+		<< opts.pca_dim.value() << " instead"<< endl);
+      }
+    }
+    if(opts.approach.value()==string("jade") && opts.pca_dim.value() > 30){
+      message("dimensionality too large for jade estimation - using --dim 30 instead" << endl);
+      opts.pca_dim.set_T(30);
+    }
+    message("Start whitening using  "<< opts.pca_dim.value()<<" dimensions ... " << endl);
+    RowVector tmpEVP;
+    tmpEVP << melodat.get_EVP();
+    float varp = 1.0;
+    if(opts.pca_dim.value() <= tmpEVP.Ncols()){
+      varp = tmpEVP(opts.pca_dim.value());
+    }
+    message("  retaining "<< varp*100 <<" percent of the variability " << endl);
+
+    RE = melodat.get_pcaE().Columns(N-opts.pca_dim.value()+1,N);
+    RD << abs(melodat.get_pcaD().SymSubMatrix(N-opts.pca_dim.value()+1,N));    
+
+    tmpWhite = sqrt(abs(RD.i()))*RE.t();
+    tmpDeWhite = RE*sqrt(RD);
+    melodat.set_white(tmpWhite);
+    melodat.set_dewhite(tmpDeWhite);
+    message(" ... done"<< endl << endl);
+   }
+
+  int MelodicPCA::pcadim()
+  { 
+    message("Estimating the number of sources from the data (PPCA) ..." << endl);
+
+    //First, estimate the smoothness of the data;
+    //   set up all strings
+
+    string SM_path = opts.binpath + "smoothest";
+    string Mask_fname = logger.appendDir("mask");
+
+    if(opts.segment.value().length()>0){
+      Mask_fname =  opts.segment.value();
+    } 
+
+    // Setup external call to smoothest:
+    char callSMOOTHESTstr[1000];
+    ostrstream osc(callSMOOTHESTstr,1000);
+    osc  << SM_path << " -d " << melodat.data_dim()
+    	 << " -r " << opts.inputfname.value() << " -m " 
+    	 << Mask_fname << " > " << logger.appendDir("smoothest") << '\0';
+    
+    message("  Calling Smoothest: " << callSMOOTHESTstr << endl);
+    system(callSMOOTHESTstr);
+
+    //read back the results
+    ifstream in;
+    string str;
+    float Resel = 1.0;
+
+    in.open(logger.appendDir("smoothest").c_str(), ios::in);
+    if(in>0){
+      for(int ctr=1; ctr<7; ctr++){ in >> str;}
+      in.close();
+      if(str!="nan"){
+	Resel = atof(str.c_str());
+      }
+    }
+
+    //cerr << "  Resels : " << Resel << endl << endl;
+    
+    melodat.set_resels(Resel);
+    
+    Matrix PPCAest;
+  
+    //   if(!opts.varnorm.value()){
+    SymmetricMatrix Corr;
+    if(opts.segment.value().length()>0){
+      Matrix Res;
+      Res = ones(melodat.get_DataVN().Nrows(),1)*melodat.get_RXweight();
+      Res = SP(melodat.get_DataVN(),Res);
+      Corr = cov(Res.t());
+     }
+    else{
+      Corr = cov(melodat.get_DataVN().t());
+    }
+    DiagonalMatrix tmpD;
+    Matrix tmpE;
+    EigenValues(Corr,tmpD,tmpE);
+    // }
+
+    RowVector AdjEV;
+    AdjEV << tmpD.AsRow();
+    AdjEV = AdjEV.Columns(3,AdjEV.Ncols());
+    AdjEV = AdjEV.Reverse();
+
+    RowVector CircleLaw;
+    int NumVox = (int) floor(melodat.data_samples()/(2.5*Resel));
+
+
+    CircleLaw = Feta(int(AdjEV.Ncols()), NumVox);
+
+    for(int ctr=1;ctr<=CircleLaw.Ncols(); ctr++){
+      if(CircleLaw(ctr)<5*10e-10){CircleLaw(ctr) = 5*10e-10;}
+    } 
+
+    //write_ascii_matrix(logger.appendDir("tmpA1"),AdjEV);
+    //AdjEV = AdjEV.Columns(2,AdjEV.Ncols());
+    //write_ascii_matrix(logger.appendDir("tmpA2"),AdjEV);
+
+    //cerr<< AdjEV.Nrows() << " x " << AdjEV.Ncols() << endl;
+    
+    //cerr<< CircleLaw.Nrows() << " x " << CircleLaw.Ncols() << endl;
+
+    float slope;
+    slope = CircleLaw.Columns(int(AdjEV.Ncols()/4),AdjEV.Ncols() - 
+			      int(AdjEV.Ncols()/4)).Sum() /  
+      AdjEV.Columns(int(AdjEV.Ncols()/4),AdjEV.Ncols() - 
+		    int(AdjEV.Ncols()/4)).Sum();
+
+    //CircleLaw = slope * (CircleLaw-1) + 1;
+
+    //    write_ascii_matrix(logger.appendDir("claw"),CircleLaw.Columns(1,AdjEV.Ncols()));
+
+    RowVector PercEV(AdjEV);
+    PercEV = cumsum(AdjEV / sum(AdjEV,2).AsScalar());
+
+    //    write_ascii_matrix(logger.appendDir("ev"),AdjEV);
+
+    //cerr << int(AdjEV.Ncols()) << "   " << NumVox << "   " << slope << endl;
+    AdjEV << SP(AdjEV,pow(CircleLaw.Columns(1,AdjEV.Ncols()),-1));
+    //  cerr << "recalculated" << endl;
+
+    SortDescending(AdjEV);
+    int maxEV = 1;
+    float threshold = 0.98;
+    for(int ctr_i = 1; ctr_i < PercEV.Ncols(); ctr_i++){ 
+      if((PercEV(ctr_i)<threshold)&&(PercEV(ctr_i+1)>=threshold)){maxEV=ctr_i;}
+    }
+
+    if(maxEV<3){maxEV=PercEV.Ncols()/2;}
+    RowVector NewEV;
+    Matrix temp1;
+    temp1 = abs(AdjEV);
+    NewEV << temp1.SubMatrix(1,1,1,maxEV);
+    PPCAest = ppca_est(NewEV, NumVox);
+    RowVector estimators(5);
+    estimators = 1.0;
+    
+    Matrix PPCA2(PPCAest);
+    
+    for(int ctr=1; ctr<=PPCA2.Ncols(); ctr++){
+      PPCA2.Column(ctr) = (PPCA2.Column(ctr) - 
+			   min(PPCA2.Column(ctr)).AsScalar()) / 
+	( max(PPCA2.Column(ctr)).AsScalar() - 
+	  min(PPCA2.Column(ctr)).AsScalar());
+    }
+    
+    int ctr_i = 1;
+    while((ctr_i< PPCAest.Nrows()-1)&&
+	  (PPCAest(ctr_i,2) < PPCAest(ctr_i+1,2))&&(ctr_i<maxEV))
+      {estimators(1)=ctr_i+1;ctr_i++;}
+    ctr_i = 1;
+    while((ctr_i< PPCAest.Nrows()-1)&&
+	  (PPCAest(ctr_i,3) < PPCAest(ctr_i+1,3))&&(ctr_i<maxEV))
+      {estimators(2)=ctr_i+1;ctr_i++;}
+    ctr_i = 1;
+    while((ctr_i< PPCAest.Nrows()-1)&&
+	  (PPCAest(ctr_i,4) < PPCAest(ctr_i+1,4))&&(ctr_i<maxEV))
+      {estimators(3)=ctr_i+1;ctr_i++;}
+    ctr_i = 1;
+    while((ctr_i< PPCAest.Nrows()-1)&&
+	  (PPCAest(ctr_i,5) < PPCAest(ctr_i+1,5))&&(ctr_i<maxEV))
+      {estimators(4)=ctr_i+1;ctr_i++;}
+    ctr_i = 1;
+    while((ctr_i< PPCAest.Nrows()-1)&&
+	  (PPCAest(ctr_i,6) < PPCAest(ctr_i+1,6))&&(ctr_i<maxEV))
+      {estimators(5)=ctr_i+1;ctr_i++;}
+
+    int res = 0;
+    ColumnVector PPCA;
+
+    if(opts.pca_est.value() == string("lap")){
+      res = int(estimators(1));
+      PPCA << PPCA2.Column(2);
+    }
+
+    if(opts.pca_est.value() == string("bic")){
+      res = int(estimators(2));
+      PPCA << PPCA2.Column(2);
+    }
+    if(opts.pca_est.value() == string("mdl")){
+      res = int(estimators(3));
+      PPCA << PPCA2.Column(4);
+    }
+    if(opts.pca_est.value() == string("aic")){
+      res = int(estimators(5));
+      PPCA << PPCA2.Column(6);
+    }
+    if(res==0){//median estimator
+      PPCA = PPCA2.Column(2);
+
+      for(int ctr=1; ctr<=PPCA2.Nrows(); ctr++){ 
+	RowVector tmp = PPCA2.SubMatrix(ctr,ctr,2,6);
+// 	SortAscending(tmp);
+// 	float themean = float(tmp.Sum()/5);
+// 	if(std::abs(int(tmp(2)-themean)) < std::abs(int(tmp(3)-themean)))
+// 	  PPCA(ctr) = tmp(2);
+// 	else
+// 	  PPCA(ctr) = tmp(3);
+
+	PPCA(ctr) = float(tmp.Sum()/5);
+      }
+
+      ctr_i = 1; 
+      while((PPCA(ctr_i) < PPCA(ctr_i+1))&&(ctr_i<maxEV)){
+	res=ctr_i+1;ctr_i++;
+      }
+    }
+
+    //    cerr << estimators << "   "  << res << endl;
+			       
+    //write_ascii_matrix(logger.appendDir("PPCA2"),PPCA2);
+    AdjEV = (AdjEV - min(AdjEV).AsScalar())/(max(AdjEV).AsScalar() - min(AdjEV).AsScalar());
+
+
+    write_ascii_matrix(logger.appendDir("PPCA"),PPCA);			      
+    write_ascii_matrix(logger.appendDir("eigenvalues_adjusted"),AdjEV.t());
+    write_ascii_matrix(logger.appendDir("eigenvalues_percent"),PercEV.t());
+
+    melodat.set_EVP(PercEV);
+    melodat.set_EV(AdjEV);
+    melodat.set_PPCA(PPCA);
+
+    //PPCA << sum(PPCAest.Columns(2,6),2);
+    
+    //ctr_i = 1;
+    
+    //while((PPCA(ctr_i) < PPCA(ctr_i+1))&&(ctr_i<maxEV)){
+    //  res=ctr_i+1;ctr_i++;
+    //} 
+    
+    //res = int(sum(estimators,2).AsScalar()/5);
+    
+    // res = int(estimators(1)); // Laplace approximation
+    //     SortAscending(estimators);
+    //     if(std::abs(int(estimators(2))-res) < std::abs(int(estimators(3))-res))
+    //       res = int(estimators(2));
+    //     else
+    //       res = int(estimators(3));
+    
+    
+    //write_ascii_matrix(logger.appendDir("PPCA"),PPCAest);
+    //write_ascii_matrix(logger.appendDir("dimest"),estimators);
+    
+    return res;
+  }
+
+RowVector MelodicPCA::Feta(int n1, int n2)
+  {
+    float nu = (float) n1/n2; 
+    float bm = pow((1-sqrt(nu)),2.0);
+    float bp = pow((1+sqrt(nu)),2.0);
+
+    //cerr << "nu, bm, bp " << nu << " " <<bm << " " << bp << endl;
+
+    float lrange = 0.9*bm;
+    float urange = 1.1*bp;
+
+    // int dummy;
+   
+    RowVector eta(30*n1);
+    float rangestepsize = (urange - lrange) / eta.Ncols(); 
+    for(int ctr_i = 0; ctr_i < eta.Ncols(); ctr_i++){ 
+      eta(ctr_i+1) = lrange + rangestepsize * (ctr_i);
+    }
+
+    RowVector teta(10*n1);
+    teta = 0;
+    float stepsize = (bp - bm) / teta.Ncols();
+    for(int ctr_i = 0; ctr_i < teta.Ncols(); ctr_i++){ 
+      teta(ctr_i+1) = stepsize*(ctr_i);
+    }  
+    
+    //cerr << teta(1)+bm << " " << teta(1000)+bm << endl;
+    //cerr << eta(1)<< " " << eta(eta.Ncols())<< endl;
+    
+    //cerr << "BP1" << endl;
+ 
+    //write_ascii_matrix(logger.appendDir("teta"),teta.t());
+
+
+    //  RowVector tmp1(teta);
+    //     tmp1 = teta + bm;
+    
+    //     cerr << "tmp1" << endl;
+    //     tmp1 =  pow(2*M_PI*nu*(tmp1),-1);
+    //     cerr << "tmp1" << endl;
+    
+    //     RowVector tmp2(teta); 
+    //     cerr << "tmp2" << endl;
+    //     tmp2 = SP(teta, bp-bm-teta);
+    //     cerr << "tmp2" << endl;
+    //     tmp2=abs(tmp2);
+    //     cerr << "tmp2" << endl;
+
+
+    RowVector feta(teta);
+    feta = SP(pow(2*M_PI*nu*(teta + bm),-1), pow(SP(teta, bp-bm-teta),0.5));
+   
+    //Matrix location;
+    teta = teta + bm;
+
+    //cerr << "teta : " << teta.Nrows() << " x " << teta.Ncols() << endl;
+    //cerr << "eta : " << eta.Nrows() << " x " << eta.Ncols() << endl;
+    //cerr << "feta : " << feta.Nrows() << " x " << feta.Ncols() << endl;
+    //c/err << "vor location (input)" << endl;
+    //cin >> dummy;
+    //location = SP(teta.t()*ones(1,eta.Ncols()),pow(ones(teta.Ncols(),1)*eta,-1));
+    //cerr << "nach location (input)" << endl;
+    //cin >> dummy;
+    //cerr << " weiter " << endl;
+
+    //for(int ctr_i = 1; ctr_i <= location.Ncols(); ctr_i++){
+    //  for(int ctr_j = 1; ctr_j <= location.Nrows(); ctr_j++){
+    //	if(location(ctr_j,ctr_i)<1){location(ctr_j,ctr_i)=1;}
+    //	else {location(ctr_j,ctr_i)=0;}
+    //  }
+    // } 
+    //write_ascii_matrix(logger.appendDir("location"),location);
+    // write_ascii_matrix(logger.appendDir("teta"),teta);
+    //write_ascii_matrix(logger.appendDir("eta"),eta);
+    //write_ascii_matrix(logger.appendDir("feta"),feta);
+ 
+  
+    //RowVector claw; 
+    //  claw = n1*(1-sum(SP(stepsize*feta.t()*ones(1,eta.Ncols()),location),1).AsRow());
+
+    RowVector claw(eta);
+    claw = 0;
+    for(int ctr_i = 1; ctr_i <= eta.Ncols(); ctr_i++){
+      double tmpval = 0.0;
+      for(int ctr_j = 1; ctr_j <= teta.Ncols(); ctr_j++){
+	if(( double(teta(ctr_j))/double(eta(ctr_i)) )<1)
+	  tmpval += feta(ctr_j);
+      }
+      claw(ctr_i) = n1*(1-stepsize*tmpval);
+    }
+    
+    //write_ascii_matrix(logger.appendDir("claw"),claw);
+    //cerr << "BP1" << endl;
+    RowVector Res(n1); //invert the CDF
+    //cerr << "n1=" << n1 << endl;
+    for(int ctr_i = 1; ctr_i < eta.Ncols(); ctr_i++){
+      if(floor(claw(ctr_i))>floor(claw(ctr_i+1))){
+	//	cerr << int(floor(claw(ctr_i))) << " ";
+	Res(int(floor(claw(ctr_i)))) = eta(ctr_i);
+      }
+    }
+ 
+    //cerr << endl;
+    //    cerr << " Done with loop " << int(floor(tmp4b(ctr_i))) << endl; 
+    //write_ascii_matrix(logger.appendDir("claw-dstn"),Res);
+    return Res;
+  }
+
+
+  RowVector MelodicPCA::cumsum(const RowVector& Inp)
+  {
+    UpperTriangularMatrix UT(Inp.Ncols());
+    UT=1.0;
+    RowVector Res;
+    Res = Inp * UT;
+    return Res;
+  }
+
+
+  Matrix MelodicPCA::ppca_est(const RowVector& eigenvalues, const int N)
+  {
+    RowVector logLambda(eigenvalues);
+    logLambda = log(eigenvalues);
+
+    int d = logLambda.Ncols();
+
+    RowVector k(d);
+    for(int ctr_i = 1; ctr_i <=d; ctr_i++){
+      k(ctr_i)=ctr_i;
+    }
+   
+    RowVector m(d);
+    m=d*k-0.5*SP(k,k+1); 
+
+    RowVector loggam(d);
+    loggam = 0.5*k.Reverse();
+    for(int ctr_i = 1; ctr_i <=d; ctr_i++){
+      loggam(ctr_i)=lgam(loggam(ctr_i));
+    }
+    loggam = cumsum(loggam); 
+
+    RowVector l_probU(d);
+    l_probU = -log(2)*k + loggam - cumsum(0.5*log(M_PI)*k.Reverse());
+
+    RowVector tmp1;
+    tmp1 = -cumsum(eigenvalues).Reverse()+sum(eigenvalues,2).AsScalar();
+    tmp1(1) = 0.95*tmp1(2);
+    tmp1=tmp1.Reverse();
+
+    RowVector tmp2;
+    tmp2 = -cumsum(logLambda).Reverse()+sum(logLambda,2).AsScalar();
+    tmp2(1)=tmp2(2);
+    tmp2=tmp2.Reverse();
+
+    RowVector tmp3;
+    tmp3 = d-k;
+    tmp3(d) = 1.0;
+
+    RowVector tmp4;
+    tmp4 = SP(tmp1,pow(tmp3,-1));    
+    for(int ctr_i = 1; ctr_i <=d; ctr_i++){
+      if(tmp4(ctr_i)<0.01){tmp4(ctr_i)=0.01;}
+      if(tmp3(ctr_i)<0.01){tmp3(ctr_i)=0.01;}
+      if(tmp1(ctr_i)<0.01){tmp1(ctr_i)=0.01;}
+    }
+
+    RowVector l_nu;
+    l_nu = SP(-N/2*(d-k),log(tmp4));
+    l_nu(d) = 0;
+
+    RowVector l_lam;
+    l_lam = -(N/2)*cumsum(logLambda);
+
+    RowVector l_lhood;
+    l_lhood = SP(pow(tmp3,-1),tmp2)-log(SP(pow(tmp3,-1),tmp1));
+
+    Matrix t1,t2, t3;
+    UpperTriangularMatrix triu(d);
+    triu = 1.0;
+    for(int ctr_i = 1; ctr_i <= triu.Ncols(); ctr_i++){
+      triu(ctr_i,ctr_i)=0.0;
+    }
+    t1 = (ones(d,1) * eigenvalues);
+    t1 = SP(triu,t1.t() - t1);
+    t2 = pow(tmp4,-1).t()*ones(1,d);
+    t3 = ones(d,1)*pow(eigenvalues,-1);
+    t2 = SP(triu, t2.t()-t3.t());
+    for(int ctr_i = 1; ctr_i <= t1.Ncols(); ctr_i++){
+      for(int ctr_j = 1; ctr_j <= t1.Nrows(); ctr_j++){
+	if(t1(ctr_j,ctr_i)<=0){t1(ctr_j,ctr_i)=1;}
+      } 
+    }
+    for(int ctr_i = 1; ctr_i <= t2.Ncols(); ctr_i++){
+      for(int ctr_j = 1; ctr_j <= t2.Nrows(); ctr_j++){
+	if(t2(ctr_j,ctr_i)<=0){t2(ctr_j,ctr_i)=1;}
+      }
+    } 
+    t1 = cumsum(sum(log(t1),2).AsRow());
+    t2 = cumsum(sum(log(t2),2).AsRow());
+
+    RowVector l_Az(d);
+    l_Az << (t1+t2);
+
+    RowVector l_lap;
+    l_lap = l_probU + l_nu +l_Az + l_lam + 0.5*log(2*M_PI)*(m+k)-0.5*log(N)*k;
+ 
+    RowVector l_BIC;
+    l_BIC = l_lam + l_nu - 0.5*log(N)*(m+k);
+
+    RowVector l_RRN;
+    l_RRN = -0.5*N*SP(k,log(SP(cumsum(eigenvalues),pow(k,-1))))+l_nu;
+
+    RowVector l_AIC;
+    l_AIC = -2*N*SP(tmp3,l_lhood)+ 2*(1+d*k+0.5*(k-1));
+    l_AIC = -l_AIC;
+
+    RowVector l_MDL;
+    l_MDL = -N*SP(tmp3,l_lhood)+ 0.5*(1+d*k+0.5*(k-1))*log(N);
+    l_MDL = -l_MDL;
+
+    Matrix Res;
+
+    Res = eigenvalues.t();
+    Res |= l_lap.t();
+    Res |= l_BIC.t();
+    Res |= l_MDL.t();
+    Res |= l_RRN.t();
+    Res |= l_AIC.t();
+    
+   
+    return Res;
+
+  }
+
+
+
+
+}
+
+
diff --git a/melpca.h b/melpca.h
new file mode 100644
index 0000000000000000000000000000000000000000..5fe727f6f7311a65aaeeeebf2d1770896701401c
--- /dev/null
+++ b/melpca.h
@@ -0,0 +1,58 @@
+ /*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    melpca.h - PCA and whitening 
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT */
+
+#ifndef __MELODICPCA_h
+#define __MELODICPCA_h
+#include "newimageall.h"
+#include "log.h"
+#include "meloptions.h"
+#include "meldata.h"
+#include "melodic.h"
+//#include "melreport.h"
+#include "newmatap.h"
+#include "newmatio.h"
+
+using namespace Utilities;
+using namespace NEWIMAGE;
+
+namespace Melodic{
+  
+  class MelodicReport;
+
+  class MelodicPCA
+    {
+    public:
+      MelodicPCA(MelodicData &pmelodat, MelodicOptions &popts, Log &plogger, MelodicReport &preport):  
+	melodat(pmelodat),
+	opts(popts),
+	logger(plogger),
+	report(preport)
+	{		
+	} 
+      
+      void perf_pca(const Matrix &Data);
+      void perf_white(const Matrix &Data);
+
+    private:
+      MelodicData &melodat;
+      MelodicOptions &opts;
+      Log &logger;
+      MelodicReport &report;
+
+      int pcadim();
+      RowVector cumsum(const RowVector& Inp);
+      Matrix ppca_est(const RowVector& eigenvalues, const int N);
+
+      RowVector Feta(int n1,int n2);
+    };   
+}
+
+#endif
diff --git a/melreport.cc b/melreport.cc
new file mode 100644
index 0000000000000000000000000000000000000000..87fb7d82e2407f85a90aa6724a9cd902a71226f3
--- /dev/null
+++ b/melreport.cc
@@ -0,0 +1,614 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    melreport.cc - report generation
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT  */
+
+#include "newimageall.h"
+#include "log.h"
+#include "melreport.h"
+
+namespace Melodic{
+  
+  void MelodicReport::IC_rep(MelGMix &mmodel, int cnum, int dim)
+  {
+    if( bool(opts.genreport.value()) ){
+      addlink(mmodel.get_prefix()+".html",num2str(cnum));
+      IChtml.setDir(report.getDir(),mmodel.get_prefix()+".html");
+      
+      {//start IC page
+
+      IChtml << "<HTML> " << endl
+	     << "<TITLE>MELODIC Component " << num2str(cnum)
+	     << "</TITLE>" << endl
+	     << "<BODY BACKGROUND=\"file:" << getenv("FSLDIR") 
+	     << "/doc/images/fsl-bg.jpg\">" << endl 
+	     << "<hr><CENTER><H1>MELODIC Component " << num2str(cnum)
+	     << "</H1>"<< endl;
+      
+      if(cnum>1)
+	IChtml << "<a href=\"" << string("IC_")+num2str(cnum-1)
+	       <<".html\">previous</a>&nbsp;-&nbsp;";
+      
+      IChtml << "<a href=\"00index.html\">&nbsp;index&nbsp;</a>" ;
+
+      if(cnum<dim)
+	IChtml << "&nbsp;-&nbsp;<a href=\"" << string("IC_")+num2str(cnum+1)
+	       <<".html\">next</a><p>";
+
+      IChtml << "<hr><p>" << endl;
+      }
+
+      
+      volume4D<float> tempVol; 
+      
+      if(mmodel.get_threshmaps().Storage()>0&&
+	 (mmodel.get_threshmaps().Ncols() == mmodel.get_data().Ncols()))
+      {//Output thresholded IC map
+
+	
+	tempVol.setmatrix(mmodel.get_threshmaps().Row(1),melodat.get_mask());
+ 	volume<float> map1;
+	volume<float> map2;
+	map1 = threshold(tempVol[0],float(0.0), tempVol[0].max());
+	map2 = threshold(tempVol[0],tempVol[0].min(), float(0.0));
+	// 	save_volume(map,report.appendDir(mmodel.get_prefix()+"_thresh")
+ 	//	    ,melodat.tempInfo);
+	volume<float> newvol;
+ 	// for(int ctr=1; ctr<500; ctr++){
+// 	  cerr << ctr << " ";
+	miscpic newpic;
+	
+	float map1min = std::max((map1 + binarise(tempVol[0],tempVol[0].min(), 
+		        float(0.0)) * map1.max()).min(),float(0.01));
+	float map1max = std::max(map1.max(),float(0.01));
+	float map2min = std::min(map2.min(),float(-0.01));
+	float map2max = std::min((map2 + binarise(tempVol[0],float(0.0), 
+			tempVol[0].max()) * map2.min()).max(),float(-0.01));
+	
+
+	newpic.overlay(newvol, melodat.get_mean(), map1, map2, 
+		       melodat.get_mean().percentile(0.02),
+		       melodat.get_mean().percentile(0.98),
+		       map1min, map1max, map2max, map2min, 
+		       0, 0, &melodat.tempInfo);
+	
+ 	char instr[10000];
+	
+	//save_volume(newvol,report.appendDir(mmodel.get_prefix()+"rendered"),
+	//      melodat.tempInfo);
+ 	sprintf(instr," ");
+ 	strcat(instr," -s 2");
+ 	strcat(instr," -A 950 ");
+ 	strcat(instr,string(report.appendDir(mmodel.get_prefix()+
+ 					     "_thresh.png")).c_str());
+ 	newpic.set_title(string("Component No. "+num2str(cnum)+
+ 				" - thresholded IC map  ")+
+			 mmodel.get_infstr(1));
+ 	newpic.set_cbar(string("ysb"));
+	//cerr << instr << endl;
+
+
+	
+	if(map1.max()-map1.min()>0.01)
+	  newpic.slicer(newvol, instr, &melodat.tempInfo); 
+	else
+	  newpic.slicer(map1, instr, &melodat.tempInfo);
+
+	}
+     //  }
+//       exit(2);
+
+      IChtml << "<a href=\""+mmodel.get_prefix()+"_MM.html\">";
+      IChtml << "<img BORDER=0 SRC=\""+mmodel.get_prefix()
+	+"_thresh.png\" ALT=\"MMfit\"></A><p>" << endl;
+      
+
+      {//plot time course
+	miscplot newplot;
+      
+	if(opts.tr.value()>0.0)
+	  newplot.timeseries(melodat.get_mix().Column(cnum).t(),
+			     report.appendDir(string("t")+num2str(cnum)+".png"),
+			     string("Timecourse (in seconds); TR = ")+
+			     float2str(opts.tr.value(),0,2,0)+" s", 
+			     opts.tr.value(),150,4,1);
+	else
+	  newplot.timeseries(melodat.get_mix().Column(cnum).t(),
+			     report.appendDir(string("t")+num2str(cnum)+".png"),
+			     string("Timecourse (in TRs)"));
+	write_ascii_matrix(report.appendDir(string("t")
+					    +num2str(cnum)+".txt"),
+			   melodat.get_mix().Column(cnum));
+	IChtml << "<A HREF=\"" << string("t")
+	  +num2str(cnum)+".txt" << "\"> ";
+	IChtml << "<img BORDER=0 SRC=\"" 
+	  +string("t")+num2str(cnum)+".png\"></A><p>" << endl;
+      }//time series plot
+      
+      {//plot frequency 
+	miscplot newplot;
+	int fact = int(std::pow(10.0,int(std::log10(float(melodat.get_mix().Nrows())))));
+      
+	if(opts.tr.value()>0.0)
+	  newplot.timeseries(melodat.get_fmix().Column(cnum).t(),
+			     report.appendDir(string("f")+
+					      num2str(cnum)+".png"),
+			     string("FFT of timecourse (in Hz / ") +num2str(fact)+")",
+			     fact/(opts.tr.value()*melodat.get_mix().Nrows()), 150,
+			     0,2);
+	else
+	  newplot.timeseries(melodat.get_fmix().Column(cnum).t(),
+			     report.appendDir(string("f")+
+					      num2str(cnum)+".png"),
+			     string(string("FFT of timecourse (in cycles); ")
+				  +"frequency(Hz)=cycles/("
+				  +num2str(melodat.get_mix().Nrows())
+				  +"* TR); period(s)=("
+				  +num2str(melodat.get_mix().Nrows())
+				  +"* TR)/cycles"));
+	write_ascii_matrix(report.appendDir(string("f")
+					    +num2str(cnum)+".txt"),
+			   melodat.get_mix().Column(cnum));
+	IChtml << "<A HREF=\"" << string("f")
+	  +num2str(cnum)+".txt" << "\"> ";
+	IChtml << "<img BORDER=0 SRC=\"" 
+	  +string("f")+num2str(cnum)+".png\"></A><p>" << endl;
+      }//frequency plot
+      
+      
+      if(mmodel.get_threshmaps().Storage()>0&&
+	 (mmodel.get_threshmaps().Ncols() == mmodel.get_data().Ncols())&&
+	 (mmodel.get_threshmaps().Nrows()>1))
+	{//Output other thresholded IC map
+	  
+	  for(int tctr=2; tctr<=mmodel.get_threshmaps().Nrows(); tctr++){
+	    tempVol.setmatrix(mmodel.get_threshmaps().Row(tctr),melodat.get_mask());
+	    volume<float> map1;
+	    volume<float> map2;
+	    map1 = threshold(tempVol[0],float(0.0), tempVol[0].max());
+	    map2 = threshold(tempVol[0],tempVol[0].min(), float(0.0));
+	    // 	save_volume(map,report.appendDir(mmodel.get_prefix()+"_thresh")
+	    //	    ,melodat.tempInfo);
+	    volume<float> newvol; 
+	    miscpic newpic;
+
+	    float map1min = (map1 + binarise(tempVol[0],tempVol[0].min(), 
+					     float(0.0)) * map1.max()).min();
+	    float map1max = map1.max();
+	    float map2min = map2.min();
+	    float map2max = (map2 + binarise(tempVol[0],float(0.0), 
+					     tempVol[0].max()) * map2.min()).max();
+	    
+	    //cerr << endl << map1min << " " << map1max << endl
+	    //  << map2min << " " << map2max << endl;
+
+	    //	    if(map1.max()-map1.min()>0.01)
+	      newpic.overlay(newvol, melodat.get_mean(), map1, map2, 
+			     melodat.get_mean().percentile(0.02),
+			     melodat.get_mean().percentile(0.98),
+			     map1min, map1max, map2max, map2min, 
+			     0, 0, &melodat.tempInfo);
+	    
+
+	    char instr[10000];
+	    
+	    //save_volume(newvol,report.appendDir(mmodel.get_prefix()+"rendered"),
+	    //      melodat.tempInfo);
+	    sprintf(instr," ");
+	    strcat(instr," -s 2");
+	    strcat(instr," -A 950 ");
+	    strcat(instr,string(report.appendDir(mmodel.get_prefix()+"_thresh"+
+						 num2str(tctr)+".png")).c_str());
+	    newpic.set_title(string("Component No. "+num2str(cnum)+
+				    " - thresholded IC map ("+
+				    num2str(tctr)+")  ")+
+			     mmodel.get_infstr(tctr));
+	    newpic.set_cbar(string("ysb"));
+	    //cerr << instr << endl;
+	    newpic.slicer(newvol, instr, &melodat.tempInfo); 
+
+	    IC_rep_det(mmodel, cnum, dim);
+	    IChtml << "<a href=\""+mmodel.get_prefix()+"_MM.html\">";
+	    IChtml << "<img BORDER=0 SRC=\""+mmodel.get_prefix()
+	      +"_thresh"+num2str(tctr)+".png\" ALT=\"MMfit\"></A><p>" << endl;
+	  }
+	}
+
+
+      { //finish IC page
+      IChtml<< "<HR><FONT SIZE=1>This page produced automatically by "
+	    << "<A HREF=\"http://www.fmrib.ox.ac.uk/fsl/melodic/index.html\"> MELODIC </A>" 
+	    << " - a part of <A HREF=\"http://www.fmrib.ox.ac.uk/fsl\">FSL - "
+	    << "FMRIB Software Library</A>.</FONT>" << endl
+	    << "</BODY></HTML>" << endl;
+      } //finish IC page
+      IC_rep_det(mmodel, cnum, dim);
+    }
+  }
+
+  void MelodicReport::IC_rep_det(MelGMix &mmodel, int cnum, int dim)
+  {
+    if( bool(opts.genreport.value()) ){
+
+      {//start IC2 page
+	IChtml2.setDir(report.getDir(),mmodel.get_prefix()+"_MM.html");
+	IChtml2 << "<HTML> " << endl
+		<< "<TITLE>Component " << num2str(cnum)
+		<< " Mixture Model fit </TITLE>" << endl
+		<< "<BODY BACKGROUND=\"file:" << getenv("FSLDIR") 
+		<< "/doc/images/fsl-bg.jpg\">" << endl 
+		<< "<hr><CENTER><H1>Component " << num2str(cnum)
+		<< " Mixture Model fit </H1>"<< endl;
+     
+	if(cnum>1)
+	  IChtml2 << "<a href=\"" << string("IC_")+num2str(cnum-1)
+		 <<"_MM.html\">previous</a>&nbsp;-&nbsp;";
+	
+	IChtml2 << "<a href=\""+ mmodel.get_prefix() + 
+	  ".html\">&nbsp;up&nbsp;to IC report&nbsp;</a>";
+
+	if(cnum<dim)
+	  IChtml2 << "&nbsp;-&nbsp;<a href=\"" << string("IC_")+num2str(cnum+1)
+		 <<"_MM.html\">next</a><p>";
+	IChtml2 << "<hr><p>" << endl;
+      }
+
+      volume4D<float> tempVol; 
+
+      if(melodat.get_IC().Storage()>0)
+      {//Output raw IC map
+
+	tempVol.setmatrix(melodat.get_IC().Row(cnum),
+			  melodat.get_mask());
+ 	volume<float> map1;
+	volume<float> map2;
+	map1 = threshold(tempVol[0],float(0.0), 
+			 tempVol[0].max());
+	map2 = threshold(tempVol[0],tempVol[0].min(), 
+			 float(-0.0));
+
+	volume<float> newvol; 
+	miscpic newpic;
+
+	//	float map1min = (map1 + binarise(tempVol[0],tempVol[0].min(), 
+	//		float(0.0)) * map1.max()).robustmin();
+	float map1max = map1.percentile(0.99);
+	float map2min = map2.percentile(0.01);
+	//float map2max = (map2 + binarise(tempVol[0],float(0.0), 
+	//		tempVol[0].max()) * map2.min()).robustmax();
+	
+ 	newpic.overlay(newvol, melodat.get_mean(), map1, map2, 
+ 		       float(0.0),
+ 		       float(0.0),
+ 		       float(0.01), map1max, float(-0.01), map2min, 
+ 		       0, 0, &melodat.tempInfo);
+
+ 	char instr[10000];
+	
+	//save_volume(newvol,report.appendDir(mmodel.get_prefix()+"rendered"),
+	//      melodat.tempInfo);
+ 	sprintf(instr," ");
+ 	strcat(instr," -s 2");
+ 	strcat(instr," -A 950 ");
+ 	strcat(instr,string(report.appendDir(mmodel.get_prefix()+
+ 					     ".png")).c_str());
+ 	newpic.set_title(string("Component No. "+num2str(cnum)+
+ 				" - raw Z transformed IC map (1 - 99 percentile)"));
+ 	newpic.set_cbar(string("ysb"));
+	
+ 	newpic.slicer(newvol, instr, &melodat.tempInfo);
+      }
+      IChtml2 << "<a href=\""+mmodel.get_prefix()+".html\">";
+      IChtml2 << "<img BORDER=0 SRC=\""+ mmodel.get_prefix()+
+	".png\"><A><p>" << endl;
+	
+      
+
+      if(mmodel.get_probmap().Storage()>0&&
+	 (mmodel.get_probmap().Ncols() == mmodel.get_data().Ncols())&&
+	 (mmodel.get_probmap().Nrows() == mmodel.get_data().Nrows()))
+	{//Output probmap  
+	  tempVol.setmatrix(mmodel.get_probmap(),melodat.get_mask());
+	  
+	  volume<float> map;
+	  map = tempVol[0];
+      
+	  volume<float> newvol; 
+	  miscpic newpic;
+
+	  newpic.overlay(newvol, melodat.get_mean(), map, map, 
+			 melodat.get_mean().percentile(0.02),
+			 melodat.get_mean().percentile(0.98),
+			 float(0.1), float(1.0), float(0.0), float(0.0),
+			 0, 0, &melodat.tempInfo);
+
+	  //newpic.set_minmax(float(0.0),float(0.0),float(0.0),
+	  //	    float(1.0),float(0.0),float(0.0));
+
+	  char instr[10000];
+
+	  sprintf(instr," ");
+	  strcat(instr,"-l render1 -s 2");
+	  strcat(instr," -A 950 ");
+	  strcat(instr,string(report.appendDir(mmodel.get_prefix()+
+					       "_prob.png")).c_str());      
+	  newpic.set_title(string("Component No. "+num2str(cnum)+
+ 			      " - Mixture Model probability map"));
+      
+	  newpic.set_cbar(string("y"));
+	  newpic.slicer(newvol, instr, &melodat.tempInfo); 
+
+// 	  {
+// 	    Log MMdetails;
+// 	    MMdetails.setDir(report.getDir(),mmodel.get_prefix()+"_MM.txt");
+// 	    MMdetails << mmodel.get_prefix() << " Mixture Model fit " 
+// 		      << endl << endl;
+// 	    MMdetails << " Means :  " << mmodel.get_means() << endl
+// 		      << " Vars  :  " << mmodel.get_vars()  << endl
+// 		      << " Prop. :  " << mmodel.get_pi()    << endl;
+// 	   // if(mmodel.get_type()=="GGM"){
+// 	   //   MMdetails << endl << " Gamma offset :  " 
+// 	//		<<  mmodel.get_offset() <<  endl;
+// 	 //   }
+// 	  }
+	  //  IChtml2 << "<A HREF=\"" +mmodel.get_prefix()+"_MM.txt\"> ";
+	  IChtml2 << "<a href=\""+mmodel.get_prefix()+".html\">";
+	  IChtml2 << "<img BORDER=0 SRC=\""+ mmodel.get_prefix()+
+	    "_prob.png\">" << endl;
+	  //	  IChtml2 << "</A>";
+	  IChtml2 << "</A><p>" << endl;
+	}
+
+      {//Output GGM/GMM fit
+	miscplot newplot;
+
+// 	cerr << endl << endl;
+//  	cerr << mmodel.get_means() << endl;
+//  	cerr << mmodel.get_vars()  << endl;
+//  	cerr << mmodel.get_pi()    << endl;
+
+	if(mmodel.get_type()=="GGM"){
+	  newplot.add_label("IC map histogram");
+	  newplot.add_label("full GGM fit");
+	  newplot.add_label("background Gaussian");
+	  newplot.add_label("Gamma distributions");
+	  newplot.gmmfit(mmodel.get_data().Row(1),
+			 mmodel.get_means(),
+			 mmodel.get_vars(),
+			 mmodel.get_pi(),
+			 report.appendDir(mmodel.get_prefix()+"_MMfit.png"),
+			 string(mmodel.get_prefix() +
+				" GGM("+num2str(mmodel.mixtures())+") fit"),
+			 true, float(0.0), float(2.0)); 
+
+	  //  newplot.histogram(mmodel.get_data().Row(1),
+	  //  report.appendDir(mmodel.get_prefix()+"_MMfit.png"),
+	  // 	     string(mmodel.get_prefix() +
+	  // 	     " GGM("+num2str(mmodel.mixtures())+") fit"));
+
+	  //, mmodel.get_offset());   
+	}
+	else{
+	  newplot.add_label("IC map histogram");
+	  newplot.add_label("full GMM fit");
+	  newplot.add_label("individual Gaussians");
+	  newplot.gmmfit(mmodel.get_data().Row(1),
+			 mmodel.get_means(),
+			 mmodel.get_vars(),
+			 mmodel.get_pi(),
+			 report.appendDir(mmodel.get_prefix()+"_MMfit.png"),
+			 string(mmodel.get_prefix() +
+				" GMM("+num2str(mmodel.mixtures())+") fit"), 
+			 false, float(0.0), float(2.0));
+   
+	}
+	//	cerr << "finish HTML2 " << endl;
+	IChtml2 << "<A HREF=\"" +mmodel.get_prefix()+"_MMfit_detail.png\"> ";
+	IChtml2 << "<img BORDER=0 SRC=\""+ mmodel.get_prefix()+
+	  "_MMfit.png\"></A><p>" << endl;
+      } //GGM/GMM plot
+      
+	  {
+	    IChtml2 << "<br> &nbsp;" << mmodel.get_prefix() 
+		    << " Mixture Model fit <br>" << endl
+		    << "<br> &nbsp; Means :  " << mmodel.get_means() << endl
+		    << "<br> &nbsp;  Vars  :  " << mmodel.get_vars()  << endl
+		    << "<br> &nbsp;  Prop. :  " << mmodel.get_pi()    << endl;
+	    // if(mmodel.get_type()=="GGM"){
+	    // 	     IChtml2 << "<br> &nbsp;   Gamma offset :  " 
+	    // 		     << mmodel.get_offset() << "<br><p>"<<  endl;
+	    // 	    }
+	  }
+
+      { //finish IC2 page
+	IChtml2<< "<HR><FONT SIZE=1>This page produced automatically by "
+	       << "<A HREF=\"http://www.fmrib.ox.ac.uk/fsl/melodic/index.html\"> MELODIC </A>" 
+	       << " - a part of <A HREF=\"http://www.fmrib.ox.ac.uk/fsl\">FSL - "
+	       << "FMRIB Software Library</A>.</FONT>" << endl
+	       << "</BODY></HTML>" << endl;
+      } //finish IC2 page
+    }
+  }
+
+
+  void MelodicReport::IC_simplerep(string prefix, int cnum, int dim)
+  {
+    if( bool(opts.genreport.value()) ){
+      addlink(prefix+".html",num2str(cnum));
+      IChtml.setDir(report.getDir(),prefix+".html");
+      
+      {//start IC page
+	
+	IChtml << "<HTML> " << endl
+	       << "<TITLE>MELODIC Component " << num2str(cnum)
+	       << "</TITLE>" << endl
+	       << "<BODY BACKGROUND=\"file:" << getenv("FSLDIR") 
+	       << "/doc/images/fsl-bg.jpg\">" << endl 
+	       << "<hr><CENTER><H1>MELODIC Component " << num2str(cnum)
+	       << "</H1>"<< endl;
+	
+	if(cnum>1)
+	  IChtml << "<a href=\"" << string("IC_")+num2str(cnum-1)
+		 <<".html\">previous</a>&nbsp;-&nbsp;";
+	
+	IChtml << "<a href=\"00index.html\">&nbsp;index&nbsp;</a>" ;
+	
+	if(cnum<dim)
+	  IChtml << "&nbsp;-&nbsp;<a href=\"" << string("IC_")+num2str(cnum+1)
+		 <<".html\">next</a><p>";
+	
+	IChtml << "<hr><p>" << endl;
+      }
+
+
+      volume4D<float> tempVol; 
+
+      if(melodat.get_IC().Storage()>0)
+      {//Output raw IC map
+
+	tempVol.setmatrix(melodat.get_IC().Row(cnum),
+			  melodat.get_mask());
+ 	volume<float> map1;
+	volume<float> map2;
+	map1 = threshold(tempVol[0],float(0.0), 
+			 tempVol[0].max());
+	map2 = threshold(tempVol[0],tempVol[0].min(), 
+			 float(-0.0));
+
+	volume<float> newvol; 
+	miscpic newpic;
+
+	//	float map1min = (map1 + binarise(tempVol[0],tempVol[0].min(), 
+	//		float(0.0)) * map1.max()).robustmin();
+	float map1max = map1.percentile(0.99);
+	float map2min = map2.percentile(0.01);
+	//float map2max = (map2 + binarise(tempVol[0],float(0.0), 
+	//		tempVol[0].max()) * map2.min()).robustmax();
+	
+ 	newpic.overlay(newvol, melodat.get_mean(), map1, map2, 
+ 		       float(0.0),
+ 		       float(0.0),
+ 		       float(0.01), map1max, float(-0.01), map2min, 
+ 		       0, 0, &melodat.tempInfo);
+
+ 	char instr[10000];
+	
+	//save_volume(newvol,report.appendDir(prefix+"rendered"),
+	//      melodat.tempInfo);
+ 	sprintf(instr," ");
+ 	strcat(instr," -s 2");
+ 	strcat(instr," -A 950 ");
+ 	strcat(instr,string(report.appendDir(prefix+
+ 					     ".png")).c_str());
+ 	newpic.set_title(string("Component No. "+num2str(cnum)+
+ 				" - raw Z transformed IC map (1 - 99 percentile)"));
+ 	newpic.set_cbar(string("ysb"));
+	
+ 	newpic.slicer(newvol, instr, &melodat.tempInfo);
+      }
+     
+      IChtml << "<img BORDER=0 SRC=\""+ prefix+
+	".png\"><p>" << endl;
+	
+      {//plot time course
+	miscplot newplot;
+	
+	if(opts.tr.value()>0.0)
+	  newplot.timeseries(melodat.get_mix().Column(cnum).t(),
+			     report.appendDir(string("t")+
+					      num2str(cnum)+".png"),
+			     string("Timecourse (in seconds); TR = ")+
+			     float2str(opts.tr.value(),0,2,0)+" s", 
+			     opts.tr.value(),150,4,1);
+	else
+	  newplot.timeseries(melodat.get_mix().Column(cnum).t(),
+			     report.appendDir(string("t")+
+					      num2str(cnum)+".png"),
+			     string("Timecourse (in TRs)"));
+	write_ascii_matrix(report.appendDir(string("t")
+					    +num2str(cnum)+".txt"),
+			   melodat.get_mix().Column(cnum));
+	IChtml << "<A HREF=\"" << string("t")
+	  +num2str(cnum)+".txt" << "\"> ";
+	IChtml << "<img BORDER=0 SRC=\"" 
+	  +string("t")+num2str(cnum)+".png\"></A><p>" << endl;
+      }//time series plot
+      
+      {//plot frequency 
+	miscplot newplot;
+	int fact = int(std::pow(10.0,
+		       int(std::log10(float(melodat.get_mix().Nrows())))));
+	
+	if(opts.tr.value()>0.0)
+	  newplot.timeseries(melodat.get_fmix().Column(cnum).t(),
+			     report.appendDir(string("f")+
+					      num2str(cnum)+".png"),
+			     string("FFT of timecourse (in Hz / ") +
+			     num2str(fact)+")",
+			     fact/(opts.tr.value()*melodat.get_mix().Nrows()),
+			     150,
+			     0,2);
+	else
+	  newplot.timeseries(melodat.get_fmix().Column(cnum).t(),
+			     report.appendDir(string("f")+
+					      num2str(cnum)+".png"),
+			     string(string("FFT of timecourse (in cycles); ")
+				    +"frequency(Hz)=cycles/("
+				    +num2str(melodat.get_mix().Nrows())
+				    +"* TR); period(s)=("
+				    +num2str(melodat.get_mix().Nrows())
+				    +"* TR)/cycles"));
+	write_ascii_matrix(report.appendDir(string("f")
+					    +num2str(cnum)+".txt"),
+			   melodat.get_mix().Column(cnum));
+	IChtml << "<A HREF=\"" << string("f")
+	  +num2str(cnum)+".txt" << "\"> ";
+	IChtml << "<img BORDER=0 SRC=\"" 
+	  +string("f")+num2str(cnum)+".png\"></A><p>" << endl;
+      }//frequency plot
+ 
+      { //finish IC page
+	IChtml<< "<HR><FONT SIZE=1>This page produced automatically by "
+	      << "<A HREF=\"http://www.fmrib.ox.ac.uk/fsl/melodic/index.html\"> MELODIC </A>" 
+	      << " - a part of <A HREF=\"http://www.fmrib.ox.ac.uk/fsl\">FSL - "
+	      << "FMRIB Software Library</A>.</FONT>" << endl
+	      << "</BODY></HTML>" << endl;
+      } //finish IC page 
+    } 
+  }
+
+  void MelodicReport::PPCA_rep(){
+    
+    {//plot time course
+      report << "<p> <H3>PCA estimates </H3> <p>" << endl;
+ 
+      Matrix what;
+      miscplot newplot;
+
+      what  = melodat.get_EV();
+      what &= melodat.get_EVP();
+
+      newplot.add_label("ordered Eigenvalues");
+      newplot.add_label("% of expl. variance");
+
+      if(melodat.get_PPCA().Storage()>0){
+	what = what.Columns(1,melodat.get_PPCA().Nrows());
+	what &= melodat.get_PPCA().t();
+	newplot.add_label("dim. estimate");
+      }
+
+      newplot.timeseries(what,
+			 report.appendDir("EVplot.png"),
+			 string("Eigenspectrum Analysis"), 
+			 0,450,4,0);
+
+      report << "<img BORDER=0 SRC=\"EVplot.png\"><p>" << endl;
+    }//time series plot
+  }
+}
diff --git a/melreport.h b/melreport.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb6b0512ba205f05af51e98f47b993924c50da46
--- /dev/null
+++ b/melreport.h
@@ -0,0 +1,248 @@
+/*  MELODIC - Multivariate exploratory linear optimized decomposition into 
+              independent components
+    
+    melreport.h - report generation
+
+    Christian F. Beckmann, FMRIB Image Analysis Group
+    
+    Copyright (C) 1999-2002 University of Oxford */
+
+/*  CCOPYRIGHT */
+
+
+#ifndef __MELODICREPORT_h
+#define __MELODICREPORT_h
+#include "newimageall.h"
+#include "log.h"
+#include "melpca.h"
+#include "meloptions.h"
+#include "meldata.h"
+#include "melgmix.h"
+#include "melodic.h"
+#include "newmatap.h"
+#include "newmatio.h"
+#include <time.h>
+#include <strstream>
+#include "miscplot.h"
+#include "miscpic.h"
+#include "options.h"
+
+using namespace Utilities;
+using namespace NEWIMAGE;
+using namespace MISCPLOT;
+using namespace MISCPIC;
+
+
+namespace Melodic{
+  
+  class MelodicReport
+    {
+    public:
+      MelodicReport(MelodicData &pmelodat, MelodicOptions &popts, Log &plogger):  
+	melodat(pmelodat),
+	opts(popts),
+	logger(plogger)
+	{
+	  if( bool(opts.genreport.value()) ){
+	  const time_t tmptime = time(NULL);
+ 
+	  report.makeDir(logger.appendDir("report"),"00index.html");
+	  report << "<HTML>" << endl << endl 
+		 << "<TITLE>MELODIC Report</TITLE>"<< endl <<endl
+		 << "<BODY BACKGROUND=\"file:" << getenv("FSLDIR") 
+		 << "/doc/images/fsl-bg.jpg\">" << endl 
+		 << endl << "<hr><CENTER> " << endl 
+		 << "<H1>MELODIC Report</H1>" 
+		 << endl
+		 << report.getDir() << "/" << report.getLogFileName() 
+		 << "<br>" << endl
+		 << ctime(&tmptime) << "<br>" << endl;
+	  /* ifstream reptest(string("../report.log").c_str()); */
+/* 	  if(!reptest) */
+/* 	    report << "<A HREF=\"/" << logger.appendDir("report.log")  */
+/* 		   << "\">report.log</A><br>" << endl; */
+/* 	  else */
+/* 	    report << "<A HREF=\"" << logger.appendDir("melodic.log")  */
+/* 		   << "\">melodic.log</A><br>" << endl; */
+/* 	  reptest.close(); */
+	  report << "</CENTER>" << endl << endl
+		 << "<hr><H2>Components:</H2> <p>" << endl << endl;
+	  }
+	}
+
+      ~MelodicReport(){
+	if( bool(opts.genreport.value()) ){
+	  report << "<HR><FONT SIZE=1>This page produced automatically by "
+		 << "<A HREF=\"http://www.fmrib.ox.ac.uk/fsl/melodic/index.html\"> MELODIC </A>" 
+		 << " - a part of <A HREF=\"http://www.fmrib.ox.ac.uk/fsl\">FSL - "
+		 << "FMRIB Software Library</A>.</FONT>" << endl
+		 << "</BODY></HTML>" << endl;
+	}
+      }
+
+      inline void analysistxt(){
+	if( bool(opts.genreport.value()) ){
+
+	  report << "<hr><h2>Analysis methods</h2> <p>"<<endl;
+	  report << "Analysis was carried out using MELODIC (Multivariate Exploratory Linear Decomposition into Independent Components) Version 2.00, part of FSL (FMRIB's Software Library, <A HREF=\"http://www.fmrib.ox.ac.uk/fsl/\">www.fmrib.ox.ac.uk/fsl</A>), an implementation for the estimation of a Probabilistic Independent Component Analysis model [Beckmann 2002]."<<endl;
+	  
+	  report << "The following melodic pre-processing was applied to the input data file: "<< endl;
+
+	  if(opts.use_mask.value())
+	    report << " masking of non-brain voxels;";
+	  
+	  report << " voxel-wise de-meaning of the data;" << endl;
+	  
+	  if(opts.varnorm.value())
+	    report << " normalisation of the voxel-wise variance; ";
+	  
+	  report << "<br>"<<endl;
+	  
+	  report << " Pre-processed data was whitened and projected into a " 
+		 << melodat.get_mix().Ncols()<< "-dimensional subspace using ";
+	  if(melodat.get_PPCA().Storage()>0){	    
+	    report << "probabilistic Principal Component Analysis where the number of dimensions was estimated using ";
+	    if(opts.pca_est.value() == string("lap"))
+	      report << "the Laplace approximation to the Bayesian evidence of the model order [Beckmann 2001, Minka 2000]. " << endl;
+	    else
+	      if(opts.pca_est.value() == string("bic"))
+		report << "the <em> Bayesian Information Criterion</em> (BIC) [Kass 1993]. " << endl;
+	      else
+		if(opts.pca_est.value() == string("mdl"))
+		  report << "<em> Minimum Description Length</em> (MDL) [Rissanen 1978]. " << endl;
+		else
+		  if(opts.pca_est.value() == string("aic"))
+		    report << "the <em> Akaike Information Criterion</em> (AIC) [Akaike 1969]. " << endl;
+		  else
+		    report << "a committee of approximations to Bayesian the model order [Beckmann 2001, Minka 2000]. " << endl;
+
+	  }	  
+	  else
+	    report << "Principal Component Analysis. ";
+	  
+	  
+	  report << " The whitened observations were decomposed into a set of time-courses and spatial maps by optimising for non-Gaussian spatial source distributions using a fixed-point iteration technique [Hyv&auml;rinen 1999]. " << endl;
+	  
+	  report << "Estimated Component maps were divided by the standard deviation of the residual noise";
+	  
+	  if(opts.perf_mm.value())
+	    report << " and thresholded by fitting a mixture model to the histogram of intensity values [Beckmann 2002]. <p>" << endl;
+	  else
+	    report <<".<p>" << endl;
+	 
+	  refstxt(); 
+	}
+      }
+
+      inline void refstxt(){
+
+	if( bool(opts.genreport.value()) ){
+	  report << "<h3>References</h3> <p>"<<endl;
+	  
+	  report << "[Hyv&auml;rinen 1999] A. Hyv&auml;rinen. Fast and Robust Fixed-Point Algorithms for Independent Component Analysis. IEEE Transactions on Neural Networks 10(3):626-634, 1999.<br> " << endl;
+ report << "[Beckmann 2002] C.F. Beckmann and S.M. Smith. Probabilistic Independent Component Analysis for FMRI. <A HREF=\"http://www.fmrib.ox.ac.uk/analysis/techrep/\">Technical Report TR02CB1</A>, FMRIB Analysis Group, 2002. <br>" << endl;
+
+	  /* if(opts.perf_mm.value()){ */
+/* 	    report << "[Bullmore 1996] E. Bullmore <em>et. al.</em> Statistical methods of estimation and inference for functional MR image analysis. Magnetic Resonance in Medicine, 35(2):261-177, 1996. <br>" << endl; */
+	   
+/* 	  } */
+
+	  if(melodat.get_PPCA().Storage()>0){	    
+	    report << "[Everson 2000] R. Everson and S. Roberts. Inferring the eigenvalues of covariance matrices from limited, noisy data. IEEE Trans Signal Processing, 48(7):2083-2091, 2000<br>"<<endl;
+	    report << "[Tipping 1999] M.E. Tipping and C.M.Bishop. Probabilistic Principal component analysis. J Royal Statistical Society B, 61(3), 1999. <br>" << endl;
+	    report << "[Beckmann 2001] C.F. Beckmann, J.A. Noble and S.M. Smith. Investigating the intrinsic dimensionality of FMRI data for ICA. In Seventh Int. Conf. on Functional Mapping of the Human Brain, 2001. <br>" << endl;
+	    if(opts.pca_est.value() == string("lap"))
+	      report << "[Minka 2000] T. Minka. Automatic choice of dimensionality for PCA. Technical Report 514, MIT Media Lab Vision and Modeling Group, 2000. <BR>"<< endl;
+	    else
+	      if(opts.pca_est.value() == string("bic"))
+		report << "[Kass 1995] R.E. Kass and A. E. Raftery. Bayes factors. Journal of the American Statistical Association, 90:733-795, 1995 <br>" << endl;
+	      else
+		if(opts.pca_est.value() == string("mdl"))
+		  report << "[Rissanen 1978]. J. Rissanen. Modelling by shortest data description. Automatica, 14:465-471, 1978. <br>" << endl;
+		else
+		  if(opts.pca_est.value() == string("aic"))
+		    report << "[Akaike 1974]. H. Akaike. A new look at statistical model identification. IEEE Transactions on Automatic Control, 19:716-723, 1974. <br>" << endl;
+		  else
+		    report << "[Minka 2000]. T. Minka. Automatic choice of dimensionality for PCA. Technical Report 514, MIT Media Lab Vision and Modeling Group, 2000. <BR>" << endl;
+
+	}
+	}
+      }
+
+      inline void addtxt(string what){
+	if( bool(opts.genreport.value()) ){
+	  report << what << endl;
+	}
+      }
+      
+      inline void addpar(string what){
+	if( bool(opts.genreport.value()) ){
+	  report << "<p>" << what << endl;
+	}
+      }
+      
+      inline void addlink(string where, string what){
+	if( bool(opts.genreport.value()) ){
+	  report << "<A HREF=\"" << where << "\"> " << what << "</A> ";
+	}
+      }
+
+      inline void addpic(string what, string link = ""){
+	if( bool(opts.genreport.value()) ){
+	  if( link.length() > 0)
+	    report << "<A HREF=\"" << link << "\"> ";
+
+	  report << "<img BORDER=0 SRC=\"" << what<< ".png\"><p>";
+	  if( link.length() > 0)
+	    report << "</A> ";
+	}
+      }
+
+      inline string getDir(){
+	return report.getDir();
+      }
+
+      void IC_rep(MelGMix &mmodel, int cnum, int dim);
+      void IC_simplerep(string prefix, int cnum, int dim);
+
+      void PPCA_rep();
+
+    private:
+      MelodicData &melodat;
+      MelodicOptions &opts;
+      Log &logger;
+      Log report;
+
+      Log IChtml;
+      Log IChtml2;
+
+      void IC_rep_det(MelGMix &mmodel, int cnum, int dim);
+      
+      string int2str(int n)
+	{
+	  ostrstream os;
+	  //    os.fill(' ');
+	  //    os.width(width);
+	  os.setf(ios::internal, ios::adjustfield);
+	  os << n << '\0';
+	  return os.str();
+	}
+      
+
+      string float2str(float f, int width, int prec, int scientif)
+	{
+	    ostrstream os;
+	    int redw = int(std::abs(std::log10(std::abs(f))))+1;
+	    if(width>0)
+	      os.width(width);
+	    if(scientif>0)
+	      os.setf(ios::scientific);
+	    os.precision(redw+std::abs(prec));
+	    os.setf(ios::internal, ios::adjustfield);
+	    os << f << '\0';
+	    return os.str();
+	}
+    };   
+
+}
+#endif
diff --git a/test.cc b/test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..26406598591ed445a9ccf69bf32975a322d4ed48
--- /dev/null
+++ b/test.cc
@@ -0,0 +1,19 @@
+#include <iostream.h>
+#include <iomanip>
+#include "miscplot.h"
+#include "miscpic.h"
+
+
+
+using namespace std;
+
+template<class T>
+int foo(const T& bar){
+  return 1;
+}
+
+int main(int argc, char *argv[])
+{
+  cerr << foo(int(5));
+  return 1;
+}