#include #include #include #include using namespace std; #include "TROOT.h" #include "TFile.h" #include "TString.h" #include "TDirectory.h" #include "TObject.h" #include "TClass.h" #include "TKey.h" #include "TH1.h" #include "TAxis.h" #include "TMath.h" #include "TCutG.h" #include "TFolder.h" bool verbose (false); TFolder *histosFolder (0); //============================================================================== void addObject (TObject *o, const TString &prefix, TFolder *opFolder=0); /** called for each file to do the addition. * loops over each object in the file, and * uses addObject to dispatch the actuall addition. */ void add (TFile *file, const TString &prefix) { //------------------------------------------------------------------------------ TString dirName (file->GetName()); if (verbose) cout << " scanning TFile" << endl; TString newPrefix (prefix + dirName + "/"); TIter i (file->GetListOfKeys()); while (TKey *k = static_cast( i())) { TObject *o (file->Get( k->GetName())); addObject( o, newPrefix); } return; } //============================================================================== /** Most histograms are added bin by bin, but if simpleAdd == false, * the xaxis values are assumed different, in which case we look up * appropriate bin numbers, and use a new extended xaxis if needed. * * Use simpleAdd=false to accumulate scaler rate histograms. */ void add (const TH1 *newh, TH1 *&hsum, TFolder *opFolder) { //------------------------------------------------------------------------------ const bool simpleAdd (newh->GetXaxis()->GetTimeDisplay() ? false : true); if (!hsum) { hsum = (TH1 *)newh->Clone(); TString title = "histoAdd: "; title += hsum->GetTitle(); if (opFolder) hsum->SetDirectory( 0); } else if (simpleAdd) hsum->Add( newh); else { // extend axis - for 1D histos with equal sized bins size_t nBinsSum = hsum->GetNbinsX(); size_t nBinsNew = newh->GetNbinsX(); vectorbin_contents; vectorhisto_edges; Int_t holder_bins; /* foundBin is either the overflow bin (if the 2 histograms don't overlap) * or it is the bin number in histoA that has the same low edge as the * lowest bin edge in histoB. The only time that histograms can overlap * is when the older scaler.cxx is used to create the histograms with * fixed bin sizes. */ Int_t foundBin = hsum->FindBin( newh->GetBinLowEdge(1) ); histo_edges.resize(foundBin); bin_contents.resize(foundBin); for( int i = 1; i <= foundBin; i++ ) { histo_edges[i-1] = hsum->GetBinLowEdge(i); bin_contents[i-1] = hsum->GetBinContent(i); } if(foundBin < nBinsSum) { //the histos overlap or we have already made holder bins holder_bins = 0; } else { //create a "place holder" histo Int_t width = 10; holder_bins = (int)((newh->GetXaxis()->GetXmin() - hsum->GetXaxis()->GetXmax())/width); if( holder_bins < width ) holder_bins = width; TH1F *bin_holder = new TH1F("bin_holder", "bin_holder", holder_bins, hsum->GetXaxis()->GetXmax(), newh->GetXaxis()->GetXmin() ); histo_edges.resize( foundBin + holder_bins ); bin_contents.resize( foundBin + holder_bins ); for( int i = 0; i < holder_bins; i++ ) { histo_edges[foundBin+i] = bin_holder->GetBinLowEdge(i+2); bin_contents[foundBin+i] = 0; } delete bin_holder; } //end else histo_edges.resize( foundBin + holder_bins + nBinsNew+1 ); bin_contents.resize( foundBin + holder_bins + nBinsNew+1 ); for( int i = 0; i <= nBinsNew; i++ ) { histo_edges[i+foundBin+holder_bins] = newh->GetBinLowEdge(i+1); bin_contents[i+foundBin+holder_bins] = newh->GetBinContent(i+1); } hsum->SetBins( histo_edges.size()-1, &histo_edges[0] ); for ( int i=1; iSetBinContent( i, bin_contents[i-1]); } if (opFolder) { //opFolder->Remove( hsum); //opFolder->Add( exth); hsum->SetDirectory( 0); } } if (verbose) { if (simpleAdd) cout << " adding counts"; else cout << " tagging on bins"; cout << endl; } return; } //============================================================================== /** Most cuts are written out just once, but if a cut is different from * the most recently written version of a cut with the same name, then * another copy of the cut is written out. Thus if a cut changes during * a series of runs, all versions of the cut will be present in the * summed file. */ void add (const TCutG *o, TCutG *&oOut, TFolder *opFolder) { //------------------------------------------------------------------------------ const char *name (o->GetName()); bool write (false); if (!oOut) write = true; else { Int_t n (o->GetN()); if (n != oOut->GetN()) write = true; else { double x1, x2, y1, y2; for (Int_t i=0; iGetPoint( i, x1, y1); oOut->GetPoint( i, x2, y2); if ((x1 != x2) || (y1 != y2)) write = true; } } } if (write) { if (verbose) { if (oOut) cout << " changed"; cout << " TCutG" << endl; } if (!opFolder) { oOut = const_cast( o); o->Write( name, TObject::kSingleKey); } else { TCutG *clone = static_cast( o->Clone()); if (oOut) opFolder->Add( clone); oOut = clone; } } else if (verbose) cout << endl; return; } //============================================================================== /** for most objects, we keep just the first version. */ void add (const TObject *o, TObject *&oSum, TFolder *opFolder) { //------------------------------------------------------------------------------ const char *name (o->GetName()); if (!oSum) { if (verbose) cout << " saving TObject" << endl; if (!opFolder) o->Write( name, TObject::kSingleKey); } else { if (verbose) cout << endl; } return; } //============================================================================== /** create the new directory and then start adding its contents */ void add (TDirectory *dir, TDirectory *&sumDir, TFolder *opFolder, const TString &prefix) { //------------------------------------------------------------------------------ TDirectory *currentDir (gDirectory); TString dirName (dir->GetName()); if (verbose) cout << " scanning TDirectory" << endl; TString newPrefix (prefix + dirName + "/"); if (!sumDir) sumDir = gDirectory->mkdir( dirName); sumDir->cd(); TIter i (dir->GetListOfKeys()); while (TKey *k = static_cast( i())) { TObject *o (dir->Get( k->GetName())); addObject( o, newPrefix, opFolder); } currentDir->cd(); return; } //============================================================================== /** create a new folder and then start adding its contents */ void add (const TFolder *folder, TFolder *&sumFolder, TFolder *parentFolder, const TString &prefix) { //------------------------------------------------------------------------------ if (verbose) cout << " scanning TFolder" << endl; const char *name (folder->GetName()); TString newPrefix (prefix + name + "/"); if (!sumFolder) sumFolder = new TFolder (name, name); if (!histosFolder) histosFolder = sumFolder; TIter i (folder->GetListOfFolders()); while (TObject *o = i()) addObject( o, newPrefix, sumFolder); return; } //============================================================================== int main (int argc, char **argv) { //------------------------------------------------------------------------------ if (argc < 3) { cerr << argv[0] << ": out_root_file in_root_file1 in_root_file2 ..." << endl; return 1; } TROOT root ("histoadd", "histoadd"); root.SetBatch(); TString opFileName (argv[1]); TFile *opFile (TFile::Open( opFileName, "RECREATE")); if (!opFile) { cerr << argv[0] << ": unable to open file: " << argv[1] << endl; return 1; } --argc; ++argv; while (++argv, --argc) { const TString prefix ("/"); if (verbose) cout << "processing file " << argv[0]; TFile *inFile (TFile::Open( argv[0], "READ")); opFile->cd(); if (inFile) { add( inFile, prefix); inFile->Close(); } else { cout << " - skipping "; if (!verbose) argv[0]; cout << endl; } } if (verbose) cout << "writing file " << opFile->GetName() << endl; opFile->Write(); if (histosFolder) histosFolder->Write(); opFile->Close(); return 0; } //============================================================================== /** helper function for add (TDirectory *, const TString &) and * add (TFolder *, const TString &). * dispatches the addition to an appropriate function. */ void addObject (TObject *addObj, const TString &prefix, TFolder *opFolder) { //------------------------------------------------------------------------------ TClass *c (addObj->IsA()); TString objName (addObj->GetName()); bool newObj (false); TObject *sumObj (gDirectory->Get( objName)); if (!sumObj) { if (opFolder) { sumObj = opFolder->FindObject( objName); } else if (histosFolder) { sumObj = histosFolder->FindObject( objName); if (!sumObj && strcmp( "histos", objName) == 0) sumObj = histosFolder; } } if (!sumObj) newObj = true; if (verbose) { cout << prefix << objName << (newObj ? " new" : "") << " (" << c->GetName() << ")"; } if (c->GetBaseClass( "TH1")) { TH1 *so (reinterpret_cast( sumObj)); add( static_cast( addObj), so, opFolder); sumObj = reinterpret_cast( so); } else if (c->GetBaseClass( "TFolder")) { TFolder *so (reinterpret_cast( sumObj)); add( static_cast( addObj), so, opFolder, prefix); sumObj = reinterpret_cast( so); } else if (c->GetBaseClass( "TCutG")) { TCutG *so (reinterpret_cast( sumObj)); add( static_cast( addObj), so, opFolder); sumObj = reinterpret_cast( so); } else if (c->GetBaseClass( "TDirectory")) { TDirectory *so (reinterpret_cast( sumObj)); add( static_cast( addObj), so, opFolder, prefix); sumObj = reinterpret_cast( so); } else /* TObjArray etc. */ { add( addObj, sumObj, opFolder); } if (opFolder && newObj) opFolder->Add( sumObj); return; }