From 70978cde28e60291eeeff3259c07ab5a48c9fed9 Mon Sep 17 00:00:00 2001
From: Christian Beckmann <c.beckmann@donders.ru.nl>
Date: Mon, 30 Jul 2007 16:42:49 +0000
Subject: [PATCH] MELODIC 3.02 with local FDR

---
 fsl_regfilt.cc | 12 ++++----
 meldata.cc     | 83 ++++++++++++++++++++++++++++++++++++--------------
 meldata.h      |  7 ++---
 melgmix.cc     | 60 +++++++++++++++++++++++-------------
 melhlprfns.cc  | 16 +++++++---
 melhlprfns.h   |  1 +
 melodic.cc     |  2 ++
 melodic.h      | 19 ++++++++++--
 meloptions.cc  |  7 ++---
 meloptions.h   | 12 ++------
 melreport.cc   | 30 +++++++++++++-----
 melreport.h    |  1 +
 test.cc        |  8 +----
 13 files changed, 168 insertions(+), 90 deletions(-)

diff --git a/fsl_regfilt.cc b/fsl_regfilt.cc
index e8f4c1c..bb16d13 100644
--- a/fsl_regfilt.cc
+++ b/fsl_regfilt.cc
@@ -23,17 +23,17 @@ using namespace std;
 // printed out as the help or usage message
 
   string title=string("fsl_regfilt (Version 1.0)")+
