Issue accessing file in nested loop

Hi all! This is a bit difficult to explain, but I’ll try my best to make it as clear as possible!

I have a vector containing 3 possible pTCut1’s and a vector containing 3 possible pT2Cut’s. What I would like to do is: I want to pick a pT1Cut and plot all 3 pT2Cut possibilities on the same graph, and then pick a different pT1Cut and again plot all 3 pT2Cut possibilities on the same graph (a different graph than the one for the first pT1Cut, but just show all the pT2Cut possibilities for this pT1Cut together).

So in total, I would like three plots on the same canvas: one for each pT1Cut and each plot containing three histograms for all the pT2Cut possibilities.

The part where I am stuck is that I need 2 for loops to achieve this (one looping over the pT1Cut possibilities and one to loop over the pTCut2 possibilities), however I don’t know how to access the right files. The path to my histograms is “L1_J20/yCut_0.6/pT1Cut_…/pT2Cut_…/Mjj”, where the ‘…’ are 50, 70 and 90 (seen in code). So I would like my first for loop to ‘fix’ a pT1Cut, eg. pT1Cut of 50 and thus choose file L1_J20/yCut_0.6/pT1Cut_50/pT2Cut_…/Mjj, and then my second loop to consecutively pick L1_J20/yCut_0.6/pT1Cut_50/pT2Cut_50/Mjj, L1_J20/yCut_0.6/pT1Cut_50/pT2Cut_70/Mjj and L1_J20/yCut_0.6/pT1Cut_50/pT2Cut_90/Mjj. And then for the next 2 pT1Cut’s the same. However, I am pretty sure my code is incorrect… Also I’d like to only choose pT2Cut’s that are smaller (or equal) than my pT1Cut, i.e. if my pT1Cut is 70, I only want pT2Cut’s of 50 or 70, but I also don’t know how to implement this.


void mjj_loop(){
  TCanvas *c = new TCanvas("c", "", 1000, 1000);
  c->SetFillColor(0);
  c->Divide(3,1);
  
  auto f = new TFile ("HaddOutput.root");
  
  std::vector<int> pT1Cut = {50, 70, 90};
  std::vector<int> pT2Cut = {50, 70, 90};

  int n1 = pT1Cut.size();  
  int n2 = pT2Cut.size();  

  TH1D *h[n1];
  TH1D *k[n2];
  
  for (unsigned i = 0; i < n1; i++) {
    c->cd(i+1);
    h[i] = (TH1D*)f->Get(Form ("L1_J20/yCut_0.6/pT1Cut_%d", pT1Cut[i]));
    
    for (unsigned j = 0; j < n2; j++) {
      h[i][j] = (TH1D*)f->Get(Form ("pT2Cut_%d/Mjj", pT2Cut[j])); 
      if (j==0) k[j]->Draw("ap");
      else k[j]->Draw("p same");
    }
  }
}

I am sorry for the long and messy explanation, I hope it’s a bit clear! Thanks!

Hi, I am trying to, but the file is too large…

Ah I’m sorry, do you have any idea how I can attach the file then?

I don’t really know what you want to achieve but maybe this will be helpful:

#include "TFile.h"
#include "TH1.h"
#include "TCanvas.h"
#include "TString.h"
#include <vector>
#include <iostream>

void mjj_loop(const char *fname = "HaddOutput.root") {
  if (!(fname && fname[0])) return; // just a precaution
  TFile *f = TFile::Open(fname);
  if ((!f) || f->IsZombie()) { delete f; return; } // just a precaution
  
  std::vector<int> pT1Cut = {50, 70, 90};
  std::vector<int> pT2Cut = {50, 70, 90};
  
  int n1 = pT1Cut.size();
  int n2 = pT2Cut.size();
  
  TCanvas *c = new TCanvas("c", "", (n1 * 300), 300);
  c->Divide(n1, 1);
  c->SetFillColor(0);
  
  TH1D *h[n1];
  TH1D *k[n1][n2];
  
  for (int i = 0; i < n1; i++) {
    c->cd(i + 1);
    f->GetObject(TString::Format("L1_J20/yCut_0.6/pT1Cut_%d/pT2Cut_0/Mjj", pT1Cut[i]), h[i]);
    if (!h[i]) continue; // just a precaution
    // std::cout << "i = " << i << std::endl;
    h[i]->Draw();
    
    for (int j = 0; j < n2; j++) {
      f->GetObject(TString::Format("L1_J20/yCut_0.6/pT1Cut_%d/pT2Cut_%d/Mjj", pT1Cut[i], pT2Cut[j]), k[i][j]);
      if (!k[i][j]) continue; // just a precaution
      // std::cout << "i = " << i << " j = " << j << std::endl;
      k[i][j]->Draw("same");
    }
  }
  c->cd(0);
}
1 Like

