How to Add a Branch as a Vector to be Used in the Invariant Mass Vector

I am trying to calculate the dimuon invariant mass. I wanted to follow one of the ROOT tutorials that started something like this:

// Create dataframe from NanoAOD files

ROOT::RDataFrame df(“Delphes;5”,

                  "tag_1_delphes_events.root");

// For simplicity, select only events with exactly two muons and require opposite charge

//auto df_2mu = df.Filter(“nMuon == 2”, “Events with exactly two muons”);

auto df_os = df.Filter(“Muon.Charge[0] != Muon.Charge[1]”, “Muons with opposite charge”);

// Compute invariant mass of the dimuon system

auto df_mass = df_os.Define(“Dimuon_mass”, InvariantMass, {“Muon.PT”, “Muon.Eta”, “Muon.Phi”, “mu_mass”});

// Make histogram of dimuon mass spectrum

auto h = df_mass.Histo1D({“Dimuon_mass”, “Dimuon_mass”, 30000, 0.25, 300}, “Dimuon_mass”);

// Request cut-flow report

auto report = df_mass.Report();

// Produce plot

However, the problem was that I did not have a Branch that contained the muon mass to be used in this line:

auto df_mass = df_os.Define(“Dimuon_mass”, InvariantMass, {“Muon.PT”, “Muon.Eta”, “Muon.Phi”, “mu_mass”})

So, I had to add the branch to my existing tree by writing:

void upd()

{

TFile *f = new TFile("tag_1_delphes_events.root","update"); 

TTree *T = (TTree*)f->Get("Delphes"); 

//float px,py; 

//float pt; 

float mu_mass;

TBranch *MuonMass = T->Branch("mu_mass",&mu_mass,"mu_mass/F"); 

//T->SetBranchAddress("px",&px); 

//T->SetBranchAddress("py",&py); 

Long64_t nentries = T->GetEntries(); 

for (Long64_t i=0;i<nentries;i++) { 

    T->GetEntry(i); 

    mu_mass = 0.1; 

    MuonMass->Fill(); 

    } 

    T->Print(); 

    T->Write(); 

    delete f; 

    }

which ended up working fine. But, when running the full code, I ran into this error:

Processing invariantmass.C…
Warning in TClass::Init: no dictionary for class HepMCEvent is available
Warning in TClass::Init: no dictionary for class Event is available
Warning in TClass::Init: no dictionary for class Weight is available
Warning in TClass::Init: no dictionary for class GenParticle is available
Warning in TClass::Init: no dictionary for class SortableObject is available
Warning in TClass::Init: no dictionary for class Track is available
Warning in TClass::Init: no dictionary for class Tower is available
Warning in TClass::Init: no dictionary for class Jet is available
Warning in TClass::Init: no dictionary for class MissingET is available
Warning in TClass::Init: no dictionary for class Electron is available
Warning in TClass::Init: no dictionary for class Photon is available
Warning in TClass::Init: no dictionary for class Muon is available
Warning in TClass::Init: no dictionary for class ScalarHT is available
terminate called after throwing an instance of ‘std::runtime_error’
what(): Cannot call operator + on vectors of different sizes.

Did I have to add the branch in another way to fix the error. Did it have to be added as a vector. How should I fix this error?

Many thank!
Please read tips for efficient and successful posting and posting code

ROOT Version: Not Provided
Platform: Not Provided
Compiler: Not Provided


Hi!

We have to sort out a few things first.

  1. What is the data type of your muons? You can find out either by opening the file in the ROOT prompt via root tag_1_delphes_events.root and then you can write Delphes->Print() or you use the getter function of RDataFrame with GetColumnType and friends (see here). Is it a collection (“vector”) or a single object per event?
  2. You can safely assume the muon mass to be 0.1 GeV in most physics cases (check this by yourself!). You can also do this directly in RDataFrame with a Define node, e.g., df.Define("muon_mass", "0.1"). However, you have to know the data structure of your muons so that everything fits together.
  3. The InvariantMass function from ROOT in this example is taken from here, so it expects a vector, or more precisely a ROOT::RVec object. I assume you are not providing this to the function?

Feel free to ask for details, but recommend to have a look at the RDataFrame docs and the tutorials.

Best
Stefan

2 Likes

Hello!

