Skip to content
Snippets Groups Projects
melreport.h 14 KiB
Newer Older
Paul McCarthy's avatar
Paul McCarthy committed
/*  MELODIC - Multivariate exploratory linear optimized decomposition into
Mark Jenkinson's avatar
Mark Jenkinson committed
              independent components
Paul McCarthy's avatar
Paul McCarthy committed

Mark Jenkinson's avatar
Mark Jenkinson committed
    melreport.h - report generation

    Christian F. Beckmann, FMRIB Analysis Group
Paul McCarthy's avatar
Paul McCarthy committed

    Copyright (C) 1999-2013 University of Oxford */
Mark Jenkinson's avatar
Mark Jenkinson committed

/*  CCOPYRIGHT */
Mark Jenkinson's avatar
Mark Jenkinson committed


#ifndef __MELODICREPORT_h
#define __MELODICREPORT_h

#include <time.h>
#include <strstream>
#include "armawrap/newmat.h"
#include "libvis/miscplot.h"
#include "libvis/miscpic.h"
#include "utils/options.h"
#include "newimage/newimageall.h"
#include "utils/log.h"
Mark Jenkinson's avatar
Mark Jenkinson committed
#include "melpca.h"
#include "meloptions.h"
#include "meldata.h"
#include "melgmix.h"
#include "melodic.h"


namespace Melodic{
Paul McCarthy's avatar
Paul McCarthy committed

Christian Beckmann's avatar
Christian Beckmann committed
  class MelodicReport{
  public:
    MelodicReport(MelodicData &pmelodat, MelodicOptions &popts, Utilities::Log &plogger):
      melodat(pmelodat),
      opts(popts),
      logger(plogger){
      if( bool(opts.genreport.value()) ){
        const time_t tmptime = time(NULL);
        system(("mkdir "+ logger.appendDir("report") + " 2>/dev/null").c_str());
        report.setDir(logger.appendDir("report"),"00index.html",true,false,std::ios::out);
        report << "<HTML><HEAD><link REL=stylesheet TYPE=text/css href=file:" +
          (std::string) getenv("FSLDIR") +"/doc/fsl.css>"
               << "<TITLE>MELODIC report</TITLE></HEAD><BODY>"
               << std::endl <<std::endl;
        loghtml.setDir(report.getDir(),"log.html");
        loghtml << "<HTML><HEAD><link REL=stylesheet TYPE=text/css href=file:" +
          (std::string) getenv("FSLDIR") +"/doc/fsl.css>"
                << "<TITLE>MELODIC report</TITLE></HEAD><BODY>"
                << std::endl <<std::endl;
        navigator.setDir(report.getDir(),"nav.html");
        head.setDir(report.getDir(),"head.html");
        navigator << "<link REL=stylesheet TYPE=text/css href=file:"+
          (std::string) getenv("FSLDIR") +"/doc/fsl.css>"  << std::endl;
        head << "<link REL=stylesheet TYPE=text/css href=file:"+
          (std::string) getenv("FSLDIR") +"/doc/fsl.css>"  << std::endl;
        head  <<"<TABLE BORDER=0><TR>" << std::endl
              <<" <TD ALIGN=CENTER WIDTH=100%>"<< std::endl
              <<"<TABLE BORDER=0>"<< std::endl
              <<"<tr><td align=center><font size=+3><b>MELODIC Report</b>"<< std::endl
              <<"</font><tr><td valign=center align=center> <p>"<< std::endl
              << report.getDir() << "/" << report.getLogFileName() << "<br>"
              << ctime(&tmptime) << "</tr>"<< std::endl
              <<"<tr valign=bottom><td align=center>"<< std::endl
              << "</tr></table>" << std::endl
              << "<TD ALIGN=RIGHT>" << std::endl
              << "<a href=http://www.fmrib.ox.ac.uk/fsl target=_top>" << std::endl
              << "<IMG BORDER=0 SRC=file:"<< getenv("FSLDIR")
              << "/doc/images/fsl-logo-big.jpg WIDTH=165></a>" << std::endl
              << "</TD>"<<std::endl<<"</TR></TABLE> <hr>"<<std::endl;
        if(opts.guireport.value()==""){
          report <<"<OBJECT data=head.html></OBJECT>" <<  std::endl;
          loghtml <<"<OBJECT data=head.html></OBJECT>" <<  std::endl;
        }else{
          report <<"<OBJECT data="<<opts.guireport.value()<< "></OBJECT>"<< std::endl;
          loghtml <<"<OBJECT data="<<opts.guireport.value()<< "></OBJECT>"<< std::endl;
        }
        report << "<IFRAME  height=80px width=100% src=nav.html frameborder=0></IFRAME><p>"<< std::endl;
        loghtml << "<IFRAME  height=100px width=100% src=nav.html frameborder=0></IFRAME><p>"
                <<"<IFRAME width=100% height=100% src=\"../log.txt\"></IFRAME>" <<std::endl;
        navigator <<"<CENTER><TABLE BORDER=0><TR>" << std::endl
                  <<"<TD ALIGN=CENTER WIDTH=100%><FONT SIZE=-1>"<<std::endl
                  <<"<A HREF=\"00index.html\" target=\"_top\">Main</A>&nbsp;-&nbsp;";
        if(opts.guireport.value()=="")
          navigator << "<A HREF=\"log.html\" target=\"_top\">Log</A>&nbsp;-&nbsp;";
        navigator	<<"Components: ";
        navigator.flush();
        axials_instr = opts.axials_str.value();
      }
    }