-		string("\nCopyright(c) 2007, University of Oxford (Christian F. Beckmann)\n")+
-		string(" Data filtering by regressing out part of a design matrix\n \n")+
-		string(" using simple OLS regression on 4D images\n\n");
-  string examples="fsl_regfilt -i <input> -d <design> -f -o <out> [options]";
+		string("\n\n Copyright(c) 2007, University of Oxford (Christian F. Beckmann)\n")+
+		string(" Data de-noising by regressing out part of a design matrix\n")+
+		string(" using simple OLS regression on 4D images");
+  string examples="fsl_regfilt -i <input> -d <design> -f <components> -o <out> [options]";
 
 //Command line Options {
   Option<string> fnin(string("-i,--in"), string(""),
 		string("        input file name (4D image)"),
 		true, requires_argument);
   Option<string> fnout(string("-o,--out"), string(""),
-		string("       output file name for the filtered data"),
+		string("output file name for the filtered data"),
 		true, requires_argument);
   Option<string> fndesign(string("-d,--design"), string(""),
 		string("file name of the GLM design matrix (time courses)"),
@@ -42,7 +42,7 @@ using namespace std;
 		string("mask image file name"),
 		false, requires_argument);
 	Option<string> filter(string("-f,--filter"),string(""),
-		string("filter out part of the regression model"),
+		string("filter out part of the regression model, e.g. -f \"1,2,3\""),
 		true, requires_argument);
 	Option<bool> perfvn(string("--vn"),FALSE,
 		string("        perfrom variance-normalisation on data"),
diff --git a/meldata.cc b/meldata.cc
index 4cbb2ba..1cb150b 100644
--- a/meldata.cc
+++ b/meldata.cc
@@ -62,6 +62,9 @@ namespace Melodic{
       message(" done" << endl);
     }
 
+    meanC = mean(tmpData,2);
+		tmpData = remmean(tmpData,2);
+
     //convert to power spectra
     if(opts.pspec.value()){
       message("  Converting data to powerspectra ...");
@@ -69,8 +72,6 @@ namespace Melodic{
       message(" done" << endl);
     }
 	
-    meanC = mean(tmpData,2);
-
     //switch dimension in case temporal ICA is required
     if(opts.temporal.value()){
       message(string("  Switching dimensions for temporal ICA") << endl);
@@ -85,7 +86,7 @@ namespace Melodic{
     //variance - normalisation
     if(opts.varnorm.value()){
       message("  Normalising by voxel-wise variance ..."); 
-      stdDev = varnorm(tmpData,tmpData.Nrows(),3.1);
+      stdDev = varnorm(tmpData,tmpData.Nrows(),2.3);
       stdDevi = pow(stdDev,-1); 
       message(" done" << endl);
     }
@@ -171,38 +172,52 @@ namespace Melodic{
       opts.approach.set_T("tica");
 
     Matrix alldat, tmpData;
+//		bool tmpvarnorm = opts.varnorm.value();
+//		opts.varnorm.set_T(false);
     alldat = process_file(opts.inputfname.value().at(0), numfiles) / numfiles;
     for(int ctr = 1; ctr < numfiles; ctr++){
       tmpData = process_file(opts.inputfname.value().at(ctr), numfiles);
       alldat += tmpData / numfiles;
     }
 
+	//	opts.varnorm.set_T(tmpvarnorm);
+		//variance - normalisation
+	 // if(opts.varnorm.value()){
+	 //   message("  Normalising by voxel-wise variance ..."); 
+	 //   stdDev = varnorm(alldat,alldat.Nrows(),3.1);
+	 //   stdDevi = pow(stdDev,-1); 
+	 //   message(" done" << endl);
+	 // }
+
     //update mask
     if(opts.update_mask.value()){
-      message("  Excluding voxels with constant value ...");
-      update_mask(Mask, alldat);
+      message("Excluding voxels with constant value ...");
+   		//   update_mask(Mask, alldat); 
       message(" done" << endl);
     }
 
-    message(endl << "Initial data size : "<<alldat.Nrows()<<" x "<<alldat.Ncols()<<endl<<endl);
+		if(numfiles>1)
+    	message(endl << "Initial data size : "<<alldat.Nrows()<<" x "<<alldat.Ncols()<<endl<<endl);
 
     //estimate model order
-    ColumnVector PPCA;
+    ColumnVector tmpPPCA;
     RowVector AdjEV, PercEV;
     Matrix Corr, tmpE;
     int order;
 
+    order = ppca_dim(alldat, RXweight, tmpPPCA, AdjEV, PercEV, Corr, pcaE, pcaD, Resels, opts.pca_est.value());	  
+
     if(opts.pca_dim.value() == 0){
-      order = ppca_dim(alldat, RXweight, PPCA, AdjEV, PercEV, Corr, pcaE, pcaD, Resels, opts.pca_est.value());	  
-      calc_white(pcaE, pcaD, order, whiteMatrix, dewhiteMatrix); 
       opts.pca_dim.set_T(order);
-    }
-    else{
-      order = opts.pca_dim.value();
-      std_pca(alldat, RXweight, Corr, pcaE, pcaD);
-      calc_white(pcaE, pcaD, order, whiteMatrix, dewhiteMatrix);
-    }  
+			PPCA=tmpPPCA;
+  	}
+    order = opts.pca_dim.value();
+    calc_white(pcaE, pcaD, order, whiteMatrix, dewhiteMatrix);
    
+		EV = AdjEV;
+		EVP = PercEV;
+
+
     if(numfiles == 1){
       Data = alldat;
       Matrix tmp = Identity(Data.Nrows());
@@ -212,16 +227,19 @@ namespace Melodic{
 		else {
       for(int ctr = 0; ctr < numfiles; ctr++){
 				tmpData = process_file(opts.inputfname.value().at(ctr), numfiles);
-	
+//				if(opts.varnorm.value())
+//					varnorm(tmpData,stdDev);
+					
 				//  whiten (separate / joint) 
 				if(!opts.joined_whiten.value()){	  
+					message("  Individual whitening in a " << order << " dimensional subspace " << endl);
       	  std_pca(tmpData, RXweight, Corr, pcaE, pcaD);
 	  			calc_white(pcaE, pcaD, order, whiteMatrix, dewhiteMatrix);
 				}
 				tmpData = whiteMatrix * tmpData;
 				DWM.push_back(dewhiteMatrix);
 				WM.push_back(whiteMatrix);
-
+				
 				//concatenate Data
 				if(Data.Storage() == 0)
 	  			Data = tmpData;
@@ -450,10 +468,21 @@ namespace Melodic{
     }while(p);
     message(endl);
     Matrix newData;
+
+		outMsize("DATA",Data);
+		outMsize("IC",IC);
+		outMsize("noiseIC",noiseIC);
+		outMsize("noiseMix",noiseMix);
+		outMsize("meanR",meanR);
+		outMsize("meanC",meanC);
+
     newData = Data - noiseMix * noiseIC.t();
-    newData = newData + meanC*ones(1,newData.Ncols());
-    newData = newData + ones(newData.Nrows(),1)*meanR;
+		if(meanC.Storage()>0)
+    	newData = newData + meanC*ones(1,newData.Ncols());
+		if(meanR.Storage()>0)
+    	newData = newData + ones(newData.Nrows(),1)*meanR;
     
+		cerr << " HERE REMOVE " << endl;
     volume4D<float> tmp;
     read_volume4D(tmp,opts.inputfname.value().at(0)); 
     tmp.setmatrix(newData,Mask);
@@ -699,14 +728,23 @@ namespace Melodic{
 		//flip IC maps to be positive (on average)
 		//flip Subject/Session modes to be positive (on average)
 		//have time courses accordingly
+
     for(int ctr_i = 1; ctr_i <= numComp; ctr_i++)
-      if(IC.Row(ctr_i).Sum()<0)
+      if(IC.Row(ctr_i).MaximumAbsoluteValue()>IC.Row(ctr_i).Maximum()){
 				flipres(ctr_i);	
-				
-    // re-order wrt standard deviation of IC maps
+			}
     message("Sorting IC maps" << endl);  
     Matrix tmpscales, tmpICrow, tmpMIXcol;
+		if(numfiles > 1){
+			set_TSmode();
+			Matrix allmodes = Smodes.at(0);
+			for(int ctr = 1; ctr < (int)Smodes.size();++ctr)
+				allmodes |= Smodes.at(ctr);
+			tmpscales = mean(allmodes).t();	
+		} else {
+    // re-order wrt standard deviation of IC maps 
     tmpscales = stdev(IC,2);
+		}
     ICstats = tmpscales;
 
     double max_val, min_val = tmpscales.Minimum()-1;
@@ -762,7 +800,6 @@ namespace Melodic{
     
     mixFFT=calc_FFT(expand_mix(), opts.logPower.value());
     unmixMatrix = pinv(mixMatrix);
-
   }
 
   void MelodicData::status(const string &txt)
diff --git a/meldata.h b/meldata.h
index 623db92..809389e 100644
--- a/meldata.h
+++ b/meldata.h
@@ -158,8 +158,8 @@ namespace Melodic{
       inline void set_EV(Matrix& Arg) {if(EV.Storage()==0)
 																				 EV = Arg;}
 
-      inline Matrix& get_PPCA() {return PPCA;}
-      inline void set_PPCA(Matrix& Arg) {if(PPCA.Storage()==0)
+      inline ColumnVector& get_PPCA() {return PPCA;}
+      inline void set_PPCA(ColumnVector& Arg) {if(PPCA.Storage()==0)
 																					 PPCA = Arg;}
 
       inline Matrix& get_stdNoisei() {return stdNoisei;}
@@ -180,7 +180,6 @@ namespace Melodic{
 				mixMatrix.Column(num) = -mixMatrix.Column(num);
 				mixFFT=calc_FFT(mixMatrix);
 				unmixMatrix = pinv(mixMatrix);
-
         if(ICstats.Storage()>0&&ICstats.Ncols()>3){
 	  			double tmp;
 	  			tmp = ICstats(num,3);
@@ -225,7 +224,7 @@ namespace Melodic{
       volume<float> background;
 
       Matrix Data;
-      Matrix PPCA;
+      ColumnVector PPCA;
       Matrix jointCC;
       
       bool after_mm;
diff --git a/melgmix.cc b/melgmix.cc
index 89ed1e5..bbe13dc 100644
--- a/melgmix.cc
+++ b/melgmix.cc
@@ -103,7 +103,7 @@ namespace Melodic{
 
     char *p;
     char t[1024];
-    const char *discard = ", [];{(})abcdeghijklmopqstuvwxyzABCEGHIJKLMNOQSTUVWXYZ~!@#$%^&*_-=+|\':></?";
+    const char *discard = ", [];{(})abceghijklmoqstuvwxyzABCEGHIJKLMNOQSTUVWXYZ~!@#$%^&*_-=+|\':></?";
 
     strcpy(t, tmpstr.c_str());
     p=strtok(t,discard);
@@ -146,7 +146,7 @@ namespace Melodic{
     if(fdr.Storage()>0){levls = levls | fdr;}
     if(nht.Storage()>0){levls = levls | nht;}
     
-    //cerr << " levles : " << levls << endl << endl;
+  //  cerr << " levles : " << levls << endl << endl;
     Res = threshold(data, levls);
     set_threshmaps(Res);
 
@@ -186,10 +186,10 @@ namespace Melodic{
 				add_infstr(" alternative hypothesis test at p > "+float2str(tests(1,4+next),0,2,false));
 				Matrix tmpNull;
 				tmpNull = dat;
-	
+/*	
 				float cutoffpos, cutoffneg;
-				cutoffpos = means(1)+6*std::sqrt(vars(1)+0.0000001);
-				cutoffneg = means(1)-6*std::sqrt(vars(1)+0.0000001);
+				cutoffpos = means(1)+100*std::sqrt(vars(1)+0.0000001);
+				cutoffneg = means(1)-100*std::sqrt(vars(1)+0.0000001);
 	
 				for(int ctr=1; ctr<=tmpNull.Ncols(); ctr++)
 	  			if( probmap(ctr) > tests(1,4+next) ){
@@ -202,7 +202,12 @@ namespace Melodic{
 				for(int ctr=1; ctr<=tmpNull.Ncols(); ctr++)
 	  			if( (dat(ctr) > cutoffneg) && (dat(ctr) < cutoffpos) )
 	    			tmpNull(1,ctr)=0.0;
-
+*/
+				for(int ctr=1; ctr<=tmpNull.Ncols(); ctr++)
+					if( probmap(ctr) < tests(1,4+next) ){	
+						tmpNull(1,ctr)=0.0;
+						}
+							
 				Res.Row(next) << tmpNull;
       }
       next++;
@@ -225,23 +230,36 @@ namespace Melodic{
 
     for(int ctr1=1;ctr1<=tests(1,3);ctr1++){
       if(4+next <=tests.Ncols()){
-				cerr << " false discovery rate " << tests(1,4+next)<< endl;
-				Matrix newcdf(Nprobs);
-				for(int ctr=1;ctr<=Nprobs.Nrows();ctr++){
-	  			newcdf.Row(ctr) << 1-props(ctr)*normcdf(dat,means(ctr),vars(ctr));
-				}
-				Matrix tmpNull;
-				tmpNull = newcdf.Row(1);
-				Matrix tmpAlt;
-				tmpAlt = sum(newcdf.Rows(2,Nprobs.Nrows()),1);
-				Matrix tmp;
-				tmp = dat; 
-				for(int ctr=1; ctr<=tmp.Ncols(); ctr++)
-	  			if(tmpNull(1,ctr) > (1-tests(1,4+next)) * tmpAlt(1,ctr))
-	    			tmp(1,ctr)=0.0;
+				message("   Local False Discovery Rate control at p < " << tests(1,4+next) << endl);
+				add_infstr(" Local False Discovery Rate control at p < "+float2str(tests(1,4+next),0,2,false));
+				RowVector tmp=dat;
+				SortAscending(tmp);
+				RowVector newcdf(tmp);
+	  		newcdf << normcdf(tmp,means(1),vars(1));
+				write_ascii_matrix(dat,"dat");
+				write_ascii_matrix(newcdf,"newcdf");
+				write_ascii_matrix(tmp,"tmpmat");
+				float thrp = tmp(tmp.Ncols())+0.01;
+				float thrn = tmp(1)-0.01;
+				int ctr=tmp.Ncols();
+				do{
+					thrp = tmp(ctr);
+					ctr-=1;
+				}while(ctr>0 && ( (1.0-newcdf(ctr))*tmp.Ncols() < (tests(1,4+next)*(tmp.Ncols()-ctr+1))   ));
+
+				ctr=1;
+				do{
+					thrn = tmp(ctr);
+					ctr+=1;
+				}while(ctr<=tmp.Ncols() && ( (newcdf(ctr))*tmp.Ncols() < (tests(1,4+next)*ctr)));
+
+				tmp = dat;
+				for(ctr=1; ctr<=tmp.Ncols();ctr++)
+					if((tmp(ctr) < thrp)&&(tmp(ctr) > thrn))
+					tmp(ctr) = 0.0;
 				Res.Row(next) << tmp;
-				next++;
       }
+			next++;
     }
 
     for(int ctr1=1;ctr1<=tests(1,4);ctr1++){
diff --git a/melhlprfns.cc b/melhlprfns.cc
index 05a73d4..eaa1d0e 100644
--- a/melhlprfns.cc
+++ b/melhlprfns.cc
@@ -121,6 +121,12 @@ namespace Melodic{
     return out;
   }  //RowVector varnorm
 
+	void varnorm(Matrix& in, RowVector& vars)
+	{
+		Matrix tmp;
+		in = SP(in,pow(ones(in.Nrows(),1) * vars,-1));
+	}
+	
   RowVector varnorm(Matrix& in, Matrix& Corr, int dim, float level)
   { 
     Matrix tmpE, white, dewhite;
@@ -132,15 +138,15 @@ namespace Melodic{
     Matrix ws = white * in;
     for(int ctr1 = 1; ctr1<=ws.Ncols(); ctr1++)
       for(int ctr2 = 1; ctr2<=ws.Nrows(); ctr2++)
-	if(std::abs(ws(ctr2,ctr1)) < level)
-	  ws(ctr2,ctr1)=0;
+				if(std::abs(ws(ctr2,ctr1)) < level)
+	  			ws(ctr2,ctr1)=0;
     tmpD = stdev(in - dewhite*ws);
     for(int ctr1 = 1; ctr1<=tmpD.Ncols(); ctr1++)
       if(tmpD(ctr1) < 0.01){
-	tmpD(ctr1) = 1.0;
-	in.Column(ctr1) = 0.0*in.Column(ctr1);
+				tmpD(ctr1) = 1.0;
+				in.Column(ctr1) = 0.0*in.Column(ctr1);
       }
-    in = SP(in,pow(ones(in.Nrows(),1) * tmpD,-1));
+	  varnorm(in,tmpD);
     return tmpD;
   }  //RowVector varnorm
 
diff --git a/melhlprfns.h b/melhlprfns.h
index 6f8d5a4..eb1327e 100644
--- a/melhlprfns.h
+++ b/melhlprfns.h
@@ -29,6 +29,7 @@ namespace Melodic{
   Matrix convert_to_pbsc(Matrix& Mat);
 
   RowVector varnorm(Matrix& in, int dim = 30, float level = 1.6);
+	void varnorm(Matrix& in, RowVector& vars);
   RowVector varnorm(Matrix& in, Matrix& Corr, int dim = 30, float level = 1.6);
 
   Matrix SP2(const Matrix& in, const Matrix& weights, bool econ = 0);
diff --git a/melodic.cc b/melodic.cc
index 70808e5..4837a28 100644
--- a/melodic.cc
+++ b/melodic.cc
@@ -159,6 +159,8 @@ int main(int argc, char *argv[]){
 
 				if( bool(opts.genreport.value()) ){
 	  			report.analysistxt();
+					if(melodat.get_numfiles()>1)
+						report.Smode_rep();
 	  			report.PPCA_rep();
 				}
 
diff --git a/melodic.h b/melodic.h
index 1d47215..949a344 100644
--- a/melodic.h
+++ b/melodic.h
@@ -34,8 +34,23 @@
 
 namespace Melodic{
 
-const string version = "3.0 beta";  
-
+const string version = "3.02";  
+
+// The two strings below specify the title and example usage that is	
+// printed out as the help or usage message
+const string title=string("MELODIC (Version ")+version+")"+
+		string("\n Multivariate Exploratory Linear Optimised Decomposition into Independent Components\n")+
+		string(" Copyright(c) 2007, University of Oxford (Christian F. Beckmann)");
+
+const string usageexmpl=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 ");
 }
 
 #endif
diff --git a/meloptions.cc b/meloptions.cc
index 5742c17..758f163 100644
--- a/meloptions.cc
+++ b/meloptions.cc
@@ -200,7 +200,7 @@ MelodicOptions* MelodicOptions::gopt = NULL;
     }
 
 void MelodicOptions::print_usage(int argc, char *argv[]){
-  print_copyright();
+ // print_copyright();
   options.usage();
   /* cout << "Usage: " << argv[0] << " ";
     Have own usage output here
@@ -208,13 +208,12 @@ void MelodicOptions::print_usage(int argc, char *argv[]){
 }
 
 void MelodicOptions::print_version(){
-  cout << endl <<"MELODIC Version " << version;
+	cout << endl <<"MELODIC Version " << version << endl;
   cout.flush();
 }
 
 void MelodicOptions::print_copyright(){
-  print_version();
-  cout << endl << "Copyright (C) 1999-2007 University of Oxford " << endl;
+  cout << endl << title << endl;
   cout.flush();
 }
 
diff --git a/meloptions.h b/meloptions.h
index 3ca7a3f..1a6913b 100644
--- a/meloptions.h
+++ b/meloptions.h
@@ -133,6 +133,7 @@ class MelodicOptions {
   	void print_version(); 
   	void print_copyright();
   	void status();
+
 };
 
  inline MelodicOptions& MelodicOptions::getInstance(){
@@ -333,16 +334,7 @@ class MelodicOptions {
 	   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 "))
+   options(title, usageexmpl)
    {
      try {  
       options.add(logdir);
diff --git a/melreport.cc b/melreport.cc
index a61db40..fc819f0 100644
--- a/melreport.cc
+++ b/melreport.cc
@@ -73,11 +73,11 @@ namespace Melodic{
 				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(0.0)) * map1.max()).min(),float(0.001));
+			  float map1max = std::max(map1.max(),float(0.001));
+				float map2min = std::min(map2.min(),float(-0.001));
 				float map2max = std::min((map2 + binarise(tempVol[0],float(0.0), 
-						  		tempVol[0].max()) * map2.min()).max(),float(-0.01));
+						  		tempVol[0].max()) * map2.min()).max(),float(-0.001));
 	
     		newpic.overlay(newvol, melodat.get_bg(), map1, map2, 
 		       		melodat.get_bg().percentile(0.02),
@@ -96,12 +96,11 @@ namespace Melodic{
 				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)
+				if((std::abs(map1.max()-map1.min())>0.01) || (std::abs(map2.max()-map2.min())>0.01))
 	  			newpic.slicer(newvol, instr, &melodat.tempInfo); 
 				else
-	  			newpic.slicer(map1, instr, &melodat.tempInfo);
+	  			newpic.slicer(newvol, instr, &melodat.tempInfo);
 	  		IChtml << "<a href=\""+mmodel.get_prefix()+"_MM.html\">";
 	    	IChtml << "<img BORDER=0 SRC=\""+mmodel.get_prefix()
 	    		+"_thresh.png\" ALT=\"MMfit\"></A><p>" << endl;
@@ -489,7 +488,7 @@ namespace Melodic{
 			 		report.appendDir(mmodel.get_prefix()+"_MMfit.png"),
 			 		string(mmodel.get_prefix() +
 					" GGM("+num2str(mmodel.mixtures())+") fit"),
-			 		true, float(0.0), float(2.0)); 
+			 		true, float(0.0), float(0.0)); 
    
 			}
 				else{
@@ -693,6 +692,7 @@ namespace Melodic{
 				newplot.add_label("dim. estimate");
       }
 
+			newplot.grid_swapdefault();
       newplot.timeseries(what,
 			 	report.appendDir("EVplot.png"),
 			 	string("Eigenspectrum Analysis"), 
@@ -701,4 +701,18 @@ namespace Melodic{
       report << "<img BORDER=0 SRC=\"EVplot.png\"><p>" << endl;
     }//time series plot
   }
+	
+	void MelodicReport::Smode_rep(){
+		report << "<p> <H3>TICA Subject/Session modes </H3> <p>" << endl;
+		miscplot newplot;
+		Matrix allmodes = melodat.get_Smodes().at(0);
+		for(int ctr = 1; ctr < (int)melodat.get_Smodes().size();++ctr)
+			allmodes |= melodat.get_Smodes().at(ctr);
+		
+		newplot.set_xysize(100+30*allmodes.Ncols(),300);
+		newplot.boxplot(allmodes,report.appendDir(string("bp_Smodes.png")),
+    string("Subject/Session modes"));
+
+  	report << "<img BORDER=0 SRC=\"bp_Smodes.png\"><p>" << endl;
+	}
 }
diff --git a/melreport.h b/melreport.h
index 68662e9..dff72ce 100644
--- a/melreport.h
+++ b/melreport.h
@@ -186,6 +186,7 @@ namespace Melodic{
       void IC_simplerep(string prefix, int cnum, int dim);
 
       void PPCA_rep();
+      void Smode_rep();
 
     private:
       MelodicData &melodat;
diff --git a/test.cc b/test.cc
index d0e0165..33ff5a6 100644
--- a/test.cc
+++ b/test.cc
@@ -80,14 +80,8 @@ int do_work(int argc, char* argv[]) {
 
 	cerr << weights << endl <<endl << Rows << endl;
 
-	cerr << SP(weights,pow(Rows,-1)) << endl;
+	cerr << remmean(SP(weights,pow(Rows,-1))) << endl;
 	
-	vector<int> vi;
-	for(int ctr=1;ctr<=5;ctr++)
-		vi.push_back(ctr);
-		
-	for(int ctr=0;ctr<5;ctr++)
-		cerr << " vi["<<ctr<<"] = " <<vi.at(ctr)<<endl; 
 	
 	return 0;
 }
-- 
GitLab