Analysis TTreeFormat

From GlueXWiki
Revision as of 00:08, 4 May 2013 by Pmatt (Talk | contribs) (Particle Data : Thrown)

Jump to: navigation, search

Why a standard TTree format?

  • For any reaction can streamline (and provide a best-practices implementation/examples of): analysis utilities, BDT setup/input, amplitude analysis setup/input(?)
  • Makes it easy for users to keep everything organized, especially handling of the combinatoric background.
  • Format is designed to be one-size-fits-all, but is still extensible (customizable).

TTree Format - Overview

ROOT Version

  • ROOT >= v5.32 will be required for building DANA
    • Much easier to code TTree creation: TClonesArray::ConstructedAt() can be used instead of calls to placement-new
    • Just about any version of ROOT is fine for reading the data

Data Hierarchy

  • One TTree per DReaction, each stored in a separate ROOT file.
    • e.g., will have different trees for missing/detected recoil proton for the same final state
  • One TTree entry per recorded physics event.
  • One TBranch per variable. (e.g. "RunNumber", "PiMinus__PathLength", etc.)
  • Variables that change with DParticleCombo will be stored in arrays/TClonesArray's: one array index per DParticleCombo
    • e.g.: "PiPlus2__ChiSq_Tracking" (Double_t[]), "Proton__P4_Measured" (TClonesArray(TLorentzVector))
  • Thrown particle data will be stored in arrays: one array index per DMCThrown.
  • Particle hypothesis data that is not used in any DParticleCombo written to the TTree will be stored in arrays: one array index per unused particle hypothesis (DChargedTrackHypothesis and DNeutralParticleHypothesis).
    • Unused beam particles are NOT saved.
  • Event-independent information (e.g. the target, the DReaction decay chain, etc.) is stored in TTree::fUserInfo (a TList*)

Object-Oriented Programming

  • Will provide tool to convert tree branch data into the C++ objects for a given event (callable from TSelector::Process())
    • C++ classes (similar to DANA classes): DTreeEvent, DTreeCombo, DTreeStep, DTreeParticle (compiled into ROOT dictionary & loadable shared library)
    • Can be used to write/execute reusable software that will work for any reaction (e.g. handling double-counting when filling histograms)

To Add/Fix

  • Kinematic fit results (chisq & ndf) from other DReaction's (highest confidence level result only (multiple particle combinations)).
  • Unsigned Integer of #thrown particles of each type (multiplexed).
  • "KINEMATICS: END" variables: currently only the time is saved, the p4 & position are NaN.
  • Locations/Times of each vertex (photoproduction, non-resonance decays) (kinfit & "measured").

Examples

Save Data to TTree

  • The below saves all of the particle combinations (for every DReaction) that survived all of the DAnalysisAction cuts.
    • I'll probably implement a boolean in the DReaction to enable/disable writing the results of individual reactions, but it's not done yet.
//In plugin evnt()
#include "ANALYSIS/DEventWriterROOT.h"
vector<const DEventWriterROOT*> locEventWriterROOTVector;
locEventLoop->Get(locEventWriterROOTVector); //creates the TTrees for all DReactions upon first call
locEventWriterROOTVector[0]->Fill_Trees(locEventLoop);
  • The below allows you to choose which DParticleCombo's (locParticleCombos) of which DReaction's (locReaction) to save.
    • Beware: the locParticleCombos MUST have originated from the locReaction or else this will probably crash (can check DParticleCombo::Get_Reaction()).
//In plugin evnt()
vector<const DEventWriterROOT*> locEventWriterROOTVector;
locEventLoop->Get(locEventWriterROOTVector); //creates the TTrees for all DReactions upon first call
locEventWriterROOTVector[0]->Fill_Tree(locEventLoop, locReaction, locParticleCombos);

Accessing TClonesArray Data

  • TTree:
MyTree->Draw("PiMinus1__P4_Measured->Theta()"); //draws all particle combinations
  • TBrowser (draws all particle combinations):
b1pi Events


  • TSelector (histogram b1pi mass distributions):
GetEntry(entry);
 