Thank you for your quick response!

  1. I looked at the data type of my muons. Muon.PT, Muon.Eta, Muon.Phi are given by:
 *Br  309 :Muon.PT   : Float_t PT[Muon_]                                      *
 *Entries :    20000 : Total  Size=     477624 bytes  File Size  =     405824 *
 *Baskets :       41 : Basket Size=      27648 bytes  Compression=   1.17     *
 *............................................................................*
 *Br  310 :Muon.Eta  : Float_t Eta[Muon_]                                     *
 *Entries :    20000 : Total  Size=     477669 bytes  File Size  =     414560 *
 *Baskets :       41 : Basket Size=      27648 bytes  Compression=   1.15     *
 *............................................................................*
 *Br  311 :Muon.Phi  : Float_t Phi[Muon_]                                     *
 *Entries :    20000 : Total  Size=     477669 bytes  File Size  =     414521 *
 *Baskets :       41 : Basket Size=      27648 bytes  Compression=   1.15     *
 *..........................................................................
  1. Instead of adding a branch with the muon mass, I wrote:
    // Enable multi-threading
    ROOT::EnableImplicitMT();
    // Create dataframe from NanoAOD files
    ROOT::RDataFrame df("Delphes;6",
                       "tag_1_delphes_events.root");
    //auto mu_mass = df.Define("muon_mass", "0.1");
    // For simplicity, select only events with exactly two muons and require opposite charge
    //auto df_2mu = df.Filter("nMuon == 2", "Events with exactly two muons");
    auto df_os = df.Filter("Muon.Charge[0] != Muon.Charge[1]", "Muons with opposite charge");
    // Compute invariant mass of the dimuon system
    auto df_mu_mass = df_os.Define("muon_mass", "0.1");
    auto df_mass = df_mu_mass.Define("Dimuon_mass", InvariantMass<float>, {"Muon.PT", "Muon.Eta", "Muon.Phi", "muon_mass"});
    // Make histogram of dimuon mass spectrum
    auto h = df_mass.Histo1D({"Dimuon_mass", "Dimuon_mass", 30000, 0.25, 300}, "Dimuon_mass");
    // Request cut-flow report
    auto report = df_mass.Report();

which then gave me:

 Processing invariantmass.C...
 Warning in <TClass::Init>: no dictionary for class HepMCEvent is available
 Warning in <TClass::Init>: no dictionary for class Event is available
 Warning in <TClass::Init>: no dictionary for class Weight is available
 Warning in <TClass::Init>: no dictionary for class GenParticle is available
 Warning in <TClass::Init>: no dictionary for class SortableObject is available
 Warning in <TClass::Init>: no dictionary for class Track is available
 Warning in <TClass::Init>: no dictionary for class Tower is available
 Warning in <TClass::Init>: no dictionary for class Jet is available
 Warning in <TClass::Init>: no dictionary for class MissingET is available
 Warning in <TClass::Init>: no dictionary for class Electron is available
 Warning in <TClass::Init>: no dictionary for class Photon is available
 Warning in <TClass::Init>: no dictionary for class Muon is available
 Warning in <TClass::Init>: no dictionary for class ScalarHT is available
 terminate called after throwing an instance of 'std::runtime_error'
   what():  RColumnValue: type specified for column "muon_mass" is ROOT::VecOps::RVec<float> but temporary column has type double

as an error.

  1. Yes, I agree that seems to be the error. I just don’t know how to insert a RVec type as the muon mass which is just a 0.1.

I will continue to look at the RDataFrame tutorials. Thank you for your extra help!

@swunsch In reference to point 2 of your reply to my question, how do I define the data structure of my muon when I write df.Define(“muon_mass”, 0.1)? That is, If the muon pt, eta, and phi are floats, how can I make define my muon mass to be a float. I have tried some things, but I have not been having luck (ie.I get errors that it must be a valid C++ expression).

Hi,

Here a snipplet, which shows you how to do this:

void test() {
    ROOT::RDataFrame df(4); // empty dataframe with 4 entries
    auto df2 = df.Define("mass", "float(0.1)"); // add mass column with 0.1 as float
    // print the column on the screen
    auto d = df2.Display();
    d->Print();
}

Is this what you want to do?

Best
Stefan

@swunsch Yes, that is what I want. But I always get the error:

terminate called after throwing an instance of ‘std::runtime_error’
what(): RColumnValue: type specified for column “muon_mass” is ROOT::VecOps::RVec but temporary column has type float

when I use InvariantMass as in my code above.

If I write instead “RVec 0.1” I get the error:

input_line_42:1:58: error: expected ‘(’ for function-style cast or type construction
namespace __rdf_1{ auto rdf_f = {return RVec 0.1
~~~~~~~~~~~ ^
terminate called after throwing an instance of ‘std::runtime_error’
what(): Cannot interpret the following expression:
RVec 0.1

Make sure it is valid C++.

(Adding parentheses makes it worse). Do you know how I can solve the problem to calculate the invariant masses

Hi!

What size has the collection, which you want to put into InvariantMass? Please read the documentation here: https://root.cern/doc/master/namespaceROOT_1_1VecOps.html#a2c531eae910edad48bbf7319cc6d7e58

The function returns the invariant mass of a collection, therefore you have to pass the masses of the single particles as vectors, or more precisely ROOT::RVec. RVecs follow the syntax of std::vectors. You can read the documentation here: https://root.cern/doc/master/classROOT_1_1VecOps_1_1RVec.html

In short: If you want a collection of size N, all filled with 0.1, then you have to write ROOT::RVec<float>(N 0.1).

Best
Stefan

@swunsch Thank you for your reply!

  1. I did read the documentation.
    I followed your suggestion and wrote:

ROOT::EnableImplicitMT();

// Create dataframe from NanoAOD files

ROOT::RDataFrame df(“Delphes”,

                  "tag_1_delphes_events.root");

auto number = df.Histo1D(“Muon.PT”);

std::cout << "numberOfMuons " << number->GetEntries() << std::endl;

ROOT::RVec (49254, 0.1);

// Compute invariant mass of the dimuon system

auto df_mu_mass = df.Define(“muon_mass”, “ROOT::RVec (49254 0.1)”);

auto df_mass = df_mu_mass.Define(“Dimuon_mass”, InvariantMass, {“Muon.PT”, “Muon.Eta”, “Muon.Phi”, “muon_mass”});

// Make histogram of dimuon mass spectrum

auto h = df_mass.Histo1D({“Dimuon_mass”, “Dimuon_mass”, 30000, 0.25, 300}, “Dimuon_mass”);

(I’ve tried other ways to define the muon mass as well after taking a look at the RDataFrame tutorial). Looking at the errors I receive, however, it seems like the problem is with writing the RVec.

root [0]
Processing invariantmass.C…
Warning in TClass::Init: no dictionary for class HepMCEvent is available
Warning in TClass::Init: no dictionary for class Event is available
Warning in TClass::Init: no dictionary for class Weight is available
Warning in TClass::Init: no dictionary for class GenParticle is available
Warning in TClass::Init: no dictionary for class SortableObject is available
Warning in TClass::Init: no dictionary for class Track is available
Warning in TClass::Init: no dictionary for class Tower is available
Warning in TClass::Init: no dictionary for class Jet is available
Warning in TClass::Init: no dictionary for class MissingET is available
Warning in TClass::Init: no dictionary for class Electron is available
Warning in TClass::Init: no dictionary for class Photon is available
Warning in TClass::Init: no dictionary for class Muon is available
Warning in TClass::Init: no dictionary for class ScalarHT is available
numberOfMuons 49254
input_line_42:1:71: error: expected ‘)’
namespace __rdf_0{ auto rdf_f = {return ROOT::RVec (49254 0.1)
^
input_line_42:1:64: note: to match this ‘(’
namespace __rdf_0{ auto rdf_f = {return ROOT::RVec (49254 0.1)
^
terminate called after throwing an instance of ‘std::runtime_error’
what(): Cannot interpret the following expression:
ROOT::RVec (49254 0.1)

Make sure it is valid C++.

I am still quite new in all of this, so I do appreciate your patience and replies! Thank you.

Hi!

Sry for the late reply.

About the number of muon: Assuming your branch Muon.PT is a vector, you can write

ROOT::RDataFrame df(...);
auto df2 = df.Define("nMuons", "Muon.PT.size()");

and then use the column “nMuons” afterwards.

Regarding the RVec issue: Most likely you are missing a comma, like ROOT::RVec(number_of_muons, 0.1).

Best
Stefan

Thank you very much. This helps

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