/***************************************************************************** * * * This is a ROOT macro created by * * Angelo Santos ( adesouza@cern.ch ) * * in December, 31th, 2013. * * *********************************** * * * * ****** Summary of the macro ****** * * * * This macro reads TTree entries from input ROOT files and * * create stacks of them, with exception of the first input * * file (which is addressed to Data events). Plots are created * * comparing Data and MC events for variables from the Tag and * * Probe method. * * * * ************ Workflow ************ * * * * There are 4 distinct blocks in this macro: * * * In the first block, global functions are declared in. * * * * * In the second block, vectors of variables are declared in. * * * * * The third block is a file called Setting_Variables.h * * where the USER may provide: * * ** paths to the input ROOT files; * * ** with corresponding weights and histogram colors; * * ** variables to be ploted; * * ** event selections; * * ** number of bins; * * ** X and Y axis ranges; * * ** X and Y axis labels; * * ** choice of canvas size; * * ** choice between log and linear scale; * * ** choice for poping up the plots or for saving them only. * * * * * In the fourth block, all USER's input parameters will * * be read into vectors and a loop starts over all variables * * required by the USER, poping up plots on the screen or saving * * them only (depending on the USER definition in the 3rd block). * * * * * In the fifth block, all functions declared in the first * * block are finally defined. Some comments follow the functions * * in order to make them clearer. * * * * * *****************************************************************************/ #include #include #include #include "TH1.h" #include "TPad.h" #include "TTree.h" #include "TFile.h" #include "THStack.h" #include "TCanvas.h" #include "TLegend.h" #include "Setting_Variables.h" using namespace std; ////////////////////////////////////////////////////////////////////////////// // // // Here starts the first block // // // ////////////////////////////////////////////////////////////////////////////// void read_trees ( vector , vector & ); void events_per_bin ( vector , vector , vector >, vector ); void create_canvas ( vector &, vector , Float_t, Int_t, Int_t, Int_t ); void fill_histograms ( vector , vector &, vector , vector , vector , vector , vector , vector , vector , Int_t, Int_t ); Double_t normalization_factor ( vector ); void setup_stack ( vector &, vector , vector , vector , vector , vector , vector , vector , vector , Int_t, Float_t ); void add_histo_in_stack ( vector , Double_t, vector &, Int_t ); void create_legend ( vector &, vector , double, double, double, double, vector , int ); ////////////////////////////////////////////////////////////////////////////// // // // Here starts the main function // // // ////////////////////////////////////////////////////////////////////////////// void TagAndProbe_stacks_V12 () { ////////////////////////////////////////////////////////////////////////////// // // // Here starts the second block // // // ////////////////////////////////////////////////////////////////////////////// vector nBins; vector histo_color; vector file; vector tree; vector output_format; vector varName; vector events_selection; vector selection_for_binning; vector > bin_edges; vector weights; vector xMin; vector xMax; vector yMin; vector yMax; vector X_label; vector Y_label; vector histo_title; vector histo_label; vector canvas; vector histoStack; vector legend; ////////////////////////////////////////////////////////////////////////////// // // // Here starts the third block // // // ////////////////////////////////////////////////////////////////////////////// cout << "**************************************************************************" << endl; cout << "**************************************************************************" << endl; cout << "*\t Reading information from the list of variables set up" << endl; cout << "*\t by the USER in the file Setting_Variables.h." << endl; cout << "*" << endl; fill_bins (bin_edges); cout << "*" << endl; cout << "*\t Applying common selection: " << default_selection.c_str() << endl; ///////////////////////////////////////////////////////////////// // // // Here starts the fourth block // // // ///////////////////////////////////////////////////////////////// cout << "**************************************************************************" << endl; // Reading each input ROOT file into a vector of TFile's. Int_t number_of_input_files = sizeof(input_files) / sizeof(string); for ( Int_t i = 0; i < number_of_input_files; i++ ) file.push_back(TFile::Open( input_files[i].c_str() )); cout << "*" << endl; cout << "****** There are _" << file.size() << "_ input root files." << endl; cout << "*" << endl; // Reading types of output format files will be saved in. Int_t nOutputFormats = ( sizeof(output_file_format) / sizeof(string) ); for (Int_t i = 0; i < nOutputFormats; i++) { output_format.push_back( output_file_format[i] ); } // Passing weights of each input ROOT file into a vector of double's. cout << "****** Weight of each input file:" << endl; for ( Int_t i = 0; i < ( sizeof(weight) / sizeof(double) ); i++ ) { weights.push_back( weight[i] ); cout << "*\t" << file[i]->GetName() << "\t-> " << weights[i] << endl; } cout << "*" << endl; // Combination between defaulf event selections ("default_selection") and // selection on the mass ("mass_selection[]") of each input ROOT file. stringstream selection_of_events; for ( Int_t i = 0; i < ( sizeof(mass_selection) / sizeof(string) ); i++ ) { if ( i == 0 ) { selection_of_events << mass_selection[i] << " && " << default_selection; selection_for_binning.push_back( selection_of_events.str() ); } else { selection_of_events << mass_selection[i] << " && " << default_selection; selection_for_binning.push_back( selection_of_events.str() ); selection_of_events.str(""); selection_of_events << "( " << mass_selection[i] << " && " << default_selection << " )*weight"; } // cout << "...... selection_of_events: " << selection_of_events.str().c_str() << endl; events_selection.push_back( selection_of_events.str() ); selection_of_events.str(""); } cout << "*" << endl; // Compute number of variables and create a vector of variables. Int_t nVariables = ( sizeof(list_of_variables) / sizeof(string) ); for (Int_t i = 0; i < nVariables; i++) { varName.push_back( list_of_variables[i] ); } // Tell the USER what variables will be plotted to. if ( output_entries_per_bin != 1 ) { cout << "****** These " << nVariables << " variables will be plotted:" << endl; for (Int_t i = 0; i < nVariables; i++) cout << "*\t-> " << varName[i] << endl; cout << "*" << endl; } // Loop over the number of variables to create vectors for the number of bins, // X and Y axis ranges, X and Y axis labels and vectors for the titles, colors // and legends of histograms. for (Int_t i = 0; i < nVariables; i++) { nBins.push_back( number_of_bins[i] ); xMin.push_back( x_minimum[i] ); xMax.push_back( x_maximum[i] ); yMin.push_back( y_minimum[i] ); yMax.push_back( y_maximum[i] ); X_label.push_back( x_axis_label[i] ); Y_label.push_back( y_axis_label[i] ); histo_title.push_back( title_of_histogram[i] ); } for (Int_t i = 0; i < file.size(); i++) { histo_color.push_back( color_of_histogram[i] ); histo_label.push_back( label_of_histogram[i] ); } // Read trees cout << "****** Tree entries of each input ROOT file:" << endl; read_trees(file, tree); cout << "*" << endl; // Output on screen of entries/bin/file/ variable. if ( output_entries_per_bin > 0 ) events_per_bin ( tree, varName, bin_edges, selection_for_binning ); // Stop to run the macro if would like only to get number of entries if ( output_entries_per_bin == 1 ) { cout << "*" << endl; cout << "*\t<<<<<< Done! >>>>>>" << endl; cout << "*" << endl; cout << "**************************************************************************" << endl; cout << "**************************************************************************" << endl; gSystem->Exit(0); } stringstream file_name; if ( gROOT->IsBatch() ) { pop_save == 1; cout << "*\tIt is running in batch mode. Plots will be saved in" << endl; for ( Int_t j = 0; j < nOutputFormats; j++ ) cout << "*\t ." << output_format[j].c_str() << " format" << endl; cout << endl; } else if ( pop_save == 0 ) cout << "*\tPlots will be poped up on the screen, but not saved." << endl; else if ( pop_save == 1 ) { gROOT->SetBatch( kTRUE ); cout << "*\tPlots will be saved in" << endl; for ( Int_t j = 0; j < nOutputFormats; j++ ) cout << "*\t ." << output_format[j].c_str() << " format" << endl; cout << endl; } else if ( pop_save == 2 ) { cout << "*\tPlots will be poped up on the screen and also saved in" << endl; for ( Int_t j = 0; j < nOutputFormats; j++ ) cout << "*\t ." << output_format[j].c_str() << " format" << endl; cout << endl; } else cout << "WARNING: Value" << pop_save << "given to \"pop_save\" is wrong. Only 0, 1 or 2 are allowed." << endl; cout << "*" << endl; // Filling histograms only for the variable mass and compute the normalization factor // in the range mass[60, 120] GeV to be applied to the DY sample with the same range. vector auxiliar_histo; Double_t normalization; for ( Int_t i = 0; i < nVariables; i++) { if ( varName[i] == "pair_newTuneP_mass" ) { // what is the vector related to the mass variable? fill_histograms ( tree, auxiliar_histo, varName, events_selection, weights, nBins, xMin, xMax, histo_color, i , 999 ); normalization = 1.0; if ( normalize == 1 ) normalization = normalization_factor ( auxiliar_histo ); break; } } // Delete components of "auxiliar_histo" vector auxiliar_histo.erase ( auxiliar_histo.begin(), auxiliar_histo.end() ); cout << "*" << endl; // Fill histograms and create stacks // // First of all, vector "histo" will be filled. Then the vector "histoStack" // is set up with labels and Y axis range. Finally, vector "histo" is added // in the stacks by vector "histoStack". cout << "****** Creating plots for each variable:" << endl; for (Int_t i = 0; i < nVariables; i++) { cout << "*\tVariable " << (i+1) << "\t:\t" << varName[i] << endl; // Create a vector of canvases. Each canvas corresponds to each variable. create_canvas (canvas, varName, canvas_ratio, wCanvas, hCanvas, i); canvas[i]->cd(); vector histo; // Filling histograms for the correspondent i-th variable fill_histograms (tree, histo, varName, events_selection, weights, nBins, xMin, xMax, histo_color, i, 0); // Setting up the stack of histograms for the correspondent i-th variable setup_stack (histoStack, nBins, xMin, xMax, yMin, yMax, histo_title, Y_label, X_label, i, y_title_offset); // Add histograms in stacks. add_histo_in_stack (histo, normalization, histoStack, i); // Linear (0) or log (1) scale if ( linear_log_scale == 1 ) gPad->SetLogy(); // Data events will be draw above stacks. histoStack[i]->Draw(); histo[0]->Draw("ep same"); // Fill the legend // // A component of the "histoStack" vector will be draw into each canvas // with respective legends. create_legend (legend, histo, xMinLegend, yMinLegend, xMaxLegend, yMaxLegend, histo_label, i); legend[i]->Draw(); gPad->RedrawAxis(); if ( pop_save > 0 ) { for ( Int_t j = 0; j < nOutputFormats; j++ ) { if ( linear_log_scale == 1 ) { if ( varName[i] == "tkIso/pair_newTuneP_probe_pt" ) file_name << output_file_name << "_" << "tkIso_pair_newTuneP_probe_pt" << "_log." << output_format[j]; else file_name << output_file_name << "_" << varName[i] << "_log." << output_format[j]; } if ( linear_log_scale == 0 ) { if ( varName[i] == "tkIso/pair_newTuneP_probe_pt" ) file_name << output_file_name << "_" << "tkIso_pair_newTuneP_probe_pt" << "_linear." << output_format[j]; else file_name << output_file_name << "_" << varName[i] << "_linear." << output_format[j]; } canvas[i]->SaveAs( file_name.str().c_str() ); file_name.str(""); } } // Delete all components of the vector "histo". histo.erase (histo.begin(), histo.end() ); } cout << "*" << endl; cout << "*\t<<<<<< Done! >>>>>>" << endl; cout << "*" << endl; cout << "**************************************************************************" << endl; cout << "**************************************************************************" << endl; } // End of the main function "void TagAndProbe_stacksV4()". ////////////////////////////////////////////////////////////////////////////// // // // Here starts the fifth block // // // ////////////////////////////////////////////////////////////////////////////// void read_trees (vector f, vector &t) { // This function reads trees from input ROOT // files into vectors of TTree's. for (Int_t i = 0; i < f.size(); i++) { t.push_back( (TTree*)f[i]->Get("tpTree/fitter_tree") ); cout << "*\t" << f[i]->GetName() << "\t-> " << t[i]->GetEntries() << endl; } } void events_per_bin ( vector t, vector variable, vector > bin_edges, vector selection_for_binning ) { // This function compute the number of entries // per bin per input file per variable. stringstream selection; cout << "****** Entries per bin per file per variable:" << endl; for ( Int_t i = 0; i < variable.size(); i++ ) { cout << "*\t* Variable -> <<<<< " << variable[i] << " >>>>>" << endl; cout << "*\t\t** Bin edges:\t\t{"; for ( Int_t j = 0; j < bin_edges[i].size(); j++ ) { cout << bin_edges[i].at(j); if ( j == (bin_edges[i].size() - 1) ) cout << "};"; else cout << ",\t"; } cout << endl; for ( Int_t j = 1; j < t.size(); j++ ) { cout << "\t\t if (sample == " << (j-1) << ")\t{long File" << "[] =\t{"; for ( Int_t k = 0; k < ( bin_edges[i].size() - 1 ); k++ ) { selection << selection_for_binning[j] << " && (" << variable[i] << " >= " << bin_edges[i].at( k ) << ") && (" << variable[i] << " < " << bin_edges[i].at( k+1 ) << ")"; if ( k < (bin_edges[i].size() - 2) ) cout << t[j]->GetEntries( selection.str().c_str() ) << ",\t"; else cout << t[j]->GetEntries( selection.str().c_str() ) << "};}"; selection.str(""); } cout << endl; } cout << "*" << endl; } } void create_canvas (vector &c, vector variable, Float_t canvas_ratio, Int_t width, Int_t height, Int_t j) { // This function sets the canvas concerning // input parameters defined by the USER. c.push_back( new TCanvas() ); c[j]->SetRightMargin( canvas_ratio ); c[j]->SetTitle( variable[j].c_str() ); c[j]->SetWindowSize(width, height); gROOT->SetStyle("Plain"); } void fill_histograms ( vector t, vector &h, vector variable, vector events_selection, vector weights, vector nBins, vector xMin, vector xMax, vector color, Int_t j, Int_t k ) { // A branch will be copied to "histo_temp", which is previously definded // by the USER. It is important because the USER can have total control // over bin numbers and x axis range. // // "h_temp" will get a copy of a branch via "histo_temp", and histogram // "h" will be a clone of "h_temp". // // Histogram "h" will be used in the stacks later on. If "h_temp" were // used, all stylistic changes in the last histogram of the vector would // affect all histograms, being against our wish that each histogram has // its own style (own color, for example). TH1F* histo_temp = 0; vector h_temp; // These string variables are used to handle the way as the histograms // are filled via "Draw()". const char* variable_name; string var_temp; stringstream h_Name = ""; // Loop over all trees. Each tree corresponds to one histogram. for (Int_t i = 0; i < t.size(); i++) { // Give a different name to the histogram "histo_temp" for each j-th // variable and i-th input root file. Then for each "j" and "i" values, // a name "histo_tempij" is given to the histogram. For example: // "histo_temp00", "histo_temp01", "histo_temp10", "histo_temp11", etc. // // If the histogram name was kept unchanged, the TH1F would be replaced // at each loop step, probably causing a fail due a memory leakage. if ( k == 999) { h_Name << "histo_temp" << j << i << k << rand()%1000; histo_temp = new TH1F( h_Name.str() .c_str(), "", 1000, xMin[j], xMax[j] ); } else { // A random number (bettwen 1 and 1000) is created to ensure all histograms // will not have the same name. h_Name << "histo_temp" << j << i << rand()%1000; histo_temp = new TH1F( h_Name.str() .c_str(), "", nBins[j], xMin[j], xMax[j] ); } // "Draw()" function gets a "const char" type as input. Then it is // necessary to handle with "string"s and "const char"s in order to // provide the correct variable name to be passed to the correct histogram. //------------------------------------------------------------------------- // if ( (variable[j].c_str() == "tag_innertrackPtRelError") && (i < 9) ) // variable_name = "tag_InnerTkSigmaPtOverPt"; // else variable_name = variable[j].c_str(); // Tell which variable would be passed in. //--------------------------------------------------------------------------------------------------------------- var_temp = variable_name; // Copy a "const char" to a "string". var_temp = var_temp + " >> " + h_Name.str(); // Include the histogram name. variable_name = ""; // Clear the "const char" object. variable_name = var_temp.c_str(); // Copy a "string" to a "const char". // Draw variable to a histogram applying event selections defined by USER. t[i]->Draw( variable_name, events_selection[i].c_str() ); // Histogram "h_temp" is filled using the histogram name "h_name". // Histogram "h_temp" is then copied into histogram "h". // A collor is set to "h". h_temp.push_back( (TH1F*)gPad->FindObject( h_Name.str() .c_str() ) ); h.push_back( (TH1F*)h_temp[i]->Clone() ); if ( i == 0 ) { h[i]->Scale( weights[i] ); h[i]->SetLineColor( 1 ); h[i]->SetMarkerColor( 1 ); h[i]->SetMarkerStyle( 20 ); h[i]->SetMarkerSize( 0.7 ); } else { h[i]->Scale( weights[i] ); h[i]->SetFillColor( color[i] ); } // Clear objects for the next loop step variable_name = ""; h_Name.str(""); h_Name.clear(); } // Delete objects to free memory. // Delete string "var_temp" and all components of the vector "h_temp". delete histo_temp; // var_temp.erase( var_temp.begin(), var_temp.end() ); // h_temp.erase( h_temp.begin(), h_temp.end() ); } // End of "void fill_histograms()". Double_t normalization_factor ( vector h ) { // This function compute integral of invariant mass distributions, // in the range between 60 and 120 GeV, for Data and MC events. // If requested by the USER, MC events are normalized by Data/MC ratio. Double_t integral = 0.; Double_t bin_min; Double_t bin_max; for ( Int_t j = 1; j < h.size(); j++ ) { bin_min = h[j]->FindBin( 60 ); bin_max = h[j]->FindBin( 120 ); integral = integral + ( h[j]->Integral( bin_min, bin_max ) ); // cout << ".... integral[" << j << "](" << bin_min << ", " << bin_max << "): " << integral << endl; } bin_min = h[0]->FindBin( 60 ); bin_max = h[0]->FindBin( 120 ); // cout << ".... integral[0](" << bin_min << ", " << bin_max << "): " << h[0]->Integral( bin_min, bin_max ) << endl; integral = h[0]->Integral( bin_min, bin_max ) / integral; cout << "****** MC normalization factor: " << integral << endl; return integral; } void setup_stack ( vector &h, vector nBins, vector xMin, vector xMax, vector yMin, vector yMax, vector title, vector y_label, vector x_label, Int_t j, Float_t Y_title_offset ) { // This fuction sets up the THStack vector "h" with labels, title // and Y axis range. Each component of "h" corresponds to one // variable (j-th variable). h.push_back( new THStack() ); stringstream h_Name = ""; h_Name << "h_stack" << j; // A way to provide labels to THStack is through a TH1F TH1F *h_stack = 0; h_stack = new TH1F( h_Name.str() .c_str(),"", nBins[j], xMin[j], xMax[j] ); h_stack->GetYaxis()->SetTitle( y_label[j].c_str() ); h_stack->GetXaxis()->SetTitle( x_label[j].c_str() ); h_stack->GetYaxis()->SetTitleOffset( Y_title_offset ); h_stack->SetStats(0); // THStack receives labels (already set up by a TH1F above) via SetHistogram(). // Title and Y axis range are provided directly to the THStack. h[j]->SetHistogram( h_stack ); h[j]->SetMinimum( yMin[j] ); // h[j]->SetMaximum( yMax[j] ); h[j]->SetTitle( title[j].c_str() ); // Clear the "stringstream" object to free the memory. h_Name.str(""); h_Name.clear(); } // End of "void setup_stack()". void add_histo_in_stack ( vector h, Double_t normalization, vector &h_Stack, Int_t j ) { // This add each component of the TH1F vector "h" in stack into // the THStack "h_Stack". It is added in descending order, so the the // histogram from the first input root file will be in the top of the // stack, while the last one will be in the bottom. Double_t stack_MC_integral = 0.; Double_t Data_integral = 0.; for (Int_t i = h.size() - 1; i > 0; i--) { // if ( i == 0 ) h[i]->Scale( normalization ); h_Stack[j]->Add( h[i] ); // cout << "Histo[" << i << "] integral: " << h[i]->Integral() << endl; stack_MC_integral = stack_MC_integral + h[i]->Integral(); } Data_integral = h[0]->Integral(); cout << "Histo[Data] integral: " << Data_integral << endl; cout << "Histo[MC] integral: " << stack_MC_integral << endl; cout << "Ratio Data/MC: " << (1.0*Data_integral)/stack_MC_integral << endl; } void create_legend ( vector &l, vector h, double xMin, double yMin, double xMax, double yMax, vector label, int j ) { // This function creates a legend for each variable. l.push_back( new TLegend(xMin, yMin, xMax, yMax) ); l[j]->SetFillColor(0); l[j]->SetBorderSize(1); // Provide legends looping over all histograms for (Int_t i = 0; i < h.size(); i++) if ( i == 0 ) l[j]->AddEntry(h[i], label[i].c_str(),"pl"); else l[j]->AddEntry(h[i], label[i].c_str(),"f"); }