//this doesn't take into account double-counting!!
for(unsigned int loc_i = 0; loc_i < NumCombos; ++loc_i) //loop over #combos
{
  TLorentzVector locPiZeroP4;
  locPiZeroP4 += *((TLorentzVector*)Gamma1__P4_KinFit->At(loc_i));
  locPiZeroP4 += *((TLorentzVector*)Gamma2__P4_KinFit->At(loc_i));
  dPiZeroMassHist->Fill(locPiZeroP4.M());
 
  TLorentzVector locOmegaP4 = locPiZeroP4;
  locOmegaP4 += *((TLorentzVector*)PiPlus2__P4_KinFit->At(loc_i));
  locOmegaP4 += *((TLorentzVector*)PiMinus2__P4_KinFit->At(loc_i));
  dOmegaMassHist->Fill(locOmegaP4.M());
 
  TLorentzVector locB1PlusP4 = locOmegaP4;
  locB1PlusP4 += *((TLorentzVector*)PiPlus1__P4_KinFit->At(loc_i));
  dB1PlusMassHist->Fill(locB1PlusP4.M());
 
  TLorentzVector locX2000P4 = locB1PlusP4;
  locX2000P4 += *((TLorentzVector*)PiMinus1__P4_KinFit->At(loc_i));
  dX2000MassHist->Fill(locX2000P4.M());
}

TTree Format - Detail

Particle Names

  • Example Reaction (b1pi):
    • γ p → X(2000), (p)
      • X(2000) → b1(1235)+, π-
        • b1(1235)+ → ω, π+
          • ω → π+, π-, π0
            • π0 → γ γ
  • Reaction Particle Names, Beam: "Beam"
  • Reaction Particle Names, Detected: "PiMinus1," "PiPlus1," "PiPlus2," "PiMinus2," "Gamma1," "Gamma2"
  • Reaction Particle Names, Decaying: "X," "b1_1235_Plus," "omega," "Pi0"
    • No branches are created for these particles. All of their properties are derivable from the other data in the tree
  • Reaction Particle Names, Missing: "Proton"
    • No branches are created for these particles. All of their properties are derivable from the other data in the tree
  • Thrown MC Particle Name: "Thrown"
    • Array entries do NOT correspond to particle combos: just a different particle in each array index
  • Unused Particle Hypothesis Name: "Unused"
    • Array entries do NOT correspond to particle combos: just a different particle hypothesis in each array index

Non-Particle Data

// EVENT DATA
"RunNumber": UInt_t
"EventNumber": UInt_t
 
// # PARTICLES //these are the array sizes for many of the other branches
"NumCombos": UInt_t
"NumThrown": UInt_t
"NumUnused": UInt_t
 
// RF
"RFTime_Thrown": Double_t
"RFTime_Measured": Double_t["NumCombos"]
"RFTime_KinFit": Double_t["NumCombos"] //only if kinematic fit performed
 
// KINEMATIC FIT
"ChiSq_KinFit": Double_t["NumCombos"] //only if kinematic fit performed
"NDF_KinFit": UInt_t["NumCombos"] //only if kinematic fit performed

Particle Data : Thrown

//IDENTIFIERS
"ID": UInt_t["NumThrown"] //each particle has its own #
"ParentID": UInt_t["NumThrown"] //the "ID" of the particle this particle decayed from (0 if none (e.g. photoproduced))
"PID_PDG": Int_t["NumThrown"]
 
//THROWN PARTICLES BY PID
"NumPIDThrown_FinalState": ULong64_t //the # of thrown final-state particles (+ pi0) of each type (multiplexed in base 10)
                                       //types: g, e+, e-, nu, mu+, mu-, pi0, pi+, pi-, KLong, K+, K-, n, p, p-bar, n-bar
                                       //e.g. particles decaying from final-state particles are NOT included (e.g. photons from pi0, muons from pions, etc.)
                                     //is sum of #-of-PID * ParticleMultiplexID() (defined in libraries/include/particleType.h)
                                     //NumParticlesOfPID() returns a different power of 10 for each final-state PID type. 
                                     //if #-of-PID >= 10 then the value will max out at 9.  So 9 is really >= 9.  
"PIDThrown_Decaying": ULong64_t //the types of the thrown decaying particles in the event (multiplexed in base 2)
                                //binary value of a PID is given by ParticleMultiplexID() (defined in libraries/include/particleType.h)
                                //types: most Particle_t's that aren't final state (e.g. lambda, eta, phi, rho0, etc.) see ParticleMultiplexID()
//Can use NumParticlesOfPID() to extract from these variables the result for a given PID type (defined in libraries/include/particleType.h)
 
//KINEMATICS: THROWN  //At the production vertex 
"X4_Thrown": TClonesArray(TLorentzVector["NumThrown"])
"P4_Thrown": TClonesArray(TLorentzVector["NumThrown"])

