Fork me on GitHub

Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#1369 closed How to (fixed)

Why does calling treeReader->UseBranch(... change outcome even if the pointer isn't used?

Reported by: flyingMoggy Owned by:
Priority: minor Milestone:
Component: Delphes code Version: Delphes 3
Keywords: Cc: Pavel Demin

Description

Apologies, I know this is the second time posting this but two of my colleagues (Alexander Titterton and Dr Emmanuel Olaiya) are just as perplexed as I am by this behavior.

I suspect I did not do a very good job of explaining what I observed in the first post, and it was closed based on a misunderstanding.

The class $ROOTSYS/Delphes/examples/Example3.C can be stripped down to simply read the momentum and energy values of particles on a jet by jet basis (as seen below).

It might be expected that branchJet would return a combination of Tracks and Towers. It will certainly contain references to objects held in other branches, perhaps branchEFlowTrack/branchEFlowPhoton/branchEFlowNeutralHadron. What is surprising is that branchJet only contains Tracks and Towers *if* a pointers to branchEFlowTrack & branchEFlowPhoton & branchEFlowNeutralHadron are created, otherwise it contains GenParticles!

Why does the contents of branchJet vary according to the the existence of other pointers? And why would it end up containing GenParticles?

Many thanks,
Henry Day-Hall

#ifdef __CLING__
R__LOAD_LIBRARY(libDelphes)
#include "classes/DelphesClasses.h"
#include "external/ExRootAnalysis/ExRootTreeReader.h"
#include "external/ExRootAnalysis/ExRootResult.h"
#else
class ExRootTreeReader;
class ExRootResult;
#endif

void AnalyseEvents(ExRootTreeReader *treeReader)
{
    {
    // Some files to write results to. ~~~~
    ofstream jetOut("jetPts.csv");
    ofstream trackOut("trackPts.csv");
    ofstream towerOut("towerPts.csv");
    ofstream genOut("genPts.csv");
    //Now get the addresses of the branches that contain the data we want ~~~~~~~~~~~~~~~~
    TClonesArray *branchParticle = treeReader->UseBranch("Particle");
    //TClonesArray *branchElectron = treeReader->UseBranch("Electron");
    //TClonesArray *branchPhoton = treeReader->UseBranch("Photon");
    //TClonesArray *branchMuon = treeReader->UseBranch("Muon");
    //~~~~~ Uncommenting this give tracks
    //TClonesArray *branchEFlowTrack = treeReader->UseBranch("EFlowTrack");
    //~~~~~ Uncommenting this give towers
    //TClonesArray *branchEFlowPhoton = treeReader->UseBranch("EFlowPhoton");
    //~~~~~ Uncommenting this give towers
    //TClonesArray *branchEFlowNeutralHadron = treeReader->UseBranch("EFlowNeutralHadron");
    //~~~~~~~ Why are the existance of unused pointers changing the output?
    TClonesArray *branchJet = treeReader->UseBranch("Jet");
    //Decide when to end the loop ~~~~~~~~~~~~~~~~
    Long64_t allEntries = treeReader->GetEntries();
    cout << "** Chain contains " << allEntries << " events" << endl;
    // make a variable to store the object found in the branch in ~~~~~~~~~~~~~~~~
    GenParticle *particle;
    //Electron *electron;
    //Photon *photon;
    //Muon *muon;
    Track *track;
    Tower *tower;

    Jet *jet;
    TObject *object;
    TLorentzVector momentum;
    //Float_t Eem, Ehad;
    //Bool_t skip;
    Long64_t entry;
    Int_t i, j; //, pdgCode;

    // Loop over all events
    for(entry = 0; entry < allEntries; ++entry)
    {
      // Load selected branches with data from specified event
      treeReader->ReadEntry(entry);
      cout << "--  New event -- " << endl;

      // Loop over all jets in event
      for(i = 0; i < branchJet->GetEntriesFast(); ++i)
      {
        jet = (Jet*) branchJet->At(i);

        momentum.SetPxPyPzE(0.0, 0.0, 0.0, 0.0);

        cout<<"Looping over jet constituents. Jet pt: "<<jet->PT<<", eta: "<<jet->Eta<<", phi: "<<jet->Phi<<endl;
        jetOut << jet->PT;

        // Loop over all jet's constituents
        for(j = 0; j < jet->Constituents.GetEntriesFast(); ++j)
        {
          object = jet->Constituents.At(j);

          // Check if the constituent is accessible
          if(object == 0) continue;

          // object->IsA() will change depending on which lines are commented/uncommented above!
          // but why? object always comes out of branchJet, why do other branches change it's behavior?
          if(object->IsA() == GenParticle::Class())
          {
            particle = (GenParticle*) object;
            cout << "    GenPart pt: " << particle->PT << ", eta: " << particle->Eta << ", phi: " << particle->Phi << endl;
            momentum += particle->P4();
            genOut << particle->PT << ",";
          }
          else if(object->IsA() == Track::Class())
          {
            track = (Track*) object;
            cout << "    Track pt: " << track->PT << ", eta: " << track->Eta << ", phi: " << track->Phi << endl;
            momentum += track->P4();
            trackOut << track->PT << ",";
          }
          else if(object->IsA() == Tower::Class())
          {
            tower = (Tower*) object;
            cout << "    Tower pt: " << tower->ET << ", eta: " << tower->Eta << ", phi: " << tower->Phi << endl;
            momentum += tower->P4();
            towerOut << tower->ET << ",";
          }
        }
        jetOut << endl;
        towerOut << endl;
        genOut << endl;
        trackOut << endl;
      }
    }
    }
}

//------------------------------------------------------------------------------

void jet_constits(const char *inputFile)
{
    gSystem->Load("libDelphes");
    TChain *chain = new TChain("Delphes");
    chain->Add(inputFile);
    ExRootTreeReader *treeReader = new ExRootTreeReader(chain);
    AnalyseEvents(treeReader);
    cout << "** Exiting..." << endl;

    delete treeReader;
    delete chain;
}

//------------------------------------------------------------------------------

Attachments (2)

jet_constits.C (5.0 KB ) - added by flyingMoggy 6 years ago.
tag_1_delphes_events.root (931.3 KB ) - added by flyingMoggy 6 years ago.

Download all attachments as: .zip

Change History (5)

by flyingMoggy, 6 years ago

Attachment: jet_constits.C added

by flyingMoggy, 6 years ago

Attachment: tag_1_delphes_events.root added

comment:1 by Pavel Demin, 6 years ago

The Constituents list in the class Jet contains only the references to constituents not the constituents themselves.

The constituents are stored in other branches (Track, Tower, etc).

If you comment out the lines that call the methods UseBranch("EFlowTrack"), UseBranch("EFlowPhoton"), etc, then the constituents from these branches aren't loaded from the ROOT file to the memory and can't be accessed via the references.

More information about the references can be found at the following links:

https://root.cern.ch/doc/master/classTRef.html
https://root.cern.ch/doc/master/classTRefArray.html

Version 1, edited 6 years ago by Pavel Demin (previous) (next) (diff)

comment:2 by Pavel Demin, 6 years ago

What is surprising is that branchJet only contains Tracks and Towers *if* a pointers to branchEFlowTrack & branchEFlowPhoton & branchEFlowNeutralHadron are created, otherwise it contains GenParticles?!

If the branches containing the referenced objects aren't loaded, then the reference could point to an object with the same UID from a previous event.

For example, if in the current event a jet has its first constituent of type Track with UID 2646 and branch EFlowTrack isn't loaded but if the previous event contained a particle from the branch Particle with the same UID 2646, then it's the particle from the previous event that is returned by jet->Constituents.At(0).

Last edited 6 years ago by Pavel Demin (previous) (diff)

comment:3 by Pavel Demin, 6 years ago

Resolution: fixed
Status: newclosed
Note: See TracTickets for help on using tickets.