/* * Histo2DAction.h * * Created on: 01/set/2009 * Author: Nicola Mori */ /*! @file Histo2DAction.h The Histo2DAction class declaration file. */ #ifndef HISTO2DACTION_H_ #define HISTO2DACTION_H_ #include "../../CollectionAction/CollectionAction.h" #include #include #include /*! @brief An abstract action that fills a 2-dimensional histogram. * * This abstract class provides all the common methods needed to produce 2-dimensional histograms, * like reading the bins from a file, setting up the root histogram and so on. It handles histograms * both as a ROOT histogram and as a matrix. The OnGood() method has to be implemented in children * classes, with the specific physical variables to fill the histogram. Eg., a dE/dx vs. rigidity * histogram class derived from Histo2DAction could have this OnGood() implementation: * * Fill(event->GetTrack(0)->GetTrkTrack()->GetRigidity(), event->GetTrack(0)->GetTrkTrack()->GetDEDX()); * * Fill() automatically fills the ROOT and the matrix histogram. * The template argument HistoType is the type of histogram (Int_t, Double_t,...). In current * implementation, ROOT histograms are only supported for Int_t, Float_t and Double_t. For all the * other types, only the the matrix histogram with text file output will be produced. If you want to * implement some new types of ROOT histograms, please specialize the template definitions of _CreateHisto() * and ~Histo2DAction() (see the specializations in the .cpp file). * * */ template class Histo2DAction: public CollectionAction { public: /*! @brief Constructor. * * The histogram binning is defined by the content of the bins vector. * * @param actionName The action's name. * @param title The ROOT histogram title. * @param outFileBase The file base name for the histogram output. If "", no output file will be produced. * @param mode The mode of ROOT file creation (see documentation of TFile constructor * in ROOT's reference guide). * @param outRoot If true, an output ROOT file named outFileBase + ".root" will be produced. * @param outText If true, an output text file named outFileBase + ".txt" will be produced. It will overwrite an * eventually existing file with the same name. */ Histo2DAction(const char *actionName, TString title = "", TString outFileBase = "", TString mode = "UPDATE", bool outRoot = false, bool outText = false); /*! @brief Destructor * * This has to be specialized for each kind of ROOT histogram. * * */ ~Histo2DAction(); /*! @brief Sets the X axis using a binning read from a a vector. * * @param label The axis' label. * @param bins A vector containing the histogram binning (with sign, eventually; from lowest to highest). */ void SetXAxis(TString label, vector &bins); /*! @brief Sets the X axis reading the binning from a file. * * @param label The axis' label. * @param binsFile The file containing the bins (with sign, eventually; from lowest to highest). */ void SetXAxis(TString label, TString binsFile); /*! @brief Sets the X axis specifying the binning parameters. * * @param label The axis' label. * @param nBins The number of bins. * @param min The lower limit of the axis. * @param max The upper limit of the axis. * @param logBinning If true, bins will be logarithmically spaced. */ void SetXAxis(TString label, unsigned int nBins, float min, float max, bool logBinning = false); /*! @brief Sets the Y axis using a binning read from a a vector. * * @param label The axis' label. * @param bins A vector containing the histogram binning (with sign, eventually; from lowest to highest). */ void SetYAxis(TString label, vector &bins); /*! @brief Sets the Y axis reading the binning from a file. * * @param label The axis' label. * @param binsFile The file containing the bins (with sign, eventually; from lowest to highest). */ void SetYAxis(TString label, TString binsFile); /*! @brief Sets the Y axis specifying the binning parameters. * * @param label The axis' label. * @param nBins The number of bins. * @param min The lower limit of the axis. * @param max The upper limit of the axis. * @param logBinning If true, bins will be logarithmically spaced. */ void SetYAxis(TString label, unsigned int nBins, float min, float max, bool logBinning = false); /*! @brief Sets the ROOT histogram's title. * * @param title The histogram title as it will appear on the histogram itself. */ void SetTitle(TString &title) { _title = title; } /*! @brief Sets up the histogram * * This routine effectively prepares the histogram, after the desired parameters has been set by #SetXAxis() and #SetYAxis(). * * @param events Pointer to PamLevel2 events (unused). */ void Setup(PamLevel2 *events) { CollectionAction::Setup(events); _InitHistos(); } /*! @ brief Post-analysis tasks. * * This method writes the output on a ROOT file if the proper option was set in the constructor. */ void Finalize(); /*! @brief Returns the histogram. * * Element [i][j] is the value of the i-th bin on the Y axis and on the j-th bin on the X axis. This sort * of index inversion is due to logically maintain the Y values on the vertical axis of the matrix, which * is indexed by the row number (which conventionally is the first index of a matrix element). * * @return A reference to a matrix containing the values of the bins of the histogram. */ SimpleMatrix &GetHisto() { return _histo; } /*! @brief Returns a pointer to the ROOT histogram. * * @return A pointer to the root histogram */ TH2 *GetRootHisto() { return _rootHisto; } /*! Fills the ROOT and the vector histogram. * * @param xValue The value of the X coordinate associated to the event. * @param yValue The value of the Y coordinate associated to the event. * @param weight The weight which will be applied to the event. */ void Fill(double xValue, double yValue, double weight = 1.); /*! @brief Gets the X overflow histogram. * * The returned vector contains the histogram filled with the X overflow events, eg., * those events whose X variable falls above the upper limit of the X axis. This histogram * is binned like the Y axis. * * @return The X overflow histogram. */ vector& GetXOverflow() { return _xOverflow; } /*! @brief Gets the X underflow histogram. * * The returned vector contains the histogram filled with the X underflow events, eg., * those events whose X variable falls below the lower limit of the X axis. This histogram * is binned like the Y axis. * * @return The X underflow histogram. */ vector& GetXUnderflow() { return _xUnderflow; } /*! @brief Gets the Y overflow histogram. * * The returned vector contains the histogram filled with the Y overflow events, eg., * those events whose Y variable falls above the upper limit of the Y axis. This histogram * is binned like the X axis. * * @return The Y overflow histogram. */ vector& GetYOverflow() { return _yOverflow; } /*! @brief Gets the Y underflow histogram. * * The returned vector contains the histogram filled with the Y underflow events, eg., * those events whose Y variable falls below the lower limit of the Y axis. This histogram * is binned like the X axis. * * @return The Y underflow histogram. */ vector& GetYUnderflow() { return _yUnderflow; } /*! @brief Gets the X-Y overflow histogram. * * This single-bin histogram is built with events which fall above the lower limits of both the * X and Y axis. * * @return The X-Y overflow histogram. */ HistoType GetXOverYOverflow() { return _xOverYOverflow; } /*! @brief Gets the X-Y underflow histogram. * * This single-bin histogram is built with events fall below the lower limits of both the X and Y axis. * * @return The X-Y overflow histogram. */ HistoType GetXUnderYUnderflow() { return _xUnderYUnderflow; } /*! @brief Gets the (X over - Y under)flow histogram. * * This single-bin histogram is built with events fall above the lower limit of the Xaxis and below * that of the Y axis. * * @return The (X over -Y under)flow histogram. */ HistoType GetXOverYUnderflow() { return _xOverYUnderflow; } /*! @brief Gets the (X under - Y over)flow histogram. * * This single-bin histogram is built with events fall below the lower limit of the X axis and above * that of the Y axis. * * @return The (X under -Y over)flow histogram. */ HistoType GetXUnderYOverflow() { return _xUnderYOverflow; } protected: /*! @brief The vector containing the limits of the X bins(from lower to higher). */ std::vector _xBins; /*! @brief The vector containing the limits of the Y bins(from lower to higher). */ std::vector _yBins; /*! @brief A matrix containing the value of the histogram for each X-Y bin. */ SimpleMatrix _histo; /*! @brief The ROOT histogram. */ TH2 *_rootHisto; private: vector _xUnderflow, _xOverflow, _yUnderflow, _yOverflow; HistoType _xUnderYUnderflow, _xOverYOverflow, _xUnderYOverflow, _xOverYUnderflow; TString _outFileBase; TString _mode; TString _title, _xLabel, _yLabel; bool _outRoot; bool _outText; void _CreateHisto(); void _InitHistos(); }; template void Histo2DAction::_CreateHisto() { // No ROOT histogram for generic type; see template specializations in .cpp file. _rootHisto = NULL; } // Specializations for _CreateHistos(). See Histo2DAction.cpp template<> void Histo2DAction::_CreateHisto(); template<> void Histo2DAction::_CreateHisto(); template<> void Histo2DAction::_CreateHisto(); template void Histo2DAction::_InitHistos() { _CreateHisto(); if (_xBins.size() < 2) // SetXAxis not called by the main program, or wrongly filled (only 1 bin limit) SetXAxis("Default X", 10, 0., 1.); if (_yBins.size() < 2) // SetYAxis not called by the main program, or wrongly filled (only 1 bin limit) SetYAxis("Default Y", 10, 0., 1.); if (_rootHisto) { Double_t *auxXArray = new Double_t[_xBins.size()]; for (unsigned int i = 0; i < _xBins.size(); i++) { auxXArray[i] = _xBins[i]; } Double_t *auxYArray = new Double_t[_yBins.size()]; for (unsigned int i = 0; i < _yBins.size(); i++) { auxYArray[i] = _yBins[i]; } _rootHisto->SetBins(_xBins.size() - 1, auxXArray, _yBins.size() - 1, auxYArray); _rootHisto->SetName(GetName()); _rootHisto->SetTitle(_title); _rootHisto->SetXTitle(_xLabel); _rootHisto->SetYTitle(_yLabel); delete[] auxXArray; delete[] auxYArray; } /* The row index (first) corresponds to the position on the vertical (Y) axis. */ _histo.Resize(_yBins.size() - 1, _xBins.size() - 1); _xUnderflow.resize(_yBins.size()); _xOverflow.resize(_yBins.size()); _yUnderflow.resize(_xBins.size()); _yOverflow.resize(_xBins.size()); } template Histo2DAction::~Histo2DAction() { delete _rootHisto; _rootHisto = NULL; } template Histo2DAction::Histo2DAction(const char *actionName, TString title, TString outFileBase, TString mode, bool outRoot, bool outText) : CollectionAction(actionName), _xBins(0), _yBins(0), _histo(0, 0), _rootHisto(NULL), _xUnderflow(0), _xOverflow(0), _yUnderflow(0), _yOverflow(0), _outFileBase(outFileBase), _mode(mode), _title(title), _xLabel(""), _yLabel(""), _outRoot(outRoot), _outText(outText) { } template void Histo2DAction::SetXAxis(TString label, vector &bins) { _xBins = bins; _xLabel = label; } template void Histo2DAction::SetYAxis(TString label, vector &bins) { _yBins = bins; _yLabel = label; } template void Histo2DAction::SetXAxis(TString label, TString binsFile) { // Reading the bins from file ifstream binListFile; binListFile.open(binsFile); TString auxString; _xBins.resize(0); while (!binListFile.eof()) { binListFile >> auxString; if (auxString != "") { _xBins.push_back(auxString.Atof()); } } binListFile.close(); _xLabel = label; } template void Histo2DAction::SetYAxis(TString label, TString binsFile) { // Reading the bins from file ifstream binListFile; binListFile.open(binsFile); TString auxString; _yBins.resize(0); while (!binListFile.eof()) { binListFile >> auxString; if (auxString != "") { _yBins.push_back(auxString.Atof()); } } binListFile.close(); _yLabel = label; } template void Histo2DAction::SetXAxis(TString label, unsigned int nBins, float min, float max, bool logBinning) { _xBins.resize(nBins + 1); if (!logBinning || (logBinning && min <= 0.)) { #ifdef DEBUGPAMCUT if (logbinning && rigMin <= 0.) cout << "Warning: logarithmic binning was chosen for X axis but min <= 0. Using linear binning." #endif float step = (max - min) / nBins; for (unsigned int i = 0; i < nBins + 1; i++) { _xBins[i] = min + i * step; } } else { double maxExp = log10(max / min); for (unsigned int i = 0; i < nBins + 1; i++) { _xBins[i] = min * pow(10., (double) i / ((double) nBins) * maxExp); } } _xLabel = label; } template void Histo2DAction::SetYAxis(TString label, unsigned int nBins, float min, float max, bool logBinning) { _yBins.resize(nBins + 1); if (!logBinning || (logBinning && min <= 0.)) { #ifdef DEBUGPAMCUT if (logbinning && rigMin <= 0.) cout << "Warning: logarithmic binning was chosen for Y axis but min <= 0. Using linear binning." #endif float step = (max - min) / nBins; for (unsigned int i = 0; i < nBins + 1; i++) { _yBins[i] = min + i * step; } } else { double maxExp = log10(max / min); for (unsigned int i = 0; i < nBins + 1; i++) { _yBins[i] = min * pow(10., (double) i / ((double) nBins) * maxExp); } } _yLabel = label; } template void Histo2DAction::Fill(double xValue, double yValue, double weight) { _rootHisto->Fill(xValue, yValue, weight); int xBin = 0, yBin = 0; bool UOflow = false; if (xValue < _xBins.front()) { xBin = -1; UOflow = true; } if (xValue >= _xBins.back()) { xBin = _xBins.size(); UOflow = true; } if (yValue < _yBins.front()) { yBin = -1; UOflow = true; } if (yValue >= _yBins.back()) { yBin = _yBins.size(); UOflow = true; } if (xBin == 0) { while (xValue >= _xBins[xBin]) { xBin++; } xBin--; } if (yBin == 0) { while (yValue >= _yBins[yBin]) { yBin++; } yBin--; } if (!UOflow) { // No under or over flow. _histo[yBin][xBin] += (HistoType) weight; return; } else { // An under or over flow has happened. if (xBin == -1) { if (yBin == -1) { _xUnderYUnderflow += (HistoType) weight; return; } else { if (yBin == (int) _yBins.size()) { _xUnderYOverflow += (HistoType) weight; return; } else { _xUnderflow[yBin] += (HistoType) weight; return; } } } if (xBin == (int) _xBins.size()) { if (yBin == -1) { _xOverYUnderflow += (HistoType) weight; return; } else { if (yBin == (int) _yBins.size()) { _xOverYOverflow += (HistoType) weight; return; } else { _xOverflow[yBin] += (HistoType) weight; return; } } } if (yBin == -1) { _yUnderflow[xBin] += (HistoType) weight; return; } if (yBin == (int) _yBins.size()) { _yOverflow[xBin] += (HistoType) weight; return; } } } template void Histo2DAction::Finalize() { if (_outFileBase != "") { // Write the ROOT file if (_rootHisto && _outRoot) { TFile outRootFile((_outFileBase + ".root"), _mode); outRootFile.cd(); _rootHisto->Write(); outRootFile.Close(); } //Write the text file if (_outText) { ofstream outTextFile((_outFileBase + ".txt").Data(), ios_base::out); for (unsigned int i = 0; i < _histo.GetNRows(); i++) { for (unsigned int j = 0; j < _histo.GetNCols(); j++) { outTextFile << _histo[i][j] << " "; } outTextFile << "\n"; } outTextFile << endl; outTextFile.close(); } } } #endif /* HISTO2DACTION_H_ */