Particle Data : Beam Reaction Particles

//IDENTIFIER
"ID": ULong64_t["NumCombos"] //each beam particle has its own #
 
//KINEMATICS: MEASURED //At the target center
"X4_Measured": TClonesArray(TLorentzVector["NumCombos"])
"P4_Measured": TClonesArray(TLorentzVector["NumCombos"])
 
//KINEMATICS: KINFIT //At the interaction vertex //only present if kinfit performed
"X4_KinFit": TClonesArray(TLorentzVector["NumCombos"])
"P4_KinFit": TClonesArray(TLorentzVector["NumCombos"])

Particle Data : Detected Reaction Particles

//IDENTIFIER
"ID": ULong64_t["NumCombos"] //each physical particle has its own # (to keep track of different pid hypotheses for the same particle)
 
//KINEMATICS: MEASURED //At the production vertex
"X4_Measured": TClonesArray(TLorentzVector["NumCombos"]) //t is the measured value in TOF/BCAL/FCAL projected back to Position_Measured
"P4_Measured": TClonesArray(TLorentzVector["NumCombos"])
 
// KINEMATICS: END //at the reconstructed position of the BCAL/FCAL/TOF hit
"X4_End": TClonesArray(TLorentzVector["NumCombos"])
"P4_End": TClonesArray(TLorentzVector["NumCombos"])
 
//KINEMATICS: KINFIT //At the production vertex //only present if kinfit performed
"X4_KinFit": TClonesArray(TLorentzVector["NumCombos"])
"P4_KinFit": TClonesArray(TLorentzVector["NumCombos"])
 
// KINEMATICS: OTHER
"PathLength": Double_t["NumCombos"] //from dPosition_KinFit/Measured (KinFit if performed) to dPosition_End
 
// PID QUALITY:
"NDF_Tracking": UInt_t["NumCombos"] //for charged only
"ChiSq_Tracking": Double_t["NumCombos"] //for charged only
"NDF_Timing": UInt_t["NumCombos"]
"ChiSq_Timing": Double_t["NumCombos"] //using kinematic fit data if kinematic fit performed (else measured data)
"ChiSq_Timing_Measured": Double_t["NumCombos"] //using measured data //only if kinematic fit performed
"NDF_DCdEdx": UInt_t["NumCombos"] //for charged only
"ChiSq_DCdEdx": Double_t["NumCombos"] //for charged only
 
// DEPOSITED ENERGY:
"dEdx_CDC": Double_t["NumCombos"] //for charged only
"dEdx_FDC": Double_t["NumCombos"] //for charged only
"dEdx_TOF": Double_t["NumCombos"] //for charged only
"dEdx_ST": Double_t["NumCombos"] //for charged only
"Energy_BCAL": Double_t["NumCombos"]
"Energy_FCAL": Double_t["NumCombos"]

Particle Data : Unused Hypotheses

//IDENTIFIERS
"ID": ULong64_t["NumUnused"] //each physical particle has its own # (to keep track of different pid hypotheses for the same particle)
"PID": UInt_t["NumUnused"] //Particle_t value
 
//KINEMATICS: MEASURED  //At the production vertex 
"P4_Measured": TClonesArray(TLorentzVector["NumUnused"])
"X4_Measured": TClonesArray(TLorentzVector["NumUnused"]) //t is the measured value in TOF/BCAL/FCAL projected back to Position_Measured
 
// KINEMATICS: END //at the reconstructed position of the BCAL/FCAL/TOF hit
"P4_End": TClonesArray(TLorentzVector["NumUnused"])
"X4_End": TClonesArray(TLorentzVector["NumUnused"])
 
// KINEMATICS: OTHER
"PathLength": Double_t["NumUnused"] //from Position_Measured to Position_End
 
// PID QUALITY:
"NDF_Tracking": UInt_t["NumUnused"] //for charged only
"ChiSq_Tracking": Double_t["NumUnused"] //for charged only
"NDF_Timing": UInt_t["NumUnused"]
"ChiSq_Timing": Double_t["NumUnused"]
"NDF_DCdEdx": UInt_t["NumUnused"] //for charged only
"ChiSq_DCdEdx": Double_t["NumUnused"] //for charged only
 
