Difference between revisions of "Analysis TTreeFormat"
From GlueXWiki
(→Save Data to TTree) |
(→Accessing TClonesArray Data) |
||
Line 66: | Line 66: | ||
//this doesn't take into account double-counting!! | //this doesn't take into account double-counting!! | ||
− | for( | + | for(UInt_t loc_i = 0; loc_i < NumCombos; ++loc_i) //loop over #combos |
{ | { | ||
TLorentzVector locPiZeroP4; | TLorentzVector locPiZeroP4; |
Revision as of 18:39, 9 May 2013
Contents
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)
Usage
Save Data to TTree
- To save data to a TTree for a given DReaction, TTree output must be first be enabled for that reaction. See DReaction Control Variables for details.
- The below saves all of the particle combinations (for TTree-output-enabled DReaction's created in the factory specified by the tag) that survived all of the DAnalysisAction cuts.
//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, "b1pi_hists"); //string is the DReaction factory tag that the DReactions were created in
- 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() #include "ANALYSIS/DEventWriterROOT.h" 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):
- TSelector (histogram b1pi mass distributions):
GetEntry(entry); //this doesn't take into account double-counting!! for(UInt_t 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 → γ γ
- ω → π+, π-, π0
- b1(1235)+ → ω, π+
- X(2000) → b1(1235)+, π-
- γ p → X(2000), (p)
- 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 (in order from 10^0 -> 10^15): 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 * 10^ParticleMultiplexPower() (defined in libraries/include/particleType.h) //ParticleMultiplexPower() 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 a value of 9 should be interpreted as >= 9. "PIDThrown_Decaying": ULong64_t //the types of the thrown decaying particles in the event (multiplexed in base 2) //binary power of a PID is given by ParticleMultiplexPower() (defined in libraries/include/particleType.h) //types: most Particle_t's that aren't final state (e.g. lambda, eta, phi, rho0, etc.) see ParticleMultiplexPower() //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_Measured": Double_t["NumCombos"] //using measured data "ChiSq_Timing_KinFit": Double_t["NumCombos"] //using kinematic fit data //only present if kinfit 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);