Copying certain events to a new file


ROOT Version: 6.32.02
Platform: win64
Compiler: MSVC 19.39.33521.0


For a while I’ve been working with a relatively large ROOT file, so naturally my computer takes a bit to run code over 10s of millions of events. Instead of placing cuts on the data (phi mass, Proton momentum, etc.) within my macro, I’d like to write a script that “filters through” the events and produces a smaller root file that only contains the events that satisfy the requirements.

How would I go about copying an entire event to a new file?

Here is what I have so far:

    TFile *filein = new TFile("flat_pi0pippim__B4.root");
    TTree *tree = (TTree *)filein->Get("pi0pippim__B4;1");

    TFile *cutFile = new TFile("flat_pi0pippim__B4_cut.root", "RECREATE");

    UInt_t kin_ndf;
    float kin_chisq;
    float Mandelstam_t;

    TLorentzVector *beam_p4_kin = 0;
    TLorentzVector *g1_p4_kin = 0;
    TLorentzVector *g2_p4_kin = 0;
    TLorentzVector *p_p4_kin = 0;
    TLorentzVector *pim_p4_kin = 0;
    TLorentzVector *pip_p4_kin = 0;

    tree->SetBranchAddress("beam_p4_kin", &beam_p4_kin);
    tree->SetBranchAddress("g1_p4_kin", &g1_p4_kin);
    tree->SetBranchAddress("g2_p4_kin", &g2_p4_kin);

    tree->SetBranchAddress("p_p4_kin", &p_p4_kin);
    tree->SetBranchAddress("pim_p4_kin", &pim_p4_kin);
    tree->SetBranchAddress("pip_p4_kin", &pip_p4_kin);

    tree->SetBranchAddress("kin_ndf", &kin_ndf);
    tree->SetBranchAddress("kin_chisq", &kin_chisq);

    TLorentzVector BeamP4, TargetP4, Gamma1P4, Gamma2P4, Pi0P4, ProtonP4, PiMinusP4, PiPlusP4, PhiP4;

    Long64_t NEntries = tree->GetEntries();

    cout << "There are " << NEntries << " entries." << endl;

    for (Long64_t i_entry = 0; i_entry < NEntries; i_entry++) {
        tree->GetEntry(i_entry);

        if (i_entry % 1000000 == 0) {
            cout << i_entry << " events processed" << endl;
        }

        BeamP4.SetPxPyPzE(beam_p4_kin->Px(), beam_p4_kin->Py(), beam_p4_kin->Pz(), beam_p4_kin->E());
        ProtonP4.SetPxPyPzE(p_p4_kin->Px(), p_p4_kin->Py(), p_p4_kin->Pz(), p_p4_kin->E());
        PiMinusP4.SetPxPyPzE(pim_p4_kin->Px(), pim_p4_kin->Py(), pim_p4_kin->Pz(), pim_p4_kin->E());
        PiPlusP4.SetPxPyPzE(pip_p4_kin->Px(), pip_p4_kin->Py(), pip_p4_kin->Pz(), pip_p4_kin->E());
        Gamma1P4.SetPxPyPzE(g1_p4_kin->Px(), g1_p4_kin->Py(), g1_p4_kin->Pz(), g1_p4_kin->E());
        Gamma2P4.SetPxPyPzE(g2_p4_kin->Px(), g2_p4_kin->Py(), g2_p4_kin->Pz(), g2_p4_kin->E());
        TargetP4.SetPxPyPzE(0, 0, 0, 0.938272);

        double ProtonMom = ProtonP4.P();
        Pi0P4 = Gamma1P4 + Gamma2P4;
        PhiP4 = PiPlusP4 + PiMinusP4 + Pi0P4;
        double PhiMass = PhiP4.M();
        Mandelstam_t = (ProtonP4 - TargetP4) * (ProtonP4 - TargetP4);

        if ((kin_chisq / kin_ndf) < 6 && -Mandelstam_t < 1 && PhiMass > 0.9 && PhiMass < 1.14 && ProtonMom > 0.3) {
            ~~~Do Something Here!!!~~~
        }
    }

I’m not entirely sure how to get ALL of the information for a given event and write it to the new file in an efficient way.
Thanks!

This is probably easier to do with RDataFrame:

{
  ROOT::RDataFrame d("mytree", "myinputfile.root");
  d.Filter("myvariable<mylimit").Snapshot("mytree", "newfile.root");  // "mytree" is the name of the new tree, does not have to be the same name as the original
}

Basically, read the tree into a dataframe, filter (define your cut) and then save it (snapshot) to a new file; you can even specify which columns (branches/leaves) to keep. See also the tutorials linked on the documentation page, for example this one.

2 Likes

Would the filter and snapshot part be inside the main for loop?

Hi @jbrom,

you don’t need to do a for loop over events - RDataFrame takes care of going through the events for you, for example:

And take a look at the tutorial linked above to see how to use snapshot itself.

Cheers,
Marta

1 Like