// DEPOSITED ENERGY:
"dEdx_CDC": Double_t["NumUnused"] //for charged only
"dEdx_FDC": Double_t["NumUnused"] //for charged only
"dEdx_TOF": Double_t["NumUnused"] //for charged only
"dEdx_ST": Double_t["NumUnused"] //for charged only
"Energy_BCAL": Double_t["NumUnused"]
"Energy_FCAL": Double_t["NumUnused"]

Event-Independent Information

  • Stored in TTree::fUserInfo (a TList*)
  • "MiscInfoMap": TMap of TObjString -> TObjString
    • "KinFitType" -> DKinFitType (converted to TObjString)
    • "Target" -> Particle_t (converted to TObjString) //if a target particle was specified
    • "Missing" -> Particle_t (converted to TObjString) //if a missing particle was specified
  • "NameToPIDMap": TMap of "UniqueParticleName" (TObjString) -> Particle_t (converted to TObjString)
  • "NameToPositionMap": TMap of "UniqueParticleName" (TObjString) -> "StepIndex_ParticleIndex" (stored in TObjString) (ParticleIndex = -1 for initial, -2 for target, 0+ for final state)
  • "PositionToNameMap": TMap of "StepIndex_ParticleIndex" (stored in TObjString) (ParticleIndex = -1 for initial, -2 for target, 0+ for final state) -> "UniqueParticleName" (TObjString)
  • "PositionToPIDMap": TMap of "StepIndex_ParticleIndex" (stored in TObjString) (ParticleIndex = -1 for initial, -2 for target, 0+ for final state) -> Particle_t (converted to TObjString)