That’s exactly what I was trying to do, thanks!


I am now trying to divide all the k[I][j] by the same histogram and plot these results (called eff) instead of the k[I][j]. I tried the following, but I get the error: “use of undeclared identifier Divide”, however I have done a similar thing before where Divide didn’t give a problem, so it might be because it is in a double for loop, but I don’t see why that would be a problem and how to solve this… Thanks!

#include "TFile.h"
#include "TH1.h"
#include "TGraphAsymmErrors.h"
#include "TCanvas.h"
#include "TString.h"
#include <vector>
#include <iostream>

void mjj_forum(const char *fname = "HaddOutput.root") {
  if (!(fname && fname[0])) return; // just a precaution
  TFile *f = TFile::Open(fname);
  if ((!f) || f->IsZombie()) { delete f; return; } // just a precaution
    
  std::vector<int> pT1Cut = {50, 70, 90};
  std::vector<int> pT2Cut = {50, 70, 90};
  
  int n1 = pT1Cut.size();
  int n2 = pT2Cut.size();
  
  TCanvas *c = new TCanvas("c", "", (n1 * 300), 300);
  c->Divide(n1, 1);
  c->SetFillColor(0);
  
  TH1D *histo = (TH1D*)f->Get("AfterCuts/yCut_0.6/pT1Cut_0/pT2Cut_0/Mjj");  
  TH1D *h[n1];
  TH1D *k[n1][n2];
  TGraphAsymmErrors *eff[n1][n2];
  
  for (int i = 0; i < n1; i++) {
    c->cd(i + 1);
    f->GetObject(TString::Format("L1_J20/yCut_0.6/pT1Cut_%d/pT2Cut_0/Mjj", pT1Cut[i]), h[i]);
    if (!h[i]) continue; // just a precaution
    
    for (int j = 0; j < n2; j++) {
      f->GetObject(TString::Format("L1_J20/yCut_0.6/pT1Cut_%d/pT2Cut_%d/Mjj", pT1Cut[i], pT2Cut[j]), k[i][j]);
      if (!k[i][j]) continue; // just a precaution
      eff[i][j] = new TGraphAsymmErrors();    
      eff[i][j] = Divide(k[i][j], histo);     
      eff[i][j]->Draw("same"); 
    }    
  }
  c->cd(0);
}
 
#include "TFile.h"
#include "TCanvas.h"
#include "TH1.h"
#include "TMultiGraph.h"
#include "TGraphAsymmErrors.h"
#include "TString.h"
#include <vector>
#include <iostream>

void mjj_loop(const char *fname = "HaddOutput.root") {
  if (!(fname && fname[0])) return; // just a precaution
  TFile *f = TFile::Open(fname);
  if ((!f) || f->IsZombie()) { delete f; return; } // just a precaution
  
#if 1 /* 0 or 1 */
  TH1D *histo;
  f->GetObject("AfterCuts/yCut_0.6/pT1Cut_0/pT2Cut_0/Mjj", histo);
  if (!histo) { delete f; return; } // just a precaution
#endif /* 0 or 1 */
  
  std::vector<int> pT1Cut = {50, 70, 90};
  std::vector<int> pT2Cut = {50, 70, 90};
  
  int n1 = pT1Cut.size();
  int n2 = pT2Cut.size();
  
  TCanvas *c = new TCanvas("c", "", (n1 * 300), 300);
  c->Divide(n1, 1);
  c->SetFillColor(0);
  
  TH1D *h[n1];
  TH1D *k[n1][n2];
  TMultiGraph *mg[n1];
  TGraphAsymmErrors *eff[n1][n2];
  
  for (int i = 0; i < n1; i++) {
    c->cd(i + 1);
    f->GetObject(TString::Format("L1_J20/yCut_0.6/pT1Cut_%d/pT2Cut_0/Mjj", pT1Cut[i]), h[i]);
    if (!h[i]) continue; // just a precaution
    // std::cout << "i = " << i << std::endl;
    mg[i] = new TMultiGraph();
    
    for (int j = 0; j < n2; j++) {
      f->GetObject(TString::Format("L1_J20/yCut_0.6/pT1Cut_%d/pT2Cut_%d/Mjj", pT1Cut[i], pT2Cut[j]), k[i][j]);
      if (!k[i][j]) continue; // just a precaution
      // std::cout << "i = " << i << " j = " << j << std::endl;
      eff[i][j] = new TGraphAsymmErrors();
#if 1 /* 0 or 1 */
      eff[i][j]->Divide(k[i][j], histo, "n");
#else /* 0 or 1 */
      eff[i][j]->Divide(k[i][j], h[i], "n");
#endif /* 0 or 1 */
      mg[i]->Add(eff[i][j]);
    }
    
    mg[i]->Draw("AL");
  }
  c->cd(0);
}
1 Like