    ~MelodicReport(){
      if( bool(opts.genreport.value()) ){
        report << "<HR><CENTER><FONT SIZE=1>This page produced automatically by "
               << "<A HREF=\"http://www.fmrib.ox.ac.uk/fsl/melodic/index.html\"> MELODIC</A> Version "
               << version << " - a part of <A HREF=\"http://www.fmrib.ox.ac.uk/fsl\">FSL - "
               << "FMRIB Software Library</A>.</FONT></CENTER>" << std::endl
               << "</BODY></HTML>" <<std::endl;
        loghtml << "<HR><CENTER><FONT SIZE=1>This page produced automatically by "
Paul McCarthy's avatar
Paul McCarthy committed
		      	<< "<A HREF=\"http://www.fmrib.ox.ac.uk/fsl/melodic/index.html\"> MELODIC</A> Version "
Christian Beckmann's avatar
Christian Beckmann committed
		      	<< version << " - a part of <A HREF=\"http://www.fmrib.ox.ac.uk/fsl\">FSL - "
		      	<< "FMRIB Software Library</A>.</FONT></CENTER>" << std::endl
		      	<< "</BODY></HTML>" <<std::endl;
        navigator << "</FONT></TD>"<<std::endl<<"</TR></TABLE></CENTER><hr>" <<std::endl;
Mark Jenkinson's avatar
Mark Jenkinson committed
      }
    }

    inline void analysistxt(){
      if( bool(opts.genreport.value()) ){

        report << "<b>Analysis methods</b> <br>"<<std::endl;
        report << "Analysis was carried out using ";

        if(opts.approach.value() != std::string("tica"))
          report << "Probabilistic Independent Component Analysis"
                 <<" [Beckmann 2004] as implemented in "<<std::endl;
        else
          report << "Tensorial Independent Component Analysis "
                 <<"[Beckmann 2005] as implemented in "<< std::endl;

        report << " MELODIC (Multivariate"
               <<" Exploratory Linear Decomposition into Independent Components)"
               <<" Version "<< version <<", part of FSL (FMRIB's Software"
               <<" Library, <A HREF=\"http://www.fmrib.ox.ac.uk/fsl/\">"
               <<"www.fmrib.ox.ac.uk/fsl</A>).<br>";

        report << "The following data pre-processing was applied to"
               <<" the input data: "<< std::endl;

        if(opts.use_mask.value())
          report << " masking of non-brain voxels;";

        report << " voxel-wise de-meaning of the data;" << std::endl;

        if(opts.varnorm.value())
          report << " normalisation of the voxel-wise variance; ";
        if(opts.pbsc.value())
          report << " conversion to %BOLD signal change; ";
        report << "<br>"<<std::endl;

        report << " Pre-processed data were 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() == std::string("lap"))
            report << "the Laplace approximation to the Bayesian"
                   <<" evidence of the model order [Minka 2000, Beckmann 2004]. " << std::endl;
          else
            if(opts.pca_est.value() == std::string("bic"))
              report << "the <em> Bayesian Information Criterion</em>"
                     <<" (BIC) [Kass 1993]. " << std::endl;
            else
              if(opts.pca_est.value() == std::string("mdl"))
                report << "<em> Minimum Description Length</em> (MDL)"
                       <<" [Rissanen 1978]. " << std::endl;
              else
                if(opts.pca_est.value() == std::string("aic"))
                  report << "the <em> Akaike Information Criterion</em>"
                         <<" (AIC) [Akaike 1969]. " << std::endl;
                else
                  report << " approximations to Bayesian the"
                         <<" model order [Beckmann 2004]. " << std::endl;
        }
        else
          report << "Principal Component Analysis. ";

        report << " <BR>The whitened observations were decomposed into "
               <<" sets of vectors which describe signal variation across"
               <<" the temporal domain (time-courses)";
        if(opts.approach.value() == std::string("tica") ||
           opts.approach.value() == std::string("concat"))
          report << ", the session/subject domain ";
        report <<"  and across the spatial domain (maps) by optimising for"
               <<" non-Gaussian spatial source distributions using a"
               <<" fixed-point iteration technique [Hyv&auml;rinen 1999]. " << std::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 2004]. <p>" << std::endl;
        else
          report <<".<p>" << std::endl;