C++ Classes (Not Implemented Yet)

  • Data Structures:
    • DTreeParticle: roughly mirrors DKinematicData: kinematics + PID info of track
    • DTreeStep: roughly mirrors DParticleComboStep: collection of DTreeParticle's for a given step of a reaction (e.g. photoproduction, Λ decay, π0 decay, etc.)
    • DTreeCombo: roughly mirrors DParticleCombo (collection of DTreeStep's for a given reaction), + detected particles not used in the combo
    • DTreeEvent: contains DTreeCombo's for each output DReaction, + thrown tracks
  • Extensible:
    • Each class has maps to contain additional data (TObject* and double, map keys are string): custom branches in the TTree will be added here.
  • Usage:
    • Process with a TSelector.
    • TTree::Draw() and TTree::Project() will not work due to nested classes/containers.

DTreeParticle

  • Roughly mirrors DKinematicData: kinematics + PID info of track
  • p3, v3, and t are stored at both the start (production) and end points (decay, TOF/BCAL/FCAL hit) of the track.
    • This is primarily motivated by the Ξ-, which is long-lived and whose trajectory is bent by the magnetic field before it decays.
  • Extensible: maps can be used by users to add their own custom information.
class DTreeParticle : public TObject
{
  public:
    // PID:
    Particle_t dPID;
 
    // KINEMATICS: Measured
    TVector3 dPosition_Measured; //the position where the particle is produced
    Double_t dTime_Measured; //time of the track at dPosition_Measured, projected from the TOF/BCAL/FCAL hit
    TVector3 dMomentum_Measured; //momentum of the track at dPosition_Start
 
    // KINEMATICS: KinFit 
    TVector3 dPosition_KinFit; //the position where the particle is produced
    Double_t dTime_KinFit; //time of the track at dPosition_KinFit
    TVector3 dMomentum_KinFit; //momentum of the track at dPosition_KinFit
 
    // KINEMATICS: End
    TVector3 dPosition_End; //detected particles: the reconstructed position of the BCAL/FCAL/TOF hit; decaying particles: the point where it decays
    Double_t dTime_End; //time of the track at dPosition_End
    TVector3 dMomentum_End; //momentum of the track at dPosition_End
 
    // KINEMATICS: Other
    Double_t dPathLength; //from dPosition_KinFit/Measured (if kinfit performed/not-performed) to dPosition_End
 
    // PID QUALITY:
    UInt_t dNDF_Tracking;
    Double_t dChiSq_Tracking;
    UInt_t dNDF_Timing;
    Double_t dChiSq_Timing;
    UInt_t dNDF_DCdEdx;
    Double_t dChiSq_DCdEdx;
 
    // DEPOSITED ENERGY:
    map<DetectorSystem_t, Double_t> dDepositedEnergies; //Is dE/dx for all but BCAL/FCAL (shower energies)
 
    // DTREESTEP POINTERS:
    const DTreeStep* dProductionStep; //the step object in which this DTreeParticle is produced (is a final-state particle)
    const DTreeStep* dDecayStep; //the step object in which this DTreeParticle decays (is an initial-state particle) (will be null if not a decaying particle!)
 
    // CUSTOM VARIABLES:
    map<string, Double_t> dCustomVariables; //key is unique string, Double_t is value
    map<string, const TObject*> dCustomObjects; //key is unique string, TObject* is object
 
  ClassDef(DTreeParticle, 1)
};

DTreeStep

  • Roughly mirrors DParticleComboStep: collection of DTreeParticle's for a given step of a reaction (e.g. photoproduction, Λ decay, π0 decay, etc.)
  • Extensible: maps can be used by users to add their own custom information.
class DTreeStep : public TObject
{
  public:
    // INITIAL PARTICLES:
    const DTreeParticle* dInitialParticle; //if is null: decaying or beam particle not yet set!
    const DTreeParticle* dTargetParticle; //NULL for no target
 
    // FINAL PARTICLES:
    deque<DParticle_t> dFinalParticleIDs; //separate in case particle is NULL (e.g. decaying resonance)
    deque<const DTreeParticle*> dFinalParticles; //particle may be NULL if it is decaying or missing (especially if no kinematic fit was performed!!)
 
    // CUSTOM VARIABLES:
    map<string, Double_t> dCustomVariables; //key is unique string, Double_t is value
    map<string, const TObject*> dCustomObjects; //key is unique string, TObject* is object
 
  ClassDef(DTreeStep, 1)
};

DTreeCombo

  • Roughly mirrors DParticleCombo (collection of DTreeStep's for a given reaction), + detected particles not used in the combo
  • Extensible: maps can be used by users to add their own custom information.
class DTreeCombo : public TObject
{
  public:
    // STEPS:
    deque<const DTreeStep*> dTreeSteps;
 
    // RF:
    Double_t dRFTime;
 
    // UNUSED PARTICLES:
    vector<const DTreeParticle*> dUnusedDetectedParticles;
    vector<const DTreeShower*> dUnusedDetectedShowers;
 
    // KINEMATIC FIT:
    DKinFitType dKinematicFitType; //Defined in DKinFitResults.h //d_NoFit if not performed
    Double_t dChiSq_KinematicFit; //NaN if not performed
    UInt_t dNDF_KinematicFit; //0 if not performed
 
    // CUSTOM VARIABLES:
    map<string, Double_t> dCustomVariables; //key is unique string, Double_t is value
    map<string, const TObject*> dCustomObjects; //key is unique string, TObject* is object
 
  ClassDef(DTreeCombo, 1)
};

DTreeEvent

  • Contains DTreeCombo's for each output DReaction, + thrown tracks
  • Extensible: maps can be used by users to add their own custom information.
class DTreeEvent : public TObject
{
  public:
    // RUN, EVENT #'s:
    UInt_t dRunNumber;
    UInt_t dEventNumber;
 
    // DATA:
    map<string, deque<const DTreeCombo*> > dTreeCombos; //string key is (D)Reaction name, deque is the particle combos
    deque<const DTreeParticle*> dThrownParticles;
 
    // CUSTOM VARIABLES:
    map<string, Double_t> dCustomVariables; //key is unique string, Double_t is value
    map<string, const TObject*> dCustomObjects; //key is unique string, TObject* is object
 
  ClassDef(DTreeEvent, 1)
};

Custom Branches

  • This is basically something that you just have to do manually.
//Create the trees
vector<const DEventWriterROOT*> locEventWriterROOTVector;
locEventLoop->Get(locEventWriterROOTVector); //creates the TTrees for all DReactions upon first call
 
//Create the branch
Double_t* locMyVariable = new Double_t;
string locReactionName = locReaction->Get_ReactionName();
string locTreeName = locReactionName + string("_Tree");
japp->RootWriteLock(); //always acquire a lock before accessing the global ROOT file
{
  //get the tree
  gDirectory->cd("/");
  gDirectory->cd(locReactionName.c_str());
  TTree* locTree = (TTree*)gDirectory->Get(locTreeName.c_str());
  locTree->Branch("MyBranchName", locMyVariable, "D");
}
japp->RootUnLock();
 
//Set the data in the branch and fill
japp->RootWriteLock(); //lock: any thread has access to the tbranch
{
  *locMyVariable = 3.0; //or whatever you want to save
}
japp->RootUnLock();
locEventWriterROOTVector[0]->Fill_Trees(locEventLoop);