Thanks a lot! Just out of curiosity, could you perhaps explain to me why I have to use a multigraph here?

You don’t “have to” use a TMultiGraph but it is convenient (to get “common” axes limits for all its graphs).

1 Like

Hi, I am sorry to bother you again, but I have one more question… I am trying to remove all the data points with an efficiency lower than 80%. I have tried this before and it worked, however, now I’m trying to do this in a triple for loop, i.e. I have 3D vectors, and something isn’t working… I was hoping you could perhaps help me out? Many thanks!

#include "TFile.h"
#include "TCanvas.h"
#include "TH1.h"
#include "TMultiGraph.h"
#include "TGraphAsymmErrors.h"
#include "TString.h"
#include <vector>
#include <iostream>

void mjj_turnon(const char *fname = "HaddOutput.root") {
  if (!(fname && fname[0])) return; // just a precaution
  TFile *f = TFile::Open(fname);
  if ((!f) || f->IsZombie()) { delete f; return; } // just a precaution
  
  std::vector<int> pT1Cut = {50, 70, 90, 110, 130};
  std::vector<int> pT2Cut = {50, 70, 90, 110, 130};
  int n1 = pT1Cut.size();
  int n2 = pT2Cut.size();
  
  TCanvas *c = new TCanvas("c", "", (n1 * 350), 1000);
  c->Divide(2, 3);
  c->SetFillColor(0);
  
  TH1D *h[n1];
  TH1D *k[n1][n2];
  TMultiGraph *mg[n1];
  TGraphAsymmErrors *eff_lim[n1][n2];
  TH1D *histo = (TH1D*)f->Get("AfterCuts/yCut_0.6/pT1Cut_0/pT2Cut_0/Mjj");  
  
  std::vector<std::vector<double> > N(5, std::vector<double>(5));

  for (int i = 0; i < n1; i++) {
    c->cd(i + 1);
    f->GetObject(TString::Format("L1_J40/yCut_0.6/pT1Cut_%d/pT2Cut_0/Mjj", pT1Cut[i]), h[i]);
    if (!h[i]) continue; // just a precaution
    mg[i] = new TMultiGraph();
    
    for (int j = 0; j < n2; j++) {
      f->GetObject(TString::Format("L1_J40/yCut_0.6/pT1Cut_%d/pT2Cut_%d/Mjj", pT1Cut[i], pT2Cut[j]), k[i][j]);
      if (!k[i][j]) continue; // just a precaution
      eff_lim[i][j] = new TGraphAsymmErrors();
      eff_lim[i][j]->Divide(k[i][j], histo, "n");
         
      std::vector<std::vector<std::vector<double> > > y_value(5, std::vector<double>(5),    std::vector<std::vector<double> >(N[i][j]));
     
      N[i][j] = eff_lim[i][j]->GetN();
   
      for (int m = (N[i][j]-1); m>=0; m--) {
        y_value[i][j][m] = eff_lim[i][j]->GetY()[m];
        if (y_value[i][j][m] < 0.8) {
          eff_lim[i][j]->RemovePoint(m);
          }
      }
    mg[i]->Add(eff_lim[i][j]);
   }            
 mg[i]->Draw("AL");   
 }    
  c->cd(0);
}

You initialize N[i][j] after you use it in std::vector...

You can get rid of all these std::vector... and use:

for (int m = (eff_lim[i][j]->GetN() - 1); m >= 0; m--)
  if (eff_lim[i][j]->GetY()[m] < 0.8) eff_lim[i][j]->RemovePoint(m);
1 Like

Thanks a lot!!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.