        refstxt();
Mark Jenkinson's avatar
Mark Jenkinson committed
      }
    }

    inline void refstxt(){
      if( bool(opts.genreport.value()) ){
        report << "<b>References</b> <br>"<<std::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> " << std::endl;
        report << "[Beckmann 2004] C.F. Beckmann and S.M. Smith."
               <<" Probabilistic Independent Component Analysis for Functional"
               <<" Magnetic Resonance Imaging. IEEE Transactions on Medical"
               <<" Imaging 23(2):137-152 2004. <br>" << std::endl;
        if(opts.approach.value() == std::string("tica") ||
           opts.approach.value() == std::string("concat") )
          report << "[Beckmann 2005] C.F. Beckmann and S.M. Smith."
                 <<" Tensorial extensions of independent component analysis"
                 << " for multisubject FMRI analysis. Neuroimage "
                 << " 25(1):294-311 2005. <br>";

        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>"<<std::endl;
          report << "[Tipping 1999] M.E. Tipping and C.M.Bishop."
                 <<" Probabilistic Principal component analysis. J Royal"
                 <<" Statistical Society B, 61(3), 1999. <br>" << std::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>" << std::endl;
          if(opts.pca_est.value() == std::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>"<< std::endl;
          else
            if(opts.pca_est.value() == std::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>" << std::endl;
            else
              if(opts.pca_est.value() == std::string("mdl"))
                report << "[Rissanen 1978]. J. Rissanen. Modelling by"
                       <<" shortest data description. Automatica,"
                       <<" 14:465-471, 1978. <br>" << std::endl;
              else
                if(opts.pca_est.value() == std::string("aic"))
                  report << "[Akaike 1974]. H. Akaike. A new look at"
                         <<" statistical model identification. IEEE Transactions"
                         <<" on Automatic Control, 19:716-723, 1974. <br>" << std::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>" << std::endl;

        }
Mark Jenkinson's avatar
Mark Jenkinson committed
      }
Mark Jenkinson's avatar
Mark Jenkinson committed

    inline void addtxt(std::string what){
      if( bool(opts.genreport.value()) ){
        report << what << std::endl;
Mark Jenkinson's avatar
Mark Jenkinson committed
      }
Paul McCarthy's avatar
Paul McCarthy committed

    inline void addpar(std::string what){
      if( bool(opts.genreport.value()) ){
        report << "<p>" << what << std::endl;
Mark Jenkinson's avatar
Mark Jenkinson committed
      }
Paul McCarthy's avatar
Paul McCarthy committed

    inline void addlink(std::string where, std::string what){
      if( bool(opts.genreport.value()) ){
        navigator << "<A HREF=\"" << where << " \"target=\"_top\"> " << what << "</A> ";
        navigator.flush();
Mark Jenkinson's avatar
Mark Jenkinson committed
      }
Mark Jenkinson's avatar
Mark Jenkinson committed

    inline void addpic(std::string what, std::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> ";
Mark Jenkinson's avatar
Mark Jenkinson committed
      }
    }

    inline std::string getDir(){
      return report.getDir();
    }

    void IC_rep(MelGMix &mmodel, int cnum, int dim, NEWMAT::Matrix ICstats);
    void IC_simplerep(std::string prefix, int cnum, int dim);

    void PPCA_rep();
    void Smode_rep();

  private:
    MelodicData &melodat;
    MelodicOptions &opts;
    Utilities::Log &logger;
    Utilities::Log report;
    Utilities::Log navigator;
    Utilities::Log head;
    Utilities::Log loghtml;

    Utilities::Log IChtml;
    Utilities::Log IChtml2;
    std::string axials_instr;

    void IC_rep_det(MelGMix &mmodel, int cnum, int dim);

    std::string int2str(int n){
      std::ostrstream os;
      //    os.fill(' ');
      //    os.width(width);
      os.setf(std::ios::internal, std::ios::adjustfield);
      os << n << '\0';
      return os.str();
    }

    std::string float2str(float f, int width, int prec, int scientif){
      std::ostrstream os;
      int redw = int(std::abs(std::log10(std::abs(f))))+1;
      if(width>0)
        os.width(width);
      if(scientif>0)
        os.setf(std::ios::scientific);
      os.precision(redw+std::abs(prec));
      os.setf(std::ios::internal, std::ios::adjustfield);
      os << f << '\0';
      return os.str();
    }
Paul McCarthy's avatar
Paul McCarthy committed
  };
Mark Jenkinson's avatar
Mark Jenkinson committed

}
#endif