Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 12:45:09

0001 //   Author:      Gero Flucke
0002 //   Date:        October 2007
0003 //   last update: $Date: 2012/05/12 19:14:58 $  
0004 //   by:          $Author: flucke $
0005 
0006 #include "GFOverlay.h"
0007 #include <TError.h>
0008 #include <TFile.h>
0009 #include <TList.h>
0010 #include <TObjArray.h>
0011 #include <TString.h>
0012 #include <TObjString.h>
0013 #include <TKey.h>
0014 #include <TH1.h>
0015 #include "GFUtils/GFHistManager.h"
0016 
0017 #include <iostream>
0018 // for strlen:
0019 #include <string.h>
0020 
0021 //________________________________________________________
0022 GFOverlay::GFOverlay(const char *fileLegendList, Option_t *option) :
0023   fHistMan(new GFHistManager), fLayer(0),
0024   fFiles(), fLegends(),
0025   fNormalise(TString(option).Contains("norm", TString::kIgnoreCase)),
0026   fSummaries(TString(option).Contains("sumperdir", TString::kIgnoreCase)),
0027   fDirNames(), fSkipDirNames(), fHistNames(), fSkipHistNames()
0028 {
0029   if (fNormalise) ::Info("GFOverlay", "Normalising hists.");
0030   if (fSummaries) ::Info("GFOverlay", "Add summary hists for each directory.");
0031 
0032   fFiles.SetOwner();
0033   fLegends.SetOwner();
0034 
0035   const TString opt(option);
0036 
0037   // directory parts to require: either generally selecetd or only for dirs
0038   fDirNames = this->FindAllBetween(opt, "name(", ")");
0039   TObjArray tmp(this->FindAllBetween(opt, "nameDir(", ")"));
0040   fDirNames.AddAll(&tmp);
0041   fDirNames.SetOwner();
0042   for (Int_t iN = 0; iN < fDirNames.GetEntriesFast(); ++iN) {
0043     ::Info("GFOverlay", "Use only directories containing '%s'.", fDirNames[iN]->GetName());
0044   }
0045   // hist name parts to require: either generally selecetd or only for hists
0046   fHistNames = this->FindAllBetween(opt, "name(", ")");
0047   tmp = this->FindAllBetween(opt, "nameHist(", ")");
0048   fHistNames.AddAll(&tmp);
0049   fHistNames.SetOwner();
0050   for (Int_t iN = 0; iN < fHistNames.GetEntriesFast(); ++iN) {
0051     ::Info("GFOverlay", "Use only hists containing '%s'.", fHistNames[iN]->GetName());
0052   }
0053 
0054   // directory name parts to skip: either generally selecetd or only for dirs
0055   fSkipDirNames = this->FindAllBetween(opt, "skip(", ")");
0056   tmp = this->FindAllBetween(opt, "skipDir(", ")");
0057   fSkipDirNames.AddAll(&tmp);
0058   fSkipDirNames.SetOwner();
0059   for (Int_t iS = 0; iS < fSkipDirNames.GetEntriesFast(); ++iS) {
0060     ::Info("GFOverlay", "Skip directories containing '%s'.", fSkipDirNames[iS]->GetName());
0061   }
0062   // hist name parts to skip: either generally selecetd or only for hists
0063   fSkipHistNames = this->FindAllBetween(opt, "skip(", ")");
0064   tmp = this->FindAllBetween(opt, "skipHist(", ")");
0065   fSkipHistNames.AddAll(&tmp);
0066   fSkipHistNames.SetOwner();
0067   for (Int_t iS = 0; iS < fSkipHistNames.GetEntriesFast(); ++iS) {
0068     ::Info("GFOverlay", "Skip hists containing '%s'.", fSkipHistNames[iS]->GetName());
0069   }
0070 
0071   fHistMan->SameWithStats(true); // to draw both statistic boxes
0072   fHistMan->SetLegendX1Y1X2Y2(.14, .72, .42, .9); // defines (absolute) coordinates of legends
0073 
0074   this->OpenFilesLegends(fileLegendList);
0075   this->Overlay(fFiles, fLegends);
0076 
0077   fHistMan->SetNumHistsXY(3,2); // how many hists in x/y per canvas
0078   fHistMan->Draw();
0079 }
0080 
0081 //________________________________________________________
0082 GFOverlay::~GFOverlay()
0083 {
0084   delete fHistMan;
0085 }
0086 
0087 //________________________________________________________
0088 TObjArray GFOverlay::FindAllBetween(const TString &text,
0089                     const char *startStr, const char *endStr) const
0090 {
0091   TObjArray result; // TObjStrings...
0092 
0093   if (text.Contains(startStr, TString::kIgnoreCase)) {
0094     Ssiz_t start = text.Index(startStr);
0095     while (start != kNPOS && start < text.Length()) {
0096       TString name = this->FindNextBetween(text, start, startStr, endStr);
0097       if (!name.IsNull()) {
0098     result.Add(new TObjString(name));
0099     start = text.Index(startStr, start + name.Length() + TString(endStr).Length());
0100       } else {
0101     break;
0102       }
0103     }
0104   }
0105 
0106   return result;
0107 }
0108 
0109 //________________________________________________________
0110 TString GFOverlay::FindNextBetween(const TString &input, Ssiz_t startInd,
0111                    const char *startStr, const char *endStr) const
0112 {
0113   // search for startStr in input, starting at index startInd
0114   // if found, return what comes after that and before endStr, otherwise return empty string
0115   TString string(input);
0116   const Ssiz_t start = string.Index(startStr, startInd, TString::kIgnoreCase)
0117     + (startStr ? strlen(startStr) : 0);
0118   if (start != kNPOS) {
0119     const Ssiz_t end = string.Index(endStr, start);
0120     if (end == kNPOS) {
0121       ::Error("GFOverlay::FindNextBetween", "Miss closing '%s' after '%s'", endStr, startStr);
0122       string = "";
0123     } else {
0124       string = string(start, end - start);
0125     }
0126   } else {
0127     string = "";
0128   }
0129 
0130   return string;
0131 }
0132 
0133 //________________________________________________________
0134 bool GFOverlay::OpenFilesLegends(const char *fileLegendList)
0135 {
0136   bool allOk = true;
0137   
0138   TObjArray *fileLegPairs = TString(fileLegendList).Tokenize(",");
0139   for (Int_t iF = 0; iF < fileLegPairs->GetEntriesFast(); ++iF) {
0140     TObjArray *aFileLegPair = TString(fileLegPairs->At(iF)->GetName()).Tokenize("=");
0141 
0142     const char *legend = "";
0143     if (aFileLegPair->GetEntriesFast() >= 2) {
0144       if (aFileLegPair->GetEntriesFast() > 2) {
0145     ::Error("GFOverlay::OpenFilesLegends", "File-legend pair %s: %d (>2) '=' separated parts!",
0146         fileLegPairs->At(iF)->GetName(), aFileLegPair->GetEntriesFast());
0147       }
0148       legend = aFileLegPair->At(1)->GetName();
0149     } else if (aFileLegPair->GetEntriesFast() < 1) {
0150       continue; // empty: should report error?
0151     } // else if (aFileLegPair->GetEntriesFast() == 1): That's OK, use empty legend.
0152 
0153     TFile *file = TFile::Open(aFileLegPair->At(0)->GetName());
0154     if (!file) {
0155       ::Error("GFOverlay::OpenFilesLegends", "Skip file-legend pair %s due to opening problems!",
0156           fileLegPairs->At(iF)->GetName());
0157       allOk = false;
0158     } else {
0159       fFiles.Add(file);
0160       fLegends.Add(new TObjString(legend));
0161     }
0162     delete aFileLegPair;
0163   }
0164 
0165   delete fileLegPairs;
0166   return allOk;
0167 }
0168 
0169 //________________________________________________________
0170 void GFOverlay::Overlay(const TObjArray &dirs, const TObjArray &legends)
0171 {
0172   // 'directories' must contain TDirectory and inheriting, being parallel with legends,
0173   // method is called recursively
0174   TDirectory *dir1 = 0;
0175   for (Int_t iDir = 0; !dir1 && iDir < dirs.GetEntriesFast(); ++iDir) {
0176     dir1 = static_cast<TDirectory*>(dirs[iDir]);
0177   }
0178   if (!dir1) return;
0179 
0180   const Int_t currentLayer = fLayer;
0181   fLayer += (fSummaries ? 2 : 1);
0182   std::vector<TH1*> meanHists, rmsHists;
0183 
0184   // Now loop on keys of first directory (i.e. first file). If not deselected, foresee hists
0185   // for plotting and directories for recursion. Other objects are ignored. 
0186   UInt_t counter = 0;
0187   TIter nextKey(dir1->GetListOfKeys());
0188 //   //  while(TKey* key = static_cast <TKey*> (nextKey())) {
0189 //   // OK, make CINT happy, i.e. make .L GFOverlay.C work without extending '+':
0190   TKey* key = NULL; 
0191   while ((key = static_cast <TKey*> (nextKey()))) {
0192     // If key's name is deselected for both cases (hist and dir), avoid reading object:
0193     if (!fHistNames.IsEmpty()   && !this->KeyContainsListMember(key->GetName(), fHistNames)
0194     && !fDirNames.IsEmpty() && !this->KeyContainsListMember(key->GetName(), fDirNames )) {
0195       continue; // type (dir/hist) independent skip: not actively selected!
0196     }
0197     if (this->KeyContainsListMember(key->GetName(), fSkipHistNames)
0198     && this->KeyContainsListMember(key->GetName(), fSkipDirNames)) {
0199       continue; // type (dir/hist) independent skip: actively deselected!
0200     }
0201     // Now read object (only of first directory/file!) to be able to check type specific
0202     // skipping (hist or dir):
0203     TObject *obj = key->ReadObj();
0204     if (!obj) continue; // What ? How that?
0205     if (obj->InheritsFrom(TH1::Class())) {
0206       if (!fHistNames.IsEmpty() && !this->KeyContainsListMember(key->GetName(), fHistNames)) {
0207     continue;
0208       }
0209       if (this->KeyContainsListMember(key->GetName(), fSkipHistNames)) continue;
0210     } else if (obj->InheritsFrom(TDirectory::Class())) {
0211       if (!fDirNames.IsEmpty() && !this->KeyContainsListMember(key->GetName(), fDirNames)) {
0212     continue;
0213       }
0214       if (this->KeyContainsListMember(key->GetName(), fSkipDirNames)) continue;
0215     }
0216     // Now key survived! First treat for hist case:
0217     TObjArray hists(this->GetTypeWithNameFromDirs(TH1::Class(), key->GetName(), dirs));
0218     if (this->AddHistsAt(hists, legends, currentLayer, counter) > 0) {
0219       if (fSummaries) {
0220     this->CreateFillMeanRms(hists, currentLayer, dir1->GetName(), meanHists, rmsHists);
0221       }
0222       ++counter;
0223     }
0224     // Now treat directory case:
0225     TObjArray subDirs(this->GetTypeWithNameFromDirs(TDirectory::Class(), key->GetName(), dirs));
0226     if (subDirs.GetEntries()) { // NOT GetEntriesFast()!
0227       ::Info("GFOverlay::Overlay", "Key '%s' is directory to do recursion.", key->GetName());
0228       this->Overlay(subDirs, legends);
0229     }
0230   } // end of loop on keys
0231    
0232   // If mean/rms hists created, add them to manager:
0233   for (unsigned int iMean = 0; iMean < meanHists.size(); ++iMean) {
0234     fHistMan->AddHistSame(meanHists[iMean], currentLayer + 1, 0, legends[iMean]->GetName());
0235     fHistMan->AddHistSame(rmsHists[iMean], currentLayer + 1, 1, legends[iMean]->GetName());
0236   }
0237 }
0238 
0239 //________________________________________________________
0240 bool GFOverlay::KeyContainsListMember(const TString &key, const TObjArray &list) const
0241 {
0242   for (Int_t i = 0; i < list.GetEntriesFast(); ++i) {
0243     if (key.Contains(list[i]->GetName())) return true; 
0244   }
0245 
0246   return false;
0247 }
0248 
0249 //________________________________________________________
0250 TObjArray GFOverlay::GetTypeWithNameFromDirs(const TClass *aType, const char *name,
0251                          const TObjArray &dirs) const
0252 {
0253   // dirs must contain TDirectory only!
0254   // do Get(name) for all dirs and adds result to return value if type fits, otherwise Add(NULL)
0255   // result has length of dirs
0256 
0257   TObjArray result(dirs.GetEntriesFast()); // default length
0258   for (Int_t iDir = 0; iDir < dirs.GetEntriesFast(); ++iDir) {
0259     TDirectory *aDir = static_cast<TDirectory*>(dirs[iDir]);
0260     TObject *obj = (aDir ? aDir->Get(name) : 0);
0261     if (obj && !obj->InheritsFrom(aType)) {
0262       // delete obj; NO! deletes things found in previous calls...
0263       obj = 0;
0264     }
0265     result.Add(obj); // might be NULL
0266   }
0267 
0268   return result;
0269 }
0270 
0271 //________________________________________________________
0272 Int_t GFOverlay::AddHistsAt(const TObjArray &hists, const TObjArray &legends, Int_t layer,Int_t pos)
0273 {
0274   // hists and legends must have same length, but might have gaps...
0275   // return number of hists found and added
0276 
0277   Int_t nHists = 0;
0278   for (Int_t iHist = 0; iHist < hists.GetEntriesFast(); ++iHist) {
0279     TH1 *hist = static_cast<TH1*>(hists[iHist]);
0280     if (!hist) continue;
0281 
0282     if (fNormalise && hist->GetEntries()) {
0283       hist->Scale(1./hist->GetEntries());
0284     }
0285 
0286     fHistMan->AddHistSame(hist, layer, pos, (legends[iHist] ? legends[iHist]->GetName() : 0));
0287     ++nHists;
0288   }
0289 
0290   return nHists;
0291 }
0292 
0293 //________________________________________________________
0294 void GFOverlay::CreateFillMeanRms(const TObjArray &hists, Int_t layer, const char *dirName,
0295                   std::vector<TH1*> &meanHists, std::vector<TH1*> &rmsHists) const
0296 {
0297   // fill mean/rms from hists into the corresponding meanHists/rmsHists
0298   // if these are empty, create one hist for each slot of hists (even for empty ones!)
0299   if (hists.IsEmpty()) return;
0300   TH1 *h1 = 0;
0301   for (Int_t iH = 0; !h1 && iH < hists.GetEntriesFast(); ++iH) {
0302     h1 = static_cast<TH1*>(hists[iH]);
0303   }
0304   if (!h1 || h1->GetDimension() > 1) return; // only for 1D hists
0305   
0306   if (meanHists.empty()) { // create mean/RMS hists if not yet done
0307     const Float_t min = h1->GetXaxis()->GetXmin()/3.;
0308     const Float_t max = h1->GetXaxis()->GetXmax()/3.;
0309     const Int_t nBins = h1->GetNbinsX()/2;
0310     for (Int_t iHist = 0; iHist < hists.GetEntriesFast(); ++iHist) {
0311       TH1 *hMean = new TH1F(Form("mean%d_%d", layer, iHist), Form("%s: mean", dirName),
0312                 nBins, min, max);
0313       meanHists.push_back(hMean);
0314       TH1 *hRms = new TH1F(Form("rms%d_%d", layer, iHist), Form("%s: RMS", dirName),
0315                nBins, 0., max);
0316       rmsHists.push_back(hRms);
0317     }
0318   }
0319 
0320   // now fill mean and rms hists
0321   for (Int_t iHist = 0; iHist < hists.GetEntriesFast(); ++iHist) {
0322     TH1 *h = static_cast<TH1*>(hists[iHist]);
0323     if (!h) continue;
0324     meanHists[iHist]->Fill(h->GetMean());
0325     rmsHists[iHist]->Fill(h->GetRMS());
0326   }
0327 }