Analysis TTreeFormat
From GlueXWiki
Revision as of 12:01, 17 April 2013 by Pmatt (Talk | contribs) (→Particle Data : Detected Reaction Particles)
Contents
Why a standard TTree format?
- For any reaction can streamline (and provide a best-practices implementation 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.
- Output can be enabled/disabled with a single flag.
- Format is designed to be one-size-fits-all, but is still extensible (customizable).
TTree Format - General
- ROOT 5.32+ will be required for building BANA (for TClonesArray::ConstructedAt(), which makes it much easier to code tree creation)
- Just about any version of ROOT is fine for reading the data
Events
- One TTree per DReaction
- e.g., will have different trees for missing/detected recoil proton for the same final state
- One TTree entry per recorded physics event.
- Each variable will have it's own TBranch
- Branch name format: "UniqueParticleName"__"VariableName" //note double underscore (so that the variable & particle names can have single underscores)
- Positions and four-momenta will be stored in TVector3 & TLorentzVector objects, all others variables are double or unsigned int.
- Users can add their own custom branches to the tree
Particle Combinations
- In a given entry, the TBranch for each variable holds an array: each index of the array corresponds to a different particle combination.
- So all of the data from particle combination #3 will be stored in index "2" of each array
- Combos will be sorted in the arrays by kinematic fit FOM (if no kinfit performed, then by overall pid FOM) (best listed first)
- TObject data (e.g. TLorentzVector, TVector3) will be stored in TClonesArray's
Saved Data
- Event identification: run#, event#, #particle combinations
- All particle data in all particle combinations (kinematics, PID chisq, dE/dx, etc.)
- All detected particle hypotheses that are not used in any of the recorded particle combinations (e.g. "UnusedPlus")
- All thrown particle data (e.g. "ThrownPlus")
- Miscellaneous data: kinematic fit chisq, rf time, etc.
TTree Format - Detail
- Example Reaction:
- γ p → η'1(2300), p
- η'1(2300) → K*(892)0, K0_bar
- K*(892)0 → K+, π-
- K0_bar → π+, π-
- K*(892)0 → K+, π-
- η'1(2300) → K*(892)0, K0_bar
- γ p → η'1(2300), p
Unique Particle Names
- Reaction Particle Names, Decaying: "EtaPrime1_2300," "KStar892_0," "KShort"
- Reaction Particle Names, Detected: "Proton," "KPlus," "PiMinus1," "PiPlus," "PiMinus2"
- Thrown MC Particle Names: "ThrownPlus," "ThrownMinus," Thrown0"
- Array entries do NOT correspond to particle combos: just a different particle in each array index
- Unused Particle Hypothesis Names: "UnusedPlus," "UnusedMinus," "Unused0"
- Array entries do NOT correspond to particle combos: just a different particle in each array index
Particle Data : Detected Reaction Particles
"ParticleIdentifier": (unsigned int)[] //each physical particle has it's own # (to keep track of different pid hypotheses for the same particle) //KINEMATICS: Start //If kinematic fit was performed, this is the kinematic fit results. Else is measured results. "Position_Start": TClonesArray(TVector3) //the position where the particle is produced "Time_Start": double[] "P4_Start": TClonesArray(TLorentzVector) // KINEMATICS: End "Position_End": TClonesArray(TVector3) //the reconstructed position of the BCAL/FCAL/TOF hit "Time_End": double[] "P4_End": TClonesArray(TLorentzVector) //KINEMATICS: Measured //If kinematic fit was performed, this is the kinematic fit results. Else is measured results. "Position_Start": TClonesArray(TVector3) //the position where the particle is produced "Time_Start": double[] //the measured value in TOF/BCAL/FCAL projected back to dPosition_Start "P4_Start": TClonesArray(TLorentzVector) // KINEMATICS: Other "PathLength": double[] //from dPosition_Start to dPosition_End // PID QUALITY: "NDF_Tracking" //(unsigned int)[] "ChiSq_Tracking" //double[] "NDF_Timing" //(unsigned int)[] "ChiSq_Timing" //using kinematic fit data "ChiSq_Timing_Measured" //using measured data "NDF_DCdEdx" //(unsigned int)[] "ChiSq_DCdEdx" //double[] "" //double[] "" //double[]
Branch Examples
"PiMinus_PathLength" //double[] "PiPlus1_ChiSq_Timing" //double[] "PiPlus2_Momentum_Measured" //
Accessing TClonesArray Data Examples
- TSelector:
GetEntry(entry); cout << ((TLorentzVector*)PiPlus2_Momentum_Measured->At(0))->Px() << endl; //At(): particle combination 0, 1, 2, ...
- TTree:
MyTree->Draw("PiPlus2_Momentum_Start->Px()"); //draws all particle combinations
Summary
- 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): users can add their own custom information here
- Otherwise they can make a friend TTree to add branches to the existing tree.
- Usage:
- Process with a TSelector.
- TTree::Draw() and TTree::Project() will not work due to nested classes/containers.
Cons
- Data is contained in nested deques/maps, which causes problems:
- Impossible to make them split properly for viewing in the TBrowser.
- 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: Start //If kinematic fit was performed, this is the kinematic fit results. Else are identical to the "Measured" kinematics. TVector3 dPosition_Start; //the position where the particle is produced double dTime_Start; //time of the track at dPosition_Start TVector3 dMomentum_Start; //momentum of the track at dPosition_Start TMatrixDSym dCovarianceMatrix; //at dPosition_Start // Order is (px, py, pz, x, y, z, t) // KINEMATICS: End TVector3 dPosition_End; //detected particles: the reconstructed position of the BCAL/FCAL/TOF hit; decaying particles: the point where it decays double dTime_End; //time of the track at dPosition_End TVector3 dMomentum_End; //momentum of the track at dPosition_End // KINEMATICS: Measured TVector3 dPosition_Measured; //the position where the particle is produced double 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: Other double dPathLength; //from dPosition_Start to dPosition_End // PID QUALITY: unsigned int dNDF_Tracking; double dChiSq_Tracking; unsigned int dNDF_Timing; double dChiSq_Timing; unsigned int dNDF_DCdEdx; double dChiSq_DCdEdx; // DEPOSITED ENERGY: map<DetectorSystem_t, double> 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> dCustomVariables; //key is unique string, double 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> dCustomVariables; //key is unique string, double 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: bool dRFTimeMatchQuality; //true if good (certain), false if bad (not confident in value (e.g. no "good" tracks have TOF hits)) double dRFTime; double dRFTimeUncertainty; // UNUSED PARTICLES: vector<const DTreeParticle*> dUnusedDetectedParticles; vector<const DTreeShower*> dUnusedDetectedShowers; // KINEMATIC FIT: DKinFitType dKinematicFitType; //Defined in DKinFitResults.h //d_NoFit if not performed double dChiSq_KinematicFit; //NaN if not performed unsigned int dNDF_KinematicFit; //0 if not performed // CUSTOM VARIABLES: map<string, double> dCustomVariables; //key is unique string, double 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: unsigned int dRunNumber; unsigned int 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> dCustomVariables; //key is unique string, double is value map<string, const TObject*> dCustomObjects; //key is unique string, TObject* is object ClassDef(DTreeEvent, 1) };
Usage Example: Create & Process Tree
- ROOT can't handle nested classes/containers as branches inside of TTree's. Therefore:
- rootcint is used to create a shared object library containing the DTreeEvent, DTreeParticle, etc. objects, which then needs to be loaded prior to processing the TTree.
- Only one branch is created: the one for DTreeEvent.
- TTree::Draw() and TTree::Project() don't work.
Create Tree
- This would be done "under-the-hood" in DANA, but a simple example is shown here: 1 event containing 1 combo, 1 step and 1 particle
void Create_Tree(void) { //load library, create file & tree gSystem->Load("libBANA_ROOT_TREE.so"); TFile* locFile = new TFile("test.root", "RECREATE"); TTree* locTree = new TTree("testtree", "testtree"); //create event: THE ONLY BRANCH ON THE TREE (set run & event #'s) DTreeEvent* locTreeEvent = new DTreeEvent(); locTree->Branch("dTreeEvent", locTreeEvent, 32000, 0); //splitlevel = 0 makes sure no sub-branches are created (ROOT doesn't do them correctly) locTreeEvent->dRunNumber = 12345; locTreeEvent->dEventNumber = 67890; //create a step with one particle in it, set start time DTreeStep* locTreeStep = new DTreeStep(); DTreeParticle* locTreeParticle = new DTreeParticle(); locTreeParticle->dTime_Start = 2.0; locTreeStep->dFinalParticles.push_back(locTreeParticle); //put the step in the combo DTreeCombo* locTreeCombo = new DTreeCombo(); locTreeCombo->dTreeSteps.push_back(locTreeStep); //put the combo in the tree deque<const DTreeCombo*> locCombos; locCombos.push_back(locTreeCombo); string locReactionName = "TestReaction"; locTreeEvent->dTreeCombos[locReactionName] = locCombos; locTree->Fill(); locFile->Write(); locFile->Close(); }
Sample TSelector
Bool_t MySelector::Process(Long64_t entry) { //dTreeEvent IS THE ONLY BRANCH (DTreeEvent*) GetEntry(entry); cout << "run, event #'s: " << dTreeEvent->dRunNumber << ", " << dTreeEvent->dEventNumber << endl; //get the combos for the given reaction string locReactionName = "TestReaction"; deque<const DTreeCombo*> locTreeCombos = dTreeEvent->dTreeCombos[locReactionName]; //grab the step, particle, and start time const DTreeStep* locTreeStep = locTreeCombos[0]->dTreeSteps[0]; const DTreeParticle* locTreeParticle = locTreeStep->dFinalParticles[0]; cout << "t = " << locTreeParticle->dTime_Start << endl; }
Process Tree
void Process_Tree(void) { string locHallDHome = getenv("HALLD_HOME"); string locIncludePath = locHallDHome + string("/include/"); gInterpreter->AddIncludePath(locIncludePath.c_str()); //for particleType.h and whatever else is needed gSystem->Load("libBANA_ROOT_TREE.so"); //load the class definitions so that can read the "dTreeEvent" tree branch TFile* locFile = new TFile("test.root", "READ"); TTree* locTree = (TTree*)locFile->Get("testtree"); locTree->Process("MySelector.C"); //process the events in the tree with this TSelector }